@elevasis/ui 2.10.0 → 2.10.2

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.
@@ -4,13 +4,13 @@ import { ResourceHealthPanel } from './chunk-TSX4I3NW.js';
4
4
  import { PageContainer } from './chunk-BZZCNLT6.js';
5
5
  import { SubshellSidebarSection } from './chunk-IIMU5YAJ.js';
6
6
  import { CustomModal, ConfirmationModal } from './chunk-GBMNCNHX.js';
7
- import { BaseNode, useGraphTheme, BaseEdge, ExecutionStats, UnifiedWorkflowGraph, WorkflowExecutionTimeline, AgentExecutionVisualizer, AgentExecutionTimeline, GraphBackground, GraphFitViewButton, GraphFitViewHandler } from './chunk-U23TW6NP.js';
7
+ import { BaseNode, useGraphTheme, BaseEdge, ExecutionStats, UnifiedWorkflowGraph, WorkflowExecutionTimeline, AgentExecutionVisualizer, AgentExecutionTimeline, GraphBackground, GraphFitViewButton, GraphFitViewHandler } from './chunk-GJVGV7QZ.js';
8
8
  import { useCyberColors, CyberDonut } from './chunk-STZJ7SY5.js';
9
9
  import { AppShellLoader } from './chunk-YEX4MQSY.js';
10
10
  import { getResourceStatusColor, useMergedExecution, useTimelineData, useAgentIterationData, getStatusIcon } from './chunk-XA34RETF.js';
11
- import { useErrorDetail, useExecution, useArchivedLogs, useDeleteExecution, useRetryExecution, useCancelExecution, useCommandQueueTotals, useStatusFilter, useResourceSearch, useResourcesDomainFilters, usePaginationState, useResources, useRecentExecutionsByResource, filterByDomainFilters, useExecuteAsync, useResourceDefinition, isSessionCapable, useDeleteTask, useCommandQueue, useSubmitAction, useCommandViewData, useCommandViewStats, useResourceExecutions, useCheckpointTasks, useCommandViewStore, useCommandViewDomainFilters, useExecutionPanelState, useDeleteSession, useCreateSession, useSessions, useSessionExecutions, useSession, showApiErrorNotification, showSuccessNotification, useBulkDeleteExecutions } from './chunk-E3IFHX6A.js';
11
+ import { useErrorDetail, useExecution, useArchivedLogs, useDeleteExecution, useRetryExecution, useCancelExecution, useCommandQueueTotals, useStatusFilter, useResourceSearch, useResourcesDomainFilters, usePaginationState, useResources, useRecentExecutionsByResource, filterByDomainFilters, useExecuteAsync, useResourceDefinition, isSessionCapable, useDeleteTask, useCommandQueue, useSubmitAction, useCommandViewData, useCommandViewStats, useCommandViewStore, useResourceExecutions, useCheckpointTasks, useExecutionPanelState, useDeleteSession, useCreateSession, useSessions, useSessionExecutions, useSession, showApiErrorNotification, showSuccessNotification, useBulkDeleteExecutions } from './chunk-E3IFHX6A.js';
12
12
  import { useGraphHighlighting, calculateGraphHeight, Graph_module_css_default, GRAPH_CONSTANTS } from './chunk-22UVE3RA.js';
13
- import { useOptionalElevasisFeatures, useElevasisFeatures } from './chunk-USVBMGMP.js';
13
+ import { useOptionalElevasisFeatures, useElevasisFeatures } from './chunk-C7BX547M.js';
14
14
  import { SubshellContentContainer } from './chunk-RX4UWZZR.js';
15
15
  import { JsonViewer, CardHeader, PageTitleCaption, CollapsibleSection, TabCountBadge, ResourceCard, ContextViewer, EmptyState, APIErrorAlert } from './chunk-SQQGLGHW.js';
16
16
  import { StyledMarkdown } from './chunk-3KMDHCAR.js';
@@ -24,10 +24,10 @@ import { useOrganization } from './chunk-DD3CCMCZ.js';
24
24
  import { useRouterContext } from './chunk-Q7DJKLEN.js';
25
25
  import { z } from 'zod';
26
26
  import { Stack, Group, Text, Badge, TextInput, Textarea, Radio, Checkbox, Select, NumberInput, Title, Alert, Button, ActionIcon, Collapse, Card, ThemeIcon, SimpleGrid, Divider, Paper, Space, CopyButton, Center, Tooltip, Code, Menu, useMantineTheme, UnstyledButton, RangeSlider, Loader, Box, Progress, Tabs, Pagination, Modal, LoadingOverlay, SegmentedControl, Switch, ScrollArea, MultiSelect } from '@mantine/core';
27
- import { IconBrain, IconFileText, IconMail, IconSend, IconClock, IconArrowUp, IconMessageCircle, IconRocket, IconEye, IconEdit, IconAlertTriangle, IconRefresh, IconX, IconCheck, IconCode, IconAlertCircle, IconChevronRight, IconTool, IconSettings, IconCpu, IconClockHour4, IconVersions, IconPlayerPlay, IconNetwork, IconSitemap, IconCopy, IconPlayerStop, IconReload, IconTrash, IconTerminal2, IconBug, IconChevronDown, IconMessage, IconArrowLeft, IconRobot, IconGitBranch, IconDotsVertical, IconFilter, IconCircleCheck, IconCategory, IconDatabase, IconApps, IconRoute, IconAdjustmentsHorizontal, IconSearch, IconCircleX, IconCircleDashed, IconExternalLink, IconTopologyStar3, IconInfoCircle, IconPlus, IconLayoutSidebarRightExpand, IconNote, IconArchive, IconDownload, IconTimeline, IconArrowsMaximize, IconShare2, IconHistory } from '@tabler/icons-react';
27
+ import { IconBrain, IconFileText, IconMail, IconSend, IconClock, IconArrowUp, IconMessageCircle, IconRocket, IconEye, IconEdit, IconAlertTriangle, IconRefresh, IconX, IconCheck, IconCode, IconAlertCircle, IconChevronRight, IconTool, IconSettings, IconCpu, IconClockHour4, IconVersions, IconPlayerPlay, IconNetwork, IconSitemap, IconCopy, IconPlayerStop, IconReload, IconTrash, IconTerminal2, IconBug, IconChevronDown, IconMessage, IconArrowLeft, IconRobot, IconGitBranch, IconDotsVertical, IconFilter, IconCircleCheck, IconCategory, IconDatabase, IconApps, IconRoute, IconAdjustmentsHorizontal, IconSearch, IconCircleX, IconCircleDashed, IconExternalLink, IconTopologyStar3, IconInfoCircle, IconPlus, IconLayoutSidebarRightExpand, IconNote, IconArchive, IconDownload, IconTimeline, IconActivityHeartbeat, IconClockPause, IconArrowsMaximize, IconShare2, IconHistory } from '@tabler/icons-react';
28
28
  import { useForm } from '@mantine/form';
29
29
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
30
- import { memo, useState, useMemo, useRef, useCallback, useEffect, useDeferredValue } from 'react';
30
+ import { memo, useState, useMemo, useRef, useCallback, useEffect, useDeferredValue, useEffectEvent } from 'react';
31
31
  import { ReactFlowProvider, ReactFlow } from '@xyflow/react';
32
32
  import dagre from '@dagrejs/dagre';
33
33
  import '@xyflow/react/dist/style.css';
@@ -35,6 +35,7 @@ import { useClipboard } from '@mantine/hooks';
35
35
  import { notifications } from '@mantine/notifications';
36
36
  import { useNavigate } from '@tanstack/react-router';
37
37
  import cytoscape from 'cytoscape';
38
+ import { create } from 'zustand';
38
39
  import { formatDistanceToNow } from 'date-fns';
39
40
 
40
41
  // ../core/src/platform/utils/debounce.ts
