@oneuptime/common 14.0.2 → 14.0.3

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 (166) hide show
  1. package/Models/DatabaseModels/AlertFeed.ts +2 -0
  2. package/Models/DatabaseModels/IncidentAlert.ts +540 -0
  3. package/Models/DatabaseModels/IncidentFeed.ts +2 -0
  4. package/Models/DatabaseModels/Index.ts +2 -0
  5. package/Models/DatabaseModels/Project.ts +60 -0
  6. package/Models/DatabaseModels/RumApplication.ts +52 -1
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
  8. package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
  9. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  10. package/Server/Services/IncidentAlertService.ts +1811 -0
  11. package/Server/Services/IncidentService.ts +210 -10
  12. package/Server/Services/IncidentStateTimelineService.ts +24 -0
  13. package/Server/Services/Index.ts +2 -0
  14. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +24 -2
  15. package/Tests/App/Dashboard/BulkIncidentLinkActions.test.tsx +869 -0
  16. package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
  17. package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
  18. package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
  19. package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -0
  20. package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +39 -0
  21. package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
  22. package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
  23. package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -0
  24. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +38 -18
  25. package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
  26. package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
  27. package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
  28. package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
  29. package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
  30. package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
  31. package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
  32. package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
  33. package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
  34. package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
  35. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -0
  36. package/Tests/App/Dashboard/IoTMetricTooltips.test.tsx +1123 -0
  37. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +837 -0
  38. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
  39. package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
  40. package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
  41. package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
  42. package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
  43. package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
  44. package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
  45. package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
  46. package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
  47. package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -0
  48. package/Tests/App/Dashboard/NetworkDeviceTooltips.test.tsx +852 -0
  49. package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
  50. package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
  51. package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -0
  52. package/Tests/App/Dashboard/ProxmoxMetricTooltips.test.ts +592 -0
  53. package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
  54. package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -0
  55. package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +1066 -0
  56. package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -0
  57. package/Tests/App/Dashboard/ServerlessMetricTooltips.test.tsx +474 -0
  58. package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
  59. package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
  60. package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
  61. package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -0
  62. package/Tests/App/Dashboard/VMwareMetricTooltips.test.ts +801 -0
  63. package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
  64. package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
  65. package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -0
  66. package/Tests/Models/DatabaseModels/IncidentAlertModel.test.ts +554 -0
  67. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
  68. package/Tests/Server/Infrastructure/Postgres/AddIncidentAlertMigration.test.ts +341 -0
  69. package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -0
  70. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +903 -0
  71. package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
  72. package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
  73. package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
  74. package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -0
  75. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +103 -0
  76. package/Tests/Types/Rum/WebVitals.test.ts +173 -0
  77. package/Tests/UI/Components/FieldLabelInfoCardTooltip.test.tsx +413 -0
  78. package/Tests/UI/Components/InfoTooltip.test.tsx +242 -0
  79. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +207 -3
  80. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
  81. package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
  82. package/Tests/UI/Components/TableHeaderTooltip.test.tsx +662 -0
  83. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +166 -9
  84. package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
  85. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
  86. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
  87. package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
  88. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
  89. package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
  90. package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
  91. package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
  92. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
  93. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
  94. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
  95. package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
  96. package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
  97. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  98. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  99. package/Tests/UI/Utils/PermissionGate.test.ts +76 -0
  100. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +696 -0
  101. package/Tests/Utils/Rum/SessionTraceState.test.ts +239 -0
  102. package/Types/Incident/IncidentAlertLink.ts +38 -0
  103. package/Types/Permission.ts +48 -0
  104. package/Types/Rum/SessionReplay.ts +25 -6
  105. package/Types/Rum/WebVitals.ts +52 -0
  106. package/UI/Components/Detail/FieldLabel.tsx +8 -0
  107. package/UI/Components/InfoCard/InfoCard.tsx +47 -1
  108. package/UI/Components/ModelTable/BaseModelTable.tsx +95 -17
  109. package/UI/Components/ModelTable/Column.ts +5 -0
  110. package/UI/Components/Table/TableHeader.tsx +47 -2
  111. package/UI/Components/Table/Types/Column.ts +7 -0
  112. package/UI/Components/Tooltip/InfoTooltip.tsx +78 -0
  113. package/UI/Utils/PermissionGate.ts +11 -2
  114. package/Utils/Incident/IncidentFromAlerts.ts +516 -0
  115. package/Utils/Rum/SessionTraceState.ts +212 -0
  116. package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
  117. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  118. package/build/dist/Models/DatabaseModels/IncidentAlert.js +553 -0
  119. package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
  120. package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -0
  121. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  122. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  123. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/Project.js +62 -0
  125. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  126. package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
  127. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  128. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
  129. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
  130. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
  131. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
  132. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  133. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  134. package/build/dist/Server/Services/IncidentAlertService.js +1370 -0
  135. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
  136. package/build/dist/Server/Services/IncidentService.js +164 -12
  137. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  138. package/build/dist/Server/Services/IncidentStateTimelineService.js +21 -0
  139. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  140. package/build/dist/Server/Services/Index.js +2 -0
  141. package/build/dist/Server/Services/Index.js.map +1 -1
  142. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +8 -0
  143. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  144. package/build/dist/Types/Incident/IncidentAlertLink.js +34 -0
  145. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
  146. package/build/dist/Types/Permission.js +42 -0
  147. package/build/dist/Types/Permission.js.map +1 -1
  148. package/build/dist/Types/Rum/WebVitals.js +25 -0
  149. package/build/dist/Types/Rum/WebVitals.js.map +1 -1
  150. package/build/dist/UI/Components/Detail/FieldLabel.js +2 -0
  151. package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
  152. package/build/dist/UI/Components/InfoCard/InfoCard.js +22 -1
  153. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  154. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +66 -14
  155. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  156. package/build/dist/UI/Components/Table/TableHeader.js +18 -2
  157. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  158. package/build/dist/UI/Components/Tooltip/InfoTooltip.js +28 -0
  159. package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
  160. package/build/dist/UI/Utils/PermissionGate.js +4 -2
  161. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  162. package/build/dist/Utils/Incident/IncidentFromAlerts.js +306 -0
  163. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
  164. package/build/dist/Utils/Rum/SessionTraceState.js +154 -0
  165. package/build/dist/Utils/Rum/SessionTraceState.js.map +1 -0
  166. package/package.json +1 -1
