@oneuptime/common 12.0.9 → 12.0.11
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/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
- package/Models/DatabaseModels/RunnerJob.ts +17 -2
- package/Server/API/LlmProviderAPI.ts +8 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
- package/Server/Services/NetworkDeviceLinkService.ts +338 -2
- package/Server/Services/NetworkDeviceService.ts +265 -12
- package/Server/Services/RunnerJobService.ts +24 -1
- package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
- package/Server/Types/Database/JSONColumnQuery.ts +42 -4
- package/Server/Utils/LLM/LLMService.ts +108 -19
- package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
- package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
- package/Server/Utils/SSRFProtection.ts +5 -4
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
- package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
- package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
- package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
- package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
- package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
- package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
- package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
- package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
- package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
- package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
- package/Tests/Types/API/URLTelScheme.test.ts +261 -0
- package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
- package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
- package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
- package/Tests/UI/Components/Button.test.tsx +279 -0
- package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
- package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
- package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
- package/Tests/UI/Components/Icon.test.tsx +57 -0
- package/Tests/UI/Components/List.test.tsx +20 -3
- package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
- package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
- package/Tests/UI/Components/Pagination.test.tsx +721 -146
- package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
- package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
- package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
- package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
- package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
- package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
- package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
- package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
- package/Types/API/Protocol.ts +9 -0
- package/Types/API/URL.ts +286 -20
- package/Types/Billing/PayAsYouGoPricing.ts +47 -0
- package/Types/CustomField/CustomFieldType.ts +28 -0
- package/Types/Monitor/MonitorType.ts +11 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
- package/Types/Runbook/RunbookStepType.ts +23 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
- package/UI/Components/Button/Button.tsx +14 -22
- package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
- package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +4 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
- package/UI/Components/Dictionary/Dictionary.tsx +4 -39
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
- package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
- package/UI/Components/Pagination/Pagination.tsx +373 -328
- package/UI/Components/Pagination/PaginationUtil.ts +263 -0
- package/UI/Components/Pagination/Screenshots/README.md +15 -0
- package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
- package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
- package/UI/Components/TextArea/TextArea.tsx +3 -0
- package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
- package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
- package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
- package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
- package/Utils/API.ts +243 -36
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
- package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +9 -1
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.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/NetworkDeviceLabelRuleEngineService.js +202 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +20 -2
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
- package/build/dist/Server/Utils/SSRFProtection.js +5 -4
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Types/API/Protocol.js +9 -0
- package/build/dist/Types/API/Protocol.js.map +1 -1
- package/build/dist/Types/API/URL.js +241 -18
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
- package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +10 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +10 -16
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
- package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
- package/build/dist/Utils/API.js +175 -34
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
- package/package.json +1 -1
|
@@ -353,8 +353,8 @@ function defineInventorySource<TModel extends BaseModel>(
|
|
|
353
353
|
|
|
354
354
|
/*
|
|
355
355
|
* Archived rows are excluded from every source that has the concept: the
|
|
356
|
-
* explorer is a view of the live estate. IoTDevice
|
|
357
|
-
* archive flag, so
|
|
356
|
+
* explorer is a view of the live estate. IoTDevice is the only source without
|
|
357
|
+
* an archive flag, so it is the only unrestricted query.
|
|
358
358
|
*/
|
|
359
359
|
export const INVENTORY_SOURCES: ReadonlyArray<ErasedInventorySource> = [
|
|
360
360
|
defineInventorySource<NetworkDevice>({
|
|
@@ -362,7 +362,7 @@ export const INVENTORY_SOURCES: ReadonlyArray<ErasedInventorySource> = [
|
|
|
362
362
|
resourceType: "NetworkDevice",
|
|
363
363
|
service: NetworkDeviceService,
|
|
364
364
|
select: { hostname: true },
|
|
365
|
-
query: {},
|
|
365
|
+
query: { isArchived: false },
|
|
366
366
|
describe: (row: NetworkDevice): Dictionary<string> => {
|
|
367
367
|
return compactAttributes({ "net.device.hostname": row.hostname });
|
|
368
368
|
},
|
|
@@ -469,6 +469,12 @@ export interface InventorySyncResult {
|
|
|
469
469
|
created: number;
|
|
470
470
|
updated: number;
|
|
471
471
|
deleted: number;
|
|
472
|
+
/**
|
|
473
|
+
* Orphans that were archived rather than deleted because they carried custom
|
|
474
|
+
* field values. Counted apart from `deleted` so the job log distinguishes
|
|
475
|
+
* "the projection went away" from "we kept someone's data".
|
|
476
|
+
*/
|
|
477
|
+
archived: number;
|
|
472
478
|
}
|
|
473
479
|
|
|
474
480
|
/**
|
|
@@ -579,15 +585,133 @@ async function mirrorRows(
|
|
|
579
585
|
}
|
|
580
586
|
|
|
581
587
|
/**
|
|
582
|
-
*
|
|
583
|
-
*
|
|
588
|
+
* Does this row carry anything a person typed?
|
|
589
|
+
*
|
|
590
|
+
* The `customFields` bag is the only user-authored content a mirrored row can
|
|
591
|
+
* hold — every other column on it is rewritten from the owning table on each
|
|
592
|
+
* pass — so it is the whole test for "deleting this loses work".
|
|
593
|
+
*
|
|
594
|
+
* An empty bag counts as nothing: the UI leaves `{}` behind when the last
|
|
595
|
+
* value is cleared, and a row whose fields were all emptied is not one anyone
|
|
596
|
+
* is keeping. A key explicitly set to null or "" is likewise not a value.
|
|
597
|
+
*/
|
|
598
|
+
export type HasCustomFieldValuesFunction = (row: InventoryItem) => boolean;
|
|
599
|
+
|
|
600
|
+
export const hasCustomFieldValues: HasCustomFieldValuesFunction = (
|
|
601
|
+
row: InventoryItem,
|
|
602
|
+
): boolean => {
|
|
603
|
+
const bag: JSONObject | undefined = row.customFields;
|
|
604
|
+
|
|
605
|
+
if (!bag || typeof bag !== "object") {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return Object.keys(bag).some((key: string) => {
|
|
610
|
+
const value: unknown = (bag as JSONObject)[key];
|
|
611
|
+
|
|
612
|
+
if (value === undefined || value === null || value === "") {
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return !(Array.isArray(value) && value.length === 0);
|
|
617
|
+
});
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
export interface OrphanPartition {
|
|
621
|
+
/** Orphans safe to remove outright — pure projections, nothing typed. */
|
|
622
|
+
deletableIds: Array<ObjectID>;
|
|
623
|
+
/** Orphans that must be kept, because they carry user-authored values. */
|
|
624
|
+
archivableIds: Array<ObjectID>;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export type PartitionOrphanRowsFunction = (data: {
|
|
628
|
+
rows: Array<InventoryItem>;
|
|
629
|
+
/** Ids still present in the owning table, from `findLiveIds`. */
|
|
630
|
+
liveResourceIds: Set<string>;
|
|
631
|
+
}) => OrphanPartition;
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* The whole decision the reverse pass makes, as a pure function of one page of
|
|
635
|
+
* registry rows and the set of owning-table ids that still exist.
|
|
636
|
+
*
|
|
637
|
+
* Split out from the IO because this is where a mistake destroys data and
|
|
638
|
+
* where a test can actually reach: getting it wrong either hard-deletes rows
|
|
639
|
+
* holding the only copy of someone's serial numbers, or lets the registry
|
|
640
|
+
* accumulate projections of devices that no longer exist.
|
|
641
|
+
*/
|
|
642
|
+
export const partitionOrphanRows: PartitionOrphanRowsFunction = (data: {
|
|
643
|
+
rows: Array<InventoryItem>;
|
|
644
|
+
liveResourceIds: Set<string>;
|
|
645
|
+
}): OrphanPartition => {
|
|
646
|
+
const deletableIds: Array<ObjectID> = [];
|
|
647
|
+
const archivableIds: Array<ObjectID> = [];
|
|
648
|
+
|
|
649
|
+
for (const row of data.rows || []) {
|
|
650
|
+
if (!row.id) {
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/*
|
|
655
|
+
* A mirrored row with no pointer cannot be matched back to anything, so
|
|
656
|
+
* it is orphaned by definition.
|
|
657
|
+
*/
|
|
658
|
+
const isOrphan: boolean =
|
|
659
|
+
!row.resourceId || !data.liveResourceIds.has(row.resourceId.toString());
|
|
660
|
+
|
|
661
|
+
if (!isOrphan) {
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (!hasCustomFieldValues(row)) {
|
|
666
|
+
deletableIds.push(row.id);
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/*
|
|
671
|
+
* Already archived on an earlier sweep. Re-archiving would rewrite
|
|
672
|
+
* `archivedAt` on every 15-minute pass, so the timestamp would report the
|
|
673
|
+
* most recent sweep rather than when the device went away.
|
|
674
|
+
*/
|
|
675
|
+
if (row.isArchived) {
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
archivableIds.push(row.id);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return { deletableIds, archivableIds };
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Reverse pass: a mirrored row whose owning inventory row is gone stops being
|
|
687
|
+
* part of the live estate. This is what catches cascade deletes, which fire no
|
|
688
|
+
* service hook.
|
|
689
|
+
*
|
|
690
|
+
* Orphans split two ways, on whether the row holds anything a person typed:
|
|
691
|
+
*
|
|
692
|
+
* - nothing typed: hard-deleted, as before. The row was a pure projection of
|
|
693
|
+
* a table row that no longer exists, so there is nothing to keep.
|
|
694
|
+
*
|
|
695
|
+
* - custom field values present: ARCHIVED, not deleted. Those values are the
|
|
696
|
+
* only copy — serial numbers, warranty dates, owning team — and they live
|
|
697
|
+
* on the registry row rather than on the device, so deleting the projection
|
|
698
|
+
* destroys them with no undo and no audit trail (`hardDeleteBy` bypasses
|
|
699
|
+
* the audit hook). Archiving takes the row out of the default list, which
|
|
700
|
+
* is the visible behaviour the delete was there to produce, and leaves the
|
|
701
|
+
* data recoverable from the Archived tab.
|
|
702
|
+
*
|
|
703
|
+
* The cost of being wrong differs by orders of magnitude between the two, which
|
|
704
|
+
* is why the split is here and not left to an operator's retention policy.
|
|
584
705
|
*/
|
|
585
|
-
async function removeOrphans(
|
|
586
|
-
|
|
706
|
+
async function removeOrphans(
|
|
707
|
+
source: ErasedInventorySource,
|
|
708
|
+
): Promise<{ deleted: number; archived: number }> {
|
|
709
|
+
const deletableIds: Array<ObjectID> = [];
|
|
710
|
+
const archivableIds: Array<ObjectID> = [];
|
|
587
711
|
let skip: number = 0;
|
|
588
712
|
|
|
589
713
|
/*
|
|
590
|
-
* Collected across a read-only pass and
|
|
714
|
+
* Collected across a read-only pass and written afterwards. Writing while
|
|
591
715
|
* paging would shift subsequent offsets and skip rows.
|
|
592
716
|
*/
|
|
593
717
|
for (;;) {
|
|
@@ -596,7 +720,12 @@ async function removeOrphans(source: ErasedInventorySource): Promise<number> {
|
|
|
596
720
|
entityType: source.entityType,
|
|
597
721
|
source: EntitySource.Inventory,
|
|
598
722
|
},
|
|
599
|
-
select: {
|
|
723
|
+
select: {
|
|
724
|
+
_id: true,
|
|
725
|
+
resourceId: true,
|
|
726
|
+
customFields: true,
|
|
727
|
+
isArchived: true,
|
|
728
|
+
},
|
|
600
729
|
skip,
|
|
601
730
|
limit: INVENTORY_SYNC_PAGE_SIZE,
|
|
602
731
|
props: { isRoot: true },
|
|
@@ -614,16 +743,13 @@ async function removeOrphans(source: ErasedInventorySource): Promise<number> {
|
|
|
614
743
|
}
|
|
615
744
|
|
|
616
745
|
const liveIds: Set<string> = await source.findLiveIds(resourceIds);
|
|
746
|
+
const partition: OrphanPartition = partitionOrphanRows({
|
|
747
|
+
rows: rows,
|
|
748
|
+
liveResourceIds: liveIds,
|
|
749
|
+
});
|
|
617
750
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
* A mirrored row with no pointer cannot be matched back to anything,
|
|
621
|
-
* so it is orphaned by definition.
|
|
622
|
-
*/
|
|
623
|
-
if (!row.resourceId || !liveIds.has(row.resourceId.toString())) {
|
|
624
|
-
orphanIds.push(row.id!);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
751
|
+
deletableIds.push(...partition.deletableIds);
|
|
752
|
+
archivableIds.push(...partition.archivableIds);
|
|
627
753
|
|
|
628
754
|
skip += rows.length;
|
|
629
755
|
|
|
@@ -632,26 +758,42 @@ async function removeOrphans(source: ErasedInventorySource): Promise<number> {
|
|
|
632
758
|
}
|
|
633
759
|
}
|
|
634
760
|
|
|
635
|
-
if (
|
|
636
|
-
|
|
761
|
+
if (deletableIds.length > 0) {
|
|
762
|
+
await InventoryItemService.hardDeleteBy({
|
|
763
|
+
query: {
|
|
764
|
+
_id: QueryHelper.any(
|
|
765
|
+
deletableIds.map((id: ObjectID) => {
|
|
766
|
+
return id.toString();
|
|
767
|
+
}),
|
|
768
|
+
),
|
|
769
|
+
// Re-asserted so a bug upstream can never widen this into a broad delete.
|
|
770
|
+
source: EntitySource.Inventory,
|
|
771
|
+
},
|
|
772
|
+
limit: deletableIds.length,
|
|
773
|
+
skip: 0,
|
|
774
|
+
props: { isRoot: true },
|
|
775
|
+
});
|
|
637
776
|
}
|
|
638
777
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
778
|
+
if (archivableIds.length > 0) {
|
|
779
|
+
await InventoryItemService.updateBy({
|
|
780
|
+
query: {
|
|
781
|
+
_id: QueryHelper.any(
|
|
782
|
+
archivableIds.map((id: ObjectID) => {
|
|
783
|
+
return id.toString();
|
|
784
|
+
}),
|
|
785
|
+
),
|
|
786
|
+
// Same reason as the delete above: never widen past mirrored rows.
|
|
787
|
+
source: EntitySource.Inventory,
|
|
788
|
+
},
|
|
789
|
+
data: { isArchived: true },
|
|
790
|
+
limit: archivableIds.length,
|
|
791
|
+
skip: 0,
|
|
792
|
+
props: { isRoot: true },
|
|
793
|
+
});
|
|
794
|
+
}
|
|
653
795
|
|
|
654
|
-
return
|
|
796
|
+
return { deleted: deletableIds.length, archived: archivableIds.length };
|
|
655
797
|
}
|
|
656
798
|
|
|
657
799
|
/** Reconciles one inventory table into the registry. */
|
|
@@ -659,8 +801,8 @@ export async function syncInventorySource(
|
|
|
659
801
|
source: ErasedInventorySource,
|
|
660
802
|
): Promise<InventorySyncResult> {
|
|
661
803
|
const { created, updated } = await mirrorRows(source);
|
|
662
|
-
const deleted
|
|
663
|
-
return { created, updated, deleted };
|
|
804
|
+
const { deleted, archived } = await removeOrphans(source);
|
|
805
|
+
return { created, updated, deleted, archived };
|
|
664
806
|
}
|
|
665
807
|
|
|
666
808
|
/**
|
|
@@ -669,7 +811,12 @@ export async function syncInventorySource(
|
|
|
669
811
|
* should not stop network devices being mirrored.
|
|
670
812
|
*/
|
|
671
813
|
export async function syncAllInventorySources(): Promise<InventorySyncResult> {
|
|
672
|
-
const total: InventorySyncResult = {
|
|
814
|
+
const total: InventorySyncResult = {
|
|
815
|
+
created: 0,
|
|
816
|
+
updated: 0,
|
|
817
|
+
deleted: 0,
|
|
818
|
+
archived: 0,
|
|
819
|
+
};
|
|
673
820
|
|
|
674
821
|
for (const source of INVENTORY_SOURCES) {
|
|
675
822
|
try {
|
|
@@ -677,6 +824,7 @@ export async function syncAllInventorySources(): Promise<InventorySyncResult> {
|
|
|
677
824
|
total.created += result.created;
|
|
678
825
|
total.updated += result.updated;
|
|
679
826
|
total.deleted += result.deleted;
|
|
827
|
+
total.archived += result.archived;
|
|
680
828
|
} catch (err) {
|
|
681
829
|
logger.error(
|
|
682
830
|
`InventoryEntityRegistry: sync failed for ${source.resourceType}:`,
|