@@ -154,6 +155,7 @@ var SurfaceDefinitionSchema = z.object({
154
155
  path: PathSchema,
155
156
  surfaceType: SurfaceTypeSchema,
156
157
  description: DescriptionSchema.optional(),
158
+ enabled: z.boolean().default(true),
157
159
  icon: IconNameSchema.optional(),
158
160
  featureId: ModelIdSchema.optional(),
159
161
  featureIds: ReferenceIdsSchema,
@@ -4916,11 +4918,31 @@ var ORGANIZATION_GRAPH_NODE_KIND_LABELS = {
4916
4918
  var DEFAULT_ORGANIZATION_GRAPH_FILTERS = {
4917
4919
  search: "",
4918
4920
  nodeKinds: [],
4919
- topologyPresence: "all"
4921
+ topologyPresence: "all",
4922
+ environmentStatus: "all",
4923
+ resourceTypes: [],
4924
+ showIntegrations: true,
4925
+ domainFilters: {}
4920
4926
  };
4921
4927
 
4922
4928
  // src/features/operations/organization-graph/helpers.ts
4923
4929
  var TOPLOGY_EDGE_TYPES = /* @__PURE__ */ new Set(["maps_to", "triggers", "uses", "approval"]);
4930
+ function getCommandViewNodes(data) {
4931
+ return [
4932
+ ...data.agents,
4933
+ ...data.workflows,
4934
+ ...data.triggers,
4935
+ ...data.integrations,
4936
+ ...data.externalResources,
4937
+ ...data.humanCheckpoints
4938
+ ];
4939
+ }
4940
+ function getCommandViewNodeForGraphNode(node, commandViewData) {
4941
+ if (!commandViewData || node.kind !== "resource" || !node.sourceId) {
4942
+ return null;
4943
+ }
4944
+ return getCommandViewNodes(commandViewData).find((item) => item.resourceId === node.sourceId) ?? null;
4945
+ }
4924
4946
  function normalizeText(value) {
4925
4947
  return value.trim().toLowerCase();
4926
4948
  }
@@ -4928,6 +4950,9 @@ function includesQuery(value, query) {
4928
4950
  if (!value) return false;
4929
4951
  return normalizeText(value).includes(query);
4930
4952
  }
4953
+ function titleCase3(value) {
4954
+ return value.replace(/_/g, " ").split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
4955
+ }
4931
4956
  function isTopologyEdge(edge) {
4932
4957
  return TOPLOGY_EDGE_TYPES.has(edge.kind) || Boolean(edge.relationshipType);
4933
4958
  }
@@ -4941,7 +4966,11 @@ function createOrganizationGraphFilters(partial) {
4941
4966
  return {
4942
4967
  search: partial?.search ?? DEFAULT_ORGANIZATION_GRAPH_FILTERS.search,
4943
4968
  nodeKinds: partial?.nodeKinds ? [...partial.nodeKinds] : [...DEFAULT_ORGANIZATION_GRAPH_FILTERS.nodeKinds],
4944
- topologyPresence: partial?.topologyPresence ?? DEFAULT_ORGANIZATION_GRAPH_FILTERS.topologyPresence
4969
+ topologyPresence: partial?.topologyPresence ?? DEFAULT_ORGANIZATION_GRAPH_FILTERS.topologyPresence,
4970
+ environmentStatus: partial?.environmentStatus ?? DEFAULT_ORGANIZATION_GRAPH_FILTERS.environmentStatus,
4971
+ resourceTypes: partial?.resourceTypes ? [...partial.resourceTypes] : [...DEFAULT_ORGANIZATION_GRAPH_FILTERS.resourceTypes],
4972
+ showIntegrations: partial?.showIntegrations ?? DEFAULT_ORGANIZATION_GRAPH_FILTERS.showIntegrations,
4973
+ domainFilters: partial?.domainFilters ? { ...partial.domainFilters } : { ...DEFAULT_ORGANIZATION_GRAPH_FILTERS.domainFilters }
4945
4974
  };
4946
4975
  }
4947
4976
  function normalizeOrganizationGraphSearch(search) {
@@ -4949,7 +4978,16 @@ function normalizeOrganizationGraphSearch(search) {
4949
4978
  }
4950
4979
  function getOrganizationGraphNodePresence(node, incidentEdges) {
4951
4980
  if (node.kind === "resource") {
4952
- return "topology-only";
4981
+ const relevantEdges = incidentEdges.filter((edge) => edge.kind !== "contains");
4982
+ const hasTopologyEdges2 = relevantEdges.some(isTopologyEdge);
4983
+ const hasSemanticEdges2 = relevantEdges.some(isSemanticEdge);
4984
+ if (hasTopologyEdges2 && hasSemanticEdges2) {
4985
+ return "bridge";
4986
+ }
4987
+ if (hasTopologyEdges2) {
4988
+ return "topology-only";
4989
+ }
4990
+ return "semantic-only";
4953
4991
  }
4954
4992
  const hasTopologyEdges = incidentEdges.some(isTopologyEdge);
4955
4993
  const hasSemanticEdges = incidentEdges.some(isSemanticEdge);
@@ -4974,10 +5012,65 @@ function getOrganizationGraphNodeKindOptions(kinds = ORGANIZATION_GRAPH_NODE_KIN
4974
5012
  label: ORGANIZATION_GRAPH_NODE_KIND_LABELS[kind]
4975
5013
  }));
4976
5014
  }
5015
+ function getOrganizationGraphResourceTypeOptions(resourceTypes = [
5016
+ "workflow",
5017
+ "agent",
5018
+ "trigger",
5019
+ "integration",
5020
+ "external",
5021
+ "human_checkpoint"
5022
+ ]) {
5023
+ return resourceTypes.map((resourceType) => ({
5024
+ resourceType,
5025
+ label: titleCase3(resourceType)
5026
+ }));
5027
+ }
5028
+ function getNodeStatus(node, commandViewData) {
5029
+ const commandViewNode = getCommandViewNodeForGraphNode(node, commandViewData);
5030
+ if (commandViewNode) {
5031
+ return commandViewNode.status;
5032
+ }
5033
+ return "status" in node && typeof node.status === "string" ? node.status : void 0;
5034
+ }
5035
+ function getExplicitNodeDomains(node, commandViewData) {
5036
+ const commandViewNode = getCommandViewNodeForGraphNode(node, commandViewData);
5037
+ if (commandViewNode?.domains?.length) {
5038
+ return commandViewNode.domains;
5039
+ }
5040
+ if (!("domains" in node) || !Array.isArray(node.domains)) {
5041
+ return [];
5042
+ }
5043
+ return node.domains.filter((domain) => typeof domain === "string");
5044
+ }
5045
+ function getNodeDomains(graph, node, commandViewData) {
5046
+ const explicitDomains = getExplicitNodeDomains(node, commandViewData);
5047
+ if (explicitDomains.length > 0) {
5048
+ return explicitDomains;
5049
+ }
5050
+ if (node.kind === "feature") {
5051
+ return node.sourceId ? [node.sourceId] : [];
5052
+ }
5053
+ if (node.kind !== "resource") {
5054
+ return [];
5055
+ }
5056
+ const domainIds = /* @__PURE__ */ new Set();
5057
+ for (const edge of graph.edges) {
5058
+ if (edge.sourceId !== node.id) {
5059
+ continue;
5060
+ }
5061
+ const targetNode = graph.nodes.find((candidate) => candidate.id === edge.targetId);
5062
+ if (targetNode?.kind === "feature" && targetNode.sourceId) {
5063
+ domainIds.add(targetNode.sourceId);
5064
+ }
5065
+ }
5066
+ return [...domainIds];
5067
+ }
4977
5068
  function matchesOrganizationGraphNodeSearch(node, search) {
4978
5069
  const query = normalizeOrganizationGraphSearch(search);
4979
5070
  if (!query) return true;
4980
- return includesQuery(node.id, query) || includesQuery(node.label, query) || includesQuery(node.description, query) || includesQuery(node.sourceId, query) || includesQuery(node.featureId, query) || includesQuery(node.surfaceType, query) || includesQuery(node.resourceType, query) || includesQuery(node.kind, query);
5071
+ const nodeStatus = getNodeStatus(node);
5072
+ const nodeDomains = getExplicitNodeDomains(node);
5073
+ return includesQuery(node.id, query) || includesQuery(node.label, query) || includesQuery(node.description, query) || includesQuery(node.sourceId, query) || includesQuery(node.featureId, query) || includesQuery(node.surfaceType, query) || includesQuery(node.resourceType, query) || includesQuery(nodeStatus, query) || nodeDomains.some((domain) => includesQuery(domain, query)) || includesQuery(node.kind, query);
4981
5074
  }
4982
5075
  function matchesOrganizationGraphEdgeSearch(edge, graph, search) {
4983
5076
  const query = normalizeOrganizationGraphSearch(search);
@@ -4990,17 +5083,71 @@ function matchesTopologyPresence(nodePresence, topologyPresence) {
4990
5083
  if (topologyPresence === "all") return true;
4991
5084
  return nodePresence === topologyPresence;
4992
5085
  }
4993
- function filterOrganizationGraph(graph, filters) {
4994
- const normalizedSearch = normalizeOrganizationGraphSearch(filters.search);
5086
+ function hasActiveDomainFilters(domainFilters) {
5087
+ return Object.values(domainFilters).some((filterState) => filterState !== "neutral");
5088
+ }
5089
+ function matchesDomainFilters(graph, node, domainFilters, commandViewData) {
5090
+ if (!hasActiveDomainFilters(domainFilters)) {
5091
+ return true;
5092
+ }
5093
+ const includedDomains = Object.entries(domainFilters).filter(([, filterState]) => filterState === "include").map(([domainId]) => domainId);
5094
+ const excludedDomains = Object.entries(domainFilters).filter(([, filterState]) => filterState === "exclude").map(([domainId]) => domainId);
5095
+ const nodeDomains = getNodeDomains(graph, node, commandViewData);
5096
+ if (excludedDomains.length > 0 && nodeDomains.some((domainId) => excludedDomains.includes(domainId))) {
5097
+ return false;
5098
+ }
5099
+ if (includedDomains.length > 0 && !nodeDomains.some((domainId) => includedDomains.includes(domainId))) {
5100
+ return false;
5101
+ }
5102
+ return true;
5103
+ }
5104
+ function matchesEnvironmentStatus(node, environmentStatus, commandViewData) {
5105
+ if (environmentStatus === "all") {
5106
+ return true;
5107
+ }
5108
+ const nodeStatus = getNodeStatus(node, commandViewData);
5109
+ if (!nodeStatus) {
5110
+ return true;
5111
+ }
5112
+ return nodeStatus === environmentStatus;
5113
+ }
5114
+ function matchesResourceTypeFilters(node, resourceTypes) {
5115
+ if (node.kind !== "resource" || resourceTypes.length === 0) {
5116
+ return true;
5117
+ }
5118
+ return Boolean(node.resourceType && resourceTypes.includes(node.resourceType));
5119
+ }
5120
+ function matchesIntegrationVisibility(node, showIntegrations) {
5121
+ if (showIntegrations) {
5122
+ return true;
5123
+ }
5124
+ return !(node.kind === "resource" && node.resourceType === "integration");
5125
+ }
5126
+ function filterOrganizationGraph(graph, filters, options) {
5127
+ const normalizedFilters = createOrganizationGraphFilters(filters);
5128
+ const normalizedSearch = normalizeOrganizationGraphSearch(normalizedFilters.search);
4995
5129
  const nodePresenceMap = getOrganizationGraphNodePresenceMap(graph);
4996
- const selectedKinds = new Set(filters.nodeKinds);
5130
+ const selectedKinds = new Set(normalizedFilters.nodeKinds);
5131
+ const commandViewData = options?.commandViewData;
4997
5132
  const visibleNodeIds = /* @__PURE__ */ new Set();
4998
5133
  for (const node of graph.nodes) {
4999
5134
  if (selectedKinds.size > 0 && !selectedKinds.has(node.kind)) {
5000
5135
  continue;
5001
5136
  }
5137
+ if (!matchesIntegrationVisibility(node, normalizedFilters.showIntegrations)) {
5138
+ continue;
5139
+ }
5140
+ if (!matchesResourceTypeFilters(node, normalizedFilters.resourceTypes)) {
5141
+ continue;
5142
+ }
5143
+ if (!matchesEnvironmentStatus(node, normalizedFilters.environmentStatus, commandViewData)) {
5144
+ continue;
5145
+ }
5146
+ if (!matchesDomainFilters(graph, node, normalizedFilters.domainFilters, commandViewData)) {
5147
+ continue;
5148
+ }
5002
5149
  const presence = nodePresenceMap.get(node.id) ?? "semantic-only";
5003
- if (!matchesTopologyPresence(presence, filters.topologyPresence)) {
5150
+ if (!matchesTopologyPresence(presence, normalizedFilters.topologyPresence)) {
5004
5151
  continue;
5005
5152
  }
5006
5153
  if (normalizedSearch && !matchesOrganizationGraphNodeSearch(node, normalizedSearch)) {
@@ -5035,13 +5182,18 @@ function filterOrganizationGraph(graph, filters) {
5035
5182
  };
5036
5183
  }
5037
5184
  function isOrganizationGraphFilterPristine(filters) {
5038
- return normalizeOrganizationGraphSearch(filters.search) === "" && filters.nodeKinds.length === 0 && filters.topologyPresence === DEFAULT_ORGANIZATION_GRAPH_FILTERS.topologyPresence;
5185
+ return normalizeOrganizationGraphSearch(filters.search) === "" && filters.nodeKinds.length === 0 && filters.topologyPresence === DEFAULT_ORGANIZATION_GRAPH_FILTERS.topologyPresence && filters.environmentStatus === DEFAULT_ORGANIZATION_GRAPH_FILTERS.environmentStatus && filters.resourceTypes.length === 0 && filters.showIntegrations === DEFAULT_ORGANIZATION_GRAPH_FILTERS.showIntegrations && !hasActiveDomainFilters(filters.domainFilters);
5039
5186
  }
5040
5187
  var TOPOLOGY_PRESENCE_OPTIONS = [
5041
5188
  { label: "All", value: "all" },
5042
5189
  { label: "Semantic only", value: "semantic-only" },
5043
5190
  { label: "Topology only", value: "topology-only" }
5044
5191
  ];
5192
+ var ENVIRONMENT_STATUS_OPTIONS = [
5193
+ { label: "All", value: "all" },
5194
+ { label: "Prod", value: "prod" },
5195
+ { label: "Dev", value: "dev" }
5196
+ ];
5045
5197
  function OrganizationGraphFilterToolbar({
5046
5198
  value,
5047
5199
  onChange,
@@ -5049,10 +5201,15 @@ function OrganizationGraphFilterToolbar({
5049
5201
  disabled = false,
5050
5202
  searchPlaceholder = "Search nodes, relationships, or IDs",
5051
5203
  kindLabel = "Node kinds",
5204
+ resourceTypeLabel = "Resource types",
5052
5205
  topologyLabel = "Relationship presence",
5053
- resetLabel = "Reset filters"
5206
+ environmentLabel = "Environment",
5207
+ showIntegrationsLabel = "Show integrations",
5208
+ resetLabel = "Reset filters",
5209
+ resetValue = createOrganizationGraphFilters()
5054
5210
  }) {
5055
5211
  const kindOptions = getOrganizationGraphNodeKindOptions(availableKinds);
5212
+ const resourceTypeOptions = getOrganizationGraphResourceTypeOptions();
5056
5213
  const canReset = !isOrganizationGraphFilterPristine(value);
5057
5214
  return /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
5058
5215
  /* @__PURE__ */ jsx(
@@ -5085,6 +5242,22 @@ function OrganizationGraphFilterToolbar({
5085
5242
  disabled
5086
5243
  }
5087
5244
  ),
5245
+ /* @__PURE__ */ jsx(
5246
+ MultiSelect,
5247
+ {
5248
+ label: resourceTypeLabel,
5249
+ placeholder: "All resource types",
5250
+ data: resourceTypeOptions.map((option) => ({ value: option.resourceType, label: option.label })),
5251
+ value: value.resourceTypes,
5252
+ onChange: (resourceTypes) => onChange({
5253
+ ...value,
5254
+ resourceTypes
5255
+ }),
5256
+ searchable: true,
5257
+ clearable: true,
5258
+ disabled
5259
+ }
5260
+ ),
5088
5261
  /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
5089
5262
  /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: topologyLabel }),
5090
5263
  /* @__PURE__ */ jsx(
@@ -5102,25 +5275,95 @@ function OrganizationGraphFilterToolbar({
5102
5275
  }
5103
5276
  )
5104
5277
  ] }),
5278
+ /* @__PURE__ */ jsxs(Stack, { gap: 6, children: [
5279
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: environmentLabel }),
5280
+ /* @__PURE__ */ jsx(
5281
+ SegmentedControl,
5282
+ {
5283
+ value: value.environmentStatus,
5284
+ onChange: (environmentStatus) => onChange({
5285
+ ...value,
5286
+ environmentStatus
5287
+ }),
5288
+ data: ENVIRONMENT_STATUS_OPTIONS,
5289
+ size: "sm",
5290
+ fullWidth: true,
5291
+ disabled
5292
+ }
5293
+ )
5294
+ ] }),
5295
+ /* @__PURE__ */ jsx(
5296
+ Switch,
5297
+ {
5298
+ label: showIntegrationsLabel,
5299
+ description: "Hide integration resources and their relationship edges.",
5300
+ checked: value.showIntegrations,
5301
+ onChange: (event) => onChange({
5302
+ ...value,
5303
+ showIntegrations: event.currentTarget.checked
5304
+ }),
5305
+ size: "sm",
5306
+ disabled
5307
+ }
5308
+ ),
5105
5309
  /* @__PURE__ */ jsx(Group, { justify: "flex-end", children: /* @__PURE__ */ jsx(
5106
5310
  Button,
5107
5311
  {
5108
5312
  variant: "subtle",
5109
5313
  leftSection: /* @__PURE__ */ jsx(IconRefresh, { size: 14 }),
5110
- onClick: () => onChange({ search: "", nodeKinds: [], topologyPresence: "all" }),
5314
+ onClick: () => onChange(resetValue),
5111
5315
  disabled: disabled || !canReset,
5112
5316
  children: resetLabel
5113
5317
  }
5114
5318
  ) })
5115
5319
  ] });
5116
5320
  }
5321
+ var useOrganizationGraphFiltersStore = create((set) => ({
5322
+ filtersByScope: {},
5323
+ initializeScope: (scope, initialFilters) => set((state) => {
5324
+ if (state.filtersByScope[scope]) {
5325
+ return state;
5326
+ }
5327
+ return {
5328
+ filtersByScope: {
5329
+ ...state.filtersByScope,
5330
+ [scope]: createOrganizationGraphFilters(initialFilters)
5331
+ }
5332
+ };
5333
+ }),
5334
+ updateScope: (scope, next) => set((state) => ({
5335
+ filtersByScope: {
5336
+ ...state.filtersByScope,
5337
+ [scope]: createOrganizationGraphFilters({
5338
+ ...state.filtersByScope[scope],
5339
+ ...next
5340
+ })
5341
+ }
5342
+ })),
5343
+ resetScope: (scope, initialFilters) => set((state) => ({
5344
+ filtersByScope: {
5345
+ ...state.filtersByScope,
5346
+ [scope]: createOrganizationGraphFilters(initialFilters)
5347
+ }
5348
+ }))
5349
+ }));
5350
+ function getOrganizationGraphFilterScope(initialFilters) {
5351
+ return JSON.stringify(createOrganizationGraphFilters(initialFilters));
5352
+ }
5117
5353
  function useOrganizationGraphFilters(initialFilters) {
5118
- const [filters, setFilters] = useState(() => createOrganizationGraphFilters(initialFilters));
5354
+ const scopeRef = useRef(getOrganizationGraphFilterScope(initialFilters));
5355
+ const fallbackFiltersRef = useRef(createOrganizationGraphFilters(initialFilters));
5356
+ const filters = useOrganizationGraphFiltersStore(
5357
+ (state) => state.filtersByScope[scopeRef.current] ?? fallbackFiltersRef.current
5358
+ );
5359
+ const initializeScope = useOrganizationGraphFiltersStore((state) => state.initializeScope);
5360
+ const updateScope = useOrganizationGraphFiltersStore((state) => state.updateScope);
5361
+ const resetScope = useOrganizationGraphFiltersStore((state) => state.resetScope);
5362
+ useEffect(() => {
5363
+ initializeScope(scopeRef.current, initialFilters);
5364
+ }, [initialFilters, initializeScope]);
5119
5365
  const updateFilters = (next) => {
5120
- setFilters((current) => ({
5121
- ...current,
5122
- ...next
5123
- }));
5366
+ updateScope(scopeRef.current, next);
5124
5367
  };
5125
5368
  const setSearch = (search) => {
5126
5369
  updateFilters({ search });
@@ -5132,7 +5375,7 @@ function useOrganizationGraphFilters(initialFilters) {
5132
5375
  updateFilters({ topologyPresence });
5133
5376
  };
5134
5377
  const resetFilters = () => {
5135
- setFilters(createOrganizationGraphFilters(initialFilters));
5378
+ resetScope(scopeRef.current, initialFilters);
5136
5379
  };
5137
5380
  return {
5138
5381
  filters,
@@ -5151,7 +5394,7 @@ function getOrganizationGraphLensConfig(lens) {
5151
5394
  return {
5152
5395
  title: "Command View",
5153
5396
  caption: "Operations lens backed by the shared organization graph. This preset focuses the graph on bridged runtime resources and their operational relationships.",
5154
- initialMode: "trace",
5397
+ initialMode: "map",
5155
5398
  initialFilters: {
5156
5399
  nodeKinds: COMMAND_VIEW_NODE_KINDS,
5157
5400
  topologyPresence: "topology-only"
@@ -5184,7 +5427,7 @@ function formatTimestamp(value) {
5184
5427
  minute: "2-digit"
5185
5428
  }).format(new Date(value));
5186
5429
  }
5187
- function getCommandViewNodes(data) {
5430
+ function getCommandViewNodes2(data) {
5188
5431
  return [
5189
5432
  ...data.agents,
5190
5433
  ...data.workflows,
@@ -5195,7 +5438,7 @@ function getCommandViewNodes(data) {
5195
5438
  ];
5196
5439
  }
5197
5440
  function getNodeByResourceId(data, resourceId) {
5198
- return getCommandViewNodes(data).find((node) => node.resourceId === resourceId) ?? null;
5441
+ return getCommandViewNodes2(data).find((node) => node.resourceId === resourceId) ?? null;
5199
5442
  }
5200
5443
  function getCommandViewOperationalOverview(data, stats) {
5201
5444
  if (!stats) {
@@ -5345,7 +5588,7 @@ function mergeStatsWithTopology(topology, stats) {
5345
5588
  }
5346
5589
 
5347
5590
  // src/features/operations/organization-graph/commandViewDrillDown.ts
5348
- function titleCase3(value) {
5591
+ function titleCase4(value) {
5349
5592
  return value.replace(/[-_.]+/g, " ").replace(/\s+/g, " ").trim().split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
5350
5593
  }
5351
5594
  function getResourceHref(resourceType, resourceId) {
@@ -5403,7 +5646,7 @@ function getExecutionDescription(execution) {
5403
5646
  if (execution.status === "completed") {
5404
5647
  return "Completed successfully";
5405
5648
  }
5406
- return titleCase3(execution.status);
5649
+ return titleCase4(execution.status);
5407
5650
  }
5408
5651
  function getTaskDescription(task) {
5409
5652
  if (task.description) {
@@ -5428,8 +5671,8 @@ function buildCommandViewDrillDownSections({
5428
5671
  if ((node.resourceType === "agent" || node.resourceType === "workflow") && executions) {
5429
5672
  sections.push({
5430
5673
  title: "Recent executions",
5431
- description: `Latest runs for this ${titleCase3(node.resourceType)} in the ${timeRange} window.`,
5432
- emptyMessage: `No executions were recorded for this ${titleCase3(node.resourceType).toLowerCase()} in the current window.`,
5674
+ description: `Latest runs for this ${titleCase4(node.resourceType)} in the ${timeRange} window.`,
5675
+ emptyMessage: `No executions were recorded for this ${titleCase4(node.resourceType).toLowerCase()} in the current window.`,
5433
5676
  primaryAction: resourceHref ? {
5434
5677
  label: "Open resource",
5435
5678
  href: resourceHref
@@ -5467,6 +5710,221 @@ function buildCommandViewDrillDownSections({
5467
5710
  }
5468
5711
  return sections;
5469
5712
  }
5713
+ var cellStyle = {
5714
+ padding: "var(--mantine-spacing-sm) var(--mantine-spacing-md)",
5715
+ borderRight: "1px solid var(--color-border)",
5716
+ display: "flex",
5717
+ alignItems: "center",
5718
+ gap: "var(--mantine-spacing-sm)",
5719
+ minWidth: 0
5720
+ };
5721
+ var lastCellStyle = {
5722
+ ...cellStyle,
5723
+ borderRight: "none"
5724
+ };
5725
+ function CommandViewHealthStrip({
5726
+ overview,
5727
+ hotspots,
5728
+ visibleResources,
5729
+ selectedLabel,
5730
+ onFocusHotspot,
5731
+ onResetFocus
5732
+ }) {
5733
+ return /* @__PURE__ */ jsxs(
5734
+ Paper,
5735
+ {
5736
+ withBorder: true,
5737
+ style: {
5738
+ display: "grid",
5739
+ gridTemplateColumns: "auto 1fr auto auto",
5740
+ background: "var(--color-surface)",
5741
+ boxShadow: "var(--card-shadow)",
5742
+ overflow: "hidden"
5743
+ },
5744
+ children: [
5745
+ /* @__PURE__ */ jsxs("div", { style: cellStyle, children: [
5746
+ /* @__PURE__ */ jsx(IconActivityHeartbeat, { size: 16, style: { flexShrink: 0, color: "var(--color-text-dimmed)" } }),
5747
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 700, style: { flexShrink: 0 }, children: overview?.successRate == null ? "N/A" : `${Math.round(overview.successRate)}%` }),
5748
+ /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
5749
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: "green", size: "xs", children: overview?.successCount ?? 0 }),
5750
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: "red", size: "xs", children: overview?.failureCount ?? 0 }),
5751
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: "yellow", size: "xs", children: overview?.warningCount ?? 0 })
5752
+ ] }),
5753
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", truncate: true, style: { flexShrink: 1, minWidth: 0 }, children: overview ? `${overview.totalRuns} runs / ${overview.trackedResources} resources` : "" })
5754
+ ] }),
5755
+ /* @__PURE__ */ jsxs("div", { style: cellStyle, children: [
5756
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 16, style: { flexShrink: 0, color: "var(--color-text-dimmed)" } }),
5757
+ hotspots.length > 0 ? /* @__PURE__ */ jsx(Group, { gap: "xs", wrap: "nowrap", style: { minWidth: 0, overflow: "hidden" }, children: hotspots.map((hotspot) => /* @__PURE__ */ jsx(Group, { gap: 4, wrap: "nowrap", children: /* @__PURE__ */ jsx(
5758
+ Badge,
5759
+ {
5760
+ variant: "light",
5761
+ color: "red",
5762
+ size: "xs",
5763
+ style: { cursor: "pointer", flexShrink: 0 },
5764
+ onClick: () => onFocusHotspot(hotspot.resourceId),
5765
+ children: hotspot.label
5766
+ }
5767
+ ) }, hotspot.nodeId)) }) : /* @__PURE__ */ jsx(Badge, { variant: "light", color: "green", size: "xs", leftSection: /* @__PURE__ */ jsx(IconCircleCheck, { size: 10 }), children: "No hotspots" })
5768
+ ] }),
5769
+ /* @__PURE__ */ jsxs("div", { style: cellStyle, children: [
5770
+ /* @__PURE__ */ jsx(IconClockPause, { size: 16, style: { flexShrink: 0, color: "var(--color-text-dimmed)" } }),
5771
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 700, style: { flexShrink: 0 }, children: overview?.pendingApprovals ?? 0 }),
5772
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", truncate: true, children: [
5773
+ "pending / ",
5774
+ overview?.activeHumanCheckpoints ?? 0,
5775
+ " queues"
5776
+ ] })
5777
+ ] }),
5778
+ /* @__PURE__ */ jsxs("div", { style: lastCellStyle, children: [
5779
+ /* @__PURE__ */ jsx(IconTopologyStar3, { size: 16, style: { flexShrink: 0, color: "var(--color-text-dimmed)" } }),
5780
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, truncate: true, style: { minWidth: 0 }, children: selectedLabel ?? `${visibleResources} resources` }),
5781
+ /* @__PURE__ */ jsx(Button, { size: "compact-xs", variant: "subtle", onClick: onResetFocus, style: { flexShrink: 0 }, children: "Reset" })
5782
+ ] })
5783
+ ]
5784
+ }
5785
+ );
5786
+ }
5787
+
5788
+ // src/features/operations/organization-graph/commandViewGraphHealth.ts
5789
+ function toResourceHealth(node, stats) {
5790
+ const resourceId = node.sourceId ?? node.id;
5791
+ if (node.resourceType === "human_checkpoint") {
5792
+ const checkpointStats = stats.humanCheckpoints[resourceId];
5793
+ if (!checkpointStats) {
5794
+ return {
5795
+ nodeId: node.id,
5796
+ resourceId,
5797
+ label: node.label,
5798
+ resourceType: node.resourceType,
5799
+ healthLevel: "inactive",
5800
+ summaryLabel: "No queue activity",
5801
+ detailLabel: "No approvals in range",
5802
+ successRate: null,
5803
+ totalRuns: 0,
5804
+ successCount: 0,
5805
+ failureCount: 0,
5806
+ warningCount: 0,
5807
+ pendingCount: 0,
5808
+ completedCount: 0,
5809
+ expiredCount: 0,
5810
+ lastActivityAt: null,
5811
+ sortScore: 0
5812
+ };
5813
+ }
5814
+ const totalQueueActivity = checkpointStats.pendingCount + checkpointStats.completedCount + checkpointStats.expiredCount;
5815
+ const healthLevel2 = checkpointStats.pendingCount > 0 ? checkpointStats.pendingCount >= 3 || checkpointStats.expiredCount > 0 ? "critical" : "warning" : totalQueueActivity > 0 ? "healthy" : "inactive";
5816
+ const summaryLabel2 = checkpointStats.pendingCount > 0 ? `${checkpointStats.pendingCount} pending` : checkpointStats.expiredCount > 0 ? `${checkpointStats.expiredCount} expired` : checkpointStats.completedCount > 0 ? `${checkpointStats.completedCount} completed` : "No queue activity";
5817
+ const detailLabel = checkpointStats.pendingCount > 0 ? `${checkpointStats.completedCount} resolved` : totalQueueActivity > 0 ? "Queue clear" : "No approvals in range";
5818
+ return {
5819
+ nodeId: node.id,
5820
+ resourceId,
5821
+ label: node.label,
5822
+ resourceType: node.resourceType,
5823
+ healthLevel: healthLevel2,
5824
+ summaryLabel: summaryLabel2,
5825
+ detailLabel,
5826
+ successRate: null,
5827
+ totalRuns: 0,
5828
+ successCount: 0,
5829
+ failureCount: 0,
5830
+ warningCount: 0,
5831
+ pendingCount: checkpointStats.pendingCount,
5832
+ completedCount: checkpointStats.completedCount,
5833
+ expiredCount: checkpointStats.expiredCount,
5834
+ lastActivityAt: checkpointStats.lastDecisionAt,
5835
+ sortScore: checkpointStats.pendingCount * 100 + checkpointStats.expiredCount * 25 + checkpointStats.completedCount
5836
+ };
5837
+ }
5838
+ const resourceStats = stats.resources[resourceId];
5839
+ if (!resourceStats || resourceStats.totalRuns <= 0) {
5840
+ return {
5841
+ nodeId: node.id,
5842
+ resourceId,
5843
+ label: node.label,
5844
+ resourceType: node.resourceType,
5845
+ healthLevel: "inactive",
5846
+ summaryLabel: "No runs",
5847
+ detailLabel: "No executions in range",
5848
+ successRate: null,
5849
+ totalRuns: 0,
5850
+ successCount: 0,
5851
+ failureCount: 0,
5852
+ warningCount: 0,
5853
+ pendingCount: 0,
5854
+ completedCount: 0,
5855
+ expiredCount: 0,
5856
+ lastActivityAt: resourceStats?.lastRunAt ?? null,
5857
+ sortScore: 0
5858
+ };
5859
+ }
5860
+ const successfulOutcomes = resourceStats.successCount + resourceStats.warningCount;
5861
+ const successRate = successfulOutcomes / resourceStats.totalRuns * 100;
5862
+ const healthLevel = successRate >= 95 ? "healthy" : successRate >= 80 ? "warning" : "critical";
5863
+ const summaryLabel = resourceStats.failureCount > 0 ? `${resourceStats.failureCount} failed` : resourceStats.warningCount > 0 ? `${resourceStats.warningCount} warnings` : `${resourceStats.totalRuns} runs`;
5864
+ return {
5865
+ nodeId: node.id,
5866
+ resourceId,
5867
+ label: node.label,
5868
+ resourceType: node.resourceType,
5869
+ healthLevel,
5870
+ summaryLabel,
5871
+ detailLabel: `${Math.round(successRate)}% healthy`,
5872
+ successRate,
5873
+ totalRuns: resourceStats.totalRuns,
5874
+ successCount: resourceStats.successCount,
5875
+ failureCount: resourceStats.failureCount,
5876
+ warningCount: resourceStats.warningCount,
5877
+ pendingCount: 0,
5878
+ completedCount: 0,
5879
+ expiredCount: 0,
5880
+ lastActivityAt: resourceStats.lastRunAt,
5881
+ sortScore: resourceStats.failureCount * 100 + resourceStats.warningCount * 25 + resourceStats.totalRuns
5882
+ };
5883
+ }
5884
+ function getCommandViewGraphNodeHealth(node, stats) {
5885
+ if (node.kind !== "resource" || !stats) {
5886
+ return null;
5887
+ }
5888
+ return toResourceHealth(node, stats);
5889
+ }
5890
+ function getCommandViewGraphHealthMap(graph, stats) {
5891
+ const healthByNodeId = /* @__PURE__ */ new Map();
5892
+ if (!graph || !stats) {
5893
+ return healthByNodeId;
5894
+ }
5895
+ for (const node of graph.nodes) {
5896
+ const health = getCommandViewGraphNodeHealth(node, stats);
5897
+ if (health) {
5898
+ healthByNodeId.set(node.id, health);
5899
+ }
5900
+ }
5901
+ return healthByNodeId;
5902
+ }
5903
+ function getHealthRank(level) {
5904
+ switch (level) {
5905
+ case "critical":
5906
+ return 0;
5907
+ case "warning":
5908
+ return 1;
5909
+ case "healthy":
5910
+ return 2;
5911
+ case "inactive":
5912
+ default:
5913
+ return 3;
5914
+ }
5915
+ }
5916
+ function rankCommandViewHotspots(entries, limit = 3) {
5917
+ return [...entries].filter((entry) => entry.healthLevel === "critical" || entry.healthLevel === "warning").sort((left, right) => {
5918
+ const healthRankDelta = getHealthRank(left.healthLevel) - getHealthRank(right.healthLevel);
5919
+ if (healthRankDelta !== 0) {
5920
+ return healthRankDelta;
5921
+ }
5922
+ if (right.sortScore !== left.sortScore) {
5923
+ return right.sortScore - left.sortScore;
5924
+ }
5925
+ return left.label.localeCompare(right.label);
5926
+ }).slice(0, limit);
5927
+ }
5470
5928
 
