@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.
- package/dist/app/index.js +2 -2
- package/dist/{chunk-OS5GFW2O.js → chunk-6PNHW4X2.js} +9 -9
- package/dist/{chunk-E4W7LB37.js → chunk-AT5XCBTU.js} +1 -1
- package/dist/{chunk-USVBMGMP.js → chunk-C7BX547M.js} +9 -8
- package/dist/{chunk-N47Z6LD4.js → chunk-CYT4PORT.js} +961 -329
- package/dist/{chunk-P5VHGY5P.js → chunk-DKQQK3WX.js} +1 -1
- package/dist/{chunk-U23TW6NP.js → chunk-GJVGV7QZ.js} +1 -1
- package/dist/{chunk-Z3OWD3A4.js → chunk-KYOF6NYW.js} +1 -1
- package/dist/{chunk-5VBR74ZS.js → chunk-LPSBID5V.js} +1 -1
- package/dist/{chunk-MOHVG62K.js → chunk-M6ZZ2FW5.js} +1 -1
- package/dist/components/index.js +10 -10
- package/dist/features/crm/index.js +4 -4
- package/dist/features/dashboard/index.js +5 -5
- package/dist/features/delivery/index.js +4 -4
- package/dist/features/lead-gen/index.js +7 -7
- package/dist/features/monitoring/index.js +4 -4
- package/dist/features/operations/index.d.ts +0 -1
- package/dist/features/operations/index.js +6 -6
- package/dist/features/settings/index.js +6 -6
- package/dist/hooks/index.js +4 -4
- package/dist/hooks/published.js +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -5
- package/dist/provider/index.d.ts +1 -0
- package/dist/provider/index.js +4 -4
- package/dist/provider/published.d.ts +1 -0
- package/dist/provider/published.js +1 -1
- package/dist/theme/index.js +2 -2
- package/package.json +2 -2
|
@@ -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-
|
|
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,
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4994
|
-
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 ${
|
|
5432
|
-
emptyMessage: `No executions were recorded for this ${
|
|
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
|
|
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
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
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":
|
|
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(
|
|
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
|
-
|
|
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__ */
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
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
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
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__ */
|
|
7118
|
+
) }),
|
|
7119
|
+
/* @__PURE__ */ jsxs(
|
|
6500
7120
|
Box,
|
|
6501
7121
|
{
|
|
6502
7122
|
style: {
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
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:
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
]
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
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
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
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: "
|
|
6617
|
-
/* @__PURE__ */ jsx(
|
|
6618
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
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__ */
|
|
6636
|
-
|
|
7284
|
+
/* @__PURE__ */ jsx(
|
|
7285
|
+
Badge,
|
|
6637
7286
|
{
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
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__ */
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
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(
|
|
6664
|
-
/* @__PURE__ */ jsx(
|
|
6665
|
-
/* @__PURE__ */ jsx(
|
|
6666
|
-
|
|
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
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
7307
|
+
graph,
|
|
7308
|
+
value: pathTraceSelection,
|
|
7309
|
+
onChange: setPathTraceSelection,
|
|
7310
|
+
disabled: graph.nodes.length === 0
|
|
6671
7311
|
}
|
|
6672
|
-
),
|
|
6673
|
-
|
|
6674
|
-
|
|
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
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
7318
|
+
selectedElement,
|
|
7319
|
+
supplementalSummary: selectionOperationalSummary,
|
|
7320
|
+
followUpSections,
|
|
7321
|
+
onClearSelection: () => setSelectedElement(null)
|
|
6700
7322
|
}
|
|
6701
|
-
)
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
"
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
"
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
" ",
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
"
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
|
|
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
|
|
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
|
|
6843
|
-
const
|
|
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
|
|
6858
|
-
|
|
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" &&
|
|
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(
|
|
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,
|
|
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) =>
|
|
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
|
|
7622
|
+
description: "Toggle integration resources in the graph projection",
|
|
6982
7623
|
checked: showIntegrations,
|
|
6983
|
-
onChange: (event) =>
|
|
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: [
|