@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
|
@@ -13,11 +13,20 @@ import FieldType from "../../../../UI/Components/Types/FieldType";
|
|
|
13
13
|
import Monitor from "../../../../Models/DatabaseModels/Monitor";
|
|
14
14
|
import MonitorCustomField from "../../../../Models/DatabaseModels/MonitorCustomField";
|
|
15
15
|
import CustomFieldType from "../../../../Types/CustomField/CustomFieldType";
|
|
16
|
+
import OneUptimeDate from "../../../../Types/Date";
|
|
17
|
+
import Timezone from "../../../../Types/Timezone";
|
|
16
18
|
import { JSONObject } from "../../../../Types/JSON";
|
|
17
19
|
import "@testing-library/jest-dom";
|
|
18
20
|
import { cleanup, render } from "@testing-library/react";
|
|
19
21
|
import React from "react";
|
|
20
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
afterAll,
|
|
24
|
+
afterEach,
|
|
25
|
+
beforeAll,
|
|
26
|
+
describe,
|
|
27
|
+
expect,
|
|
28
|
+
test,
|
|
29
|
+
} from "@jest/globals";
|
|
21
30
|
|
|
22
31
|
/*
|
|
23
32
|
* Custom field *definitions* live in a per-resource table; the *values* live in
|
|
@@ -1211,3 +1220,342 @@ describe("CustomFieldColumns generated getElement", () => {
|
|
|
1211
1220
|
);
|
|
1212
1221
|
});
|
|
1213
1222
|
});
|
|
1223
|
+
|
|
1224
|
+
/*
|
|
1225
|
+
* ---------------------------------------------------------------------------
|
|
1226
|
+
* Date and DateTime custom fields
|
|
1227
|
+
* ---------------------------------------------------------------------------
|
|
1228
|
+
*
|
|
1229
|
+
* A date custom field is kept in the jsonb bag as an ISO-8601 string, because
|
|
1230
|
+
* that is the one representation that is both comparable in a query (ISO-8601
|
|
1231
|
+
* sorts identically as text and as an instant) and unambiguous about which
|
|
1232
|
+
* instant it names. It is also unreadable in a table cell, so the renderer
|
|
1233
|
+
* hands it to the same local formatter the Detail view uses - a row and the
|
|
1234
|
+
* item page it opens then agree about what day something happened.
|
|
1235
|
+
*
|
|
1236
|
+
* Two things here break silently. The `isDateOnly` flag: drop it and a
|
|
1237
|
+
* warranty-expiry column grows a meaningless "00:00" that nobody entered, and
|
|
1238
|
+
* nothing else about the cell changes to give it away. And the export value:
|
|
1239
|
+
* humanise it and every CSV that feeds an external CMDB stops round-tripping,
|
|
1240
|
+
* which is only discovered on the import side, in someone else's system.
|
|
1241
|
+
*
|
|
1242
|
+
* The formatter resolves wall clocks in the viewer's timezone and picks 12- or
|
|
1243
|
+
* 24-hour from the browser locale, so both are pinned below. Without that these
|
|
1244
|
+
* assertions would pass or fail depending on the machine running the suite,
|
|
1245
|
+
* which is the same thing as not asserting anything.
|
|
1246
|
+
*/
|
|
1247
|
+
|
|
1248
|
+
const dateDefinition: CustomFieldDefinition = {
|
|
1249
|
+
name: "Warranty Expiry",
|
|
1250
|
+
customFieldType: CustomFieldType.Date,
|
|
1251
|
+
};
|
|
1252
|
+
|
|
1253
|
+
const dateTimeDefinition: CustomFieldDefinition = {
|
|
1254
|
+
name: "Last Audited At",
|
|
1255
|
+
customFieldType: CustomFieldType.DateTime,
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1258
|
+
/*
|
|
1259
|
+
* 14:30 UTC on purpose: a stored midnight would render as the same calendar day
|
|
1260
|
+
* in half the world's zones by luck, so it could not tell a timezone-aware
|
|
1261
|
+
* rendering apart from a naive string slice.
|
|
1262
|
+
*/
|
|
1263
|
+
const storedIsoValue: string = "2026-08-17T14:30:00.000Z";
|
|
1264
|
+
|
|
1265
|
+
describe("CustomFieldColumns date custom fields", () => {
|
|
1266
|
+
beforeAll(() => {
|
|
1267
|
+
OneUptimeDate.setUserTimezone(Timezone.UTC);
|
|
1268
|
+
|
|
1269
|
+
/*
|
|
1270
|
+
* getUserPrefers12HourFormat sniffs the browser locale, so on one developer
|
|
1271
|
+
* machine the cell reads "14:30" and on the next "02:30 PM". Pin it rather
|
|
1272
|
+
* than write an assertion loose enough to accept both - a loose assertion
|
|
1273
|
+
* would also accept the time going missing entirely.
|
|
1274
|
+
*/
|
|
1275
|
+
jest
|
|
1276
|
+
.spyOn(OneUptimeDate, "getUserPrefers12HourFormat")
|
|
1277
|
+
.mockReturnValue(false);
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
afterEach(() => {
|
|
1281
|
+
// A test that re-pins the zone must not hand it to the next one.
|
|
1282
|
+
OneUptimeDate.setUserTimezone(Timezone.UTC);
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
afterAll(() => {
|
|
1286
|
+
// Never leak either pin into the rest of the suite.
|
|
1287
|
+
OneUptimeDate.setUserTimezone(null);
|
|
1288
|
+
jest.restoreAllMocks();
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
describe("renderCustomFieldValue", () => {
|
|
1292
|
+
test("renders a Date value as a calendar date with no time of day", () => {
|
|
1293
|
+
/*
|
|
1294
|
+
* A Date field is a day, not an instant - a warranty expires on a date.
|
|
1295
|
+
* Rendering the stored midnight-relative time next to it would invent a
|
|
1296
|
+
* precision the person filling the field never entered.
|
|
1297
|
+
*/
|
|
1298
|
+
expect(
|
|
1299
|
+
renderValue({ value: storedIsoValue, definition: dateDefinition })
|
|
1300
|
+
.textContent,
|
|
1301
|
+
).toEqual("Aug 17, 2026");
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
test("renders a Date value without any clock time in it at all", () => {
|
|
1305
|
+
// Belt and braces on the above: no "14:30", and no stray zone suffix.
|
|
1306
|
+
const text: string =
|
|
1307
|
+
renderValue({ value: storedIsoValue, definition: dateDefinition })
|
|
1308
|
+
.textContent || "";
|
|
1309
|
+
|
|
1310
|
+
expect(text).not.toContain(":");
|
|
1311
|
+
expect(text).not.toContain("UTC");
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
test("renders a DateTime value with the time of day and the zone", () => {
|
|
1315
|
+
/*
|
|
1316
|
+
* The other half of the field pair: "last audited at" is an instant, and
|
|
1317
|
+
* without the zone abbreviation a wall clock names a different instant to
|
|
1318
|
+
* every reader.
|
|
1319
|
+
*/
|
|
1320
|
+
expect(
|
|
1321
|
+
renderValue({ value: storedIsoValue, definition: dateTimeDefinition })
|
|
1322
|
+
.textContent,
|
|
1323
|
+
).toEqual("Aug 17 2026, 14:30 UTC");
|
|
1324
|
+
});
|
|
1325
|
+
|
|
1326
|
+
test("renders the very same stored string differently for Date and DateTime", () => {
|
|
1327
|
+
/*
|
|
1328
|
+
* This is the whole isDateOnly flag. Passing the wrong one - or dropping
|
|
1329
|
+
* the argument so both types take the default - still produces a
|
|
1330
|
+
* plausible-looking cell, so nothing but a direct comparison of the two
|
|
1331
|
+
* catches it.
|
|
1332
|
+
*/
|
|
1333
|
+
const asDate: string =
|
|
1334
|
+
renderValue({ value: storedIsoValue, definition: dateDefinition })
|
|
1335
|
+
.textContent || "";
|
|
1336
|
+
const asDateTime: string =
|
|
1337
|
+
renderValue({ value: storedIsoValue, definition: dateTimeDefinition })
|
|
1338
|
+
.textContent || "";
|
|
1339
|
+
|
|
1340
|
+
expect(asDate).not.toEqual(asDateTime);
|
|
1341
|
+
expect(asDateTime).toContain("14:30");
|
|
1342
|
+
expect(asDate).not.toContain("14:30");
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
test("resolves the instant in the viewer's timezone, not in UTC as stored", () => {
|
|
1346
|
+
/*
|
|
1347
|
+
* The stored string is UTC; the cell is read by a person. A New York
|
|
1348
|
+
* viewer must see their own 10:30 - and, at the edges of the day, their
|
|
1349
|
+
* own calendar date - or the table disagrees with every other date in
|
|
1350
|
+
* the product.
|
|
1351
|
+
*/
|
|
1352
|
+
OneUptimeDate.setUserTimezone(Timezone.AmericaNew_York);
|
|
1353
|
+
|
|
1354
|
+
expect(
|
|
1355
|
+
renderValue({ value: storedIsoValue, definition: dateTimeDefinition })
|
|
1356
|
+
.textContent,
|
|
1357
|
+
).toEqual("Aug 17 2026, 10:30 EDT");
|
|
1358
|
+
});
|
|
1359
|
+
|
|
1360
|
+
test("reads an offset-form ISO string as the same instant as the Z form", () => {
|
|
1361
|
+
/*
|
|
1362
|
+
* Both spellings are legal ISO-8601 and both are in the wild - the form
|
|
1363
|
+
* writes "Z", an API client may well post "+00:00" - and they name the
|
|
1364
|
+
* same moment, so they have to render the same.
|
|
1365
|
+
*/
|
|
1366
|
+
expect(
|
|
1367
|
+
renderValue({
|
|
1368
|
+
value: "2026-08-17T14:30:00+00:00",
|
|
1369
|
+
definition: dateTimeDefinition,
|
|
1370
|
+
}).textContent,
|
|
1371
|
+
).toEqual("Aug 17 2026, 14:30 UTC");
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
test("renders a date as plain text rather than as a dropdown badge", () => {
|
|
1375
|
+
/*
|
|
1376
|
+
* The date branch has to sit above the dropdown and fall-through text
|
|
1377
|
+
* branches. A date wearing a badge would read as a tag, which is a
|
|
1378
|
+
* different kind of value.
|
|
1379
|
+
*/
|
|
1380
|
+
const container: HTMLElement = renderValue({
|
|
1381
|
+
value: storedIsoValue,
|
|
1382
|
+
definition: dateDefinition,
|
|
1383
|
+
});
|
|
1384
|
+
|
|
1385
|
+
expect(getBadgeLabels(container)).toEqual([]);
|
|
1386
|
+
expect(
|
|
1387
|
+
container.querySelector('[data-dropdown-value-badge="true"]'),
|
|
1388
|
+
).toBeNull();
|
|
1389
|
+
expect(getPlaceholder(container)).toBeNull();
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
test("renders the placeholder for a date nobody has filled in", () => {
|
|
1393
|
+
/*
|
|
1394
|
+
* Not "Invalid date": an unset date is the ordinary state of a field that
|
|
1395
|
+
* was added to the project last week, and a whole column of red herrings
|
|
1396
|
+
* would train people to ignore the one row that really is broken.
|
|
1397
|
+
*/
|
|
1398
|
+
for (const definition of [dateDefinition, dateTimeDefinition]) {
|
|
1399
|
+
for (const value of [undefined, null, ""]) {
|
|
1400
|
+
const container: HTMLElement = renderValue({
|
|
1401
|
+
value: value,
|
|
1402
|
+
definition: definition,
|
|
1403
|
+
});
|
|
1404
|
+
|
|
1405
|
+
expect(container.textContent).toEqual("-");
|
|
1406
|
+
expect(getPlaceholder(container)).not.toBeNull();
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
test("uses the column's noValueMessage for a missing date", () => {
|
|
1412
|
+
// The empty branch is shared, so a date field inherits the same override.
|
|
1413
|
+
expect(
|
|
1414
|
+
renderValue({
|
|
1415
|
+
value: null,
|
|
1416
|
+
definition: dateTimeDefinition,
|
|
1417
|
+
noValueMessage: "Never audited",
|
|
1418
|
+
}).textContent,
|
|
1419
|
+
).toEqual("Never audited");
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1422
|
+
test("falls back to the raw stored string when the value will not parse", () => {
|
|
1423
|
+
/*
|
|
1424
|
+
* A value written over the API - or pasted into a CSV import - before the
|
|
1425
|
+
* field was turned into a date is still sitting in the jsonb bag, and the
|
|
1426
|
+
* cell is the only place anyone will ever see it. Showing what is
|
|
1427
|
+
* actually stored is what lets someone work out WHY the row is wrong;
|
|
1428
|
+
* "Invalid date" says only that something is, and looks identical for
|
|
1429
|
+
* every kind of garbage, so the fix (re-import "Q3 2026" as a real date)
|
|
1430
|
+
* is invisible from the table.
|
|
1431
|
+
*/
|
|
1432
|
+
expect(
|
|
1433
|
+
renderValue({ value: "not-a-date", definition: dateDefinition })
|
|
1434
|
+
.textContent,
|
|
1435
|
+
).toEqual("not-a-date");
|
|
1436
|
+
expect(
|
|
1437
|
+
renderValue({ value: "Q3 2026", definition: dateTimeDefinition })
|
|
1438
|
+
.textContent,
|
|
1439
|
+
).toEqual("Q3 2026");
|
|
1440
|
+
});
|
|
1441
|
+
});
|
|
1442
|
+
|
|
1443
|
+
describe("getCustomFieldColumns", () => {
|
|
1444
|
+
test("still disables sorting on a date column", () => {
|
|
1445
|
+
/*
|
|
1446
|
+
* Being a date makes a jsonb key look more orderable than it is - it is
|
|
1447
|
+
* still reachable only through an explicit ->> expression, which the sort
|
|
1448
|
+
* path has no concept of, so a clickable header would push an unknown
|
|
1449
|
+
* property into the query builder exactly as it would for text.
|
|
1450
|
+
*/
|
|
1451
|
+
const columns: Columns<Monitor> = getCustomFieldColumns<Monitor>({
|
|
1452
|
+
definitions: [dateDefinition, dateTimeDefinition],
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1455
|
+
for (const column of columns) {
|
|
1456
|
+
expect(column.disableSort).toBe(true);
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
test("still hides a date column by default", () => {
|
|
1461
|
+
// Date fields are no more special than the rest in the column picker.
|
|
1462
|
+
const columns: Columns<Monitor> = getCustomFieldColumns<Monitor>({
|
|
1463
|
+
definitions: [dateDefinition, dateTimeDefinition],
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
for (const column of columns) {
|
|
1467
|
+
expect(column.isHiddenByDefault).toBe(true);
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
test("exports the raw ISO string for a Date field, not the humanised one", () => {
|
|
1472
|
+
/*
|
|
1473
|
+
* Deliberate: the CSV is fed back into an external CMDB, which wants a
|
|
1474
|
+
* machine-readable timestamp. "Aug 17, 2026" would have to be re-parsed
|
|
1475
|
+
* on the far side by a locale nobody agreed on, and a date-only rendering
|
|
1476
|
+
* has already thrown the time away.
|
|
1477
|
+
*/
|
|
1478
|
+
const column: Column<Monitor> = columnAt(
|
|
1479
|
+
getCustomFieldColumns<Monitor>({ definitions: [dateDefinition] }),
|
|
1480
|
+
0,
|
|
1481
|
+
);
|
|
1482
|
+
|
|
1483
|
+
expect(
|
|
1484
|
+
exportValueOf(
|
|
1485
|
+
column,
|
|
1486
|
+
monitorWithFields({ "Warranty Expiry": storedIsoValue }),
|
|
1487
|
+
),
|
|
1488
|
+
).toEqual(storedIsoValue);
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1491
|
+
test("exports the raw ISO string for a DateTime field too", () => {
|
|
1492
|
+
const column: Column<Monitor> = columnAt(
|
|
1493
|
+
getCustomFieldColumns<Monitor>({ definitions: [dateTimeDefinition] }),
|
|
1494
|
+
0,
|
|
1495
|
+
);
|
|
1496
|
+
|
|
1497
|
+
expect(
|
|
1498
|
+
exportValueOf(
|
|
1499
|
+
column,
|
|
1500
|
+
monitorWithFields({ "Last Audited At": storedIsoValue }),
|
|
1501
|
+
),
|
|
1502
|
+
).toEqual(storedIsoValue);
|
|
1503
|
+
});
|
|
1504
|
+
|
|
1505
|
+
test("exports an empty cell for a date nobody has filled in", () => {
|
|
1506
|
+
// Not the literal "undefined", and not today's date either.
|
|
1507
|
+
const column: Column<Monitor> = columnAt(
|
|
1508
|
+
getCustomFieldColumns<Monitor>({ definitions: [dateDefinition] }),
|
|
1509
|
+
0,
|
|
1510
|
+
);
|
|
1511
|
+
|
|
1512
|
+
expect(exportValueOf(column, new Monitor())).toEqual("");
|
|
1513
|
+
expect(
|
|
1514
|
+
exportValueOf(column, monitorWithFields({ "Warranty Expiry": null })),
|
|
1515
|
+
).toEqual("");
|
|
1516
|
+
});
|
|
1517
|
+
|
|
1518
|
+
test("renders the humanised date off the row while exporting the ISO one", () => {
|
|
1519
|
+
/*
|
|
1520
|
+
* The end-to-end version of the split: the same column, the same row,
|
|
1521
|
+
* two different strings on purpose. Collapsing them - either way round -
|
|
1522
|
+
* breaks one of the two audiences.
|
|
1523
|
+
*/
|
|
1524
|
+
const column: Column<Monitor> = columnAt(
|
|
1525
|
+
getCustomFieldColumns<Monitor>({ definitions: [dateDefinition] }),
|
|
1526
|
+
0,
|
|
1527
|
+
);
|
|
1528
|
+
const monitor: Monitor = monitorWithFields({
|
|
1529
|
+
"Warranty Expiry": storedIsoValue,
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
expect(renderColumn(column, monitor).textContent).toEqual("Aug 17, 2026");
|
|
1533
|
+
expect(exportValueOf(column, monitor)).toEqual(storedIsoValue);
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
test("renders a DateTime straight off the row", () => {
|
|
1537
|
+
const column: Column<Monitor> = columnAt(
|
|
1538
|
+
getCustomFieldColumns<Monitor>({ definitions: [dateTimeDefinition] }),
|
|
1539
|
+
0,
|
|
1540
|
+
);
|
|
1541
|
+
|
|
1542
|
+
expect(
|
|
1543
|
+
renderColumn(
|
|
1544
|
+
column,
|
|
1545
|
+
monitorWithFields({ "Last Audited At": storedIsoValue }),
|
|
1546
|
+
).textContent,
|
|
1547
|
+
).toEqual("Aug 17 2026, 14:30 UTC");
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
test("renders the placeholder for a row with no date stored", () => {
|
|
1551
|
+
const column: Column<Monitor> = columnAt(
|
|
1552
|
+
getCustomFieldColumns<Monitor>({ definitions: [dateDefinition] }),
|
|
1553
|
+
0,
|
|
1554
|
+
);
|
|
1555
|
+
|
|
1556
|
+
expect(
|
|
1557
|
+
getPlaceholder(renderColumn(column, new Monitor())),
|
|
1558
|
+
).not.toBeNull();
|
|
1559
|
+
});
|
|
1560
|
+
});
|
|
1561
|
+
});
|