5471
5929
  // src/features/operations/organization-graph/path-tracing/trace.ts
5472
5930
  var NODE_KIND_ORDER = {
@@ -5972,21 +6430,40 @@ function getNodeScore(node, graph) {
5972
6430
  const relationshipCount = graph.edges.filter((edge) => edge.sourceId === node.id || edge.targetId === node.id).length;
5973
6431
  return Math.max(1, relationshipCount);
5974
6432
  }
5975
- function toCytoscapeElements(graph, tokens) {
6433
+ function getCommandViewRingColor(level, tokens) {
6434
+ switch (level) {
6435
+ case "healthy":
6436
+ return tokens.success;
6437
+ case "warning":
6438
+ return tokens.warning;
6439
+ case "critical":
6440
+ return tokens.error;
6441
+ case "inactive":
6442
+ default:
6443
+ return mixColors(tokens.textDimmed, tokens.border, 0.6);
6444
+ }
6445
+ }
6446
+ function toCytoscapeElementsWithHealth(graph, tokens, commandViewHealthByNodeId) {
5976
6447
  const nodeThemeByKind = getNodeThemeByKind(tokens);
5977
6448
  return [
5978
6449
  ...graph.nodes.map((node) => {
5979
6450
  const size = getNodeSize(node.kind);
5980
6451
  const theme = nodeThemeByKind[node.kind];
6452
+ const health = commandViewHealthByNodeId?.get(node.id) ?? null;
6453
+ const fillColor = health && node.kind === "resource" ? mixColors(tokens.surfaceHover, tokens.background, 0.76) : theme.background;
6454
+ const borderColor = health ? getCommandViewRingColor(health.healthLevel, tokens) : theme.border;
6455
+ const label = health ? `${node.label}
6456
+ ${health.summaryLabel}` : node.label;
5981
6457
  return {
5982
6458
  data: {
5983
6459
  ...node,
5984
6460
  width: size.width,
5985
6461
  height: size.height,
5986
6462
  score: getNodeScore(node, graph),
5987
- fillColor: theme.background,
5988
- borderColor: theme.border,
5989
- textColor: theme.color
6463
+ label,
6464
+ fillColor,
6465
+ borderColor,
6466
+ textColor: health ? tokens.text : theme.color
5990
6467
  }
5991
6468
  };
5992
6469
  }),
@@ -6064,9 +6541,10 @@ function createCytoscapeStyle(tokens) {
6064
6541
  height: "data(height)",
6065
6542
  "background-color": "data(fillColor)",
6066
6543
  "border-width": 2,
6544
+ "border-style": "solid",
6067
6545
  "border-color": "data(borderColor)",
6068
6546
  color: "data(textColor)",
6069
- "font-size": 13,
6547
+ "font-size": 12,
6070
6548
  "font-weight": 700,
6071
6549
  "text-wrap": "wrap",
6072
6550
  "text-max-width": "150px",
@@ -6240,12 +6718,17 @@ function OrganizationGraphCanvas({
6240
6718
  selectedElement,
6241
6719
  traceResult,
6242
6720
  themeTokens,
6721
+ commandViewHealthByNodeId,
6722
+ focusRequest,
6243
6723
  onSelectElement
6244
6724
  }) {
6245
6725
  const containerRef = useRef(null);
6246
6726
  const cytoscapeRef = useRef(null);
6247
6727
  const previousModeRef = useRef(mode);
6248
- const elements = useMemo(() => toCytoscapeElements(graph, themeTokens), [graph, themeTokens]);
6728
+ const elements = useMemo(
6729
+ () => toCytoscapeElementsWithHealth(graph, themeTokens, commandViewHealthByNodeId),
6730
+ [commandViewHealthByNodeId, graph, themeTokens]
6731
+ );
6249
6732
  const cytoscapeStyle = useMemo(() => createCytoscapeStyle(themeTokens), [themeTokens]);
6250
6733
  useEffect(() => {
6251
6734
  if (!containerRef.current) {
@@ -6303,6 +6786,28 @@ function OrganizationGraphCanvas({
6303
6786
  }
6304
6787
  syncGraphClasses(cy, selectedElement, traceResult);
6305
6788
  }, [selectedElement, traceResult]);
6789
+ useEffect(() => {
6790
+ const cy = cytoscapeRef.current;
6791
+ if (!cy || !focusRequest) {
6792
+ return;
6793
+ }
6794
+ const node = cy.getElementById(focusRequest.nodeId);
6795
+ if (node.empty()) {
6796
+ return;
6797
+ }
6798
+ cy.animate(
6799
+ {
6800
+ fit: {
6801
+ eles: node.closedNeighborhood(),
6802
+ padding: 96
6803
+ },
6804
+ duration: 280
6805
+ },
6806
+ {
6807
+ easing: "ease-out-cubic"
6808
+ }
6809
+ );
6810
+ }, [focusRequest]);
6306
6811
  return /* @__PURE__ */ jsxs(
6307
6812
  Box,
6308
6813
  {
@@ -6356,12 +6861,18 @@ function OrganizationGraphPage({ lens = "default", timeRange = "24h" }) {
6356
6861
  const { organizationModel, organizationGraph } = useElevasisFeatures();
6357
6862
  const { data: commandViewData, isLoading, error } = useCommandViewData();
6358
6863
  const { data: commandViewStats } = useCommandViewStats(timeRange, { enabled: lens === "command-view" });
6864
+ const setSelectedNodeId = useCommandViewStore((state) => state.setSelectedNodeId);
6359
6865
  const lensConfig = useMemo(() => getOrganizationGraphLensConfig(lens), [lens]);
6360
6866
  const [mode, setMode] = useState(lensConfig.initialMode);
6361
6867
  const [activePanelTab, setActivePanelTab] = useState("controls");
6362
6868
  const [selectedElement, setSelectedElement] = useState(null);
6869
+ const [focusRequest, setFocusRequest] = useState(null);
6363
6870
  const [pathTraceSelection, setPathTraceSelection] = useState(EMPTY_TRACE_SELECTION);
6364
6871
  const { filters, resetFilters, updateFilters } = useOrganizationGraphFilters(lensConfig.initialFilters);
6872
+ const toolbarResetValue = useMemo(
6873
+ () => createOrganizationGraphFilters(lensConfig.initialFilters),
6874
+ [lensConfig.initialFilters]
6875
+ );
6365
6876
  const deferredFilters = useDeferredValue(filters);
6366
6877
  const rawThemeTokens = readGraphThemeTokens();
6367
6878
  const themeSignature = Object.values(rawThemeTokens).join("|");
@@ -6379,8 +6890,10 @@ function OrganizationGraphPage({ lens = "default", timeRange = "24h" }) {
6379
6890
  if (!baseGraph) {
6380
6891
  return null;
6381
6892
  }
6382
- return filterOrganizationGraph(baseGraph, deferredFilters);
6383
- }, [baseGraph, deferredFilters]);
6893
+ return filterOrganizationGraph(baseGraph, deferredFilters, {
6894
+ commandViewData
6895
+ });
6896
+ }, [baseGraph, commandViewData, deferredFilters]);
6384
6897
  const selectedGraphNode = useMemo(() => {
6385
6898
  if (!graph || !selectedElement || selectedElement.type !== "node") {
6386
6899
  return null;
@@ -6423,6 +6936,52 @@ function OrganizationGraphPage({ lens = "default", timeRange = "24h" }) {
6423
6936
  }) : [],
6424
6937
  [checkpointTasksData, lens, resourceExecutionsData, selectedGraphNode, timeRange]
6425
6938
  );
6939
+ const commandViewHealthByNodeId = useMemo(
6940
+ () => lens === "command-view" ? getCommandViewGraphHealthMap(baseGraph, commandViewStats) : null,
6941
+ [baseGraph, commandViewStats, lens]
6942
+ );
6943
+ const visibleCommandViewHealth = useMemo(
6944
+ () => graph && commandViewHealthByNodeId ? graph.nodes.map((node) => commandViewHealthByNodeId.get(node.id) ?? null).filter((entry) => entry !== null) : [],
6945
+ [commandViewHealthByNodeId, graph]
6946
+ );
6947
+ const visibleHotspots = useMemo(() => rankCommandViewHotspots(visibleCommandViewHealth), [visibleCommandViewHealth]);
6948
+ const pendingCheckpointHotspot = useMemo(
6949
+ () => [...visibleCommandViewHealth].filter((entry) => entry.resourceType === "human_checkpoint" && entry.pendingCount > 0).sort((left, right) => right.pendingCount - left.pendingCount)[0] ?? null,
6950
+ [visibleCommandViewHealth]
6951
+ );
6952
+ const jumpToResourceOptions = useMemo(
6953
+ () => (graph?.nodes ?? []).filter((node) => node.kind === "resource").map((node) => ({
6954
+ value: node.id,
6955
+ label: node.label
6956
+ })).sort((left, right) => left.label.localeCompare(right.label)),
6957
+ [graph]
6958
+ );
6959
+ const focusGraphNode = useEffectEvent((nodeId2) => {
6960
+ setFocusRequest({
6961
+ nodeId: nodeId2,
6962
+ nonce: Date.now()
6963
+ });
6964
+ });
6965
+ const focusCommandViewResource = useEffectEvent((resourceId) => {
6966
+ const focusNode = graph?.nodes.find((node) => node.kind === "resource" && node.sourceId === resourceId);
6967
+ if (!focusNode) {
6968
+ return;
6969
+ }
6970
+ setMode("map");
6971
+ setSelectedElement({ type: "node", id: focusNode.id });
6972
+ focusGraphNode(focusNode.id);
6973
+ });
6974
+ const handleSelectElement = useEffectEvent((element) => {
6975
+ if (!element) {
6976
+ setSelectedElement(null);
6977
+ return;
6978
+ }
6979
+ if (mode === "map" && element.type === "node" && selectedElement?.type === "node" && selectedElement.id === element.id) {
6980
+ setActivePanelTab("details");
6981
+ return;
6982
+ }
6983
+ setSelectedElement(element);
6984
+ });
6426
6985
  useEffect(() => {
6427
6986
  if (!graph || !selectedElement) {
6428
6987
  return;
@@ -6432,6 +6991,18 @@ function OrganizationGraphPage({ lens = "default", timeRange = "24h" }) {
6432
6991
  setSelectedElement(null);
6433
6992
  }
6434
6993
  }, [graph, selectedElement]);
6994
+ useEffect(() => {
6995
+ if (lens !== "command-view") {
6996
+ return;
6997
+ }
6998
+ const selectedResourceId = selectedElement?.type === "node" ? selectedGraphNode?.sourceId ?? null : null;
6999
+ setSelectedNodeId(selectedResourceId);
7000
+ }, [lens, selectedElement, selectedGraphNode, setSelectedNodeId]);
7001
+ useEffect(() => {
7002
+ return () => {
7003
+ setSelectedNodeId(null);
7004
+ };
7005
+ }, [setSelectedNodeId]);
6435
7006
  useEffect(() => {
6436
7007
  if (!graph) {
6437
7008
  setPathTraceSelection((current) => {
@@ -6471,295 +7042,344 @@ function OrganizationGraphPage({ lens = "default", timeRange = "24h" }) {
6471
7042
  ) })
6472
7043
  ] });
6473
7044
  }
6474
- return /* @__PURE__ */ jsx(Stack, { gap: "lg", style: { flex: 1, minHeight: 0, overflowX: "hidden", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Tabs, { value: activePanelTab, onChange: setActivePanelTab, keepMounted: false, children: /* @__PURE__ */ jsxs(
6475
- Paper,
6476
- {
6477
- withBorder: true,
6478
- p: "md",
6479
- style: {
6480
- display: "flex",
6481
- flexDirection: "column",
6482
- background: "var(--glass-background)",
6483
- backdropFilter: "var(--glass-blur)",
6484
- boxShadow: "var(--card-shadow)"
6485
- },
6486
- children: [
6487
- /* @__PURE__ */ jsx(Box, { style: { height: "65vh", minHeight: 560, position: "relative" }, children: graph && graph.nodes.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
6488
- /* @__PURE__ */ jsx(
6489
- OrganizationGraphCanvas,
7045
+ return /* @__PURE__ */ jsx(Stack, { gap: "lg", style: { flex: 1, minHeight: 0, overflowX: "hidden", overflowY: "auto" }, children: /* @__PURE__ */ jsxs(Tabs, { value: activePanelTab, onChange: setActivePanelTab, keepMounted: false, children: [
7046
+ lens === "command-view" ? /* @__PURE__ */ jsx(Box, { mb: "sm", children: /* @__PURE__ */ jsx(
7047
+ CommandViewHealthStrip,
7048
+ {
7049
+ overview: operationalOverview,
7050
+ hotspots: visibleHotspots,
7051
+ visibleResources: getGraphCountByKind(graph, "resource"),
7052
+ selectedLabel: selectedGraphNode?.label ?? null,
7053
+ onFocusHotspot: focusCommandViewResource,
7054
+ onResetFocus: () => {
7055
+ setMode("map");
7056
+ setSelectedElement(null);
7057
+ }
7058
+ }
7059
+ ) }) : null,
7060
+ /* @__PURE__ */ jsxs(
7061
+ Paper,
7062
+ {
7063
+ withBorder: true,
7064
+ style: {
7065
+ display: "flex",
7066
+ flexDirection: "column",
7067
+ background: "var(--glass-background)",
7068
+ backdropFilter: "var(--glass-blur)",
7069
+ boxShadow: "var(--card-shadow)"
7070
+ },
7071
+ children: [
7072
+ /* @__PURE__ */ jsx(Box, { style: { height: "65vh", minHeight: 560, position: "relative" }, children: graph && graph.nodes.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
7073
+ /* @__PURE__ */ jsx(
7074
+ OrganizationGraphCanvas,
7075
+ {
7076
+ graph,
7077
+ mode,
7078
+ selectedElement,
7079
+ traceResult: activeTraceResult,
7080
+ themeTokens,
7081
+ commandViewHealthByNodeId,
7082
+ focusRequest,
7083
+ onSelectElement: handleSelectElement
7084
+ }
7085
+ ),
7086
+ /* @__PURE__ */ jsx(
7087
+ Box,
7088
+ {
7089
+ style: {
7090
+ position: "absolute",
7091
+ top: 16,
7092
+ right: 16,
7093
+ zIndex: 3,
7094
+ maxWidth: "calc(100% - 320px)"
7095
+ },
7096
+ children: /* @__PURE__ */ jsx(
7097
+ SegmentedControl,
7098
+ {
7099
+ value: mode,
7100
+ onChange: (value) => setMode(value),
7101
+ size: "xs",
7102
+ data: [
7103
+ { label: "Map", value: "map" },
7104
+ { label: "Trace", value: "trace" },
7105
+ { label: "Impact", value: "impact" }
7106
+ ]
7107
+ }
7108
+ )
7109
+ }
7110
+ )
7111
+ ] }) : /* @__PURE__ */ jsx(
7112
+ EmptyState,
6490
7113
  {
6491
- graph,
6492
- mode,
6493
- selectedElement,
6494
- traceResult: activeTraceResult,
6495
- themeTokens,
6496
- onSelectElement: setSelectedElement
7114
+ icon: IconTopologyStar3,
7115
+ title: "No graph elements match the current filters",
7116
+ description: "Adjust the graph controls to bring semantic nodes, topology nodes, or relationship matches back into view."
6497
7117
  }
6498
- ),
6499
- /* @__PURE__ */ jsx(
7118
+ ) }),
7119
+ /* @__PURE__ */ jsxs(
6500
7120
  Box,
6501
7121
  {
6502
7122
  style: {
6503
- position: "absolute",
6504
- top: 16,
6505
- right: 72,
6506
- zIndex: 3,
6507
- maxWidth: "calc(100% - 320px)"
7123
+ marginLeft: "calc(var(--mantine-spacing-md) * -1)",
7124
+ marginRight: "calc(var(--mantine-spacing-md) * -1)",
7125
+ marginBottom: "calc(var(--mantine-spacing-md) * -1)",
7126
+ marginTop: "var(--mantine-spacing-md)",
7127
+ borderTop: "1px solid var(--color-border)"
6508
7128
  },
6509
- children: /* @__PURE__ */ jsx(
6510
- SegmentedControl,
6511
- {
6512
- value: mode,
6513
- onChange: (value) => setMode(value),
6514
- size: "xs",
6515
- data: [
6516
- { label: "Map", value: "map" },
6517
- { label: "Trace", value: "trace" },
6518
- { label: "Impact", value: "impact" }
6519
- ]
6520
- }
6521
- )
6522
- }
6523
- )
6524
- ] }) : /* @__PURE__ */ jsx(
6525
- EmptyState,
6526
- {
6527
- icon: IconTopologyStar3,
6528
- title: "No graph elements match the current filters",
6529
- description: "Adjust the graph controls to bring semantic nodes, topology nodes, or relationship matches back into view."
6530
- }
6531
- ) }),
6532
- /* @__PURE__ */ jsxs(
6533
- Box,
6534
- {
6535
- style: {
6536
- marginLeft: "calc(var(--mantine-spacing-md) * -1)",
6537
- marginRight: "calc(var(--mantine-spacing-md) * -1)",
6538
- marginBottom: "calc(var(--mantine-spacing-md) * -1)",
6539
- marginTop: "var(--mantine-spacing-md)",
6540
- borderTop: "1px solid var(--color-border)"
6541
- },
6542
- children: [
6543
- /* @__PURE__ */ jsx(Box, { p: "sm", children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", wrap: "wrap", children: [
6544
- /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "wrap", children: [
6545
- /* @__PURE__ */ jsx(Text, { fw: 700, size: "sm", children: lens === "command-view" ? "Command View" : lensConfig.title }),
6546
- /* @__PURE__ */ jsxs(Tabs.List, { children: [
6547
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "controls", children: "Controls" }),
6548
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "trace", children: "Trace" }),
6549
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "details", children: "Details" }),
6550
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "runtime", children: "Runtime" })
6551
- ] })
6552
- ] }),
6553
- /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "wrap", children: [
6554
- /* @__PURE__ */ jsx(
6555
- Button,
6556
- {
6557
- size: "xs",
6558
- variant: "subtle",
6559
- onClick: () => setSelectedElement(null),
6560
- disabled: !selectedElement,
6561
- children: "Clear selection"
6562
- }
6563
- ),
6564
- /* @__PURE__ */ jsx(
6565
- Button,
6566
- {
6567
- size: "xs",
6568
- variant: "subtle",
6569
- onClick: () => setPathTraceSelection(EMPTY_TRACE_SELECTION),
6570
- disabled: !pathTraceSelection.sourceId && !pathTraceSelection.targetId,
6571
- children: "Clear trace"
6572
- }
6573
- ),
6574
- /* @__PURE__ */ jsx(Button, { size: "xs", variant: "subtle", onClick: resetFilters, children: "Reset filters" })
6575
- ] })
6576
- ] }) }),
6577
- /* @__PURE__ */ jsxs(
6578
- Box,
6579
- {
6580
- className: HIDE_SCROLLBAR_CLASS_NAME,
6581
- style: {
6582
- padding: "var(--mantine-spacing-md)",
6583
- paddingTop: 0
6584
- },
6585
- children: [
6586
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "controls", pt: 0, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
6587
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, lg: 3 }, spacing: "md", children: [
6588
- /* @__PURE__ */ jsx(
6589
- Paper,
6590
- {
6591
- withBorder: true,
6592
- p: "md",
6593
- radius: "lg",
6594
- style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
6595
- children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
6596
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 700, children: "Filters" }),
6597
- /* @__PURE__ */ jsx(
6598
- OrganizationGraphFilterToolbar,
6599
- {
6600
- value: filters,
6601
- onChange: updateFilters,
6602
- disabled: !baseGraph
6603
- }
6604
- )
6605
- ] })
7129
+ children: [
7130
+ /* @__PURE__ */ jsx(Box, { p: "sm", children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", wrap: "wrap", children: [
7131
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "wrap", children: [
7132
+ /* @__PURE__ */ jsx(Text, { fw: 700, size: "sm", children: lens === "command-view" ? "Command View" : lensConfig.title }),
7133
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
7134
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "controls", children: "Controls" }),
7135
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "trace", children: "Trace" }),
7136
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "details", children: "Details" }),
7137
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "runtime", children: "Runtime" })
7138
+ ] })
7139
+ ] }),
7140
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "wrap", children: [
7141
+ /* @__PURE__ */ jsx(
7142
+ Select,
7143
+ {
7144
+ placeholder: "Jump to resource",
7145
+ searchable: true,
7146
+ clearable: true,
7147
+ size: "xs",
7148
+ data: jumpToResourceOptions,
7149
+ value: selectedElement?.type === "node" ? selectedElement.id : null,
7150
+ onChange: (value) => {
7151
+ if (!value) {
7152
+ return;
6606
7153
  }
6607
- ),
6608
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, spacing: "md", style: { gridColumn: "span 2" }, children: [
6609
- /* @__PURE__ */ jsxs(
6610
- Card,
7154
+ setMode("map");
7155
+ setSelectedElement({ type: "node", id: value });
7156
+ focusGraphNode(value);
7157
+ },
7158
+ styles: {
7159
+ root: { minWidth: 220 }
7160
+ },
7161
+ nothingFoundMessage: "No matching resource"
7162
+ }
7163
+ ),
7164
+ /* @__PURE__ */ jsx(
7165
+ Button,
7166
+ {
7167
+ size: "xs",
7168
+ variant: "subtle",
7169
+ onClick: () => setSelectedElement(null),
7170
+ disabled: !selectedElement,
7171
+ children: "Clear selection"
7172
+ }
7173
+ ),
7174
+ /* @__PURE__ */ jsx(
7175
+ Button,
7176
+ {
7177
+ size: "xs",
7178
+ variant: "subtle",
7179
+ onClick: () => setPathTraceSelection(EMPTY_TRACE_SELECTION),
7180
+ disabled: !pathTraceSelection.sourceId && !pathTraceSelection.targetId,
7181
+ children: "Clear trace"
7182
+ }
7183
+ ),
7184
+ /* @__PURE__ */ jsx(Button, { size: "xs", variant: "subtle", onClick: resetFilters, children: "Reset filters" })
7185
+ ] })
7186
+ ] }) }),
7187
+ /* @__PURE__ */ jsxs(
7188
+ Box,
7189
+ {
7190
+ className: HIDE_SCROLLBAR_CLASS_NAME,
7191
+ style: {
7192
+ padding: "var(--mantine-spacing-md)",
7193
+ paddingTop: 0
7194
+ },
7195
+ children: [
7196
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "controls", pt: 0, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7197
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, lg: 3 }, spacing: "md", children: [
7198
+ /* @__PURE__ */ jsx(
7199
+ Paper,
6611
7200
  {
6612
7201
  withBorder: true,
7202
+ p: "md",
6613
7203
  radius: "lg",
6614
7204
  style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
6615
- children: [
6616
- /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Tracked runs" : "Visible nodes" }),
6617
- /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? operationalOverview?.totalRuns ?? 0 : graph?.nodes.length ?? 0 }),
6618
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? `${timeRange} execution window` : `of ${baseGraph?.nodes.length ?? 0} total` })
6619
- ]
7205
+ children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
7206
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 700, children: "Filters" }),
7207
+ /* @__PURE__ */ jsx(
7208
+ OrganizationGraphFilterToolbar,
7209
+ {
7210
+ value: filters,
7211
+ onChange: updateFilters,
7212
+ disabled: !baseGraph,
7213
+ resetValue: toolbarResetValue
7214
+ }
7215
+ )
7216
+ ] })
6620
7217
  }
