@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,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure pagination math, kept out of the component so the page-window and
|
|
3
|
+
* range arithmetic can be unit tested without rendering anything.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A slot in the rendered page list. Numbers are clickable pages; the two
|
|
8
|
+
* ellipsis markers are the gaps that were collapsed on either side of the
|
|
9
|
+
* current page. They are distinct values so the renderer can give them
|
|
10
|
+
* stable React keys (a list can contain both).
|
|
11
|
+
*/
|
|
12
|
+
export type PageWindowItem = number | "ellipsis-start" | "ellipsis-end";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Page sizes offered in the "rows per page" dropdown. Anything else the
|
|
16
|
+
* table is already using (a shared link can carry an arbitrary size) is
|
|
17
|
+
* merged in by `getItemsOnPageOptions` so the select always has a value
|
|
18
|
+
* that matches what is on screen.
|
|
19
|
+
*/
|
|
20
|
+
export const DefaultItemsOnPageOptions: Array<number> = [10, 20, 25, 50, 100];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* How many slots the numbered page list may occupy, ellipses included.
|
|
24
|
+
* Five is the whole story a page list has to tell - where you are, where
|
|
25
|
+
* both ends are, and that there is more in between - and it keeps the
|
|
26
|
+
* control a constant width from page 1 through page 10,000. Stepping to a
|
|
27
|
+
* neighbour is what the arrows are for; landing somewhere arbitrary is what
|
|
28
|
+
* the gaps are for.
|
|
29
|
+
*/
|
|
30
|
+
export const DefaultMaxVisiblePages: number = 5;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The narrowest window the collapsing rules can honour: first, gap, current,
|
|
34
|
+
* gap, last. Anything smaller is raised to this.
|
|
35
|
+
*/
|
|
36
|
+
const MinMaxVisiblePages: number = 5;
|
|
37
|
+
|
|
38
|
+
export interface ItemRange {
|
|
39
|
+
firstItemNumber: number;
|
|
40
|
+
lastItemNumber: number;
|
|
41
|
+
isEmpty: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ItemRangeInput {
|
|
45
|
+
currentPageNumber: number;
|
|
46
|
+
itemsOnPage: number;
|
|
47
|
+
totalItemsCount: number;
|
|
48
|
+
/*
|
|
49
|
+
* Rows this page actually rendered, when the caller knows. Analytics list
|
|
50
|
+
* endpoints over-fetch one probe row to derive `hasMore` and count it in
|
|
51
|
+
* `totalItemsCount` even though the payload dropped it, so the printed
|
|
52
|
+
* range has to be clamped to rows the page can really show.
|
|
53
|
+
*/
|
|
54
|
+
itemsOnCurrentPage?: number | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default class PaginationUtil {
|
|
58
|
+
/**
|
|
59
|
+
* Total pages for a known item count. Always at least 1 — an empty table
|
|
60
|
+
* still sits on "page 1 of 1" rather than "page 1 of 0".
|
|
61
|
+
*/
|
|
62
|
+
public static getTotalPageCount(
|
|
63
|
+
totalItemsCount: number,
|
|
64
|
+
itemsOnPage: number,
|
|
65
|
+
): number {
|
|
66
|
+
const safeItemsOnPage: number = Math.max(Math.floor(itemsOnPage) || 0, 1);
|
|
67
|
+
const safeTotalItemsCount: number = Math.max(
|
|
68
|
+
Math.floor(totalItemsCount) || 0,
|
|
69
|
+
0,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return Math.max(Math.ceil(safeTotalItemsCount / safeItemsOnPage), 1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Clamp a page number into the pages that exist. Used both for what the
|
|
77
|
+
* control highlights and for what a hand-typed "go to page" is allowed to
|
|
78
|
+
* request.
|
|
79
|
+
*/
|
|
80
|
+
public static clampPageNumber(
|
|
81
|
+
pageNumber: number,
|
|
82
|
+
totalPageCount: number,
|
|
83
|
+
): number {
|
|
84
|
+
const safeTotalPageCount: number = Math.max(
|
|
85
|
+
Math.floor(totalPageCount) || 0,
|
|
86
|
+
1,
|
|
87
|
+
);
|
|
88
|
+
const safePageNumber: number = Math.floor(pageNumber) || 1;
|
|
89
|
+
|
|
90
|
+
if (safePageNumber < 1) {
|
|
91
|
+
return 1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return Math.min(safePageNumber, safeTotalPageCount);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The page numbers to render, with collapsed gaps marked. When the list
|
|
99
|
+
* fits it is returned whole; otherwise the first and last pages are always
|
|
100
|
+
* present (so "jump to the start / end" is one click) and the pages around
|
|
101
|
+
* the current one fill the remaining slots.
|
|
102
|
+
*/
|
|
103
|
+
public static getPageWindow(
|
|
104
|
+
currentPageNumber: number,
|
|
105
|
+
totalPageCount: number,
|
|
106
|
+
maxVisiblePages: number = DefaultMaxVisiblePages,
|
|
107
|
+
): Array<PageWindowItem> {
|
|
108
|
+
const safeTotalPageCount: number = Math.max(
|
|
109
|
+
Math.floor(totalPageCount) || 0,
|
|
110
|
+
1,
|
|
111
|
+
);
|
|
112
|
+
const safeMaxVisiblePages: number = Math.max(
|
|
113
|
+
Math.floor(maxVisiblePages) || 0,
|
|
114
|
+
MinMaxVisiblePages,
|
|
115
|
+
);
|
|
116
|
+
const currentPage: number = PaginationUtil.clampPageNumber(
|
|
117
|
+
currentPageNumber,
|
|
118
|
+
safeTotalPageCount,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const allPages: (from: number, to: number) => Array<PageWindowItem> = (
|
|
122
|
+
from: number,
|
|
123
|
+
to: number,
|
|
124
|
+
): Array<PageWindowItem> => {
|
|
125
|
+
const pages: Array<PageWindowItem> = [];
|
|
126
|
+
for (let page: number = from; page <= to; page++) {
|
|
127
|
+
pages.push(page);
|
|
128
|
+
}
|
|
129
|
+
return pages;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
if (safeTotalPageCount <= safeMaxVisiblePages) {
|
|
133
|
+
return allPages(1, safeTotalPageCount);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
* Pages kept on each side of the current one. Five slots are already
|
|
138
|
+
* spent on the first page, the last page, the current page and the two
|
|
139
|
+
* ellipses, so whatever a wider window is given goes here - and the
|
|
140
|
+
* rendered width stays at `safeMaxVisiblePages`.
|
|
141
|
+
*/
|
|
142
|
+
const siblingCount: number = Math.max(
|
|
143
|
+
Math.floor((safeMaxVisiblePages - 5) / 2),
|
|
144
|
+
0,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
/*
|
|
148
|
+
* A gap has to hide at least two pages to be worth drawing: an ellipsis
|
|
149
|
+
* standing in for a single page number is both a lie and wider than the
|
|
150
|
+
* number it replaced. Where only one page would be hidden, the run of
|
|
151
|
+
* pages is extended to swallow it instead.
|
|
152
|
+
*/
|
|
153
|
+
const hasGapBefore: boolean = currentPage - siblingCount > 3;
|
|
154
|
+
const hasGapAfter: boolean =
|
|
155
|
+
currentPage + siblingCount < safeTotalPageCount - 2;
|
|
156
|
+
|
|
157
|
+
if (!hasGapBefore && hasGapAfter) {
|
|
158
|
+
const headCount: number = safeMaxVisiblePages - 2;
|
|
159
|
+
return [...allPages(1, headCount), "ellipsis-end", safeTotalPageCount];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (hasGapBefore && !hasGapAfter) {
|
|
163
|
+
const tailCount: number = safeMaxVisiblePages - 2;
|
|
164
|
+
return [
|
|
165
|
+
1,
|
|
166
|
+
"ellipsis-start",
|
|
167
|
+
...allPages(safeTotalPageCount - tailCount + 1, safeTotalPageCount),
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (hasGapBefore && hasGapAfter) {
|
|
172
|
+
return [
|
|
173
|
+
1,
|
|
174
|
+
"ellipsis-start",
|
|
175
|
+
...allPages(currentPage - siblingCount, currentPage + siblingCount),
|
|
176
|
+
"ellipsis-end",
|
|
177
|
+
safeTotalPageCount,
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/*
|
|
182
|
+
* Unreachable for a list longer than the window — with neither gap the
|
|
183
|
+
* list is at most `safeMaxVisiblePages - 2` pages long — but returning
|
|
184
|
+
* the whole list is the honest fallback rather than an exception.
|
|
185
|
+
*/
|
|
186
|
+
return allPages(1, safeTotalPageCount);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The "Showing 21-30 of 240" range. `itemsOnCurrentPage`, when given, caps
|
|
191
|
+
* the range at rows the page really rendered, which is what keeps a short
|
|
192
|
+
* final page (and the analytics probe row) from being over-reported.
|
|
193
|
+
*/
|
|
194
|
+
public static getItemRange(input: ItemRangeInput): ItemRange {
|
|
195
|
+
const itemsOnPage: number = Math.max(Math.floor(input.itemsOnPage) || 0, 1);
|
|
196
|
+
const totalItemsCount: number = Math.max(
|
|
197
|
+
Math.floor(input.totalItemsCount) || 0,
|
|
198
|
+
0,
|
|
199
|
+
);
|
|
200
|
+
const currentPageNumber: number = Math.max(
|
|
201
|
+
Math.floor(input.currentPageNumber) || 1,
|
|
202
|
+
1,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const alreadySeenCount: number = itemsOnPage * (currentPageNumber - 1);
|
|
206
|
+
const firstItemNumber: number = alreadySeenCount + 1;
|
|
207
|
+
|
|
208
|
+
// What the count proves is left after the pages already paged past.
|
|
209
|
+
const provenOnPage: number = Math.max(
|
|
210
|
+
totalItemsCount - alreadySeenCount,
|
|
211
|
+
0,
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
* A page can hold no more than its page size, no more than the count
|
|
216
|
+
* proves is left, and - where the caller says so - no more than it
|
|
217
|
+
* actually rendered.
|
|
218
|
+
*/
|
|
219
|
+
const countOnPage: number = Math.min(
|
|
220
|
+
provenOnPage,
|
|
221
|
+
itemsOnPage,
|
|
222
|
+
input.itemsOnCurrentPage === undefined
|
|
223
|
+
? Number.POSITIVE_INFINITY
|
|
224
|
+
: Math.max(input.itemsOnCurrentPage, 0),
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const lastItemNumber: number = alreadySeenCount + countOnPage;
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
firstItemNumber: firstItemNumber,
|
|
231
|
+
lastItemNumber: lastItemNumber,
|
|
232
|
+
isEmpty: lastItemNumber < firstItemNumber,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The page sizes to offer. The size in use is always present and the list
|
|
238
|
+
* stays sorted, so a table restored from a link with `itemsOnPage=37`
|
|
239
|
+
* shows 37 as the selected option instead of silently snapping to 10.
|
|
240
|
+
*/
|
|
241
|
+
public static getItemsOnPageOptions(
|
|
242
|
+
itemsOnPage: number,
|
|
243
|
+
options: Array<number> = DefaultItemsOnPageOptions,
|
|
244
|
+
): Array<number> {
|
|
245
|
+
const validOptions: Array<number> = options.filter((option: number) => {
|
|
246
|
+
return Number.isFinite(option) && option > 0;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const uniqueOptions: Array<number> = Array.from(new Set(validOptions));
|
|
250
|
+
|
|
251
|
+
if (
|
|
252
|
+
Number.isFinite(itemsOnPage) &&
|
|
253
|
+
itemsOnPage > 0 &&
|
|
254
|
+
!uniqueOptions.includes(itemsOnPage)
|
|
255
|
+
) {
|
|
256
|
+
uniqueOptions.push(itemsOnPage);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return uniqueOptions.sort((a: number, b: number) => {
|
|
260
|
+
return a - b;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Pagination screenshots
|
|
2
|
+
|
|
3
|
+
What the shared pagination control (`../Pagination.tsx`) looks like in the
|
|
4
|
+
states that are worth arguing about. Rendered from the real component against
|
|
5
|
+
the dashboard's own Tailwind build, on a mock table.
|
|
6
|
+
|
|
7
|
+
| File | Shows |
|
|
8
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
9
|
+
| `pagination-before-after.png` | The control before this change (page size and page number hidden behind a light-grey icon button) and after it (rows per page, the pages and the range all on the page). |
|
|
10
|
+
| `pagination-long-list.png` | Deep in a 24-page list, with the gaps collapsed; a short final page; and an empty result set. |
|
|
11
|
+
| `pagination-go-to-page-modal.png` | The jump-to-a-page dialog, opened by clicking one of the collapsed gaps. |
|
|
12
|
+
| `pagination-telemetry.png` | The compact skin used under logs and traces, and has-more mode, where the endpoint skips `COUNT(*)` so there is no last page to link to. |
|
|
13
|
+
| `pagination-mobile.png` | A narrow screen, where the numbered list gives way to a page-of-pages indicator. |
|
|
14
|
+
|
|
15
|
+
Re-shoot these when the control's layout changes.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -8,6 +8,13 @@ export interface SavedViewsDropdownProps {
|
|
|
8
8
|
savedViews: Array<SavedViewOption>;
|
|
9
9
|
selectedSavedViewId?: string | null | undefined;
|
|
10
10
|
onSelect: (viewId: string) => void;
|
|
11
|
+
/*
|
|
12
|
+
* Deselect the active view and return the explorer to its unfiltered
|
|
13
|
+
* default. Without this the checkmark is a one-way door: a view can be
|
|
14
|
+
* applied but never taken off. Hosts that cannot express "no view" simply
|
|
15
|
+
* omit it, and both clear affordances below disappear with it.
|
|
16
|
+
*/
|
|
17
|
+
onClear?: (() => void) | undefined;
|
|
11
18
|
onCreate?: (() => void) | undefined;
|
|
12
19
|
onEdit?: ((viewId: string) => void) | undefined;
|
|
13
20
|
onDelete?: ((viewId: string) => void) | undefined;
|
|
@@ -32,6 +39,17 @@ const SavedViewsDropdown: FunctionComponent<SavedViewsDropdownProps> = (
|
|
|
32
39
|
},
|
|
33
40
|
);
|
|
34
41
|
|
|
42
|
+
/*
|
|
43
|
+
* Clearing is only offered once a view is actually applied — an inert
|
|
44
|
+
* "Clear view" row sitting above an unfiltered explorer says nothing.
|
|
45
|
+
*/
|
|
46
|
+
const canClear: boolean = Boolean(props.onClear && selectedView);
|
|
47
|
+
|
|
48
|
+
const clearSelection: () => void = (): void => {
|
|
49
|
+
props.onClear?.();
|
|
50
|
+
setIsComponentVisible(false);
|
|
51
|
+
};
|
|
52
|
+
|
|
35
53
|
return (
|
|
36
54
|
<div className="relative" ref={ref}>
|
|
37
55
|
<button
|
|
@@ -77,6 +95,31 @@ const SavedViewsDropdown: FunctionComponent<SavedViewsDropdownProps> = (
|
|
|
77
95
|
props.dropdownAlignment === "right" ? "right-0" : "left-0"
|
|
78
96
|
}`}
|
|
79
97
|
>
|
|
98
|
+
{/*
|
|
99
|
+
* Explicit way back to the unfiltered explorer. Clicking the
|
|
100
|
+
* applied view also clears it, but that is only discoverable once
|
|
101
|
+
* you try it — this row says so out loud.
|
|
102
|
+
*/}
|
|
103
|
+
{canClear && (
|
|
104
|
+
<div className="border-b border-gray-100 py-1">
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
className="flex w-full items-center gap-2 px-3 py-1.5 text-left transition-colors hover:bg-gray-50"
|
|
108
|
+
onClick={clearSelection}
|
|
109
|
+
>
|
|
110
|
+
<span
|
|
111
|
+
className="w-4 shrink-0 text-center text-xs text-gray-400"
|
|
112
|
+
aria-hidden="true"
|
|
113
|
+
>
|
|
114
|
+
✕
|
|
115
|
+
</span>
|
|
116
|
+
<span className="truncate text-sm text-gray-600">
|
|
117
|
+
Clear view
|
|
118
|
+
</span>
|
|
119
|
+
</button>
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
|
|
80
123
|
{/* View list */}
|
|
81
124
|
<div className="max-h-72 overflow-y-auto py-1">
|
|
82
125
|
{props.savedViews.length === 0 && (
|
|
@@ -98,13 +141,35 @@ const SavedViewsDropdown: FunctionComponent<SavedViewsDropdownProps> = (
|
|
|
98
141
|
<button
|
|
99
142
|
type="button"
|
|
100
143
|
className="flex min-w-0 flex-1 items-center gap-2 text-left"
|
|
144
|
+
/*
|
|
145
|
+
* Spelled out so the row announces as its own name: the
|
|
146
|
+
* ✓ is aria-hidden, and the "default" tag reads as a word
|
|
147
|
+
* rather than a bare token appended to the view name.
|
|
148
|
+
*/
|
|
149
|
+
aria-label={
|
|
150
|
+
view.isDefault ? `${view.name} (default)` : view.name
|
|
151
|
+
}
|
|
152
|
+
/*
|
|
153
|
+
* The checkmark reads as a checkbox, so the row behaves
|
|
154
|
+
* like one: clicking the applied view takes it off again
|
|
155
|
+
* instead of silently re-applying what is already on.
|
|
156
|
+
*/
|
|
157
|
+
aria-pressed={isSelected}
|
|
101
158
|
onClick={() => {
|
|
159
|
+
if (isSelected && props.onClear) {
|
|
160
|
+
clearSelection();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
102
164
|
props.onSelect(view.id);
|
|
103
165
|
setIsComponentVisible(false);
|
|
104
166
|
}}
|
|
105
167
|
>
|
|
106
168
|
{/* Checkmark for selected */}
|
|
107
|
-
<span
|
|
169
|
+
<span
|
|
170
|
+
className="w-4 shrink-0 text-center text-xs"
|
|
171
|
+
aria-hidden="true"
|
|
172
|
+
>
|
|
108
173
|
{isSelected ? (
|
|
109
174
|
<span className="text-indigo-600">✓</span>
|
|
110
175
|
) : (
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Pagination from "../../Pagination/Pagination";
|
|
1
2
|
import React, { FunctionComponent, ReactElement } from "react";
|
|
2
3
|
|
|
3
4
|
export interface TelemetryPaginationProps {
|
|
@@ -11,103 +12,48 @@ export interface TelemetryPaginationProps {
|
|
|
11
12
|
itemLabel?: string | undefined;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* The telemetry footer is the shared pagination control in its compact skin,
|
|
17
|
+
* so "rows per page" and jump-to-page behave the same here as they do under
|
|
18
|
+
* every table in the product.
|
|
19
|
+
*/
|
|
14
20
|
const TelemetryPagination: FunctionComponent<TelemetryPaginationProps> = (
|
|
15
21
|
props: TelemetryPaginationProps,
|
|
16
22
|
): ReactElement => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const safeCurrentPage: number = Math.min(props.currentPage, totalPages);
|
|
27
|
-
|
|
28
|
-
const firstItemIndex: number =
|
|
29
|
-
props.totalItems === 0 ? 0 : (safeCurrentPage - 1) * props.pageSize + 1;
|
|
30
|
-
const lastItemIndex: number =
|
|
31
|
-
props.totalItems === 0
|
|
32
|
-
? 0
|
|
33
|
-
: Math.min(props.totalItems, safeCurrentPage * props.pageSize);
|
|
34
|
-
|
|
35
|
-
const disablePrev: boolean =
|
|
36
|
-
props.isDisabled || props.totalItems === 0 || safeCurrentPage <= 1;
|
|
37
|
-
const disableNext: boolean =
|
|
38
|
-
props.isDisabled || props.totalItems === 0 || safeCurrentPage >= totalPages;
|
|
23
|
+
/*
|
|
24
|
+
* Callers pass a plural label ("traces", "spans"). The singular is only
|
|
25
|
+
* used for a one-row result set, where trimming a trailing "s" is right
|
|
26
|
+
* for every label these views pass.
|
|
27
|
+
*/
|
|
28
|
+
const pluralLabel: string = props.itemLabel || "results";
|
|
29
|
+
const singularLabel: string = pluralLabel.endsWith("s")
|
|
30
|
+
? pluralLabel.slice(0, -1)
|
|
31
|
+
: pluralLabel;
|
|
39
32
|
|
|
40
33
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
onChange={(event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
65
|
-
const size: number = Number(event.target.value) || props.pageSize;
|
|
66
|
-
props.onPageSizeChange(size);
|
|
67
|
-
}}
|
|
68
|
-
disabled={props.isDisabled}
|
|
69
|
-
>
|
|
70
|
-
{props.pageSizeOptions.map((option: number) => {
|
|
71
|
-
return (
|
|
72
|
-
<option key={option} value={option}>
|
|
73
|
-
{option}
|
|
74
|
-
</option>
|
|
75
|
-
);
|
|
76
|
-
})}
|
|
77
|
-
</select>
|
|
78
|
-
</label>
|
|
79
|
-
|
|
80
|
-
<div className="inline-flex items-center gap-1 rounded-lg border border-gray-200 bg-white p-0.5">
|
|
81
|
-
<button
|
|
82
|
-
type="button"
|
|
83
|
-
className="rounded-md px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-300 disabled:cursor-not-allowed disabled:opacity-40"
|
|
84
|
-
onClick={() => {
|
|
85
|
-
if (!disablePrev) {
|
|
86
|
-
props.onPageChange(Math.max(1, safeCurrentPage - 1));
|
|
87
|
-
}
|
|
88
|
-
}}
|
|
89
|
-
disabled={disablePrev}
|
|
90
|
-
>
|
|
91
|
-
Previous
|
|
92
|
-
</button>
|
|
93
|
-
<span className="px-3 text-[11px] text-gray-400">
|
|
94
|
-
Page {safeCurrentPage} / {totalPages}
|
|
95
|
-
</span>
|
|
96
|
-
<button
|
|
97
|
-
type="button"
|
|
98
|
-
className="rounded-md px-3 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-300 disabled:cursor-not-allowed disabled:opacity-40"
|
|
99
|
-
onClick={() => {
|
|
100
|
-
if (!disableNext) {
|
|
101
|
-
props.onPageChange(Math.min(totalPages, safeCurrentPage + 1));
|
|
102
|
-
}
|
|
103
|
-
}}
|
|
104
|
-
disabled={disableNext}
|
|
105
|
-
>
|
|
106
|
-
Next
|
|
107
|
-
</button>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
34
|
+
<Pagination
|
|
35
|
+
dataTestId="telemetry-pagination"
|
|
36
|
+
singularLabel={singularLabel}
|
|
37
|
+
pluralLabel={pluralLabel}
|
|
38
|
+
currentPageNumber={props.currentPage}
|
|
39
|
+
totalItemsCount={props.totalItems}
|
|
40
|
+
itemsOnPage={props.pageSize}
|
|
41
|
+
itemsOnPageOptions={props.pageSizeOptions}
|
|
42
|
+
isCompact={true}
|
|
43
|
+
className="bg-gray-50/50"
|
|
44
|
+
isLoading={false}
|
|
45
|
+
isError={false}
|
|
46
|
+
isDisabled={Boolean(props.isDisabled)}
|
|
47
|
+
onNavigateToPage={(pageNumber: number, itemsOnPage: number) => {
|
|
48
|
+
if (itemsOnPage !== props.pageSize) {
|
|
49
|
+
props.onPageSizeChange(itemsOnPage);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (pageNumber !== props.currentPage) {
|
|
53
|
+
props.onPageChange(pageNumber);
|
|
54
|
+
}
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
111
57
|
);
|
|
112
58
|
};
|
|
113
59
|
|
|
@@ -22,6 +22,8 @@ export interface ComponentProps {
|
|
|
22
22
|
autoFocus?: boolean | undefined;
|
|
23
23
|
dataTestId?: string | undefined;
|
|
24
24
|
disableSpellCheck?: boolean | undefined;
|
|
25
|
+
/** The id of the element that names this control, when it is labelled elsewhere. */
|
|
26
|
+
ariaLabelledby?: string | undefined;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const TextArea: FunctionComponent<ComponentProps> = (
|
|
@@ -71,6 +73,7 @@ const TextArea: FunctionComponent<ComponentProps> = (
|
|
|
71
73
|
value={text}
|
|
72
74
|
rows={6}
|
|
73
75
|
spellCheck={!props.disableSpellCheck}
|
|
76
|
+
aria-labelledby={props.ariaLabelledby}
|
|
74
77
|
aria-invalid={props.error ? "true" : undefined}
|
|
75
78
|
aria-describedby={props.error ? "textarea-error-message" : undefined}
|
|
76
79
|
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
@@ -6,7 +6,10 @@ import { CustomElementProps } from "../Forms/Types/Field";
|
|
|
6
6
|
import FormValues from "../Forms/Types/FormValues";
|
|
7
7
|
import ComponentValuePickerModal from "./ComponentValuePickerModal";
|
|
8
8
|
import CronScheduleField from "./CronScheduleField";
|
|
9
|
-
import ModelColumnEditor, {
|
|
9
|
+
import ModelColumnEditor, {
|
|
10
|
+
ModelColumnEditorMode,
|
|
11
|
+
RecordIntent,
|
|
12
|
+
} from "./ModelColumnEditor";
|
|
10
13
|
import ModelFieldPicker from "./ModelFieldPicker";
|
|
11
14
|
import {
|
|
12
15
|
componentInputTypeToFormFieldType,
|
|
@@ -488,6 +491,20 @@ const ArgumentsForm: FunctionComponent<ComponentProps> = (
|
|
|
488
491
|
<ModelColumnEditor
|
|
489
492
|
tableName={component.metadata.tableName as string}
|
|
490
493
|
mode={columnEditorMode}
|
|
494
|
+
/*
|
|
495
|
+
* A create writes a whole record, so it opens with a
|
|
496
|
+
* row for every column it must be given. An update
|
|
497
|
+
* legitimately writes one column, and seeding it
|
|
498
|
+
* with six would present five fields nobody asked
|
|
499
|
+
* for. The create payload is the argument called
|
|
500
|
+
* "json" (BaseModel components); an update's is
|
|
501
|
+
* "data".
|
|
502
|
+
*/
|
|
503
|
+
recordIntent={
|
|
504
|
+
arg.id === "json"
|
|
505
|
+
? RecordIntent.Create
|
|
506
|
+
: RecordIntent.Update
|
|
507
|
+
}
|
|
491
508
|
initialValue={customProps.initialValue}
|
|
492
509
|
onChange={(value: string) => {
|
|
493
510
|
void customProps.onChange?.(value);
|