@oneuptime/common 14.0.5 → 14.0.7
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/Models/DatabaseModels/InventoryItem.ts +23 -12
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AlertService.ts +32 -36
- package/Server/Services/IncidentAlertService.ts +609 -2
- package/Server/Services/IncidentService.ts +134 -44
- package/Server/Services/InventoryItemService.ts +38 -0
- package/Server/Services/IoTDeviceCredentialService.ts +13 -4
- package/Server/Services/MetricService.ts +1 -1
- package/Server/Services/ScheduledMaintenanceService.ts +50 -46
- package/Server/Services/UserNotificationRuleService.ts +55 -53
- package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
- package/Server/Types/Database/QueryHelper.ts +54 -1
- package/Server/Utils/AI/Toolbox/MetricTools.ts +13 -2
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +12 -1
- package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
- package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +1 -1
- package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +33 -0
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +4 -3
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +3 -1
- package/Server/Utils/Response.ts +31 -0
- package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
- package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
- package/Server/Utils/Topology/TopologyRequest.ts +463 -0
- package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
- package/Server/Utils/Topology/TopologySql.ts +1024 -0
- package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
- package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
- package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
- package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
- package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
- package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
- package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
- package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +292 -1
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
- package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
- package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
- package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
- package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
- package/Tests/App/Dashboard/NetworkTopologyExplorerSearch.test.tsx +1267 -0
- package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +4 -1
- package/Tests/App/Dashboard/RumOverviewPage.test.tsx +127 -0
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
- package/Tests/App/Dashboard/SiteSearchBox.test.tsx +2110 -0
- package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +168 -8
- package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
- package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
- package/Tests/Server/Services/DomainService.test.ts +525 -0
- package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
- package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
- package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
- package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
- package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
- package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
- package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +12 -0
- package/Tests/Server/Services/SavedViewDefaults.test.ts +325 -0
- package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
- package/Tests/Server/Services/StatusPageCertificateService.test.ts +169 -0
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +191 -0
- package/Tests/Server/Types/Database/QueryHelperSearchAllWords.test.ts +651 -0
- package/Tests/Server/Utils/AI/AlertWriteTools.test.ts +256 -0
- package/Tests/Server/Utils/AI/IncidentWriteTools.test.ts +482 -0
- package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
- package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +54 -0
- package/Tests/Server/Utils/Monitor/MetricDecimalThreshold.test.ts +417 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +96 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
- package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
- package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
- package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
- package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
- package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
- package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
- package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
- package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
- package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
- package/Tests/Types/BaseDatabase/AggregationType.test.ts +5 -1
- package/Tests/Types/Dashboard/KubernetesDashboardTemplate.test.ts +184 -0
- package/Tests/Types/Dashboard/KubernetesDashboardTemplates.test.ts +107 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +8 -14
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +4 -3
- package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +27 -6
- package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +76 -0
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +53 -0
- package/Tests/UI/Rum/ReplaySignals.test.ts +54 -0
- package/Tests/Utils/Dashboard/KubernetesClusterCpuTileRepair.test.ts +370 -0
- package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
- package/Tests/Utils/Rules/MonitorTypeRuleCriteria.test.ts +181 -0
- package/Types/BaseDatabase/AggregationType.ts +7 -0
- package/Types/Dashboard/DashboardTemplates.ts +20 -7
- package/Types/Incident/IncidentAlertLink.ts +19 -0
- package/Types/Rum/SessionReplayCustomEvents.ts +29 -3
- package/Types/Rum/WebVitals.ts +13 -0
- package/Types/Telemetry/InventoryLiveness.ts +26 -0
- package/Types/Topology/TopologyApi.ts +428 -0
- package/Types/Topology/TopologyTypeRules.ts +191 -0
- package/UI/Components/Input/Input.tsx +11 -0
- package/Utils/Dashboard/KubernetesClusterCpuTileRepair.ts +147 -0
- package/Utils/Incident/IncidentFromAlerts.ts +78 -0
- package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +21 -33
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentAlertService.js +457 -3
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +96 -42
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +31 -0
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
- package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +37 -40
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +47 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +13 -2
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +12 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +1 -1
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +31 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +30 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
- package/build/dist/Types/BaseDatabase/AggregationType.js +7 -0
- package/build/dist/Types/BaseDatabase/AggregationType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +20 -7
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -1
- package/build/dist/Types/Rum/WebVitals.js +12 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
- package/build/dist/Types/Topology/TopologyApi.js +55 -0
- package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/Utils/Dashboard/KubernetesClusterCpuTileRepair.js +110 -0
- package/build/dist/Utils/Dashboard/KubernetesClusterCpuTileRepair.js.map +1 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
import { JSONObject } from "../JSON";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Wire contract of the Topology API (POST /api/telemetry/topology/...).
|
|
5
|
+
*
|
|
6
|
+
* The Topology maps used to download the whole inventory — every item and
|
|
7
|
+
* every relationship — and build the maps in the browser, which stopped at
|
|
8
|
+
* 10,000 rows of each. These endpoints do the graph work in Postgres instead
|
|
9
|
+
* and return only what each view draws, so counts, search and connections
|
|
10
|
+
* cover the whole inventory however large it is.
|
|
11
|
+
*
|
|
12
|
+
* This is an internal contract between the server and the Dashboard bundle
|
|
13
|
+
* that shipped with it, not a public API. `formatVersion` changes whenever a
|
|
14
|
+
* response shape does, so an old bundle talking to a new server can tell the
|
|
15
|
+
* user to reload instead of misreading the payload.
|
|
16
|
+
*
|
|
17
|
+
* Every request carries `rangeStart` (ISO 8601). The server floors it to the
|
|
18
|
+
* minute, uses it for every "reported in range" decision, and echoes the value
|
|
19
|
+
* it used; the client must compute activity against the echoed value so both
|
|
20
|
+
* sides agree about which resources are active. Timestamps in responses are
|
|
21
|
+
* epoch milliseconds.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export const TOPOLOGY_API_FORMAT_VERSION: number = 1;
|
|
25
|
+
|
|
26
|
+
export enum TopologyApiPath {
|
|
27
|
+
ServiceMap = "/telemetry/topology/service-map",
|
|
28
|
+
Infrastructure = "/telemetry/topology/infrastructure",
|
|
29
|
+
InfrastructureCollection = "/telemetry/topology/infrastructure/collection",
|
|
30
|
+
InfrastructureCollectionSearch = "/telemetry/topology/infrastructure/collection-search",
|
|
31
|
+
Entity = "/telemetry/topology/entity",
|
|
32
|
+
EntityConnections = "/telemetry/topology/entity/connections",
|
|
33
|
+
/*
|
|
34
|
+
* The same sections over everything the inventory holds rather than over a
|
|
35
|
+
* range (see TopologyEntityAllTimeRequestJSON): the inventory item page's
|
|
36
|
+
* Connections card, which has no time range.
|
|
37
|
+
*/
|
|
38
|
+
EntityAllTime = "/telemetry/topology/entity/all-time",
|
|
39
|
+
EntityAllTimeConnections = "/telemetry/topology/entity/all-time/connections",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const TopologyApiLimits: {
|
|
43
|
+
/*
|
|
44
|
+
* Safety valves. Discovery budgets keep real projects far below these; they
|
|
45
|
+
* exist so a future budget override cannot turn one request into gigabytes.
|
|
46
|
+
* Hitting one is reported (never silent) with exact totals.
|
|
47
|
+
*/
|
|
48
|
+
MaxServiceMapEntities: number;
|
|
49
|
+
MaxServiceMapDependencies: number;
|
|
50
|
+
MaxInfrastructureNodes: number;
|
|
51
|
+
/*
|
|
52
|
+
* A flat infrastructure type (see isFlatInfrastructureType) with more
|
|
53
|
+
* non-archived items than this is returned as a collection — exact counts,
|
|
54
|
+
* rows paged from the server on demand — instead of row by row.
|
|
55
|
+
*/
|
|
56
|
+
InlineFlatItemsPerType: number;
|
|
57
|
+
CollectionPageSizeDefault: number;
|
|
58
|
+
CollectionPageSizeMax: number;
|
|
59
|
+
MaxSearchTerms: number;
|
|
60
|
+
MaxSearchTermLength: number;
|
|
61
|
+
MaxCollectionSearchTypes: number;
|
|
62
|
+
/* Rows returned per drawer section before "Show more". */
|
|
63
|
+
EntityDependencyRows: number;
|
|
64
|
+
EntityOtherRows: number;
|
|
65
|
+
EntityConnectionsPageSizeMax: number;
|
|
66
|
+
/*
|
|
67
|
+
* Most relationships the drawer reads for one entity. A cluster that has
|
|
68
|
+
* seen hundreds of thousands of short-lived pods in the range stops here and
|
|
69
|
+
* reports its totals as lower bounds ("100,000+") instead of timing out.
|
|
70
|
+
*/
|
|
71
|
+
EntityConnectionScanLimit: number;
|
|
72
|
+
/*
|
|
73
|
+
* Oldest range start the two maps honour, in days before now; an older one
|
|
74
|
+
* is clamped to it and the clamped value is echoed. Well past the longest
|
|
75
|
+
* relative range the time picker offers (3 months) and past every retention
|
|
76
|
+
* that matters (relationships are pruned after 30 days), and it bounds how
|
|
77
|
+
* many distinct minutes — each a separate whole-inventory build and cache
|
|
78
|
+
* entry — a caller can ask for.
|
|
79
|
+
*/
|
|
80
|
+
MaxMapRangeStartAgeDays: number;
|
|
81
|
+
} = {
|
|
82
|
+
MaxServiceMapEntities: 50_000,
|
|
83
|
+
MaxServiceMapDependencies: 200_000,
|
|
84
|
+
MaxInfrastructureNodes: 200_000,
|
|
85
|
+
InlineFlatItemsPerType: 1_000,
|
|
86
|
+
CollectionPageSizeDefault: 50,
|
|
87
|
+
CollectionPageSizeMax: 200,
|
|
88
|
+
MaxSearchTerms: 10,
|
|
89
|
+
MaxSearchTermLength: 100,
|
|
90
|
+
MaxCollectionSearchTypes: 100,
|
|
91
|
+
EntityDependencyRows: 100,
|
|
92
|
+
EntityOtherRows: 25,
|
|
93
|
+
EntityConnectionsPageSizeMax: 200,
|
|
94
|
+
EntityConnectionScanLimit: 100_000,
|
|
95
|
+
MaxMapRangeStartAgeDays: 400,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------- requests
|
|
99
|
+
|
|
100
|
+
export interface TopologyRangeRequestJSON {
|
|
101
|
+
/** ISO 8601; floored to the minute by the server. */
|
|
102
|
+
rangeStart: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** The Service Map and Infrastructure maps. */
|
|
106
|
+
export interface TopologyMapRequestJSON extends TopologyRangeRequestJSON {
|
|
107
|
+
/*
|
|
108
|
+
* An explicit refresh by the user ("Refresh topology"). The maps are served
|
|
109
|
+
* from a short-lived per-process cache (up to a minute old); a fresh
|
|
110
|
+
* request skips that cached copy and rebuilds — still sharing a build of
|
|
111
|
+
* the same map that is already running — and the new result replaces the
|
|
112
|
+
* cached one. Omit (or false) for every other load.
|
|
113
|
+
*/
|
|
114
|
+
fresh?: boolean | undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type TopologyServiceMapRequestJSON = TopologyMapRequestJSON;
|
|
118
|
+
|
|
119
|
+
export type TopologyInfrastructureRequestJSON = TopologyMapRequestJSON;
|
|
120
|
+
|
|
121
|
+
export interface TopologyCollectionCursorJSON {
|
|
122
|
+
/** Display name of the last row of the previous page ("" when it had none). */
|
|
123
|
+
name: string;
|
|
124
|
+
key: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** One page of a collection, ordered by display name then entity key. */
|
|
128
|
+
export interface TopologyCollectionRequestJSON
|
|
129
|
+
extends TopologyRangeRequestJSON {
|
|
130
|
+
entityType: string;
|
|
131
|
+
includeInactive: boolean;
|
|
132
|
+
/*
|
|
133
|
+
* Case-insensitive substrings that must ALL appear in the display name.
|
|
134
|
+
* Search terms the client already matched against the type's label are
|
|
135
|
+
* left out, mirroring how the in-browser search matches name OR type label.
|
|
136
|
+
*/
|
|
137
|
+
nameTerms?: Array<string> | undefined;
|
|
138
|
+
cursor?: TopologyCollectionCursorJSON | null | undefined;
|
|
139
|
+
limit?: number | undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** How many items of each collection match a search. */
|
|
143
|
+
export interface TopologyCollectionSearchRequestJSON
|
|
144
|
+
extends TopologyRangeRequestJSON {
|
|
145
|
+
includeInactive: boolean;
|
|
146
|
+
types: Array<{ entityType: string; nameTerms: Array<string> }>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Which entity a drawer or inventory read is about. */
|
|
150
|
+
export interface TopologyEntityTargetJSON {
|
|
151
|
+
entityKey: string;
|
|
152
|
+
/* Narrows the lookup when the caller knows it; the key alone is enough. */
|
|
153
|
+
entityType?: string | null | undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface TopologyEntityRequestJSON
|
|
157
|
+
extends TopologyRangeRequestJSON,
|
|
158
|
+
TopologyEntityTargetJSON {}
|
|
159
|
+
|
|
160
|
+
export type TopologyConnectionSection =
|
|
161
|
+
| "calls"
|
|
162
|
+
| "calledBy"
|
|
163
|
+
| "runsOn"
|
|
164
|
+
| "related";
|
|
165
|
+
|
|
166
|
+
export const TOPOLOGY_CONNECTION_SECTIONS: ReadonlyArray<TopologyConnectionSection> =
|
|
167
|
+
["calls", "calledBy", "runsOn", "related"];
|
|
168
|
+
|
|
169
|
+
/** Where one page of one section starts, and how many rows it holds. */
|
|
170
|
+
export interface TopologyConnectionsPageRequestJSON {
|
|
171
|
+
section: TopologyConnectionSection;
|
|
172
|
+
offset: number;
|
|
173
|
+
limit?: number | undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** "Show more" for one drawer section. */
|
|
177
|
+
export interface TopologyEntityConnectionsRequestJSON
|
|
178
|
+
extends TopologyEntityRequestJSON,
|
|
179
|
+
TopologyConnectionsPageRequestJSON {}
|
|
180
|
+
|
|
181
|
+
/*
|
|
182
|
+
* The all-time variant, for the inventory item page. It has no range start:
|
|
183
|
+
* every relationship the inventory holds counts however long ago it was last
|
|
184
|
+
* seen (edges drawn by hand are never re-bumped and never pruned, so a range
|
|
185
|
+
* would hide them), and archived items count as items — both the entity
|
|
186
|
+
* asked about, which the inventory page still shows, and the other ends.
|
|
187
|
+
*/
|
|
188
|
+
export type TopologyEntityAllTimeRequestJSON = TopologyEntityTargetJSON;
|
|
189
|
+
|
|
190
|
+
export interface TopologyEntityAllTimeConnectionsRequestJSON
|
|
191
|
+
extends TopologyEntityTargetJSON,
|
|
192
|
+
TopologyConnectionsPageRequestJSON {}
|
|
193
|
+
|
|
194
|
+
// --------------------------------------------------------------- responses
|
|
195
|
+
|
|
196
|
+
export interface TopologyResponseEnvelopeJSON {
|
|
197
|
+
formatVersion: number;
|
|
198
|
+
/** The range start the server used (ISO 8601, floored to the minute). */
|
|
199
|
+
rangeStart: string;
|
|
200
|
+
/** ISO 8601. */
|
|
201
|
+
generatedAt: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface TopologyTruncationJSON {
|
|
205
|
+
shown: number;
|
|
206
|
+
total: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** The lean inventory item every map row is built from. */
|
|
210
|
+
export interface TopologyEntityJSON {
|
|
211
|
+
key: string;
|
|
212
|
+
type: string;
|
|
213
|
+
name: string | null;
|
|
214
|
+
source: string;
|
|
215
|
+
/** Epoch ms. */
|
|
216
|
+
lastSeenAt: number | null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface TopologyServiceMapEntityJSON extends TopologyEntityJSON {
|
|
220
|
+
/*
|
|
221
|
+
* Only SERVICE_MAP_DETAIL_ATTRIBUTE_KEYS whose value is a string, per bag.
|
|
222
|
+
* The bags stay separate because the reader prefers descriptive values.
|
|
223
|
+
*/
|
|
224
|
+
descriptiveAttributes?: Record<string, string> | undefined;
|
|
225
|
+
identifyingAttributes?: Record<string, string> | undefined;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** An in-range `depends-on` relationship whose caller is a service. */
|
|
229
|
+
export interface TopologyDependencyJSON {
|
|
230
|
+
from: string;
|
|
231
|
+
to: string;
|
|
232
|
+
callCount: number | null;
|
|
233
|
+
errorCount: number | null;
|
|
234
|
+
avgDurationMs: number | null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Distinct resources of one type a service runs on (runs-on / hosted-on). */
|
|
238
|
+
export interface TopologyRunsOnCountJSON {
|
|
239
|
+
service: string;
|
|
240
|
+
type: string;
|
|
241
|
+
/** Targets that reported in range. */
|
|
242
|
+
active: number;
|
|
243
|
+
/** All non-archived targets. */
|
|
244
|
+
total: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface TopologyServiceMapResponseJSON
|
|
248
|
+
extends TopologyResponseEnvelopeJSON {
|
|
249
|
+
/*
|
|
250
|
+
* Every non-archived service (active or not, so inactive services can be
|
|
251
|
+
* counted), plus every non-archived item a service calls.
|
|
252
|
+
*/
|
|
253
|
+
entities: Array<TopologyServiceMapEntityJSON>;
|
|
254
|
+
/* In the order the old list API returned them: createdAt DESC, _id ASC. */
|
|
255
|
+
dependencies: Array<TopologyDependencyJSON>;
|
|
256
|
+
runsOn: Array<TopologyRunsOnCountJSON>;
|
|
257
|
+
entityTruncation: TopologyTruncationJSON | null;
|
|
258
|
+
dependencyTruncation: TopologyTruncationJSON | null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/*
|
|
262
|
+
* One infrastructure resource and where it nests. The server chooses each
|
|
263
|
+
* resource's container in SQL with the Dashboard's own nesting rules, so the
|
|
264
|
+
* browser never needs the relationships themselves.
|
|
265
|
+
*/
|
|
266
|
+
export interface TopologyInfrastructureNodeJSON extends TopologyEntityJSON {
|
|
267
|
+
/*
|
|
268
|
+
* Index into `nodes` of the best container among ALL nodes, and the type
|
|
269
|
+
* of the relationship that won. Absent when nothing contains it.
|
|
270
|
+
*/
|
|
271
|
+
parent?: number | undefined;
|
|
272
|
+
parentVia?: string | undefined;
|
|
273
|
+
/*
|
|
274
|
+
* The best container among ACTIVE nodes, sent only when it differs from
|
|
275
|
+
* `parent` (i.e. `parent` did not report in range). -1 means no active node
|
|
276
|
+
* contains it. With inactive resources hidden the browser falls back to it.
|
|
277
|
+
*/
|
|
278
|
+
activeParent?: number | undefined;
|
|
279
|
+
activeParentVia?: string | undefined;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export interface TopologyInfrastructureServiceJSON {
|
|
283
|
+
key: string;
|
|
284
|
+
name: string | null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** A flat infrastructure type too large to ship row by row. */
|
|
288
|
+
export interface TopologyInfrastructureCollectionJSON {
|
|
289
|
+
type: string;
|
|
290
|
+
/** Non-archived items of this type. */
|
|
291
|
+
total: number;
|
|
292
|
+
/** Of those, the ones that reported in range. */
|
|
293
|
+
active: number;
|
|
294
|
+
/** Epoch ms: latest lastSeenAt over all items, and over active ones. */
|
|
295
|
+
lastSeenAt: number | null;
|
|
296
|
+
activeLastSeenAt: number | null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/*
|
|
300
|
+
* An in-range `depends-on` relationship between two placed services (see
|
|
301
|
+
* `placements`), by index into `services`. The map draws it as traffic
|
|
302
|
+
* between the resources those services run on.
|
|
303
|
+
*/
|
|
304
|
+
export interface TopologyInfrastructureDependencyJSON {
|
|
305
|
+
from: number;
|
|
306
|
+
to: number;
|
|
307
|
+
callCount: number | null;
|
|
308
|
+
errorCount: number | null;
|
|
309
|
+
avgDurationMs: number | null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export interface TopologyInfrastructureResponseJSON
|
|
313
|
+
extends TopologyResponseEnvelopeJSON {
|
|
314
|
+
/* Ordered by (type, key). */
|
|
315
|
+
nodes: Array<TopologyInfrastructureNodeJSON>;
|
|
316
|
+
/* Every non-archived service, so placements and labels resolve. */
|
|
317
|
+
services: Array<TopologyInfrastructureServiceJSON>;
|
|
318
|
+
/* Distinct [index into services, index into nodes] from in-range runs-on / hosted-on. */
|
|
319
|
+
placements: Array<[number, number]>;
|
|
320
|
+
/*
|
|
321
|
+
* In-range calls between services that both run on a shipped node,
|
|
322
|
+
* ordered by (from, to). The browser reads a payload without them as "no
|
|
323
|
+
* traffic known", so the field needs no format version of its own.
|
|
324
|
+
*/
|
|
325
|
+
dependencies: Array<TopologyInfrastructureDependencyJSON>;
|
|
326
|
+
/* The dependency cap (MaxServiceMapDependencies), when it was hit. */
|
|
327
|
+
dependencyTruncation: TopologyTruncationJSON | null;
|
|
328
|
+
collections: Array<TopologyInfrastructureCollectionJSON>;
|
|
329
|
+
/* Every non-archived infrastructure item, collections included. */
|
|
330
|
+
totals: { resources: number; activeResources: number };
|
|
331
|
+
truncation: TopologyTruncationJSON | null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export interface TopologyCollectionResponseJSON
|
|
335
|
+
extends TopologyResponseEnvelopeJSON {
|
|
336
|
+
entityType: string;
|
|
337
|
+
/** Items matching the request's filters, across all pages. */
|
|
338
|
+
total: number;
|
|
339
|
+
items: Array<TopologyEntityJSON>;
|
|
340
|
+
nextCursor: TopologyCollectionCursorJSON | null;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export interface TopologyCollectionSearchResponseJSON
|
|
344
|
+
extends TopologyResponseEnvelopeJSON {
|
|
345
|
+
/* Only types with at least one match. */
|
|
346
|
+
matches: Array<{ entityType: string; count: number }>;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export interface TopologyEntityDetailJSON extends TopologyEntityJSON {
|
|
350
|
+
/** InventoryItem _id. */
|
|
351
|
+
id: string;
|
|
352
|
+
firstSeenAt: number | null;
|
|
353
|
+
resourceType: string | null;
|
|
354
|
+
resourceId: string | null;
|
|
355
|
+
identifyingAttributes: JSONObject | null;
|
|
356
|
+
descriptiveAttributes: JSONObject | null;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export interface TopologyConnectionRowJSON {
|
|
360
|
+
relationshipType: string;
|
|
361
|
+
/* "out" when the entity is the relationship's `from` (self-loops too). */
|
|
362
|
+
direction: "out" | "in";
|
|
363
|
+
otherKey: string;
|
|
364
|
+
/*
|
|
365
|
+
* false when the other end is not a non-archived item ("Undiscovered
|
|
366
|
+
* resource"); for the all-time endpoints, when it is not an item at all.
|
|
367
|
+
*/
|
|
368
|
+
otherKnown: boolean;
|
|
369
|
+
/*
|
|
370
|
+
* InventoryItem _id of the other end, so the inventory page can link to it.
|
|
371
|
+
* Sent by the all-time endpoints only; null when otherKnown is false.
|
|
372
|
+
*/
|
|
373
|
+
otherId?: string | null | undefined;
|
|
374
|
+
otherName: string | null;
|
|
375
|
+
otherType: string | null;
|
|
376
|
+
callCount: number | null;
|
|
377
|
+
errorCount: number | null;
|
|
378
|
+
avgDurationMs: number | null;
|
|
379
|
+
lastSeenAt: number | null;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export interface TopologyConnectionSectionJSON {
|
|
383
|
+
/* Exact unless the response says it is scan limited. */
|
|
384
|
+
total: number;
|
|
385
|
+
/* How many of `total` point at something no longer in inventory. */
|
|
386
|
+
unknownTotal: number;
|
|
387
|
+
rows: Array<TopologyConnectionRowJSON>;
|
|
388
|
+
/* Offset for the next page, or null when `rows` reached the end. */
|
|
389
|
+
nextOffset: number | null;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/*
|
|
393
|
+
* Sections classify an entity's in-range relationships the way the drawer
|
|
394
|
+
* always has: depends-on out = calls, depends-on in = calledBy, outbound
|
|
395
|
+
* runs-on / hosted-on from a service = runsOn, everything else = related.
|
|
396
|
+
* calls / calledBy are ordered by callCount desc, then label; runsOn /
|
|
397
|
+
* related put known resources first, then order by label.
|
|
398
|
+
*/
|
|
399
|
+
export interface TopologyEntityResponseJSON
|
|
400
|
+
extends TopologyResponseEnvelopeJSON {
|
|
401
|
+
/* null when no non-archived item has this key (sections are then empty). */
|
|
402
|
+
entity: TopologyEntityDetailJSON | null;
|
|
403
|
+
sections: Record<TopologyConnectionSection, TopologyConnectionSectionJSON>;
|
|
404
|
+
/* The scan stopped at EntityConnectionScanLimit: totals are lower bounds. */
|
|
405
|
+
isScanLimited: boolean;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export interface TopologyEntityConnectionsResponseJSON
|
|
409
|
+
extends TopologyResponseEnvelopeJSON {
|
|
410
|
+
section: TopologyConnectionSection;
|
|
411
|
+
connections: TopologyConnectionSectionJSON;
|
|
412
|
+
isScanLimited: boolean;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/*
|
|
416
|
+
* The all-time responses (TopologyEntityAllTimeRequestJSON) are shaped like
|
|
417
|
+
* the drawer's, without a range start to echo: `entity` is found among
|
|
418
|
+
* archived items too, and every row carries `otherId`.
|
|
419
|
+
*/
|
|
420
|
+
export type TopologyEntityAllTimeResponseJSON = Omit<
|
|
421
|
+
TopologyEntityResponseJSON,
|
|
422
|
+
"rangeStart"
|
|
423
|
+
>;
|
|
424
|
+
|
|
425
|
+
export type TopologyEntityAllTimeConnectionsResponseJSON = Omit<
|
|
426
|
+
TopologyEntityConnectionsResponseJSON,
|
|
427
|
+
"rangeStart"
|
|
428
|
+
>;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import EntityRelationshipType from "../Telemetry/EntityRelationshipType";
|
|
2
|
+
import EntityType from "../Telemetry/EntityType";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* The rules that shape the Topology maps, shared by the server (which reduces
|
|
6
|
+
* the inventory graph in SQL) and the Dashboard (which builds the maps from
|
|
7
|
+
* the reduced data). Keeping them in one place is what lets the server hand
|
|
8
|
+
* the browser a few rows per resource instead of every relationship and still
|
|
9
|
+
* produce exactly the tree the Dashboard would have built from all of them.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/*
|
|
13
|
+
* Types the Service Map owns. They describe software and its dependencies,
|
|
14
|
+
* not where anything runs, so they never become Infrastructure rows.
|
|
15
|
+
*/
|
|
16
|
+
export const TOPOLOGY_APPLICATION_TYPES: ReadonlySet<string> = new Set<string>([
|
|
17
|
+
EntityType.Service,
|
|
18
|
+
EntityType.ServiceInstance,
|
|
19
|
+
EntityType.TelemetrySdk,
|
|
20
|
+
EntityType.Database,
|
|
21
|
+
EntityType.RemoteService,
|
|
22
|
+
EntityType.Process,
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
/** Types that may nest inside a structural container. */
|
|
26
|
+
export const NESTABLE_CHILD_TYPES: Set<EntityType> = new Set<EntityType>([
|
|
27
|
+
EntityType.Container,
|
|
28
|
+
EntityType.Process,
|
|
29
|
+
EntityType.KubernetesPod,
|
|
30
|
+
EntityType.KubernetesNode,
|
|
31
|
+
EntityType.KubernetesNamespace,
|
|
32
|
+
EntityType.KubernetesDeployment,
|
|
33
|
+
EntityType.ProxmoxNode,
|
|
34
|
+
EntityType.ProxmoxGuest,
|
|
35
|
+
EntityType.VMwareCluster,
|
|
36
|
+
EntityType.VMwareHost,
|
|
37
|
+
EntityType.VMwareVirtualMachine,
|
|
38
|
+
EntityType.VMwareDatastore,
|
|
39
|
+
EntityType.DockerSwarmNode,
|
|
40
|
+
EntityType.DockerSwarmService,
|
|
41
|
+
EntityType.DockerSwarmTask,
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
* Valid structural containers, higher = more specific. Doubles as the
|
|
46
|
+
* allow-list of parent types: a candidate whose parent type is absent here
|
|
47
|
+
* (e.g. a Service) is rejected before priority is compared.
|
|
48
|
+
*/
|
|
49
|
+
export const CONTAINER_SPECIFICITY: Partial<Record<EntityType, number>> = {
|
|
50
|
+
[EntityType.KubernetesCluster]: 0,
|
|
51
|
+
[EntityType.ProxmoxCluster]: 0,
|
|
52
|
+
/*
|
|
53
|
+
* vSphere nests vCenter ⊃ cluster ⊃ ESXi host ⊃ VM; datastores sit
|
|
54
|
+
* directly under the vCenter. The cluster is optional (standalone hosts
|
|
55
|
+
* hang straight off the vCenter), so the host is more specific than the
|
|
56
|
+
* cluster but both may parent directly to the vCenter.
|
|
57
|
+
*/
|
|
58
|
+
[EntityType.VMwareVCenter]: 0,
|
|
59
|
+
[EntityType.VMwareCluster]: 1,
|
|
60
|
+
[EntityType.CephCluster]: 0,
|
|
61
|
+
[EntityType.DockerSwarmCluster]: 0,
|
|
62
|
+
[EntityType.Host]: 1,
|
|
63
|
+
[EntityType.KubernetesNamespace]: 1,
|
|
64
|
+
[EntityType.KubernetesNode]: 2,
|
|
65
|
+
[EntityType.KubernetesDeployment]: 2,
|
|
66
|
+
[EntityType.ProxmoxNode]: 2,
|
|
67
|
+
[EntityType.VMwareHost]: 2,
|
|
68
|
+
[EntityType.DockerSwarmNode]: 2,
|
|
69
|
+
[EntityType.KubernetesPod]: 3,
|
|
70
|
+
[EntityType.ProxmoxGuest]: 3,
|
|
71
|
+
[EntityType.VMwareVirtualMachine]: 3,
|
|
72
|
+
[EntityType.DockerSwarmTask]: 3,
|
|
73
|
+
[EntityType.Container]: 4,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/* Which relationship expresses containment best: part-of > runs-on > member-of. */
|
|
77
|
+
export const NESTING_RELATIONSHIP_PRIORITY: Partial<
|
|
78
|
+
Record<EntityRelationshipType, number>
|
|
79
|
+
> = {
|
|
80
|
+
[EntityRelationshipType.PartOf]: 3,
|
|
81
|
+
[EntityRelationshipType.RunsOn]: 2,
|
|
82
|
+
[EntityRelationshipType.MemberOf]: 1,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/* Replicas worth collapsing: leaf resources that come in fleets. */
|
|
86
|
+
export const REPLICA_GROUPABLE_TYPES: ReadonlySet<string> = new Set<string>([
|
|
87
|
+
EntityType.Host,
|
|
88
|
+
EntityType.KubernetesPod,
|
|
89
|
+
EntityType.Container,
|
|
90
|
+
EntityType.DockerSwarmTask,
|
|
91
|
+
EntityType.ProxmoxGuest,
|
|
92
|
+
EntityType.VMwareVirtualMachine,
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
/* service → where it runs (service→host is hosted-on, service→pod runs-on). */
|
|
96
|
+
export const PLACEMENT_RELATIONSHIP_TYPES: ReadonlySet<string> =
|
|
97
|
+
new Set<string>([
|
|
98
|
+
EntityRelationshipType.RunsOn,
|
|
99
|
+
EntityRelationshipType.HostedOn,
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* The attributes the Service Map reads to label a node ("Node.js",
|
|
104
|
+
* "PostgreSQL"), in the order it tries them. The server ships only these, so
|
|
105
|
+
* the list lives here rather than beside the reader.
|
|
106
|
+
*/
|
|
107
|
+
export const SERVICE_MAP_DETAIL_ATTRIBUTE_KEYS: ReadonlyArray<string> = [
|
|
108
|
+
"telemetry.sdk.language",
|
|
109
|
+
"db.system.name",
|
|
110
|
+
"network.protocol.name",
|
|
111
|
+
"messaging.system",
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* Orders two keys by Unicode code point, which is the order Postgres gives
|
|
116
|
+
* `COLLATE "C"` on a UTF-8 database (UTF-8 bytes sort like code points). The
|
|
117
|
+
* server breaks ranking ties that way, so wherever the Dashboard must pick
|
|
118
|
+
* the same winner it compares with this rather than with `<`.
|
|
119
|
+
*
|
|
120
|
+
* JavaScript's `<` compares UTF-16 code units. The two orders agree
|
|
121
|
+
* everywhere except where a character beyond U+FFFF (stored as a surrogate
|
|
122
|
+
* pair, U+D800-U+DFFF) meets one in U+E000-U+FFFF: as code units the
|
|
123
|
+
* surrogate is smaller, as code points it is larger. Keys made only of
|
|
124
|
+
* characters up to U+FFFF therefore compare exactly as `<` compares them.
|
|
125
|
+
*/
|
|
126
|
+
export function compareCodePoints(a: string, b: string): number {
|
|
127
|
+
if (a === b) {
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
const length: number = Math.min(a.length, b.length);
|
|
131
|
+
for (let index: number = 0; index < length; index++) {
|
|
132
|
+
const left: number = a.charCodeAt(index);
|
|
133
|
+
const right: number = b.charCodeAt(index);
|
|
134
|
+
if (left === right) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (left >= 0xd800 && right >= 0xd800) {
|
|
138
|
+
const leftIsSurrogate: boolean = left <= 0xdfff;
|
|
139
|
+
const rightIsSurrogate: boolean = right <= 0xdfff;
|
|
140
|
+
if (leftIsSurrogate !== rightIsSurrogate) {
|
|
141
|
+
/* The half of a character beyond U+FFFF outranks U+E000-U+FFFF. */
|
|
142
|
+
return leftIsSurrogate ? 1 : -1;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return left < right ? -1 : 1;
|
|
146
|
+
}
|
|
147
|
+
/* One is a prefix of the other: the shorter sorts first. */
|
|
148
|
+
return a.length < b.length ? -1 : 1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function isTopologyInfrastructureType(
|
|
152
|
+
entityType: string | undefined | null,
|
|
153
|
+
): boolean {
|
|
154
|
+
return (
|
|
155
|
+
Boolean(entityType) &&
|
|
156
|
+
entityType !== EntityType.Service &&
|
|
157
|
+
!TOPOLOGY_APPLICATION_TYPES.has(entityType!)
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Structural infrastructure types can take part in the tree: they nest, hold
|
|
163
|
+
* other resources, or are grouped with their replicas. Everything else that is
|
|
164
|
+
* infrastructure (network devices, IoT devices, cloud resources, manually
|
|
165
|
+
* registered appliances, types this version does not know) is flat: it never
|
|
166
|
+
* has a parent, never contains anything, and nothing groups it. Flat types are
|
|
167
|
+
* also the ones whose volume is not bounded by the discovery budgets, so the
|
|
168
|
+
* server summarizes a large flat type instead of shipping every row.
|
|
169
|
+
*/
|
|
170
|
+
export function isStructuralInfrastructureType(
|
|
171
|
+
entityType: string | undefined | null,
|
|
172
|
+
): boolean {
|
|
173
|
+
if (!isTopologyInfrastructureType(entityType)) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
const type: EntityType = entityType as EntityType;
|
|
177
|
+
return (
|
|
178
|
+
NESTABLE_CHILD_TYPES.has(type) ||
|
|
179
|
+
CONTAINER_SPECIFICITY[type] !== undefined ||
|
|
180
|
+
REPLICA_GROUPABLE_TYPES.has(type)
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function isFlatInfrastructureType(
|
|
185
|
+
entityType: string | undefined | null,
|
|
186
|
+
): boolean {
|
|
187
|
+
return (
|
|
188
|
+
isTopologyInfrastructureType(entityType) &&
|
|
189
|
+
!isStructuralInfrastructureType(entityType)
|
|
190
|
+
);
|
|
191
|
+
}
|
|
@@ -30,6 +30,14 @@ export interface ComponentProps {
|
|
|
30
30
|
ariaHasPopup?: "dialog" | "listbox" | "menu" | "grid" | "tree" | undefined;
|
|
31
31
|
ariaExpanded?: boolean | undefined;
|
|
32
32
|
ariaControls?: string | undefined;
|
|
33
|
+
/*
|
|
34
|
+
* A text box that drives a list of suggestions is a combobox; the option
|
|
35
|
+
* the arrow keys are on is named by ariaActiveDescendant, since focus
|
|
36
|
+
* itself never leaves the input.
|
|
37
|
+
*/
|
|
38
|
+
role?: "combobox" | undefined;
|
|
39
|
+
ariaAutoComplete?: "list" | "both" | "inline" | "none" | undefined;
|
|
40
|
+
ariaActiveDescendant?: string | undefined;
|
|
33
41
|
// For inputs with no visible label element to point ariaLabelledby at.
|
|
34
42
|
ariaLabel?: string | undefined;
|
|
35
43
|
/*
|
|
@@ -219,6 +227,9 @@ const Input: FunctionComponent<ComponentProps> = (
|
|
|
219
227
|
aria-haspopup={props.ariaHasPopup}
|
|
220
228
|
aria-expanded={props.ariaExpanded}
|
|
221
229
|
aria-controls={props.ariaControls}
|
|
230
|
+
role={props.role}
|
|
231
|
+
aria-autocomplete={props.ariaAutoComplete}
|
|
232
|
+
aria-activedescendant={props.ariaActiveDescendant}
|
|
222
233
|
aria-invalid={props.error || props.ariaInvalid ? "true" : undefined}
|
|
223
234
|
aria-describedby={
|
|
224
235
|
props.error ? "input-error-message" : props.ariaDescribedby
|