6621
7218
  ),
6622
- /* @__PURE__ */ jsxs(
6623
- Card,
7219
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 1, sm: 2 }, spacing: "md", style: { gridColumn: "span 2" }, children: [
7220
+ /* @__PURE__ */ jsxs(
7221
+ Card,
7222
+ {
7223
+ withBorder: true,
7224
+ radius: "lg",
7225
+ style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
7226
+ children: [
7227
+ /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Tracked runs" : "Visible nodes" }),
7228
+ /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? operationalOverview?.totalRuns ?? 0 : graph?.nodes.length ?? 0 }),
7229
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? `${timeRange} execution window` : `of ${baseGraph?.nodes.length ?? 0} total` })
7230
+ ]
7231
+ }
7232
+ ),
7233
+ /* @__PURE__ */ jsxs(
7234
+ Card,
7235
+ {
7236
+ withBorder: true,
7237
+ radius: "lg",
7238
+ style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
7239
+ children: [
7240
+ /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Success rate" : "Visible edges" }),
7241
+ /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? `${Math.round(operationalOverview?.successRate ?? 0)}%` : graph?.edges.length ?? 0 }),
7242
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? `${operationalOverview?.successCount ?? 0} successful runs` : `of ${baseGraph?.edges.length ?? 0} total` })
7243
+ ]
7244
+ }
7245
+ ),
7246
+ /* @__PURE__ */ jsxs(
7247
+ Card,
7248
+ {
7249
+ withBorder: true,
7250
+ radius: "lg",
7251
+ style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
7252
+ children: [
7253
+ /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Failing resources" : "Visible features" }),
7254
+ /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? operationalOverview?.topFailingResources.length ?? 0 : getGraphCountByKind(graph, "feature") }),
7255
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? operationalOverview?.topFailingResources.length ? operationalOverview.topFailingResources.map((resource) => `${resource.label} (${resource.failureCount})`).join(", ") : "No failing resources in the current window" : `of ${getGraphCountByKind(baseGraph, "feature")} total` })
7256
+ ]
7257
+ }
7258
+ ),
7259
+ /* @__PURE__ */ jsxs(
7260
+ Card,
7261
+ {
7262
+ withBorder: true,
7263
+ radius: "lg",
7264
+ style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
7265
+ children: [
7266
+ /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Pending approvals" : "Visible resources" }),
7267
+ /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? operationalOverview?.pendingApprovals ?? 0 : getGraphCountByKind(graph, "resource") }),
7268
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? `${operationalOverview?.activeHumanCheckpoints ?? 0} active checkpoint queues` : `of ${getGraphCountByKind(baseGraph, "resource")} total` })
7269
+ ]
7270
+ }
7271
+ )
7272
+ ] })
7273
+ ] }),
7274
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
7275
+ /* @__PURE__ */ jsx(Badge, { variant: "light", children: lens === "command-view" ? "Operations lens" : "Shared graph" }),
7276
+ /* @__PURE__ */ jsx(
7277
+ Badge,
6624
7278
  {
6625
- withBorder: true,
6626
- radius: "lg",
6627
- style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
6628
- children: [
6629
- /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Success rate" : "Visible edges" }),
6630
- /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? `${Math.round(operationalOverview?.successRate ?? 0)}%` : graph?.edges.length ?? 0 }),
6631
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? `${operationalOverview?.successCount ?? 0} successful runs` : `of ${baseGraph?.edges.length ?? 0} total` })
6632
- ]
7279
+ variant: "light",
7280
+ color: organizationGraph.available ? "var(--color-success)" : "var(--color-text-subtle)",
7281
+ children: organizationGraph.available ? "Provider graph surface ready" : "Provider graph surface missing"
6633
7282
  }
