@oneuptime/common 12.0.34 → 13.0.0
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/GlobalConfig.ts +12 -12
- package/Models/DatabaseModels/InventoryItem.ts +44 -1
- package/Models/DatabaseModels/NetworkDevice.ts +126 -0
- package/Server/EnvironmentConfig.ts +47 -16
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Infrastructure/Redis.ts +8 -8
- package/Server/Infrastructure/Status.ts +10 -4
- package/Server/Services/DatabaseService.ts +65 -13
- package/Server/Services/InventoryItemService.ts +31 -1
- package/Server/Services/MonitorTemplateService.ts +140 -19
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +349 -41
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +87 -2
- package/Server/Services/NetworkDeviceService.ts +69 -0
- package/Server/Services/UserNotificationRuleService.ts +76 -25
- package/Server/Types/Database/Permissions/ReadPermission.ts +45 -5
- package/Server/Types/Database/QueryUtil.ts +56 -0
- package/Server/Types/Markdown.ts +93 -1
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +82 -17
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +10 -1
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +2 -2
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +82 -35
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +31 -5
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +202 -37
- package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +82 -9
- package/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.ts +16 -7
- package/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.ts +29 -17
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +107 -48
- package/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.ts +158 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +27 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +11 -1
- package/Server/Utils/Telemetry/TelemetryEntity.ts +83 -9
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +32 -0
- package/Tests/App/Dashboard/AdoptedDeviceDrawer.test.tsx +374 -0
- package/Tests/App/Dashboard/DashboardLabelVariables.test.tsx +580 -0
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +438 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +5 -2
- package/Tests/App/Dashboard/DeviceAttachmentCard.test.tsx +273 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +505 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +163 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +401 -0
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +232 -0
- package/Tests/App/Dashboard/InventoryItems.test.tsx +201 -0
- package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +798 -0
- package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +320 -0
- package/Tests/App/Dashboard/NetworkTopologyToolbar.test.tsx +275 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedEmptyState.test.tsx +975 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +63 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +626 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +348 -0
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +331 -0
- package/Tests/App/Dashboard/UserSettingsEmailPreferences.test.tsx +603 -0
- package/Tests/App/Dashboard/UserSettingsNotificationSettings.test.tsx +324 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +13 -4
- package/Tests/App/StatusPage/StatusPageOidcOrigin.test.tsx +223 -0
- package/Tests/Models/InventoryItemStatus.test.ts +147 -0
- package/Tests/Models/NetworkDeviceMacAddressColumn.test.ts +294 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +129 -0
- package/Tests/Server/EnvironmentConfigValkey.test.ts +227 -0
- package/Tests/Server/Infrastructure/Postgres/AddMacAddressToNetworkDeviceMigration.test.ts +365 -0
- package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +62 -23
- package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +265 -0
- package/Tests/Server/Middleware/HttpMetricsMiddleware.test.ts +382 -0
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +525 -0
- package/Tests/Server/Services/DatabaseServiceAggregateBy.test.ts +291 -56
- package/Tests/Server/Services/DatabaseServiceSortTiebreaker.test.ts +151 -0
- package/Tests/Server/Services/InventoryItemManualCreate.test.ts +105 -0
- package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +178 -0
- package/Tests/Server/Services/MonitorTemplateServiceCustomFieldSync.test.ts +502 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1133 -81
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanRegistration.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceMacAddressNormalization.test.ts +572 -0
- package/Tests/Server/Types/Database/InventoryStatusPostgres.test.ts +368 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +261 -14
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroups.test.ts +169 -0
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroupsPostgres.test.ts +297 -0
- package/Tests/Server/Types/Markdown.test.ts +194 -1
- package/Tests/Server/Types/Workflow/Components/IncomingWebhookUtils.test.ts +279 -0
- package/Tests/Server/Types/Workflow/Components/TextToJson.test.ts +212 -0
- package/Tests/Server/Utils/CustomField/CustomFieldMappingRegistry.test.ts +436 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +214 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +10 -3
- package/Tests/Server/Utils/EventLoop.test.ts +359 -0
- package/Tests/Server/Utils/JsonWebToken.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +242 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +13 -7
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +29 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +30 -6
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +246 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEmailEvalLogAgreement.test.ts +280 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +224 -10
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +570 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilderUnits.test.ts +30 -5
- package/Tests/Server/Utils/Monitor/MonitorCriteriaMessageBuilderUnits.test.ts +68 -21
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +36 -19
- package/Tests/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.test.ts +573 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +317 -0
- package/Tests/Server/Utils/Telemetry/ContextSpanProcessor.test.ts +281 -0
- package/Tests/Server/Utils/Telemetry/InventoryDuplicateIdentity.test.ts +316 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +111 -8
- package/Tests/Types/Database/IncludesAnyOfGroups.test.ts +106 -0
- package/Tests/Types/JSONFunctions.test.ts +40 -0
- package/Tests/Types/NetworkAutomation/AutoImportRunMerge.test.ts +235 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +66 -0
- package/Tests/Types/NetworkAutomation/RuleRunResultDescribe.test.ts +309 -1
- package/Tests/Types/Telemetry/InventoryLiveness.test.ts +99 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +160 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +133 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +10 -2
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +514 -0
- package/Tests/UI/Rum/ReplayTimeFormat.test.ts +94 -0
- package/Tests/UI/Rum/ReplayUi.test.tsx +559 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +11 -1
- package/Tests/Utils/Dashboard/LabelVariable.test.ts +257 -0
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +144 -14
- package/Tests/Utils/MetricUnitUtil.test.ts +81 -0
- package/Tests/Utils/Monitor/DeviceMacLearningUtil.test.ts +497 -0
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +546 -0
- package/Tests/Utils/Monitor/MonitorTemplateCustomFieldUtil.test.ts +218 -0
- package/Tests/Utils/Monitor/NetworkTopologyEndpointAdoption.test.ts +1755 -0
- package/Tests/Utils/NetworkAutomation/AutoImportRunChain.test.ts +320 -0
- package/Types/BaseDatabase/IncludesAnyOfGroups.ts +77 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
- package/Types/Dashboard/DashboardVariable.ts +8 -0
- package/Types/JSON.ts +4 -0
- package/Types/JSONFunctions.ts +16 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +402 -13
- package/Types/SerializableObjectDictionary.ts +4 -0
- package/Types/Telemetry/InventoryLiveness.ts +56 -0
- package/UI/Components/CSVFileUpload/CSVFileUpload.tsx +9 -2
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +46 -21
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +285 -0
- package/UI/esbuild-config.js +6 -0
- package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +12 -1
- package/Utils/Dashboard/LabelVariable.ts +152 -0
- package/Utils/Dashboard/VariableUrlState.ts +27 -5
- package/Utils/MetricUnitUtil.ts +34 -0
- package/Utils/Monitor/DeviceMacLearningUtil.ts +177 -0
- package/Utils/Monitor/MetricValueFormatter.ts +342 -0
- package/Utils/Monitor/MonitorTemplateCustomFieldUtil.ts +124 -0
- package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +7 -2
- package/Utils/Monitor/NetworkTopologyUtil.ts +693 -0
- package/Utils/NetworkAutomation/AutoImportRunChain.ts +138 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +12 -12
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +34 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +128 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +44 -12
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.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/Infrastructure/Redis.js +8 -8
- package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
- package/build/dist/Server/Infrastructure/Status.js +10 -4
- package/build/dist/Server/Infrastructure/Status.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +58 -13
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +28 -1
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +116 -17
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +270 -37
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +65 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +54 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +60 -25
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +29 -4
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +36 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +75 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +53 -18
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +10 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +2 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +58 -35
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +29 -5
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +166 -35
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +58 -9
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js +9 -3
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js +26 -12
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +74 -33
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js +114 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +25 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +9 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +70 -13
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js +54 -0
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardVariable.js +1 -0
- package/build/dist/Types/Dashboard/DashboardVariable.js.map +1 -1
- package/build/dist/Types/JSON.js +1 -0
- package/build/dist/Types/JSON.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +13 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +291 -6
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
- package/build/dist/Types/SerializableObjectDictionary.js +4 -0
- package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +37 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js +7 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +9 -2
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +137 -0
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +9 -1
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/LabelVariable.js +96 -0
- package/build/dist/Utils/Dashboard/LabelVariable.js.map +1 -0
- package/build/dist/Utils/Dashboard/VariableUrlState.js +19 -4
- package/build/dist/Utils/Dashboard/VariableUrlState.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +26 -0
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js +112 -0
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +276 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js +101 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +7 -2
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +484 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js +59 -0
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/test-setup.sh +9 -9
- package/tsconfig.json +51 -11
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +0 -399
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import EntitySource from "../../../Types/Telemetry/EntitySource";
|
|
2
|
+
import {
|
|
3
|
+
InventoryLiveness,
|
|
4
|
+
INVENTORY_LIVE_WINDOW_MINUTES,
|
|
5
|
+
INVENTORY_STALE_AFTER_MINUTES,
|
|
6
|
+
getInventoryLivenessState,
|
|
7
|
+
} from "../../../Types/Telemetry/InventoryLiveness";
|
|
8
|
+
|
|
9
|
+
const NOW: Date = new Date("2026-09-07T12:00:00.000Z");
|
|
10
|
+
|
|
11
|
+
describe("inventory heartbeat classification", () => {
|
|
12
|
+
test.each([
|
|
13
|
+
[-60_000, InventoryLiveness.Live],
|
|
14
|
+
[0, InventoryLiveness.Live],
|
|
15
|
+
[30 * 60_000, InventoryLiveness.Live],
|
|
16
|
+
[31 * 60_000 - 1, InventoryLiveness.Live],
|
|
17
|
+
[31 * 60_000, InventoryLiveness.Recent],
|
|
18
|
+
[31 * 60_000 + 1, InventoryLiveness.Recent],
|
|
19
|
+
[1440 * 60_000, InventoryLiveness.Recent],
|
|
20
|
+
[1441 * 60_000 - 1, InventoryLiveness.Recent],
|
|
21
|
+
[1441 * 60_000, InventoryLiveness.Stale],
|
|
22
|
+
[1441 * 60_000 + 1, InventoryLiveness.Stale],
|
|
23
|
+
[365 * 24 * 60 * 60_000, InventoryLiveness.Stale],
|
|
24
|
+
])(
|
|
25
|
+
"an age of %s ms has status %s",
|
|
26
|
+
(age: number, status: InventoryLiveness) => {
|
|
27
|
+
expect(
|
|
28
|
+
getInventoryLivenessState({
|
|
29
|
+
source: EntitySource.Discovered,
|
|
30
|
+
lastSeenAt: new Date(NOW.getTime() - age),
|
|
31
|
+
now: NOW,
|
|
32
|
+
}),
|
|
33
|
+
).toBe(status);
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
test.each([undefined, null, "not-a-date", new Date(NaN)])(
|
|
38
|
+
"an absent or invalid discovered heartbeat is never seen (%s)",
|
|
39
|
+
(lastSeenAt: Date | string | undefined | null) => {
|
|
40
|
+
expect(
|
|
41
|
+
getInventoryLivenessState({
|
|
42
|
+
source: EntitySource.Discovered,
|
|
43
|
+
lastSeenAt,
|
|
44
|
+
now: NOW,
|
|
45
|
+
}),
|
|
46
|
+
).toBe(InventoryLiveness.Never);
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
test.each([
|
|
51
|
+
EntitySource.Inventory,
|
|
52
|
+
EntitySource.Manual,
|
|
53
|
+
"unknown",
|
|
54
|
+
undefined,
|
|
55
|
+
])("%s is never aged as telemetry", (source: string | undefined) => {
|
|
56
|
+
for (const lastSeenAt of [
|
|
57
|
+
undefined,
|
|
58
|
+
null,
|
|
59
|
+
"not-a-date",
|
|
60
|
+
NOW,
|
|
61
|
+
new Date("2000-01-01T00:00:00.000Z"),
|
|
62
|
+
]) {
|
|
63
|
+
expect(getInventoryLivenessState({ source, lastSeenAt, now: NOW })).toBe(
|
|
64
|
+
InventoryLiveness.NotTracked,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("serialized dates and Date objects classify identically", () => {
|
|
70
|
+
for (const minutes of [0, 30, 31, 1440, 1441]) {
|
|
71
|
+
const lastSeenAt: Date = new Date(NOW.getTime() - minutes * 60_000);
|
|
72
|
+
expect(
|
|
73
|
+
getInventoryLivenessState({
|
|
74
|
+
source: EntitySource.Discovered,
|
|
75
|
+
lastSeenAt: lastSeenAt.toISOString(),
|
|
76
|
+
now: NOW,
|
|
77
|
+
}),
|
|
78
|
+
).toBe(
|
|
79
|
+
getInventoryLivenessState({
|
|
80
|
+
source: EntitySource.Discovered,
|
|
81
|
+
lastSeenAt,
|
|
82
|
+
now: NOW,
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("thresholds retain the established inventory badge vocabulary", () => {
|
|
89
|
+
expect(INVENTORY_LIVE_WINDOW_MINUTES).toBe(30);
|
|
90
|
+
expect(INVENTORY_STALE_AFTER_MINUTES).toBe(1440);
|
|
91
|
+
expect(Object.values(InventoryLiveness)).toEqual([
|
|
92
|
+
"live",
|
|
93
|
+
"recent",
|
|
94
|
+
"stale",
|
|
95
|
+
"never",
|
|
96
|
+
"not-tracked",
|
|
97
|
+
]);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -78,7 +78,9 @@ import CustomFieldsDetail from "../../../../UI/Components/CustomFields/CustomFie
|
|
|
78
78
|
import BaseModel from "../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
79
79
|
import Incident from "../../../../Models/DatabaseModels/Incident";
|
|
80
80
|
import IncidentCustomField from "../../../../Models/DatabaseModels/IncidentCustomField";
|
|
81
|
+
import { CardButtonSchema } from "../../../../UI/Components/Card/Card";
|
|
81
82
|
import CustomFieldType from "../../../../Types/CustomField/CustomFieldType";
|
|
83
|
+
import IconProp from "../../../../Types/Icon/IconProp";
|
|
82
84
|
import { JSONObject } from "../../../../Types/JSON";
|
|
83
85
|
import ObjectID from "../../../../Types/ObjectID";
|
|
84
86
|
|
|
@@ -153,6 +155,8 @@ const resolveListWith: ResolveListFunction = (data: Array<BaseModel>): void => {
|
|
|
153
155
|
interface RenderOptions {
|
|
154
156
|
hideIfEmpty?: boolean | undefined;
|
|
155
157
|
isEditable?: boolean | undefined;
|
|
158
|
+
additionalButtons?: Array<CardButtonSchema> | undefined;
|
|
159
|
+
onValuesLoaded?: ((customFields: JSONObject) => void) | undefined;
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
type RenderCardFunction = (options?: RenderOptions) => void;
|
|
@@ -169,6 +173,8 @@ const renderCard: RenderCardFunction = (options?: RenderOptions): void => {
|
|
|
169
173
|
modelId={INCIDENT_ID}
|
|
170
174
|
hideIfEmpty={options?.hideIfEmpty}
|
|
171
175
|
isEditable={options?.isEditable}
|
|
176
|
+
additionalButtons={options?.additionalButtons}
|
|
177
|
+
onValuesLoaded={options?.onValuesLoaded}
|
|
172
178
|
/>,
|
|
173
179
|
);
|
|
174
180
|
};
|
|
@@ -717,3 +723,157 @@ describe("CustomFieldsDetail - a rejected save", () => {
|
|
|
717
723
|
expect(container).toBeEmptyDOMElement();
|
|
718
724
|
});
|
|
719
725
|
});
|
|
726
|
+
|
|
727
|
+
/*
|
|
728
|
+
* Both props exist for the Monitor Template's Custom Field Defaults card
|
|
729
|
+
* (issue #3548), which needs a second button — "Sync Custom Fields to Linked
|
|
730
|
+
* Monitors" — and needs to word and enable that button from the values this
|
|
731
|
+
* card has actually loaded.
|
|
732
|
+
*/
|
|
733
|
+
describe("CustomFieldsDetail - additionalButtons", () => {
|
|
734
|
+
const buildSyncButton: (onClick: () => void) => CardButtonSchema = (
|
|
735
|
+
onClick: () => void,
|
|
736
|
+
): CardButtonSchema => {
|
|
737
|
+
return {
|
|
738
|
+
title: "Sync Custom Fields",
|
|
739
|
+
icon: IconProp.Refresh,
|
|
740
|
+
onClick: onClick,
|
|
741
|
+
};
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
test("renders beside the edit button and calls back when clicked", async () => {
|
|
745
|
+
const onSyncClick: MockFunction = getJestMockFunction();
|
|
746
|
+
resolveListWith(buildSchema([{ name: "Vendor" }]));
|
|
747
|
+
getItemMock.mockResolvedValue(buildIncident({ Vendor: "Cisco" }) as never);
|
|
748
|
+
|
|
749
|
+
renderCard({
|
|
750
|
+
additionalButtons: [
|
|
751
|
+
buildSyncButton(() => {
|
|
752
|
+
onSyncClick();
|
|
753
|
+
}),
|
|
754
|
+
],
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
expect(await screen.findByText("Edit Fields")).toBeInTheDocument();
|
|
758
|
+
const syncButton: HTMLElement = screen.getByText("Sync Custom Fields");
|
|
759
|
+
|
|
760
|
+
fireEvent.click(syncButton);
|
|
761
|
+
|
|
762
|
+
expect(onSyncClick).toHaveBeenCalledTimes(1);
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
/*
|
|
766
|
+
* A disabled extra button stays on screen: its tooltip is where the reason
|
|
767
|
+
* lives ("Set at least one default above before syncing"), and a button that
|
|
768
|
+
* vanishes takes the explanation with it.
|
|
769
|
+
*/
|
|
770
|
+
test("honours disabled without removing the button", async () => {
|
|
771
|
+
const onSyncClick: MockFunction = getJestMockFunction();
|
|
772
|
+
resolveListWith(buildSchema([{ name: "Vendor" }]));
|
|
773
|
+
getItemMock.mockResolvedValue(buildIncident(undefined) as never);
|
|
774
|
+
|
|
775
|
+
renderCard({
|
|
776
|
+
additionalButtons: [
|
|
777
|
+
{
|
|
778
|
+
...buildSyncButton(() => {
|
|
779
|
+
onSyncClick();
|
|
780
|
+
}),
|
|
781
|
+
disabled: true,
|
|
782
|
+
},
|
|
783
|
+
],
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
fireEvent.click(await screen.findByText("Sync Custom Fields"));
|
|
787
|
+
|
|
788
|
+
expect(onSyncClick).not.toHaveBeenCalled();
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
/*
|
|
792
|
+
* The gating on "Edit Fields" is about whether there is anything to edit
|
|
793
|
+
* here. Whether a push to OTHER records is worth offering is the caller's
|
|
794
|
+
* question, and it still has an answer on a record with no values — that is
|
|
795
|
+
* exactly when the caller wants to say why the push is unavailable.
|
|
796
|
+
*/
|
|
797
|
+
test("renders even when there is no edit button to sit beside", async () => {
|
|
798
|
+
resolveListWith([]);
|
|
799
|
+
getItemMock.mockResolvedValue(buildIncident(undefined) as never);
|
|
800
|
+
|
|
801
|
+
renderCard({
|
|
802
|
+
additionalButtons: [
|
|
803
|
+
buildSyncButton(() => {
|
|
804
|
+
// Nothing: this test is about the button existing.
|
|
805
|
+
}),
|
|
806
|
+
],
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
expect(await screen.findByText(NO_FIELDS_MESSAGE)).toBeInTheDocument();
|
|
810
|
+
expect(screen.queryByText("Edit Fields")).not.toBeInTheDocument();
|
|
811
|
+
expect(screen.getByText("Sync Custom Fields")).toBeInTheDocument();
|
|
812
|
+
});
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
describe("CustomFieldsDetail - onValuesLoaded", () => {
|
|
816
|
+
test("reports the record's stored bag once the load settles", async () => {
|
|
817
|
+
const onValuesLoaded: MockFunction = getJestMockFunction();
|
|
818
|
+
resolveListWith(buildSchema([{ name: "Vendor" }]));
|
|
819
|
+
getItemMock.mockResolvedValue(buildIncident({ Vendor: "Cisco" }) as never);
|
|
820
|
+
|
|
821
|
+
renderCard({
|
|
822
|
+
onValuesLoaded: (customFields: JSONObject): void => {
|
|
823
|
+
onValuesLoaded(customFields);
|
|
824
|
+
},
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
await waitFor(() => {
|
|
828
|
+
expect(onValuesLoaded).toHaveBeenCalledWith({ Vendor: "Cisco" });
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
// A record with nothing stored is a value, not a missing callback.
|
|
833
|
+
test("reports an empty bag for a record with no custom fields", async () => {
|
|
834
|
+
const onValuesLoaded: MockFunction = getJestMockFunction();
|
|
835
|
+
resolveListWith(buildSchema([{ name: "Vendor" }]));
|
|
836
|
+
getItemMock.mockResolvedValue(buildIncident(undefined) as never);
|
|
837
|
+
|
|
838
|
+
renderCard({
|
|
839
|
+
onValuesLoaded: (customFields: JSONObject): void => {
|
|
840
|
+
onValuesLoaded(customFields);
|
|
841
|
+
},
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
await waitFor(() => {
|
|
845
|
+
expect(onValuesLoaded).toHaveBeenCalledWith({});
|
|
846
|
+
});
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
/*
|
|
850
|
+
* The reason this is a callback rather than something the caller fetches
|
|
851
|
+
* itself: an edit made in this card has to reach the caller, or its extra
|
|
852
|
+
* button goes on explaining a state that is two saves out of date.
|
|
853
|
+
*/
|
|
854
|
+
test("reports again with the new values after a save", async () => {
|
|
855
|
+
const onValuesLoaded: MockFunction = getJestMockFunction();
|
|
856
|
+
resolveListWith(buildSchema([{ name: "Vendor" }]));
|
|
857
|
+
getItemMock.mockResolvedValue(buildIncident(undefined) as never);
|
|
858
|
+
updateByIdMock.mockResolvedValue(undefined as never);
|
|
859
|
+
|
|
860
|
+
renderCard({
|
|
861
|
+
onValuesLoaded: (customFields: JSONObject): void => {
|
|
862
|
+
onValuesLoaded(customFields);
|
|
863
|
+
},
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
await waitFor(() => {
|
|
867
|
+
expect(onValuesLoaded).toHaveBeenCalledWith({});
|
|
868
|
+
});
|
|
869
|
+
|
|
870
|
+
getItemMock.mockResolvedValue(buildIncident({ Vendor: "Cisco" }) as never);
|
|
871
|
+
|
|
872
|
+
fireEvent.click(await screen.findByText("Edit Fields"));
|
|
873
|
+
fireEvent.click(await screen.findByText("Save"));
|
|
874
|
+
|
|
875
|
+
await waitFor(() => {
|
|
876
|
+
expect(onValuesLoaded).toHaveBeenCalledWith({ Vendor: "Cisco" });
|
|
877
|
+
});
|
|
878
|
+
});
|
|
879
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { afterAll, describe, expect, test } from "@jest/globals";
|
|
2
|
+
import childProcess from "child_process";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
const REPOSITORY_ROOT: string = path.resolve(__dirname, "..", "..", "..");
|
|
8
|
+
const COMMON_MODULES: string = path.join(
|
|
9
|
+
REPOSITORY_ROOT,
|
|
10
|
+
"Common",
|
|
11
|
+
"node_modules",
|
|
12
|
+
);
|
|
13
|
+
const ESBUILD_CONFIG: string = path.join(
|
|
14
|
+
REPOSITORY_ROOT,
|
|
15
|
+
"Common",
|
|
16
|
+
"UI",
|
|
17
|
+
"esbuild-config.js",
|
|
18
|
+
);
|
|
19
|
+
const APP_LINK: string = path.join(
|
|
20
|
+
REPOSITORY_ROOT,
|
|
21
|
+
"App/FeatureSet/Dashboard/src/Components/AppLink/AppLink.tsx",
|
|
22
|
+
);
|
|
23
|
+
const temporaryRoots: Array<string> = [];
|
|
24
|
+
|
|
25
|
+
interface RenderResult {
|
|
26
|
+
html: string;
|
|
27
|
+
error: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* PublicDashboard mounts its own router but reuses Dashboard widgets and their
|
|
32
|
+
* AppLink. Separate package installations otherwise create two router contexts.
|
|
33
|
+
* A mocked AppLink or Jest's react-router-dom module mapper hides that failure,
|
|
34
|
+
* so bundle the actual link source against two physical router installations.
|
|
35
|
+
*/
|
|
36
|
+
function renderSharedLink(nodeEnv: string): RenderResult {
|
|
37
|
+
const root: string = fs.mkdtempSync(
|
|
38
|
+
path.join(os.tmpdir(), "oneuptime-router-"),
|
|
39
|
+
);
|
|
40
|
+
temporaryRoots.push(root);
|
|
41
|
+
fs.symlinkSync(COMMON_MODULES, path.join(root, "node_modules"), "dir");
|
|
42
|
+
|
|
43
|
+
for (const packageName of ["public", "shared"]) {
|
|
44
|
+
const moduleDirectory: string = path.join(
|
|
45
|
+
root,
|
|
46
|
+
packageName,
|
|
47
|
+
"node_modules",
|
|
48
|
+
);
|
|
49
|
+
fs.mkdirSync(moduleDirectory, { recursive: true });
|
|
50
|
+
for (const dependency of ["react-router", "react-router-dom"]) {
|
|
51
|
+
fs.cpSync(
|
|
52
|
+
path.join(COMMON_MODULES, dependency),
|
|
53
|
+
path.join(moduleDirectory, dependency),
|
|
54
|
+
{ recursive: true, dereference: true },
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fs.copyFileSync(APP_LINK, path.join(root, "shared", "AppLink.tsx"));
|
|
60
|
+
const entry: string = path.join(root, "public", "Entry.tsx");
|
|
61
|
+
fs.writeFileSync(
|
|
62
|
+
entry,
|
|
63
|
+
`
|
|
64
|
+
import React from "react";
|
|
65
|
+
import { MemoryRouter } from "react-router-dom";
|
|
66
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
67
|
+
import AppLink from "../shared/AppLink";
|
|
68
|
+
|
|
69
|
+
globalThis.routerFixtureMarkup = renderToStaticMarkup(
|
|
70
|
+
<MemoryRouter initialEntries={["/public-dashboard"]}>
|
|
71
|
+
<AppLink to={{ toString: () => "/dashboard/monitors/example" }}>
|
|
72
|
+
Unit 0660 monitor
|
|
73
|
+
</AppLink>
|
|
74
|
+
</MemoryRouter>,
|
|
75
|
+
);
|
|
76
|
+
`,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const script: string = `
|
|
80
|
+
const path = require("path");
|
|
81
|
+
const configModule = require(${JSON.stringify(ESBUILD_CONFIG)});
|
|
82
|
+
const esbuild = require(require.resolve("esbuild", {
|
|
83
|
+
paths: [${JSON.stringify(COMMON_MODULES)}],
|
|
84
|
+
}));
|
|
85
|
+
const config = configModule.createConfig({
|
|
86
|
+
serviceName: "PublicDashboard",
|
|
87
|
+
publicPath: "/public-dashboard/dist/",
|
|
88
|
+
entryPoint: ${JSON.stringify(entry)},
|
|
89
|
+
});
|
|
90
|
+
config.write = false;
|
|
91
|
+
config.splitting = false;
|
|
92
|
+
config.format = "cjs";
|
|
93
|
+
config.sourcemap = false;
|
|
94
|
+
config.logLevel = "silent";
|
|
95
|
+
|
|
96
|
+
esbuild.build(config).then((result) => {
|
|
97
|
+
const output = result.outputFiles[0].text;
|
|
98
|
+
new Function("require", "module", "exports", output)(require, { exports: {} }, {});
|
|
99
|
+
console.log(JSON.stringify({ html: globalThis.routerFixtureMarkup, error: "" }));
|
|
100
|
+
}).catch((error) => {
|
|
101
|
+
console.log(JSON.stringify({ html: "", error: String(error) }));
|
|
102
|
+
});
|
|
103
|
+
`;
|
|
104
|
+
|
|
105
|
+
return JSON.parse(
|
|
106
|
+
childProcess.execFileSync(process.execPath, ["-e", script], {
|
|
107
|
+
cwd: REPOSITORY_ROOT,
|
|
108
|
+
env: { ...process.env, NODE_ENV: nodeEnv },
|
|
109
|
+
encoding: "utf8",
|
|
110
|
+
timeout: 120000,
|
|
111
|
+
maxBuffer: 1024 * 1024,
|
|
112
|
+
}),
|
|
113
|
+
) as RenderResult;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
afterAll(() => {
|
|
117
|
+
for (const root of temporaryRoots) {
|
|
118
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("shared public dashboard router context", () => {
|
|
123
|
+
test.each(["production", "development"])(
|
|
124
|
+
"renders the real shared AppLink inside the public router in %s",
|
|
125
|
+
(nodeEnv: string) => {
|
|
126
|
+
const result: RenderResult = renderSharedLink(nodeEnv);
|
|
127
|
+
expect(result.error).toBe("");
|
|
128
|
+
expect(result.html).toContain('href="/dashboard/monitors/example"');
|
|
129
|
+
expect(result.html).toContain("Unit 0660 monitor");
|
|
130
|
+
},
|
|
131
|
+
180000,
|
|
132
|
+
);
|
|
133
|
+
});
|
|
@@ -139,6 +139,14 @@ describe("ReplayHeader", () => {
|
|
|
139
139
|
});
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
+
/*
|
|
143
|
+
* The clock is its own right-hand block since the header redesign: the
|
|
144
|
+
* wall-clock time leads on its own line, with the start date and the
|
|
145
|
+
* "playhead / length" pair under it. It used to be one inline run
|
|
146
|
+
* where the offset pair needed parentheses to stay legible; the pair
|
|
147
|
+
* is asserted without them now, and the wall clock is asserted from
|
|
148
|
+
* its own element either way.
|
|
149
|
+
*/
|
|
142
150
|
describe("clock", () => {
|
|
143
151
|
it("shows the playhead as wall-clock time next to the offset and the length", () => {
|
|
144
152
|
render(<ReplayHeader {...makeProps()} />);
|
|
@@ -148,7 +156,7 @@ describe("ReplayHeader", () => {
|
|
|
148
156
|
"10:13:22",
|
|
149
157
|
);
|
|
150
158
|
expect(screen.getByTestId("replay-header-clock")).toHaveTextContent(
|
|
151
|
-
"
|
|
159
|
+
"0:41 / 4:12",
|
|
152
160
|
);
|
|
153
161
|
});
|
|
154
162
|
|
|
@@ -162,7 +170,7 @@ describe("ReplayHeader", () => {
|
|
|
162
170
|
/Invalid/,
|
|
163
171
|
);
|
|
164
172
|
expect(screen.getByTestId("replay-header-clock")).toHaveTextContent(
|
|
165
|
-
"
|
|
173
|
+
"0:41 / 4:12",
|
|
166
174
|
);
|
|
167
175
|
});
|
|
168
176
|
|