@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.
Files changed (262) hide show
  1. package/Models/DatabaseModels/NetworkDevice.ts +44 -0
  2. package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
  3. package/Models/DatabaseModels/RunnerJob.ts +17 -2
  4. package/Server/API/LlmProviderAPI.ts +8 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
  8. package/Server/Services/NetworkDeviceLinkService.ts +338 -2
  9. package/Server/Services/NetworkDeviceService.ts +265 -12
  10. package/Server/Services/RunnerJobService.ts +24 -1
  11. package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
  12. package/Server/Types/Database/JSONColumnQuery.ts +42 -4
  13. package/Server/Utils/LLM/LLMService.ts +108 -19
  14. package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
  15. package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
  16. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
  17. package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
  18. package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
  19. package/Server/Utils/SSRFProtection.ts +5 -4
  20. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
  21. package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
  22. package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
  23. package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
  24. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
  25. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
  26. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
  27. package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
  28. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
  29. package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
  30. package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
  31. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
  32. package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
  33. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
  34. package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
  35. package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
  36. package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
  37. package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
  38. package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
  39. package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
  40. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
  41. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
  42. package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
  43. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
  44. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
  45. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
  46. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
  47. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
  48. package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
  49. package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
  50. package/Tests/Types/API/URLTelScheme.test.ts +261 -0
  51. package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
  52. package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
  53. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
  54. package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
  55. package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
  56. package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
  57. package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
  58. package/Tests/UI/Components/Button.test.tsx +279 -0
  59. package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
  60. package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
  61. package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
  62. package/Tests/UI/Components/Icon.test.tsx +57 -0
  63. package/Tests/UI/Components/List.test.tsx +20 -3
  64. package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
  65. package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
  66. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
  67. package/Tests/UI/Components/Pagination.test.tsx +721 -146
  68. package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
  69. package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
  70. package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
  71. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
  72. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
  73. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
  74. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
  75. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
  76. package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
  77. package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
  78. package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
  79. package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
  80. package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
  81. package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
  82. package/Types/API/Protocol.ts +9 -0
  83. package/Types/API/URL.ts +286 -20
  84. package/Types/Billing/PayAsYouGoPricing.ts +47 -0
  85. package/Types/CustomField/CustomFieldType.ts +28 -0
  86. package/Types/Monitor/MonitorType.ts +11 -0
  87. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
  88. package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
  89. package/Types/Runbook/RunbookStepType.ts +23 -0
  90. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
  91. package/UI/Components/Button/Button.tsx +14 -22
  92. package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
  93. package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
  94. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
  95. package/UI/Components/Charts/Line/LineChart.tsx +4 -2
  96. package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
  97. package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
  98. package/UI/Components/Dictionary/Dictionary.tsx +4 -39
  99. package/UI/Components/Icon/Icon.tsx +1 -1
  100. package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
  101. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
  102. package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
  103. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
  104. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
  105. package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
  106. package/UI/Components/Pagination/Pagination.tsx +373 -328
  107. package/UI/Components/Pagination/PaginationUtil.ts +263 -0
  108. package/UI/Components/Pagination/Screenshots/README.md +15 -0
  109. package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
  110. package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
  111. package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
  112. package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
  113. package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
  114. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
  115. package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
  116. package/UI/Components/TextArea/TextArea.tsx +3 -0
  117. package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
  118. package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
  119. package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
  120. package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
  121. package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
  122. package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
  123. package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
  124. package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
  125. package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
  126. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
  127. package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
  128. package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
  129. package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
  130. package/Utils/API.ts +243 -36
  131. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
  132. package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
  133. package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
  134. package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
  135. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  136. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
  137. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
  138. package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
  139. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  140. package/build/dist/Server/API/LlmProviderAPI.js +9 -1
  141. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  146. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
  147. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  148. package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
  149. package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
  150. package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
  151. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  152. package/build/dist/Server/Services/RunnerJobService.js +20 -2
  153. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  154. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
  155. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
  156. package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
  157. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
  158. package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
  159. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  160. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
  161. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  162. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
  163. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  164. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
  165. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  166. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
  167. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  168. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
  169. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
  170. package/build/dist/Server/Utils/SSRFProtection.js +5 -4
  171. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  172. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
  173. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  174. package/build/dist/Types/API/Protocol.js +9 -0
  175. package/build/dist/Types/API/Protocol.js.map +1 -1
  176. package/build/dist/Types/API/URL.js +241 -18
  177. package/build/dist/Types/API/URL.js.map +1 -1
  178. package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
  179. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
  180. package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
  181. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  182. package/build/dist/Types/Monitor/MonitorType.js +10 -0
  183. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  184. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
  185. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
  186. package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
  187. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  188. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  189. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  190. package/build/dist/UI/Components/Button/Button.js +10 -16
  191. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
  193. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  194. package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
  195. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  196. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
  197. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  198. package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
  199. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  200. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
  201. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  202. package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
  203. package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
  204. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  205. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  206. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
  207. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  208. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
  209. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  210. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
  211. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
  212. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  213. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  214. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
  215. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  216. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
  217. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  218. package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
  219. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  220. package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
  221. package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
  222. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
  223. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  224. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
  225. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
  226. package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
  227. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  228. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
  229. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  230. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
  231. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
  232. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
  233. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
  234. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
  235. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
  236. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
  237. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
  238. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
  239. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
  240. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
  241. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
  242. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
  243. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
  244. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
  245. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
  246. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
  247. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
  248. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
  249. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
  250. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
  251. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
  252. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
  253. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
  254. package/build/dist/Utils/API.js +175 -34
  255. package/build/dist/Utils/API.js.map +1 -1
  256. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
  257. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
  258. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
  259. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  260. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
  261. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
  262. package/package.json +1 -1