6634
7283
  ),
6635
- /* @__PURE__ */ jsxs(
6636
- Card,
7284
+ /* @__PURE__ */ jsx(
7285
+ Badge,
6637
7286
  {
6638
- withBorder: true,
6639
- radius: "lg",
6640
- style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
6641
- children: [
6642
- /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Failing resources" : "Visible features" }),
6643
- /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? operationalOverview?.topFailingResources.length ?? 0 : getGraphCountByKind(graph, "feature") }),
6644
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? operationalOverview?.topFailingResources.length ? operationalOverview.topFailingResources.map((resource) => `${resource.label} (${resource.failureCount})`).join(", ") : "No failing resources in the current window" : `of ${getGraphCountByKind(baseGraph, "feature")} total` })
6645
- ]
7287
+ variant: "light",
7288
+ color: commandViewData ? "var(--color-primary)" : "var(--color-text-subtle)",
7289
+ children: commandViewData ? "Topology bridged" : isLoading ? "Topology loading" : "Semantic only"
6646
7290
  }
6647
7291
  ),
6648
- /* @__PURE__ */ jsxs(
6649
- Card,
6650
- {
6651
- withBorder: true,
6652
- radius: "lg",
6653
- style: { background: "var(--color-surface)", boxShadow: "var(--card-shadow)" },
6654
- children: [
6655
- /* @__PURE__ */ jsx(Text, { size: "xs", tt: "uppercase", fw: 700, c: "dimmed", children: lens === "command-view" ? "Pending approvals" : "Visible resources" }),
6656
- /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: lens === "command-view" ? operationalOverview?.pendingApprovals ?? 0 : getGraphCountByKind(graph, "resource") }),
6657
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: lens === "command-view" ? `${operationalOverview?.activeHumanCheckpoints ?? 0} active checkpoint queues` : `of ${getGraphCountByKind(baseGraph, "resource")} total` })
6658
- ]
6659
- }
6660
- )
7292
+ error ? /* @__PURE__ */ jsx(Badge, { variant: "light", color: "var(--color-error)", children: "Topology unavailable" }) : null
7293
+ ] }),
7294
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7295
+ "Showing ",
7296
+ graph?.nodes.length ?? 0,
7297
+ " nodes and ",
7298
+ graph?.edges.length ?? 0,
7299
+ " edges in the current projection. In map mode, single-click isolates a node neighborhood and clicking another node pivots the focus."
6661
7300
  ] })
