@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
|
@@ -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
|
+
};
|