@@ -0,0 +1,517 @@
1
+ /*
2
+ * Stored JSON <-> rows, in both directions.
3
+ *
4
+ * The last step out is always buildColumnValueJson, and the operator wrappers
5
+ * are always built by buildDictionaryValue, so the bytes that reach the server
6
+ * are produced by exactly the code that produced them before this editor
7
+ * existed. Everything here decides *what* to hand those two functions.
8
+ *
9
+ * The rule that shapes the whole file: reading a value and writing it back
10
+ * unchanged must produce the same bytes. An editor that quietly rewrites
11
+ * {"port": "8080"} into {"port": 8080} the moment someone opens a workflow and
12
+ * saves it is worse than one that asks a question it should not have needed to
13
+ * ask.
14
+ */
15
+
16
+ import GreaterThan from "../../../../Types/BaseDatabase/GreaterThan";
17
+ import GreaterThanOrEqual from "../../../../Types/BaseDatabase/GreaterThanOrEqual";
18
+ import LessThan from "../../../../Types/BaseDatabase/LessThan";
19
+ import LessThanOrEqual from "../../../../Types/BaseDatabase/LessThanOrEqual";
20
+ import Dictionary from "../../../../Types/Dictionary";
21
+ import { JSONObject } from "../../../../Types/JSON";
22
+ import { getTemplateExpressionRegex } from "../../../../Types/Workflow/TemplateSyntax";
23
+ import {
24
+ DictionaryEntryValue,
25
+ DictionaryFilterOperator,
26
+ DictionaryFilterOperatorOption,
27
+ buildDictionaryValue,
28
+ detectOperatorFromValue,
29
+ getOperatorOption,
30
+ } from "../../Dictionary/DictionaryFilterOperator";
31
+ import {
32
+ ModelColumnEditorMode,
33
+ buildColumnValueJson,
34
+ } from "../ModelColumnEditor";
35
+ import {
36
+ ModelSchemaColumn,
37
+ findColumn,
38
+ requiredWritableColumns,
39
+ } from "../ModelSchema";
40
+ import { controlForColumn, literalFitsControl } from "./ColumnControl";
41
+ import {
42
+ ColumnValueMode,
43
+ ModelColumnControl,
44
+ ModelColumnRow,
45
+ makeColumnRow,
46
+ } from "./ColumnRow";
47
+
48
+ export type ContainsTemplateExpressionFunction = (value: string) => boolean;
49
+
50
+ /**
51
+ * Does this text hold a {{ }} reference?
52
+ *
53
+ * Uses the runtime's own matcher rather than a hand-rolled `/{{/`, so a value
54
+ * this editor calls a reference is one the runner will actually substitute.
55
+ */
56
+ export const containsTemplateExpression: ContainsTemplateExpressionFunction = (
57
+ value: string,
58
+ ): boolean => {
59
+ return getTemplateExpressionRegex().test(value);
60
+ };
61
+
62
+ type UnwrapOperatorValueFunction = (value: unknown) => unknown;
63
+
64
+ /*
65
+ * The scalar inside an operator wrapper, or the value itself when it is not
66
+ * one. detectOperatorFromValue gives back a string for display; this keeps the
67
+ * original JavaScript type so a stored number stays a number.
68
+ */
69
+ const unwrapOperatorValue: UnwrapOperatorValueFunction = (
70
+ value: unknown,
71
+ ): unknown => {
72
+ if (value && typeof value === "object" && "value" in value) {
73
+ return (value as { value?: unknown }).value;
74
+ }
75
+
76
+ return value;
77
+ };
78
+
79
+ type LiteralTextForFunction = (
80
+ control: ModelColumnControl,
81
+ value: unknown,
82
+ ) => string;
83
+
84
+ const literalTextFor: LiteralTextForFunction = (
85
+ control: ModelColumnControl,
86
+ value: unknown,
87
+ ): string => {
88
+ if (value === undefined || value === null) {
89
+ return "";
90
+ }
91
+
92
+ /*
93
+ * Only a real boolean is spelled out. Mapping everything else to "false" put
94
+ * a stored "true" - or "yes", or 1 - on screen as the word "false", which is
95
+ * the opposite of what the workflow does, and this function also names the
96
+ * text of a raw row, where the value is by definition not a boolean.
97
+ */
98
+ if (control === ModelColumnControl.Boolean && typeof value === "boolean") {
99
+ return value ? "true" : "false";
100
+ }
101
+
102
+ return String(value);
103
+ };
104
+
105
+ export type ClassifyRowValueFunction = (
106
+ control: ModelColumnControl,
107
+ value: unknown,
108
+ ) => Pick<ModelColumnRow, "valueMode" | "text" | "rawValue">;
109
+
110
+ /**
111
+ * Which of the three editing modes a stored value belongs in.
112
+ *
113
+ * Inferred once, when the value is read. Never guessed at render time - a cell
114
+ * that decided for itself what it was holding would flip modes as the builder
115
+ * typed.
116
+ */
117
+ export const classifyRowValue: ClassifyRowValueFunction = (
118
+ control: ModelColumnControl,
119
+ value: unknown,
120
+ ): Pick<ModelColumnRow, "valueMode" | "text" | "rawValue"> => {
121
+ if (typeof value === "string" && containsTemplateExpression(value)) {
122
+ return { valueMode: ColumnValueMode.Reference, text: value };
123
+ }
124
+
125
+ /*
126
+ * null is a real stored value and no empty control can express it: an empty
127
+ * control emits "", which a record drops entirely. So it is kept raw and
128
+ * re-emitted verbatim until the builder types over it.
129
+ */
130
+ if (value === null) {
131
+ return { valueMode: ColumnValueMode.Raw, text: "", rawValue: null };
132
+ }
133
+
134
+ if (literalFitsControl(control, value)) {
135
+ return {
136
+ valueMode: ColumnValueMode.Literal,
137
+ text: literalTextFor(control, value),
138
+ };
139
+ }
140
+
141
+ return {
142
+ valueMode: ColumnValueMode.Raw,
143
+ text: literalTextFor(control, value),
144
+ rawValue: value,
145
+ };
146
+ };
147
+
148
+ export type RowsFromParsedValueFunction = (
149
+ parsed: JSONObject | null,
150
+ columns: Array<ModelSchemaColumn>,
151
+ mode: ModelColumnEditorMode,
152
+ ) => Array<ModelColumnRow>;
153
+
154
+ /**
155
+ * The stored object, as rows, in the order its keys were written.
156
+ *
157
+ * Order is never sorted. The picker is sorted (the endpoint does it by title),
158
+ * but the rows are the document, and reordering them is rewriting the stored
159
+ * bytes for nothing.
160
+ */
161
+ export const rowsFromParsedValue: RowsFromParsedValueFunction = (
162
+ parsed: JSONObject | null,
163
+ columns: Array<ModelSchemaColumn>,
164
+ mode: ModelColumnEditorMode,
165
+ ): Array<ModelColumnRow> => {
166
+ if (!parsed) {
167
+ return [];
168
+ }
169
+
170
+ const isQuery: boolean = mode === ModelColumnEditorMode.Query;
171
+ const rows: Array<ModelColumnRow> = [];
172
+
173
+ for (const key of Object.keys(parsed)) {
174
+ const value: unknown = parsed[key];
175
+ const column: ModelSchemaColumn | undefined = findColumn(columns, key);
176
+ const control: ModelColumnControl = controlForColumn(column);
177
+
178
+ if (!isQuery) {
179
+ rows.push(
180
+ makeColumnRow({
181
+ columnId: key,
182
+ operator: DictionaryFilterOperator.EqualTo,
183
+ ...classifyRowValue(control, value),
184
+ }),
185
+ );
186
+ continue;
187
+ }
188
+
189
+ const detected: {
190
+ operator: DictionaryFilterOperator;
191
+ rawValue: string;
192
+ rawValues?: Array<string> | undefined;
193
+ } = detectOperatorFromValue(value);
194
+
195
+ const option: DictionaryFilterOperatorOption = getOperatorOption(
196
+ detected.operator,
197
+ );
198
+
199
+ if (option.expectsMultiValue) {
200
+ rows.push(
201
+ makeColumnRow({
202
+ columnId: key,
203
+ operator: detected.operator,
204
+ values: detected.rawValues || [],
205
+ }),
206
+ );
207
+ continue;
208
+ }
209
+
210
+ if (option.hidesValueInput) {
211
+ rows.push(makeColumnRow({ columnId: key, operator: detected.operator }));
212
+ continue;
213
+ }
214
+
215
+ rows.push(
216
+ makeColumnRow({
217
+ columnId: key,
218
+ operator: detected.operator,
219
+ ...classifyRowValue(control, unwrapOperatorValue(value)),
220
+ }),
221
+ );
222
+ }
223
+
224
+ return rows;
225
+ };
226
+
227
+ export type SeedRequiredRowsFunction = (
228
+ rows: Array<ModelColumnRow>,
229
+ columns: Array<ModelSchemaColumn>,
230
+ ) => Array<ModelColumnRow>;
231
+
232
+ /**
233
+ * One blank row per column a create must be given a value for, appended after
234
+ * whatever was stored.
235
+ *
236
+ * Appended, never inserted: the stored keys keep their order, so seeding cannot
237
+ * change the bytes of a workflow that is only opened and closed. Seeded rows
238
+ * hold "" and are dropped on the way out, so an untouched Create One still
239
+ * reads as empty to form validation and to the graph linter.
240
+ */
241
+ export const seedRequiredRows: SeedRequiredRowsFunction = (
242
+ rows: Array<ModelColumnRow>,
243
+ columns: Array<ModelSchemaColumn>,
244
+ ): Array<ModelColumnRow> => {
245
+ const present: Set<string> = new Set(
246
+ rows.map((row: ModelColumnRow) => {
247
+ return row.columnId;
248
+ }),
249
+ );
250
+
251
+ const seeded: Array<ModelColumnRow> = [];
252
+
253
+ for (const column of requiredWritableColumns(columns)) {
254
+ if (present.has(column.id)) {
255
+ continue;
256
+ }
257
+
258
+ seeded.push(makeColumnRow({ columnId: column.id, isSeeded: true }));
259
+ }
260
+
261
+ return [...rows, ...seeded];
262
+ };
263
+
264
+ type EmitLiteralValueFunction = (
265
+ control: ModelColumnControl,
266
+ text: string,
267
+ ) => DictionaryEntryValue;
268
+
269
+ /**
270
+ * A row's text, as the JSON value it stands for.
271
+ *
272
+ * "" is returned as "" rather than as null or omitted, because that is the
273
+ * marker buildColumnValueJson reads to drop a blank field from a record.
274
+ */
275
+ const emitLiteralValue: EmitLiteralValueFunction = (
276
+ control: ModelColumnControl,
277
+ text: string,
278
+ ): DictionaryEntryValue => {
279
+ if (text === "") {
280
+ return "";
281
+ }
282
+
283
+ if (control === ModelColumnControl.Number) {
284
+ const asNumber: number = Number(text);
285
+
286
+ /*
287
+ * Text that is not a number is emitted as text, not dropped and not turned
288
+ * into NaN. The row shows why it is wrong; throwing the value away would
289
+ * take the builder's work with it.
290
+ */
291
+ if (text.trim() === "" || isNaN(asNumber)) {
292
+ return text;
293
+ }
294
+
295
+ return asNumber;
296
+ }
297
+
298
+ if (control === ModelColumnControl.Boolean) {
299
+ if (text === "true") {
300
+ return true;
301
+ }
302
+
303
+ if (text === "false") {
304
+ return false;
305
+ }
306
+
307
+ return text;
308
+ }
309
+
310
+ return text;
311
+ };
312
+
313
+ export type EmitRowValueFunction = (
314
+ row: ModelColumnRow,
315
+ control: ModelColumnControl,
316
+ ) => DictionaryEntryValue;
317
+
318
+ /**
319
+ * The value half of a row, before any operator wrapper is put around it.
320
+ */
321
+ export const emitRowValue: EmitRowValueFunction = (
322
+ row: ModelColumnRow,
323
+ control: ModelColumnControl,
324
+ ): DictionaryEntryValue => {
325
+ if (row.valueMode === ColumnValueMode.Raw) {
326
+ return row.rawValue as DictionaryEntryValue;
327
+ }
328
+
329
+ /*
330
+ * A reference is always emitted as a string, on every column type. The
331
+ * runner substitutes the text and the result is parsed as JSON, so an
332
+ * unquoted substitution on a numeric column would be a gamble on what the
333
+ * referenced value happens to look like. Postgres casts '5' to 5 on the way
334
+ * into an integer column; it cannot rescue a document that does not parse.
335
+ */
336
+ if (row.valueMode === ColumnValueMode.Reference) {
337
+ return row.text;
338
+ }
339
+
340
+ return emitLiteralValue(control, row.text);
341
+ };
342
+
343
+ type BuildComparisonWrapperFunction = (
344
+ operator: DictionaryFilterOperator,
345
+ value: string,
346
+ ) => DictionaryEntryValue | null;
347
+
348
+ /*
349
+ * The ordering operators built over a string rather than a number.
350
+ *
351
+ * buildDictionaryValue does `new GreaterThan(Number(text))`, which is right for
352
+ * a number and silently destructive for anything else: a date or a {{ }}
353
+ * reference becomes NaN, and JSON.stringify writes NaN as null - a query
354
+ * against NULL that matches nothing and reports no error. These columns are
355
+ * declared CompareType = number | Date | string, so the string form is a value
356
+ * the wrapper was always able to hold.
357
+ */
358
+ const buildComparisonWrapper: BuildComparisonWrapperFunction = (
359
+ operator: DictionaryFilterOperator,
360
+ value: string,
361
+ ): DictionaryEntryValue | null => {
362
+ switch (operator) {
363
+ case DictionaryFilterOperator.GreaterThan:
364
+ return new GreaterThan<string>(value);
365
+ case DictionaryFilterOperator.GreaterThanOrEqual:
366
+ return new GreaterThanOrEqual<string>(value);
367
+ case DictionaryFilterOperator.LessThan:
368
+ return new LessThan<string>(value);
369
+ case DictionaryFilterOperator.LessThanOrEqual:
370
+ return new LessThanOrEqual<string>(value);
371
+ default:
372
+ return null;
373
+ }
374
+ };
375
+
376
+ export type BuildOperatorValueFunction = (
377
+ row: ModelColumnRow,
378
+ control: ModelColumnControl,
379
+ ) => DictionaryEntryValue;
380
+
381
+ /**
382
+ * A query row, wrapped in whatever its operator needs.
383
+ *
384
+ * Delegates to buildDictionaryValue for every case it handles correctly, so
385
+ * each wrapper class's own toJSON() still produces the bytes and the key order
386
+ * inside {_type, value} is unchanged.
387
+ */
388
+ export const buildOperatorValue: BuildOperatorValueFunction = (
389
+ row: ModelColumnRow,
390
+ control: ModelColumnControl,
391
+ ): DictionaryEntryValue => {
392
+ const option: DictionaryFilterOperatorOption = getOperatorOption(
393
+ row.operator,
394
+ );
395
+
396
+ if (option.hidesValueInput) {
397
+ return buildDictionaryValue({ operator: row.operator, rawValue: "" });
398
+ }
399
+
400
+ if (option.expectsMultiValue) {
401
+ return buildDictionaryValue({
402
+ operator: row.operator,
403
+ rawValue: "",
404
+ rawValues: row.values,
405
+ });
406
+ }
407
+
408
+ const emitted: DictionaryEntryValue = emitRowValue(row, control);
409
+
410
+ /*
411
+ * Equality carries no wrapper at all - it is stored as the bare value, which
412
+ * is what every query written before operators existed looks like.
413
+ */
414
+ if (row.operator === DictionaryFilterOperator.EqualTo) {
415
+ return emitted;
416
+ }
417
+
418
+ if (option.expectsNumericValue && typeof emitted !== "number") {
419
+ const wrapper: DictionaryEntryValue | null = buildComparisonWrapper(
420
+ row.operator,
421
+ typeof emitted === "string" ? emitted : String(emitted ?? ""),
422
+ );
423
+
424
+ if (wrapper !== null) {
425
+ return wrapper;
426
+ }
427
+ }
428
+
429
+ return buildDictionaryValue({
430
+ operator: row.operator,
431
+ rawValue: typeof emitted === "string" ? emitted : String(emitted ?? ""),
432
+ });
433
+ };
434
+
435
+ export type RowsToEntryDictionaryFunction = (
436
+ rows: Array<ModelColumnRow>,
437
+ columns: Array<ModelSchemaColumn>,
438
+ mode: ModelColumnEditorMode,
439
+ ) => Dictionary<DictionaryEntryValue>;
440
+
441
+ export const rowsToEntryDictionary: RowsToEntryDictionaryFunction = (
442
+ rows: Array<ModelColumnRow>,
443
+ columns: Array<ModelSchemaColumn>,
444
+ mode: ModelColumnEditorMode,
445
+ ): Dictionary<DictionaryEntryValue> => {
446
+ const entries: Dictionary<DictionaryEntryValue> = {};
447
+ const isQuery: boolean = mode === ModelColumnEditorMode.Query;
448
+
449
+ for (const row of rows) {
450
+ if (row.columnId.trim() === "") {
451
+ continue;
452
+ }
453
+
454
+ const control: ModelColumnControl = controlForColumn(
455
+ findColumn(columns, row.columnId),
456
+ );
457
+
458
+ entries[row.columnId] = isQuery
459
+ ? buildOperatorValue(row, control)
460
+ : emitRowValue(row, control);
461
+ }
462
+
463
+ return entries;
464
+ };
465
+
466
+ export type SerializeColumnRowsFunction = (
467
+ rows: Array<ModelColumnRow>,
468
+ columns: Array<ModelSchemaColumn>,
469
+ mode: ModelColumnEditorMode,
470
+ ) => string;
471
+
472
+ /**
473
+ * The rows, as the string stored on the workflow argument.
474
+ *
475
+ * Ends in buildColumnValueJson, unchanged, which is what drops blank record
476
+ * fields and collapses an empty editor to "" rather than to "{}".
477
+ */
478
+ export const serializeColumnRows: SerializeColumnRowsFunction = (
479
+ rows: Array<ModelColumnRow>,
480
+ columns: Array<ModelSchemaColumn>,
481
+ mode: ModelColumnEditorMode,
482
+ ): string => {
483
+ return buildColumnValueJson(rowsToEntryDictionary(rows, columns, mode), mode);
484
+ };
485
+
486
+ export type RowIssueFunction = (
487
+ row: ModelColumnRow,
488
+ column: ModelSchemaColumn | undefined,
489
+ ) => string | null;
490
+
491
+ /**
492
+ * What is wrong with what has been typed into this row, in one sentence, or
493
+ * null when nothing is.
494
+ *
495
+ * Advisory only. Nothing here blocks saving: the value is still written, and
496
+ * the builder can still be right about a column this endpoint describes badly.
497
+ */
498
+ export const rowIssue: RowIssueFunction = (
499
+ row: ModelColumnRow,
500
+ column: ModelSchemaColumn | undefined,
501
+ ): string | null => {
502
+ if (row.valueMode !== ColumnValueMode.Literal || row.text === "") {
503
+ return null;
504
+ }
505
+
506
+ const control: ModelColumnControl = controlForColumn(column);
507
+
508
+ if (control === ModelColumnControl.Number && isNaN(Number(row.text))) {
509
+ return "This column takes a number.";
510
+ }
511
+
512
+ if (control === ModelColumnControl.Date && isNaN(Date.parse(row.text))) {
513
+ return "This column takes a date and time.";
514
+ }
515
+
516
+ return null;
517
+ };