@@ -3,6 +3,7 @@ export const WebVitalDefinitions = [
3
3
  {
4
4
  key: "lcp",
5
5
  label: "Largest Contentful Paint",
6
+ description: "How long until the biggest image or block of text on screen has rendered - roughly when the page looks loaded to the visitor.",
6
7
  unit: "ms",
7
8
  thresholds: { warn: 2500, danger: 4000 },
8
9
  names: [
@@ -15,6 +16,7 @@ export const WebVitalDefinitions = [
15
16
  {
16
17
  key: "inp",
17
18
  label: "Interaction to Next Paint",
19
+ description: "How quickly the page reacts to clicks, taps and key presses: the delay before the screen visibly updates, for close to the slowest interaction on the page.",
18
20
  unit: "ms",
19
21
  thresholds: { warn: 200, danger: 500 },
20
22
  names: [
@@ -27,6 +29,7 @@ export const WebVitalDefinitions = [
27
29
  {
28
30
  key: "cls",
29
31
  label: "Cumulative Layout Shift",
32
+ description: "How much the page jumps around while it loads - content moving under the visitor's cursor or finger. A score, not a time: lower is better and 0 means nothing moved.",
30
33
  unit: "score",
31
34
  thresholds: { warn: 0.1, danger: 0.25 },
32
35
  names: [
@@ -39,6 +42,7 @@ export const WebVitalDefinitions = [
39
42
  {
40
43
  key: "fcp",
41
44
  label: "First Contentful Paint",
45
+ description: "How long until the first text or image appears, so the visitor can see the page has started loading.",
42
46
  unit: "ms",
43
47
  thresholds: { warn: 1800, danger: 3000 },
44
48
  names: [
@@ -51,6 +55,7 @@ export const WebVitalDefinitions = [
51
55
  {
52
56
  key: "ttfb",
53
57
  label: "Time to First Byte",
58
+ description: "How long the browser waited for the first byte of the page from your server, including redirects, looking up the address and connecting.",
54
59
  unit: "ms",
55
60
  thresholds: { warn: 800, danger: 1800 },
56
61
  names: [
@@ -61,4 +66,24 @@ export const WebVitalDefinitions = [
61
66
  ],
62
67
  },
63
68
  ];
69
+ // A threshold the way a person would say it: "2.5 s", "800 ms", "0.1".
70
+ export function formatWebVitalThreshold(value, unit) {
71
+ if (unit === "score") {
72
+ return String(value);
73
+ }
74
+ if (value < 1000) {
75
+ return `${value} ms`;
76
+ }
77
+ return `${Number((value / 1000).toFixed(2))} s`;
78
+ }
79
+ /*
80
+ * The Good / Poor limits in words, matching how the overview rates a value:
81
+ * below `warn` is Good, at or above `danger` is Poor, and anything between
82
+ * needs work.
83
+ */
84
+ export function describeWebVitalThresholds(definition) {
85
+ const warn = formatWebVitalThreshold(definition.thresholds.warn, definition.unit);
86
+ const danger = formatWebVitalThreshold(definition.thresholds.danger, definition.unit);
87
+ return `Good below ${warn}; poor at ${danger} or more.`;
88
+ }
64
89
  //# sourceMappingURL=WebVitals.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebVitals.js","sourceRoot":"","sources":["../../../../Types/Rum/WebVitals.ts"],"names":[],"mappings":"AAQA,uEAAuE;AACvE,MAAM,CAAC,MAAM,mBAAmB,GAA8B;IAC5D;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,0BAA0B;QACjC,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QACxC,KAAK,EAAE;YACL,eAAe;YACf,kCAAkC;YAClC,0BAA0B;YAC1B,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,2BAA2B;QAClC,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;QACtC,KAAK,EAAE;YACL,eAAe;YACf,mCAAmC;YACnC,2BAA2B;YAC3B,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,yBAAyB;QAChC,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QACvC,KAAK,EAAE;YACL,eAAe;YACf,iCAAiC;YACjC,yBAAyB;YACzB,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,wBAAwB;QAC/B,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QACxC,KAAK,EAAE;YACL,eAAe;YACf,gCAAgC;YAChC,wBAAwB;YACxB,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,MAAM;QACX,KAAK,EAAE,oBAAoB;QAC3B,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QACvC,KAAK,EAAE;YACL,gBAAgB;YAChB,4BAA4B;YAC5B,oBAAoB;YACpB,iBAAiB;SAClB;KACF;CACF,CAAC"}
1
+ {"version":3,"file":"WebVitals.js","sourceRoot":"","sources":["../../../../Types/Rum/WebVitals.ts"],"names":[],"mappings":"AAcA,uEAAuE;AACvE,MAAM,CAAC,MAAM,mBAAmB,GAA8B;IAC5D;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,+HAA+H;QACjI,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QACxC,KAAK,EAAE;YACL,eAAe;YACf,kCAAkC;YAClC,0BAA0B;YAC1B,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,2BAA2B;QAClC,WAAW,EACT,6JAA6J;QAC/J,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;QACtC,KAAK,EAAE;YACL,eAAe;YACf,mCAAmC;YACnC,2BAA2B;YAC3B,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,sKAAsK;QACxK,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QACvC,KAAK,EAAE;YACL,eAAe;YACf,iCAAiC;YACjC,yBAAyB;YACzB,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EACT,sGAAsG;QACxG,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QACxC,KAAK,EAAE;YACL,eAAe;YACf,gCAAgC;YAChC,wBAAwB;YACxB,gBAAgB;SACjB;KACF;IACD;QACE,GAAG,EAAE,MAAM;QACX,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,0IAA0I;QAC5I,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QACvC,KAAK,EAAE;YACL,gBAAgB;YAChB,4BAA4B;YAC5B,oBAAoB;YACpB,iBAAiB;SAClB;KACF;CACF,CAAC;AAEF,uEAAuE;AACvE,MAAM,UAAU,uBAAuB,CACrC,KAAa,EACb,IAAgC;IAEhC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,KAAK,GAAG,IAAI,EAAE,CAAC;QACjB,OAAO,GAAG,KAAK,KAAK,CAAC;IACvB,CAAC;IAED,OAAO,GAAG,MAAM,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,UAA2D;IAE3D,MAAM,IAAI,GAAW,uBAAuB,CAC1C,UAAU,CAAC,UAAU,CAAC,IAAI,EAC1B,UAAU,CAAC,IAAI,CAChB,CAAC;IACF,MAAM,MAAM,GAAW,uBAAuB,CAC5C,UAAU,CAAC,UAAU,CAAC,MAAM,EAC5B,UAAU,CAAC,IAAI,CAChB,CAAC;IAEF,OAAO,cAAc,IAAI,aAAa,MAAM,WAAW,CAAC;AAC1D,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import Link from "../Link/Link";
2
2
  import useTranslateValue from "../../Utils/Translation";
3
+ import InfoTooltip from "../Tooltip/InfoTooltip";
3
4
  import React from "react";
4
5
  export var Size;
5
6
  (function (Size) {
@@ -18,6 +19,7 @@ const FieldLabelElement = (props) => {
18
19
  translatedTitle && (React.createElement("label", { className: `${props.size || "text-xs"} font-semibold uppercase tracking-widest ${isCardStyle ? "text-gray-500" : "text-gray-500"} flex items-center gap-2` },
19
20
  React.createElement("span", { className: `${props.alignClassName} flex items-center gap-1.5` },
20
21
  translatedTitle,
22
+ React.createElement(InfoTooltip, { label: translatedTitle, text: props.tooltip, className: "relative z-10 normal-case tracking-normal" }),
21
23
  React.createElement("span", { className: "w-1 h-1 rounded-full bg-gray-300" })),
22
24
  props.sideLink && translatedSideLinkText && ((_b = props.sideLink) === null || _b === void 0 ? void 0 : _b.url) && (React.createElement(Link, { to: (_c = props.sideLink) === null || _c === void 0 ? void 0 : _c.url, className: "inline-flex items-center gap-1 text-indigo-500 hover:text-indigo-600 transition-all duration-200 font-medium normal-case tracking-normal text-xs hover:underline underline-offset-2" },
23
25
  translatedSideLinkText,
@@ -1 +1 @@
1
- {"version":3,"file":"FieldLabel.js","sourceRoot":"","sources":["../../../../../UI/Components/Detail/FieldLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,cAAc,CAAC;AAEhC,OAAO,iBAAiB,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAA0C,MAAM,OAAO,CAAC;AAE/D,MAAM,CAAN,IAAY,IAIX;AAJD,WAAY,IAAI;IACd,0BAAkB,CAAA;IAClB,4BAAoB,CAAA;IACpB,yBAAiB,CAAA;AACnB,CAAC,EAJW,IAAI,KAAJ,IAAI,QAIf;AAWD,MAAM,iBAAiB,GAAsC,CAC3D,KAAqB,EACP,EAAE;;IAChB,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAChE,MAAM,eAAe,GAAuB,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzE,MAAM,qBAAqB,GACzB,cAAc,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACpC,MAAM,sBAAsB,GAAuB,eAAe,CAChE,MAAA,KAAK,CAAC,QAAQ,0CAAE,IAAI,CACrB,CAAC;IACF,MAAM,WAAW,GAAY,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC;IAExD,OAAO,CACL,6BAAK,SAAS,EAAC,WAAW;QACvB,eAAe,IAAI,CAClB,+BACE,SAAS,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,SAAS,4CACnC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAClC,0BAA0B;YAE1B,8BAAM,SAAS,EAAE,GAAG,KAAK,CAAC,cAAc,4BAA4B;gBACjE,eAAe;gBAChB,8BAAM,SAAS,EAAC,kCAAkC,GAAQ,CACrD;YACN,KAAK,CAAC,QAAQ,IAAI,sBAAsB,KAAI,MAAA,KAAK,CAAC,QAAQ,0CAAE,GAAG,CAAA,IAAI,CAClE,oBAAC,IAAI,IACH,EAAE,EAAE,MAAA,KAAK,CAAC,QAAQ,0CAAE,GAAG,EACvB,SAAS,EAAC,qLAAqL;gBAE9L,sBAAsB;gBACvB,6BACE,SAAS,EAAC,SAAS,EACnB,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,EACnB,MAAM,EAAC,cAAc;oBAErB,8BACE,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,CAAC,EACd,CAAC,EAAC,8EAA8E,GAChF,CACE,CACD,CACR,CACK,CACT;QACA,qBAAqB,IAAI,CACxB,2BACE,SAAS,EAAE,GAAG,KAAK,CAAC,cAAc,+CAA+C,IAEhF,qBAAqB,CACpB,CACL,CACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"FieldLabel.js","sourceRoot":"","sources":["../../../../../UI/Components/Detail/FieldLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,cAAc,CAAC;AAEhC,OAAO,iBAAiB,MAAM,yBAAyB,CAAC;AACxD,OAAO,WAAW,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAA0C,MAAM,OAAO,CAAC;AAE/D,MAAM,CAAN,IAAY,IAIX;AAJD,WAAY,IAAI;IACd,0BAAkB,CAAA;IAClB,4BAAoB,CAAA;IACpB,yBAAiB,CAAA;AACnB,CAAC,EAJW,IAAI,KAAJ,IAAI,QAIf;AAaD,MAAM,iBAAiB,GAAsC,CAC3D,KAAqB,EACP,EAAE;;IAChB,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAChE,MAAM,eAAe,GAAuB,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzE,MAAM,qBAAqB,GACzB,cAAc,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACpC,MAAM,sBAAsB,GAAuB,eAAe,CAChE,MAAA,KAAK,CAAC,QAAQ,0CAAE,IAAI,CACrB,CAAC;IACF,MAAM,WAAW,GAAY,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC;IAExD,OAAO,CACL,6BAAK,SAAS,EAAC,WAAW;QACvB,eAAe,IAAI,CAClB,+BACE,SAAS,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,SAAS,4CACnC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAClC,0BAA0B;YAE1B,8BAAM,SAAS,EAAE,GAAG,KAAK,CAAC,cAAc,4BAA4B;gBACjE,eAAe;gBAChB,oBAAC,WAAW,IACV,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,KAAK,CAAC,OAAO,EACnB,SAAS,EAAC,2CAA2C,GACrD;gBACF,8BAAM,SAAS,EAAC,kCAAkC,GAAQ,CACrD;YACN,KAAK,CAAC,QAAQ,IAAI,sBAAsB,KAAI,MAAA,KAAK,CAAC,QAAQ,0CAAE,GAAG,CAAA,IAAI,CAClE,oBAAC,IAAI,IACH,EAAE,EAAE,MAAA,KAAK,CAAC,QAAQ,0CAAE,GAAG,EACvB,SAAS,EAAC,qLAAqL;gBAE9L,sBAAsB;gBACvB,6BACE,SAAS,EAAC,SAAS,EACnB,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,EACnB,MAAM,EAAC,cAAc;oBAErB,8BACE,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,CAAC,EACd,CAAC,EAAC,8EAA8E,GAChF,CACE,CACD,CACR,CACK,CACT;QACA,qBAAqB,IAAI,CACxB,2BACE,SAAS,EAAE,GAAG,KAAK,CAAC,cAAc,+CAA+C,IAEhF,qBAAqB,CACpB,CACL,CACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import FieldLabelElement from "../Detail/FieldLabel";
2
2
  import React from "react";
3
3
  const InfoCard = (props) => {
4
+ var _a;
4
5
  const isClickable = Boolean(props.onClick);
5
6
  /*
6
7
  * A selected card swaps its border rather than adding one: Tailwind emits
@@ -10,6 +11,26 @@ const InfoCard = (props) => {
10
11
  const borderClassName = isClickable && props.isSelected
11
12
  ? "border-indigo-500 ring-1 ring-indigo-500"
12
13
  : "border-gray-200";
14
+ /*
15
+ * A clickable card with a tooltip cannot stay a role="button" div: the (i)
16
+ * is a button of its own, and a button's children are presentational, so
17
+ * screen readers would never reach it. The card becomes a plain container
18
+ * with a real button laid over it, and the (i) sits above that button
19
+ * (FieldLabel lifts it with relative z-10). Cards without a tooltip keep
20
+ * the markup below, unchanged.
21
+ */
22
+ if (isClickable && ((_a = props.tooltip) === null || _a === void 0 ? void 0 : _a.trim())) {
23
+ return (React.createElement("div", { className: `relative rounded-xl bg-white border ${borderClassName} shadow-sm hover:shadow-md transition-shadow duration-200 p-5 ${props.className || ""}` },
24
+ React.createElement("button", { type: "button", onClick: props.onClick, "aria-pressed": props.isSelected !== undefined
25
+ ? Boolean(props.isSelected)
26
+ : undefined, "aria-label": props.ariaLabel ||
27
+ (typeof props.value === "string"
28
+ ? `${props.title} ${props.value}`
29
+ : props.title), className: "absolute inset-0 rounded-xl cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2" }),
30
+ React.createElement("div", { className: "mb-2" },
31
+ React.createElement(FieldLabelElement, { title: props.title, tooltip: props.tooltip })),
32
+ React.createElement("div", { className: props.textClassName || "text-gray-900" }, props.value)));
33
+ }
13
34
  return (React.createElement("div", { onClick: props.onClick,
14
35
  /*
15
36
  * Click handlers on a div are invisible to the keyboard and to screen
@@ -30,7 +51,7 @@ const InfoCard = (props) => {
30
51
  }
31
52
  : undefined, className: `rounded-xl bg-white border ${borderClassName} shadow-sm hover:shadow-md transition-shadow duration-200 p-5 ${isClickable ? "cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2" : ""} ${props.className || ""}` },
32
53
  React.createElement("div", { className: "mb-2" },
33
- React.createElement(FieldLabelElement, { title: props.title })),
54
+ React.createElement(FieldLabelElement, { title: props.title, tooltip: props.tooltip })),
34
55
  React.createElement("div", { className: props.textClassName || "text-gray-900" }, props.value)));
35
56
  };
36
57
  export default InfoCard;
@@ -1 +1 @@
1
- {"version":3,"file":"InfoCard.js","sourceRoot":"","sources":["../../../../../UI/Components/InfoCard/InfoCard.tsx"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAA0C,MAAM,OAAO,CAAC;AAuB/D,MAAM,QAAQ,GAAsC,CAClD,KAAqB,EACP,EAAE;IAChB,MAAM,WAAW,GAAY,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEpD;;;;OAIG;IACH,MAAM,eAAe,GACnB,WAAW,IAAI,KAAK,CAAC,UAAU;QAC7B,CAAC,CAAC,0CAA0C;QAC5C,CAAC,CAAC,iBAAiB,CAAC;IAExB,OAAO,CACL,6BACE,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB;;;;WAIG;QACH,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EACxC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,kBASnC,WAAW,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAC3C,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;YAC3B,CAAC,CAAC,SAAS,gBAEH,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACrD,SAAS,EACP,WAAW;YACT,CAAC,CAAC,CAAC,KAA0C,EAAE,EAAE;;gBAC7C,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;oBAC/C,OAAO;gBACT,CAAC;gBACD,2DAA2D;gBAC3D,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,MAAA,KAAK,CAAC,OAAO,qDAAI,CAAC;YACpB,CAAC;YACH,CAAC,CAAC,SAAS,EAEf,SAAS,EAAE,8BAA8B,eAAe,iEAAiE,WAAW,CAAC,CAAC,CAAC,kHAAkH,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,CAAC,SAAS,IAAI,EAAE,EAAE;QAEzR,6BAAK,SAAS,EAAC,MAAM;YACnB,oBAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAI,CACrC;QACN,6BAAK,SAAS,EAAE,KAAK,CAAC,aAAa,IAAI,eAAe,IACnD,KAAK,CAAC,KAAK,CACR,CACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"InfoCard.js","sourceRoot":"","sources":["../../../../../UI/Components/InfoCard/InfoCard.tsx"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAA0C,MAAM,OAAO,CAAC;AAyB/D,MAAM,QAAQ,GAAsC,CAClD,KAAqB,EACP,EAAE;;IAChB,MAAM,WAAW,GAAY,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEpD;;;;OAIG;IACH,MAAM,eAAe,GACnB,WAAW,IAAI,KAAK,CAAC,UAAU;QAC7B,CAAC,CAAC,0CAA0C;QAC5C,CAAC,CAAC,iBAAiB,CAAC;IAExB;;;;;;;OAOG;IACH,IAAI,WAAW,KAAI,MAAA,KAAK,CAAC,OAAO,0CAAE,IAAI,EAAE,CAAA,EAAE,CAAC;QACzC,OAAO,CACL,6BACE,SAAS,EAAE,uCAAuC,eAAe,iEAAiE,KAAK,CAAC,SAAS,IAAI,EAAE,EAAE;YAEzJ,gCACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,KAAK,CAAC,OAAO,kBAEpB,KAAK,CAAC,UAAU,KAAK,SAAS;oBAC5B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;oBAC3B,CAAC,CAAC,SAAS,gBAQb,KAAK,CAAC,SAAS;oBACf,CAAC,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;wBAC9B,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE;wBACjC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAElB,SAAS,EAAC,8IAA8I,GACxJ;YACF,6BAAK,SAAS,EAAC,MAAM;gBACnB,oBAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,GAAI,CAC7D;YACN,6BAAK,SAAS,EAAE,KAAK,CAAC,aAAa,IAAI,eAAe,IACnD,KAAK,CAAC,KAAK,CACR,CACF,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,6BACE,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB;;;;WAIG;QACH,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EACxC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,kBASnC,WAAW,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAC3C,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;YAC3B,CAAC,CAAC,SAAS,gBAEH,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACrD,SAAS,EACP,WAAW;YACT,CAAC,CAAC,CAAC,KAA0C,EAAE,EAAE;;gBAC7C,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;oBAC/C,OAAO;gBACT,CAAC;gBACD,2DAA2D;gBAC3D,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,MAAA,KAAK,CAAC,OAAO,qDAAI,CAAC;YACpB,CAAC;YACH,CAAC,CAAC,SAAS,EAEf,SAAS,EAAE,8BAA8B,eAAe,iEAAiE,WAAW,CAAC,CAAC,CAAC,kHAAkH,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,CAAC,SAAS,IAAI,EAAE,EAAE;QAEzR,6BAAK,SAAS,EAAC,MAAM;YACnB,oBAAC,iBAAiB,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,GAAI,CAC7D;QACN,6BAAK,SAAS,EAAE,KAAK,CAAC,aAAa,IAAI,eAAe,IACnD,KAAK,CAAC,KAAK,CACR,CACF,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -152,9 +152,38 @@ const BaseModelTable = (props) => {
152
152
  const [tableView, setTableView] = useState(null);
153
153
  const matchBulkSelectedItemByField = ((_a = props.bulkActions) === null || _a === void 0 ? void 0 : _a.matchBulkSelectedItemByField) || "_id";
154
154
  const model = new props.modelType();
155
+ /*
156
+ * The header's create button, "<verb> <noun>". Translating the two words
157
+ * separately reads the verb out of context - "Link" comes back as the noun
158
+ * in many languages, and word order differs - so the whole phrase is looked
159
+ * up first ("Link Alert") and the word-by-word join is only the fallback
160
+ * for a phrase with no entry of its own. In English both are the same.
161
+ */
162
+ const getCreateButtonTitle = () => {
163
+ const verb = props.createVerb || "Create";
164
+ const noun = props.singularName || model.singularName || "";
165
+ if (noun) {
166
+ const phrase = `${verb} ${noun}`;
167
+ const translatedPhrase = tx(phrase);
168
+ if (translatedPhrase && translatedPhrase !== phrase) {
169
+ return translatedPhrase;
170
+ }
171
+ }
172
+ return `${tx(verb)} ${tx(noun)}`;
173
+ };
155
174
  const getActionGate = (action) => {
175
+ var _a, _b;
176
+ /*
177
+ * A table that calls its delete "Unlink" must not say the locked button
178
+ * would delete the row's noun ("permission to delete this Alert"). Keyed
179
+ * on deleteVerb alone: deleteButtonText is also set by tables such as
180
+ * "Remove from Project", which keep the default "delete" sentence.
181
+ */
156
182
  const result = PermissionGate.check(model, action, {
157
183
  singularName: props.singularName || model.singularName || undefined,
184
+ verb: action === ModelAction.Delete
185
+ ? ((_b = (_a = props.bulkActions) === null || _a === void 0 ? void 0 : _a.deleteVerb) === null || _b === void 0 ? void 0 : _b.trim()) || undefined
186
+ : undefined,
158
187
  });
159
188
  if (result.isAllowed) {
160
189
  return { show: true, disabled: false, tooltip: undefined };
@@ -1535,7 +1564,7 @@ const BaseModelTable = (props) => {
1535
1564
  createGate.show &&
1536
1565
  showAs !== ShowAs.OrderedStatesList) {
1537
1566
  headerbuttons.push({
1538
- title: `${tx(props.createVerb || "Create")} ${tx(props.singularName || model.singularName || "")}`,
1567
+ title: getCreateButtonTitle(),
1539
1568
  buttonStyle: ButtonStyleType.NORMAL,
1540
1569
  buttonSize: ButtonSize.Normal,
1541
1570
  className: "",
@@ -1770,6 +1799,7 @@ const BaseModelTable = (props) => {
1770
1799
  };
1771
1800
  }, [showColumnCustomizationModal, attributeColumnKey]);
1772
1801
  const setActionSchema = () => {
1802
+ var _a, _b, _c;
1773
1803
  const permissions = PermissionUtil.getAllPermissions();
1774
1804
  const actionsSchema = [];
1775
1805
  if (props.showViewIdButton) {
@@ -1862,10 +1892,14 @@ const BaseModelTable = (props) => {
1862
1892
  });
1863
1893
  }
1864
1894
  const deleteGate = getActionGate(ModelAction.Delete);
1895
+ /* The row action wears the same icon as the bulk one it stands for. */
1896
+ const rowDeleteIcon = (((_b = (_a = props.bulkActions) === null || _a === void 0 ? void 0 : _a.deleteVerb) === null || _b === void 0 ? void 0 : _b.trim()) &&
1897
+ ((_c = props.bulkActions) === null || _c === void 0 ? void 0 : _c.deleteIcon)) ||
1898
+ IconProp.Trash;
1865
1899
  if (props.isDeleteable && deleteGate.show) {
1866
1900
  actionsSchema.push({
1867
1901
  title: tx(props.deleteButtonText || "Delete"),
1868
- icon: IconProp.Trash,
1902
+ icon: rowDeleteIcon,
1869
1903
  buttonStyleType: ButtonStyleType.DANGER_OUTLINE,
1870
1904
  disabled: deleteGate.disabled,
1871
1905
  tooltip: deleteGate.tooltip,
@@ -1936,25 +1970,35 @@ const BaseModelTable = (props) => {
1936
1970
  itemsOnPage,
1937
1971
  ]);
1938
1972
  const getDeleteBulkAction = () => {
1973
+ var _a, _b, _c;
1974
+ /*
1975
+ * A table that names its own verb ("Unlink") removes relationships, not
1976
+ * things, so its sentence drops "This action cannot be undone" - that
1977
+ * would say the opposite of the warning it usually appends.
1978
+ */
1979
+ const deleteVerb = ((_b = (_a = props.bulkActions) === null || _a === void 0 ? void 0 : _a.deleteVerb) === null || _b === void 0 ? void 0 : _b.trim()) || undefined;
1980
+ const getItemLabel = (items) => {
1981
+ return items.length === 1
1982
+ ? props.singularName || model.singularName || "item"
1983
+ : props.pluralName || model.pluralName || "items";
1984
+ };
1939
1985
  return {
1940
- title: "Delete",
1986
+ title: deleteVerb || "Delete",
1941
1987
  buttonStyleType: ButtonStyleType.DANGER,
1942
- icon: IconProp.Trash,
1988
+ icon: (deleteVerb && ((_c = props.bulkActions) === null || _c === void 0 ? void 0 : _c.deleteIcon)) || IconProp.Trash,
1943
1989
  confirmMessage: (items) => {
1944
1990
  var _a;
1945
- const itemLabel = items.length === 1
1946
- ? props.singularName || model.singularName || "item"
1947
- : props.pluralName || model.pluralName || "items";
1991
+ const itemLabel = getItemLabel(items);
1948
1992
  const warning = ((_a = props.bulkActions) === null || _a === void 0 ? void 0 : _a.deleteConfirmationWarning)
1949
1993
  ? ` ${props.bulkActions.deleteConfirmationWarning}`
1950
1994
  : "";
1995
+ if (deleteVerb) {
1996
+ return `Are you sure you want to ${deleteVerb.toLowerCase()} ${items.length} ${itemLabel.toLowerCase()}?${warning}`;
1997
+ }
1951
1998
  return `Are you sure you want to delete ${items.length} ${itemLabel}? This action cannot be undone.${warning}`;
1952
1999
  },
1953
2000
  confirmTitle: (items) => {
1954
- const itemLabel = items.length === 1
1955
- ? props.singularName || model.singularName || "item"
1956
- : props.pluralName || model.pluralName || "items";
1957
- return `Delete ${items.length} ${itemLabel}`;
2001
+ return `${deleteVerb || "Delete"} ${items.length} ${getItemLabel(items)}`;
1958
2002
  },
1959
2003
  confirmButtonStyleType: ButtonStyleType.DANGER,
1960
2004
  onClick: async ({ items, onProgressInfo, onBulkActionStart, onBulkActionEnd, }) => {
@@ -2051,7 +2095,7 @@ const BaseModelTable = (props) => {
2051
2095
  : "rounded-lg border-2 border-gray-200 p-6 pt-0 pb-5", tableContainerClassName: props.cardProps ? "" : "overflow-hidden rounded", onFilterRefreshClick: async () => {
2052
2096
  await getFilterDropdownItems();
2053
2097
  }, bulkActions: (() => {
2054
- var _a, _b;
2098
+ var _a, _b, _c, _d;
2055
2099
  const bulkDeleteGate = getActionGate(ModelAction.Delete);
2056
2100
  /*
2057
2101
  * Whether to auto-add the default Delete still follows the model
@@ -2077,7 +2121,16 @@ const BaseModelTable = (props) => {
2077
2121
  * Table derives the row checkboxes from this array being non-empty,
2078
2122
  * so injecting a locked Delete into an otherwise empty array would
2079
2123
  * grow a selection column onto tables that have never had one.
2124
+ *
2125
+ * A page's own button counts as the delete action when it carries
2126
+ * the title the default one would have: "Delete", or the table's
2127
+ * deleteVerb.
2080
2128
  */
2129
+ const deleteActionTitles = ["Delete"];
2130
+ const bulkDeleteVerb = ((_d = (_c = props.bulkActions) === null || _c === void 0 ? void 0 : _c.deleteVerb) === null || _d === void 0 ? void 0 : _d.trim()) || undefined;
2131
+ if (bulkDeleteVerb) {
2132
+ deleteActionTitles.push(bulkDeleteVerb);
2133
+ }
2081
2134
  const alreadyHasDeleteAction = sourceButtons.some((action) => {
2082
2135
  if (action === ModalTableBulkDefaultActions.Delete) {
2083
2136
  return true;
@@ -2085,8 +2138,7 @@ const BaseModelTable = (props) => {
2085
2138
  if (typeof action === "object" &&
2086
2139
  action !== null &&
2087
2140
  "title" in action &&
2088
- action.title ===
2089
- "Delete") {
2141
+ deleteActionTitles.includes(action.title)) {
2090
2142
  return true;
2091
2143
  }
2092
2144
  return false;