6662
- ] }),
6663
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
6664
- /* @__PURE__ */ jsx(Badge, { variant: "light", children: lens === "command-view" ? "Operations lens" : "Shared graph" }),
6665
- /* @__PURE__ */ jsx(
6666
- Badge,
7301
+ ] }) }),
7302
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "trace", pt: 0, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
7303
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Trace mode resolves shortest directed paths inside the current filtered graph." }),
7304
+ graph ? /* @__PURE__ */ jsx(
7305
+ OrganizationGraphPathTraceControls,
6667
7306
  {
6668
- variant: "light",
6669
- color: organizationGraph.available ? "var(--color-success)" : "var(--color-text-subtle)",
6670
- children: organizationGraph.available ? "Provider graph surface ready" : "Provider graph surface missing"
7307
+ graph,
7308
+ value: pathTraceSelection,
7309
+ onChange: setPathTraceSelection,
7310
+ disabled: graph.nodes.length === 0
6671
7311
  }
6672
- ),
6673
- /* @__PURE__ */ jsx(
6674
- Badge,
6675
- {
6676
- variant: "light",
6677
- color: commandViewData ? "var(--color-primary)" : "var(--color-text-subtle)",
6678
- children: commandViewData ? "Topology bridged" : isLoading ? "Topology loading" : "Semantic only"
6679
- }
6680
- ),
6681
- error ? /* @__PURE__ */ jsx(Badge, { variant: "light", color: "var(--color-error)", children: "Topology unavailable" }) : null
6682
- ] }),
6683
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6684
- "Showing ",
6685
- graph?.nodes.length ?? 0,
6686
- " nodes and ",
6687
- graph?.edges.length ?? 0,
6688
- " edges in the current projection."
6689
- ] })
6690
- ] }) }),
6691
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "trace", pt: 0, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
6692
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Trace mode resolves shortest directed paths inside the current filtered graph." }),
6693
- graph ? /* @__PURE__ */ jsx(
6694
- OrganizationGraphPathTraceControls,
7312
+ ) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Graph data is not available yet." })
7313
+ ] }) }),
7314
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "details", pt: 0, children: /* @__PURE__ */ jsx(
7315
+ OrganizationGraphDetailPanel,
6695
7316
  {
6696
7317
  graph,
6697
- value: pathTraceSelection,
6698
- onChange: setPathTraceSelection,
6699
- disabled: graph.nodes.length === 0
7318
+ selectedElement,
7319
+ supplementalSummary: selectionOperationalSummary,
7320
+ followUpSections,
7321
+ onClearSelection: () => setSelectedElement(null)
6700
7322
  }
6701
- ) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Graph data is not available yet." })
6702
- ] }) }),
6703
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "details", pt: 0, children: /* @__PURE__ */ jsx(
6704
- OrganizationGraphDetailPanel,
6705
- {
6706
- graph,
6707
- selectedElement,
6708
- supplementalSummary: selectionOperationalSummary,
6709
- followUpSections,
6710
- onClearSelection: () => setSelectedElement(null)
6711
- }
6712
- ) }),
6713
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "runtime", pt: 0, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
6714
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6715
- "Active Lens: ",
6716
- lens
6717
- ] }),
6718
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6719
- "Surface ID: ",
6720
- organizationGraph.surfaceId ?? "unresolved"
6721
- ] }),
6722
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6723
- "Surface Path: ",
6724
- organizationGraph.surfacePath ?? "unresolved"
6725
- ] }),
6726
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6727
- "Active Mode: ",
6728
- mode
6729
- ] }),
6730
- operationalOverview ? /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6731
- "Operational Snapshot: ",
6732
- operationalOverview.trackedResources,
6733
- " resources,",
6734
- " ",
6735
- operationalOverview.pendingApprovals,
6736
- " pending approvals, generated",
6737
- " ",
6738
- formatGeneratedTimestamp(operationalOverview.generatedAt)
6739
- ] }) : null,
6740
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Graph Build: semantic derivation plus bridged Command View topology" }),
6741
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
6742
- "Projection: ",
6743
- graph?.nodes.length ?? 0,
6744
- " visible nodes, ",
6745
- graph?.edges.length ?? 0,
6746
- " visible edges"
6747
- ] }),
6748
- isLoading ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Topology bridge is still loading; semantic nodes remain available." }) : null,
6749
- error ? /* @__PURE__ */ jsxs(Text, { size: "sm", c: "red", children: [
6750
- "Topology bridge error: ",
6751
- error.message
6752
- ] }) : null
6753
- ] }) })
6754
- ]
6755
- }
6756
- )
6757
- ]
6758
- }
6759
- )
6760
- ]
6761
- }
6762
- ) }) });
7323
+ ) }),
7324
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "runtime", pt: 0, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
7325
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7326
+ "Active Lens: ",
7327
+ lens
7328
+ ] }),
7329
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7330
+ "Surface ID: ",
7331
+ organizationGraph.surfaceId ?? "unresolved"
7332
+ ] }),
7333
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7334
+ "Surface Path: ",
7335
+ organizationGraph.surfacePath ?? "unresolved"
7336
+ ] }),
7337
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7338
+ "Active Mode: ",
7339
+ mode
7340
+ ] }),
7341
+ operationalOverview ? /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7342
+ "Operational Snapshot: ",
7343
+ operationalOverview.trackedResources,
7344
+ " resources,",
7345
+ " ",
7346
+ operationalOverview.pendingApprovals,
7347
+ " pending approvals, generated",
7348
+ " ",
7349
+ formatGeneratedTimestamp(operationalOverview.generatedAt)
7350
+ ] }) : null,
7351
+ pendingCheckpointHotspot ? /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7352
+ "Active queue hotspot: ",
7353
+ pendingCheckpointHotspot.resourceId,
7354
+ " with",
7355
+ " ",
7356
+ pendingCheckpointHotspot.pendingCount,
7357
+ " pending approvals."
7358
+ ] }) : null,
7359
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Graph Build: semantic derivation plus bridged Command View topology" }),
7360
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
7361
+ "Projection: ",
7362
+ graph?.nodes.length ?? 0,
7363
+ " visible nodes, ",
7364
+ graph?.edges.length ?? 0,
7365
+ " visible edges"
7366
+ ] }),
7367
+ isLoading ? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Topology bridge is still loading; semantic nodes remain available." }) : null,
7368
+ error ? /* @__PURE__ */ jsxs(Text, { size: "sm", c: "red", children: [
7369
+ "Topology bridge error: ",
7370
+ error.message
7371
+ ] }) : null
7372
+ ] }) })
7373
+ ]
7374
+ }
7375
+ )
7376
+ ]
7377
+ }
7378
+ )
7379
+ ]
7380
+ }
7381
+ )
7382
+ ] }) });
6763
7383
  }
