@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,178 @@
1
+ /*
2
+ * One field of a record: the column's real name and description on the left,
3
+ * the value on the right.
4
+ *
5
+ * This is a settings form, not a table of key/value pairs, because the keys are
6
+ * not the builder's to invent - they are the model's columns, and the model has
7
+ * already said what each one is called and what it means.
8
+ */
9
+
10
+ import IconProp from "../../../../Types/Icon/IconProp";
11
+ import AutocompleteTextInput from "../../AutocompleteTextInput/AutocompleteTextInput";
12
+ import Button, { ButtonStyleType } from "../../Button/Button";
13
+ import { ModelSchemaColumn } from "../ModelSchema";
14
+ import { columnTypeLabel, controlForColumn } from "./ColumnControl";
15
+ import {
16
+ ColumnValueMode,
17
+ ModelColumnControl,
18
+ ModelColumnRow,
19
+ changeColumnRow,
20
+ } from "./ColumnRow";
21
+ import { rowIssue } from "./ColumnRowSerialization";
22
+ import ColumnValueInput from "./ColumnValueInput";
23
+ import React, { FunctionComponent, ReactElement, useId } from "react";
24
+
25
+ export interface ComponentProps {
26
+ row: ModelColumnRow;
27
+ /** Undefined when the stored key is not a column this model describes. */
28
+ column: ModelSchemaColumn | undefined;
29
+ /** Every column id, offered as autocomplete when a key has to be retyped. */
30
+ knownColumnIds: Array<string>;
31
+ isRequired: boolean;
32
+ suggestions?: Array<string> | undefined;
33
+ /** Focused on mount, so a field added from the picker is ready to type into. */
34
+ autoFocus?: boolean | undefined;
35
+ onChange: (row: ModelColumnRow) => void;
36
+ onRemove: () => void;
37
+ }
38
+
39
+ const ColumnFieldRow: FunctionComponent<ComponentProps> = (
40
+ props: ComponentProps,
41
+ ): ReactElement => {
42
+ const labelId: string = useId();
43
+ const control: ModelColumnControl = controlForColumn(props.column);
44
+ const issue: string | null = rowIssue(props.row, props.column);
45
+ const isUnknownColumn: boolean = !props.column;
46
+ const typeLabel: string = columnTypeLabel(props.column);
47
+
48
+ /*
49
+ * An empty required field is worth pointing at, but only quietly: the step
50
+ * cannot be saved without it anyway (form validation reads the whole value),
51
+ * and a red row for something the builder has not reached yet reads as an
52
+ * error they made.
53
+ */
54
+ const isEmptyRequired: boolean =
55
+ props.isRequired && props.row.text === "" && props.row.values.length === 0;
56
+
57
+ return (
58
+ <div
59
+ className="group relative grid grid-cols-1 items-start gap-x-4 gap-y-2 px-3 py-3 transition-colors hover:bg-gray-50/60 sm:grid-cols-[minmax(0,14rem)_minmax(0,1fr)_auto]"
60
+ data-testid="model-column-row"
61
+ >
62
+ {isEmptyRequired && (
63
+ <span
64
+ className="absolute left-0 top-2 bottom-2 w-0.5 rounded-r bg-amber-400"
65
+ aria-hidden="true"
66
+ />
67
+ )}
68
+
69
+ <div className="min-w-0">
70
+ {isUnknownColumn ? (
71
+ <div>
72
+ <AutocompleteTextInput
73
+ value={props.row.columnId}
74
+ placeholder="Column name"
75
+ suggestions={props.knownColumnIds}
76
+ outerDivClassName="relative w-full"
77
+ className="block w-full rounded-md border border-amber-300 bg-white py-1.5 pl-2 pr-2 font-mono text-xs text-gray-900 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
78
+ disableSpellCheck={true}
79
+ onChange={(value: string) => {
80
+ props.onChange(changeColumnRow(props.row, { columnId: value }));
81
+ }}
82
+ />
83
+ <span className="mt-1 inline-block rounded bg-amber-50 px-1.5 py-0.5 text-[11px] text-amber-700">
84
+ Not a column on this model
85
+ </span>
86
+ </div>
87
+ ) : (
88
+ <>
89
+ <label
90
+ id={labelId}
91
+ className="block truncate text-sm font-medium text-gray-900"
92
+ >
93
+ {props.column?.title}
94
+ {props.isRequired && (
95
+ <span className="ml-0.5 text-red-500" aria-hidden="true">
96
+ *
97
+ </span>
98
+ )}
99
+ </label>
100
+ {/*
101
+ The column name and its type share a line. Stacked they made every
102
+ field four lines tall, and the two together are one fact: what this
103
+ key is called on the wire, and what shape of value it takes.
104
+
105
+ The type is dropped when it would only repeat the field's own name -
106
+ a column called "Color" does not need "Color" printed under it.
107
+ */}
108
+ <span className="mt-1 flex items-center gap-1.5 text-[11px] text-gray-500">
109
+ <span className="truncate rounded bg-gray-100 px-1.5 py-0.5 font-mono">
110
+ {props.row.columnId}
111
+ </span>
112
+ {typeLabel.toLowerCase() !==
113
+ (props.column?.title || "").toLowerCase() && (
114
+ <span className="truncate text-gray-400">{typeLabel}</span>
115
+ )}
116
+ </span>
117
+ {/*
118
+ Wrapped rather than truncated. This sentence is the model's own
119
+ explanation of the field and is often the only thing that settles
120
+ what to type; cutting it off mid-word and hiding the rest behind a
121
+ hover is not a real answer inside a modal.
122
+ */}
123
+ {props.column?.description && (
124
+ <span className="mt-1 block text-xs leading-snug text-gray-500">
125
+ {props.column.description}
126
+ </span>
127
+ )}
128
+ </>
129
+ )}
130
+ </div>
131
+
132
+ <div className="min-w-0">
133
+ <ColumnValueInput
134
+ control={control}
135
+ valueMode={props.row.valueMode}
136
+ text={props.row.text}
137
+ values={props.row.values}
138
+ placeholder={props.column?.example || props.column?.placeholder}
139
+ suggestions={props.suggestions}
140
+ ariaLabelledby={isUnknownColumn ? undefined : labelId}
141
+ autoFocus={props.autoFocus}
142
+ dataTestId={`model-column-value-${props.row.columnId}`}
143
+ onChange={(change: Partial<ModelColumnRow>) => {
144
+ props.onChange(changeColumnRow(props.row, change));
145
+ }}
146
+ />
147
+
148
+ {props.row.valueMode === ColumnValueMode.Raw && (
149
+ <p className="mt-1 text-[11px] text-amber-600">
150
+ Kept exactly as it was saved. Editing it rewrites it in this
151
+ column&apos;s own type.
152
+ </p>
153
+ )}
154
+
155
+ {issue && <p className="mt-1 text-[11px] text-red-500">{issue}</p>}
156
+
157
+ {props.column?.isTenantColumn && (
158
+ <p className="mt-1 text-[11px] text-gray-500">
159
+ The workflow sets this itself and ignores what you type here.
160
+ </p>
161
+ )}
162
+ </div>
163
+
164
+ <div className="flex items-center pt-1">
165
+ <Button
166
+ buttonStyle={ButtonStyleType.ICON}
167
+ icon={IconProp.Trash}
168
+ title="Remove"
169
+ dataTestId={`model-column-remove-${props.row.columnId}`}
170
+ className="opacity-0 transition-opacity focus-visible:opacity-100 group-hover:opacity-100"
171
+ onClick={props.onRemove}
172
+ />
173
+ </div>
174
+ </div>
175
+ );
176
+ };
177
+
178
+ export default ColumnFieldRow;
@@ -0,0 +1,206 @@
1
+ /*
2
+ * Which comparisons a column can be filtered by, and what to call them.
3
+ *
4
+ * The old row editor offered all fourteen operators against every column, so a
5
+ * Boolean column offered "starts with" and an ID column offered "greater than".
6
+ * Both are accepted by the form and neither means anything - `uuid ILIKE '%x%'`
7
+ * needs a cast Postgres will not do for you.
8
+ *
9
+ * Only the labels change here. The DictionaryFilterOperator members, and
10
+ * therefore every byte that reaches the server, are exactly the ones the
11
+ * Dictionary form already emitted.
12
+ */
13
+
14
+ import {
15
+ DICTIONARY_FILTER_OPERATOR_OPTIONS,
16
+ DictionaryFilterOperator,
17
+ DictionaryFilterOperatorOption,
18
+ getOperatorOption,
19
+ } from "../../Dictionary/DictionaryFilterOperator";
20
+ import { ModelColumnControl } from "./ColumnRow";
21
+
22
+ const TEXT_OPERATORS: Array<DictionaryFilterOperator> = [
23
+ DictionaryFilterOperator.EqualTo,
24
+ DictionaryFilterOperator.NotEqual,
25
+ DictionaryFilterOperator.Contains,
26
+ DictionaryFilterOperator.NotContains,
27
+ DictionaryFilterOperator.StartsWith,
28
+ DictionaryFilterOperator.EndsWith,
29
+ DictionaryFilterOperator.IsAnyOf,
30
+ DictionaryFilterOperator.IsNoneOf,
31
+ DictionaryFilterOperator.IsEmpty,
32
+ DictionaryFilterOperator.IsNotEmpty,
33
+ ];
34
+
35
+ const NUMBER_OPERATORS: Array<DictionaryFilterOperator> = [
36
+ DictionaryFilterOperator.EqualTo,
37
+ DictionaryFilterOperator.NotEqual,
38
+ DictionaryFilterOperator.GreaterThan,
39
+ DictionaryFilterOperator.GreaterThanOrEqual,
40
+ DictionaryFilterOperator.LessThan,
41
+ DictionaryFilterOperator.LessThanOrEqual,
42
+ DictionaryFilterOperator.IsAnyOf,
43
+ DictionaryFilterOperator.IsNoneOf,
44
+ DictionaryFilterOperator.IsEmpty,
45
+ DictionaryFilterOperator.IsNotEmpty,
46
+ ];
47
+
48
+ const DATE_OPERATORS: Array<DictionaryFilterOperator> = [
49
+ DictionaryFilterOperator.EqualTo,
50
+ DictionaryFilterOperator.NotEqual,
51
+ DictionaryFilterOperator.GreaterThan,
52
+ DictionaryFilterOperator.GreaterThanOrEqual,
53
+ DictionaryFilterOperator.LessThan,
54
+ DictionaryFilterOperator.LessThanOrEqual,
55
+ DictionaryFilterOperator.IsEmpty,
56
+ DictionaryFilterOperator.IsNotEmpty,
57
+ ];
58
+
59
+ const IDENTIFIER_OPERATORS: Array<DictionaryFilterOperator> = [
60
+ DictionaryFilterOperator.EqualTo,
61
+ DictionaryFilterOperator.NotEqual,
62
+ DictionaryFilterOperator.IsAnyOf,
63
+ DictionaryFilterOperator.IsNoneOf,
64
+ DictionaryFilterOperator.IsEmpty,
65
+ DictionaryFilterOperator.IsNotEmpty,
66
+ ];
67
+
68
+ const BOOLEAN_OPERATORS: Array<DictionaryFilterOperator> = [
69
+ DictionaryFilterOperator.EqualTo,
70
+ DictionaryFilterOperator.NotEqual,
71
+ DictionaryFilterOperator.IsEmpty,
72
+ DictionaryFilterOperator.IsNotEmpty,
73
+ ];
74
+
75
+ /*
76
+ * A date reads far better as "is after" than as ">", and the ordering
77
+ * operators are the whole point of filtering on one. Anything not listed keeps
78
+ * the shared label from DICTIONARY_FILTER_OPERATOR_OPTIONS.
79
+ */
80
+ const DATE_OPERATOR_LABELS: Partial<Record<DictionaryFilterOperator, string>> =
81
+ {
82
+ [DictionaryFilterOperator.EqualTo]: "is",
83
+ [DictionaryFilterOperator.NotEqual]: "is not",
84
+ [DictionaryFilterOperator.GreaterThan]: "is after",
85
+ [DictionaryFilterOperator.GreaterThanOrEqual]: "is on or after",
86
+ [DictionaryFilterOperator.LessThan]: "is before",
87
+ [DictionaryFilterOperator.LessThanOrEqual]: "is on or before",
88
+ [DictionaryFilterOperator.IsEmpty]: "is not set",
89
+ [DictionaryFilterOperator.IsNotEmpty]: "is set",
90
+ };
91
+
92
+ const BOOLEAN_OPERATOR_LABELS: Partial<
93
+ Record<DictionaryFilterOperator, string>
94
+ > = {
95
+ [DictionaryFilterOperator.EqualTo]: "is",
96
+ [DictionaryFilterOperator.NotEqual]: "is not",
97
+ [DictionaryFilterOperator.IsEmpty]: "is not set",
98
+ [DictionaryFilterOperator.IsNotEmpty]: "is set",
99
+ };
100
+
101
+ const DEFAULT_OPERATOR_LABELS: Partial<
102
+ Record<DictionaryFilterOperator, string>
103
+ > = {
104
+ [DictionaryFilterOperator.IsEmpty]: "is not set",
105
+ [DictionaryFilterOperator.IsNotEmpty]: "is set",
106
+ };
107
+
108
+ export type OperatorsForControlFunction = (
109
+ control: ModelColumnControl,
110
+ currentOperator?: DictionaryFilterOperator | undefined,
111
+ ) => Array<DictionaryFilterOperator>;
112
+
113
+ /**
114
+ * The operators offered for a column, in the order they should be listed.
115
+ *
116
+ * `currentOperator` is always included even when the type filter would drop it.
117
+ * A query saved before this filter existed can hold "contains" on an ID column;
118
+ * leaving it out of the list would render a blank dropdown, and the next
119
+ * unrelated edit to that row would silently rewrite the operator to equals.
120
+ */
121
+ export const operatorsForControl: OperatorsForControlFunction = (
122
+ control: ModelColumnControl,
123
+ currentOperator?: DictionaryFilterOperator | undefined,
124
+ ): Array<DictionaryFilterOperator> => {
125
+ let operators: Array<DictionaryFilterOperator>;
126
+
127
+ switch (control) {
128
+ case ModelColumnControl.Number:
129
+ operators = NUMBER_OPERATORS;
130
+ break;
131
+ case ModelColumnControl.Date:
132
+ operators = DATE_OPERATORS;
133
+ break;
134
+ case ModelColumnControl.ObjectId:
135
+ case ModelColumnControl.Color:
136
+ operators = IDENTIFIER_OPERATORS;
137
+ break;
138
+ case ModelColumnControl.Boolean:
139
+ operators = BOOLEAN_OPERATORS;
140
+ break;
141
+ default:
142
+ /*
143
+ * Unsupported lands here too. It is never offered in the picker, but a
144
+ * stored condition on such a column still gets a row, and that row should
145
+ * have the widest set rather than the narrowest.
146
+ */
147
+ operators = TEXT_OPERATORS;
148
+ break;
149
+ }
150
+
151
+ if (currentOperator && !operators.includes(currentOperator)) {
152
+ return [...operators, currentOperator];
153
+ }
154
+
155
+ return [...operators];
156
+ };
157
+
158
+ export type DefaultOperatorForControlFunction = (
159
+ control: ModelColumnControl,
160
+ ) => DictionaryFilterOperator;
161
+
162
+ export const defaultOperatorForControl: DefaultOperatorForControlFunction =
163
+ (): DictionaryFilterOperator => {
164
+ /*
165
+ * Equals for every type. It is the only operator that is right more often
166
+ * than not, and it is the one the value serializes without a wrapper.
167
+ */
168
+ return DictionaryFilterOperator.EqualTo;
169
+ };
170
+
171
+ export type OperatorLabelForFunction = (
172
+ operator: DictionaryFilterOperator,
173
+ control: ModelColumnControl,
174
+ ) => string;
175
+
176
+ export const operatorLabelFor: OperatorLabelForFunction = (
177
+ operator: DictionaryFilterOperator,
178
+ control: ModelColumnControl,
179
+ ): string => {
180
+ const overrides: Partial<Record<DictionaryFilterOperator, string>> =
181
+ control === ModelColumnControl.Date
182
+ ? DATE_OPERATOR_LABELS
183
+ : control === ModelColumnControl.Boolean
184
+ ? BOOLEAN_OPERATOR_LABELS
185
+ : DEFAULT_OPERATOR_LABELS;
186
+
187
+ const override: string | undefined = overrides[operator];
188
+
189
+ if (override) {
190
+ return override;
191
+ }
192
+
193
+ return getOperatorOption(operator).label;
194
+ };
195
+
196
+ export type IsKnownOperatorFunction = (value: string) => boolean;
197
+
198
+ export const isKnownOperator: IsKnownOperatorFunction = (
199
+ value: string,
200
+ ): boolean => {
201
+ return DICTIONARY_FILTER_OPERATOR_OPTIONS.some(
202
+ (option: DictionaryFilterOperatorOption) => {
203
+ return option.operator === value;
204
+ },
205
+ );
206
+ };
@@ -0,0 +1,157 @@
1
+ /*
2
+ * The row model shared by the record form and the query builder.
3
+ *
4
+ * A row is one column of the model plus the value the builder typed for it.
5
+ * Everything the editor knows about a row that is not the schema lives here,
6
+ * and the two React bodies hold no state of their own — ModelColumnEditor owns
7
+ * the array and hands it down, so a row can never disagree with the JSON the
8
+ * argument is stored as.
9
+ */
10
+
11
+ import { DictionaryFilterOperator } from "../../Dictionary/DictionaryFilterOperator";
12
+
13
+ /**
14
+ * The kind of control a column's value is typed into.
15
+ *
16
+ * Deliberately much smaller than TableColumnType: the builder does not need a
17
+ * different box for Email than for Slug, and every extra control is another
18
+ * thing that can render the wrong way round. What matters is the shape of the
19
+ * value that comes out — string, number, boolean, ISO date — because that is
20
+ * what ends up in the JSON the server parses.
21
+ */
22
+ export enum ModelColumnControl {
23
+ Text = "Text",
24
+ LongText = "LongText",
25
+ Number = "Number",
26
+ Boolean = "Boolean",
27
+ Date = "Date",
28
+ ObjectId = "ObjectId",
29
+ Color = "Color",
30
+ /** Buffers, files, nested JSON, monitor steps — no row can hold one. */
31
+ Unsupported = "Unsupported",
32
+ }
33
+
34
+ /**
35
+ * How the value in a row is being edited.
36
+ *
37
+ * Literal is the type-appropriate control. Reference is the {{ }} autocomplete,
38
+ * available on every column type because most creates are assembled out of an
39
+ * earlier step's return values. Raw is the escape hatch for a stored scalar
40
+ * whose JavaScript type disagrees with the column's — `{"port": "8080"}` on a
41
+ * numeric column — which is re-emitted exactly as it was read until the builder
42
+ * edits that one cell. Without Raw, opening a workflow and saving it again
43
+ * would quietly rewrite the stored bytes.
44
+ */
45
+ export enum ColumnValueMode {
46
+ Literal = "Literal",
47
+ Reference = "Reference",
48
+ Raw = "Raw",
49
+ }
50
+
51
+ /**
52
+ * One row of the editor.
53
+ *
54
+ * `text` is what the control shows and is always a string, whatever the column
55
+ * type — the conversion to a JSON number/boolean/null happens once, on the way
56
+ * out, in ColumnRowSerialization. `values` is only used by the multi-value
57
+ * operators (is any of / is none of), which Record mode never offers.
58
+ */
59
+ export interface ModelColumnRow {
60
+ /**
61
+ * This row's identity for React, fixed when the row is created.
62
+ *
63
+ * It cannot be the column name: an unknown column is edited in a text box, so
64
+ * keying on the name would give the row a new identity on every keystroke,
65
+ * unmount it mid-word and take the focused input with it.
66
+ */
67
+ key: string;
68
+ /** The column name as it will be written into the JSON object. */
69
+ columnId: string;
70
+ operator: DictionaryFilterOperator;
71
+ valueMode: ColumnValueMode;
72
+ text: string;
73
+ values: Array<string>;
74
+ /**
75
+ * True for a blank row the editor opened with because the model says a create
76
+ * must supply this column. Seeded rows serialize away while they are empty,
77
+ * so an untouched Create One still reads as "nothing set" to form validation
78
+ * and to the graph linter.
79
+ */
80
+ isSeeded: boolean;
81
+ /**
82
+ * The value exactly as it was read from storage, kept only for
83
+ * ColumnValueMode.Raw so that round-tripping is byte-for-byte.
84
+ */
85
+ rawValue?: unknown;
86
+ }
87
+
88
+ /*
89
+ * A counter rather than a random id, so a row's identity is reproducible and
90
+ * two editors mounted in the same page can never collide.
91
+ */
92
+ let nextRowKey: number = 0;
93
+
94
+ export type MakeColumnRowFunction = (
95
+ row: Partial<ModelColumnRow> & { columnId: string },
96
+ ) => ModelColumnRow;
97
+
98
+ export const makeColumnRow: MakeColumnRowFunction = (
99
+ row: Partial<ModelColumnRow> & { columnId: string },
100
+ ): ModelColumnRow => {
101
+ nextRowKey = nextRowKey + 1;
102
+
103
+ return {
104
+ key: row.key || `row-${nextRowKey}`,
105
+ columnId: row.columnId,
106
+ operator: row.operator || DictionaryFilterOperator.EqualTo,
107
+ valueMode: row.valueMode || ColumnValueMode.Literal,
108
+ text: row.text === undefined ? "" : row.text,
109
+ values: row.values || [],
110
+ isSeeded: Boolean(row.isSeeded),
111
+ ...(row.rawValue === undefined ? {} : { rawValue: row.rawValue }),
112
+ };
113
+ };
114
+
115
+ /**
116
+ * A row with some of its fields changed.
117
+ *
118
+ * Every edit goes through here rather than through several separate callbacks,
119
+ * because two callbacks fired from one event both close over the same render's
120
+ * row and the second silently discards the first. That is how editing a raw
121
+ * cell came to change the box on screen without changing what was stored.
122
+ *
123
+ * Leaving Raw drops the stored original: from that point the builder's own
124
+ * value is what the row means, in the column's own type.
125
+ */
126
+ export type ChangeColumnRowFunction = (
127
+ row: ModelColumnRow,
128
+ change: Partial<
129
+ Pick<
130
+ ModelColumnRow,
131
+ "columnId" | "operator" | "valueMode" | "text" | "values"
132
+ >
133
+ >,
134
+ ) => ModelColumnRow;
135
+
136
+ export const changeColumnRow: ChangeColumnRowFunction = (
137
+ row: ModelColumnRow,
138
+ change: Partial<
139
+ Pick<
140
+ ModelColumnRow,
141
+ "columnId" | "operator" | "valueMode" | "text" | "values"
142
+ >
143
+ >,
144
+ ): ModelColumnRow => {
145
+ const next: ModelColumnRow = {
146
+ ...row,
147
+ ...change,
148
+ // Any edit means the row is no longer just a blank the editor opened with.
149
+ isSeeded: false,
150
+ };
151
+
152
+ if (next.valueMode !== ColumnValueMode.Raw) {
153
+ delete next.rawValue;
154
+ }
155
+
156
+ return next;
157
+ };