6764
7384
  function CommandViewPage({ timeRange }) {
6765
7385
  return /* @__PURE__ */ jsx(OrganizationGraphPage, { lens: "command-view", timeRange });
@@ -6832,15 +7452,22 @@ function ExecutionStatusSection({ executions, status, title, badgeColor, resourc
6832
7452
  function CommandViewSidebarContent({ timeRange }) {
6833
7453
  const theme = useMantineTheme();
6834
7454
  const colors = useCyberColors();
6835
- const statusFilter = useCommandViewStore((s) => s.statusFilter);
6836
- const setStatusFilter = useCommandViewStore((s) => s.setStatusFilter);
6837
- const showIntegrations = useCommandViewStore((s) => s.showIntegrations);
6838
- const setShowIntegrations = useCommandViewStore((s) => s.setShowIntegrations);
6839
- const fitViewOnFilter = useCommandViewStore((s) => s.fitViewOnFilter);
6840
- const setFitViewOnFilter = useCommandViewStore((s) => s.setFitViewOnFilter);
7455
+ const lensConfig = getOrganizationGraphLensConfig("command-view");
6841
7456
  const selectedNodeId = useCommandViewStore((s) => s.selectedNodeId);
6842
- const domainFilters = useCommandViewDomainFilters((s) => s.filters);
6843
- const cycleDomainFilter = useCommandViewDomainFilters((s) => s.cycle);
7457
+ const { filters, updateFilters } = useOrganizationGraphFilters(lensConfig.initialFilters);
7458
+ const statusFilter = filters.environmentStatus;
7459
+ const showIntegrations = filters.showIntegrations;
7460
+ const domainFilters = filters.domainFilters;
7461
+ const cycleDomainFilter = (domainId) => {
7462
+ const current = domainFilters[domainId] ?? "neutral";
7463
+ const nextState = current === "neutral" ? "include" : current === "include" ? "exclude" : "neutral";
7464
+ updateFilters({
7465
+ domainFilters: {
7466
+ ...domainFilters,
7467
+ [domainId]: nextState
7468
+ }
7469
+ });
7470
+ };
6844
7471
  const { data, isLoading } = useCommandViewData();
6845
7472
  const { data: statsData } = useCommandViewStats(timeRange);
6846
7473
  const cleanData = data ?? null;
@@ -6851,17 +7478,29 @@ function CommandViewSidebarContent({ timeRange }) {
6851
7478
  }, [cleanData, statsData]);
6852
7479
  const { donutSuccessCount, donutFailedCount } = useMemo(() => {
6853
7480
  if (!cleanData || !statsData) return { donutSuccessCount: 0, donutFailedCount: 0 };
6854
- const allResources = [...cleanData.agents, ...cleanData.workflows];
6855
7481
  const includes = Object.entries(domainFilters).filter(([, v]) => v === "include").map(([k]) => k);
6856
7482
  const excludes = Object.entries(domainFilters).filter(([, v]) => v === "exclude").map(([k]) => k);
6857
- const filtered = allResources.filter((r) => {
6858
- const domains = r.domains || [];
7483
+ const allResources = [
7484
+ ...cleanData.agents,
7485
+ ...cleanData.workflows,
7486
+ ...cleanData.triggers,
7487
+ ...showIntegrations ? cleanData.integrations : [],
7488
+ ...cleanData.externalResources ?? [],
7489
+ ...cleanData.humanCheckpoints ?? []
7490
+ ].filter((resource) => {
7491
+ const domains = resource.domains || [];
6859
7492
  if (excludes.length > 0 && domains.some((d) => excludes.includes(d))) return false;
6860
7493
  if (includes.length > 0 && !domains.some((d) => includes.includes(d))) return false;
6861
- if (statusFilter !== "all" && r.status !== statusFilter) return false;
7494
+ if (statusFilter !== "all" && resource.status !== statusFilter) return false;
7495
+ if (filters.resourceTypes.length > 0) {
7496
+ const normalizedResourceType = resource.type === "human" ? "human_checkpoint" : resource.type;
7497
+ if (!filters.resourceTypes.includes(normalizedResourceType)) {
7498
+ return false;
7499
+ }
7500
+ }
6862
7501
  return true;
6863
7502
  });
6864
- const filteredIds = new Set(filtered.map((r) => r.resourceId));
7503
+ const filteredIds = new Set(allResources.map((resource) => resource.resourceId));
6865
7504
  let success = 0;
6866
7505
  let failed = 0;
6867
7506
  for (const [id, stats] of Object.entries(statsData.resources)) {
@@ -6871,7 +7510,7 @@ function CommandViewSidebarContent({ timeRange }) {
6871
7510
  }
6872
7511
  }
6873
7512
  return { donutSuccessCount: success, donutFailedCount: failed };
6874
- }, [cleanData, statsData, domainFilters, statusFilter]);
7513
+ }, [cleanData, domainFilters, filters.resourceTypes, showIntegrations, statsData, statusFilter]);
6875
7514
  const domainDefinitions = cleanData?.domainDefinitions ?? [];
6876
7515
  const selectedNode = useMemo(() => {
6877
7516
  if (!selectedNodeId || !dataWithStats) return null;
@@ -6962,7 +7601,9 @@ function CommandViewSidebarContent({ timeRange }) {
6962
7601
  SegmentedControl,
6963
7602
  {
6964
7603
  value: statusFilter,
6965
- onChange: (value) => setStatusFilter(value),
7604
+ onChange: (value) => updateFilters({
7605
+ environmentStatus: value
7606
+ }),
6966
7607
  data: [
6967
7608
  { label: "All", value: "all" },
6968
7609
  { label: "Prod", value: "prod" },
@@ -6978,9 +7619,11 @@ function CommandViewSidebarContent({ timeRange }) {
6978
7619
  Switch,
6979
7620
  {
6980
7621
  label: "Show Integrations",
6981
- description: "Toggle integration relationship edges",
7622
+ description: "Toggle integration resources in the graph projection",
6982
7623
  checked: showIntegrations,
6983
- onChange: (event) => setShowIntegrations(event.currentTarget.checked),
7624
+ onChange: (event) => updateFilters({
7625
+ showIntegrations: event.currentTarget.checked
7626
+ }),
6984
7627
  size: "sm"
6985
7628
  }
6986
7629
  ),
@@ -7035,17 +7678,6 @@ function CommandViewSidebarContent({ timeRange }) {
7035
7678
  }) })
7036
7679
  ] })
7037
7680
  ] }),
7038
- /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconSettings, label: "Settings", withTopBorder: true }),
7039
- /* @__PURE__ */ jsx(Stack, { gap: "sm", p: "sm", children: /* @__PURE__ */ jsx(
7040
- Switch,
7041
- {
7042
- label: "Fit view on filter",
7043
- description: "Re-center graph when filters change",
7044
- checked: fitViewOnFilter,
7045
- onChange: (event) => setFitViewOnFilter(event.currentTarget.checked),
7046
- size: "sm"
7047
- }
7048
- ) }),
7049
7681
  selectedNode && /* @__PURE__ */ jsxs(Fragment, { children: [
7050
7682
  /* @__PURE__ */ jsx(Divider, {}),
7051
7683
  /* @__PURE__ */ jsxs(Stack, { gap: "xs", p: "sm", mt: 8, children: [