@marinoscar/platform-web 0.1.0-next.19 → 0.1.0-next.21

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 (174) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +5 -3
  3. package/dist/alerts/headless/client.d.ts +134 -0
  4. package/dist/alerts/headless/client.d.ts.map +1 -0
  5. package/dist/alerts/headless/client.js +105 -0
  6. package/dist/alerts/headless/client.js.map +1 -0
  7. package/dist/alerts/headless/format.d.ts +95 -0
  8. package/dist/alerts/headless/format.d.ts.map +1 -0
  9. package/dist/alerts/headless/format.js +164 -0
  10. package/dist/alerts/headless/format.js.map +1 -0
  11. package/dist/alerts/headless/hooks.d.ts +245 -0
  12. package/dist/alerts/headless/hooks.d.ts.map +1 -0
  13. package/dist/alerts/headless/hooks.js +315 -0
  14. package/dist/alerts/headless/hooks.js.map +1 -0
  15. package/dist/alerts/headless/index.d.ts +9 -0
  16. package/dist/alerts/headless/index.d.ts.map +1 -0
  17. package/dist/alerts/headless/index.js +9 -0
  18. package/dist/alerts/headless/index.js.map +1 -0
  19. package/dist/alerts/headless/rule-draft.d.ts +175 -0
  20. package/dist/alerts/headless/rule-draft.d.ts.map +1 -0
  21. package/dist/alerts/headless/rule-draft.js +261 -0
  22. package/dist/alerts/headless/rule-draft.js.map +1 -0
  23. package/dist/alerts/ui/AlertIncidentDrawer.d.ts +30 -0
  24. package/dist/alerts/ui/AlertIncidentDrawer.d.ts.map +1 -0
  25. package/dist/alerts/ui/AlertIncidentDrawer.js +33 -0
  26. package/dist/alerts/ui/AlertIncidentDrawer.js.map +1 -0
  27. package/dist/alerts/ui/AlertRuleDialog.d.ts +47 -0
  28. package/dist/alerts/ui/AlertRuleDialog.d.ts.map +1 -0
  29. package/dist/alerts/ui/AlertRuleDialog.js +124 -0
  30. package/dist/alerts/ui/AlertRuleDialog.js.map +1 -0
  31. package/dist/alerts/ui/AlertRuleTestResult.d.ts +23 -0
  32. package/dist/alerts/ui/AlertRuleTestResult.d.ts.map +1 -0
  33. package/dist/alerts/ui/AlertRuleTestResult.js +30 -0
  34. package/dist/alerts/ui/AlertRuleTestResult.js.map +1 -0
  35. package/dist/alerts/ui/AlertsPage.d.ts +41 -0
  36. package/dist/alerts/ui/AlertsPage.d.ts.map +1 -0
  37. package/dist/alerts/ui/AlertsPage.js +238 -0
  38. package/dist/alerts/ui/AlertsPage.js.map +1 -0
  39. package/dist/alerts/ui/FiringAlertsBanner.d.ts +28 -0
  40. package/dist/alerts/ui/FiringAlertsBanner.d.ts.map +1 -0
  41. package/dist/alerts/ui/FiringAlertsBanner.js +45 -0
  42. package/dist/alerts/ui/FiringAlertsBanner.js.map +1 -0
  43. package/dist/alerts/ui/copy.d.ts +15 -0
  44. package/dist/alerts/ui/copy.d.ts.map +1 -0
  45. package/dist/alerts/ui/copy.js +14 -0
  46. package/dist/alerts/ui/copy.js.map +1 -0
  47. package/dist/alerts/ui/index.d.ts +14 -0
  48. package/dist/alerts/ui/index.d.ts.map +1 -0
  49. package/dist/alerts/ui/index.js +12 -0
  50. package/dist/alerts/ui/index.js.map +1 -0
  51. package/dist/alerts/ui/parts.d.ts +26 -0
  52. package/dist/alerts/ui/parts.d.ts.map +1 -0
  53. package/dist/alerts/ui/parts.js +27 -0
  54. package/dist/alerts/ui/parts.js.map +1 -0
  55. package/dist/alerts/ui/settings.d.ts +27 -0
  56. package/dist/alerts/ui/settings.d.ts.map +1 -0
  57. package/dist/alerts/ui/settings.js +37 -0
  58. package/dist/alerts/ui/settings.js.map +1 -0
  59. package/dist/nodes/headless/api.d.ts +3 -1
  60. package/dist/nodes/headless/api.d.ts.map +1 -1
  61. package/dist/nodes/headless/api.js +22 -0
  62. package/dist/nodes/headless/api.js.map +1 -1
  63. package/dist/nodes/headless/index.d.ts +7 -2
  64. package/dist/nodes/headless/index.d.ts.map +1 -1
  65. package/dist/nodes/headless/index.js +4 -1
  66. package/dist/nodes/headless/index.js.map +1 -1
  67. package/dist/nodes/headless/node-events.d.ts +43 -0
  68. package/dist/nodes/headless/node-events.d.ts.map +1 -0
  69. package/dist/nodes/headless/node-events.js +150 -0
  70. package/dist/nodes/headless/node-events.js.map +1 -0
  71. package/dist/nodes/headless/power.d.ts +43 -0
  72. package/dist/nodes/headless/power.d.ts.map +1 -0
  73. package/dist/nodes/headless/power.js +74 -0
  74. package/dist/nodes/headless/power.js.map +1 -0
  75. package/dist/nodes/headless/types.d.ts +40 -3
  76. package/dist/nodes/headless/types.d.ts.map +1 -1
  77. package/dist/nodes/headless/types.js +1 -1
  78. package/dist/nodes/headless/types.js.map +1 -1
  79. package/dist/nodes/headless/use-node-events.d.ts +59 -0
  80. package/dist/nodes/headless/use-node-events.d.ts.map +1 -0
  81. package/dist/nodes/headless/use-node-events.js +159 -0
  82. package/dist/nodes/headless/use-node-events.js.map +1 -0
  83. package/dist/nodes/ui/NodeEventsTimeline.d.ts +39 -0
  84. package/dist/nodes/ui/NodeEventsTimeline.d.ts.map +1 -0
  85. package/dist/nodes/ui/NodeEventsTimeline.js +63 -0
  86. package/dist/nodes/ui/NodeEventsTimeline.js.map +1 -0
  87. package/dist/nodes/ui/NodePowerBadge.d.ts +27 -0
  88. package/dist/nodes/ui/NodePowerBadge.d.ts.map +1 -0
  89. package/dist/nodes/ui/NodePowerBadge.js +48 -0
  90. package/dist/nodes/ui/NodePowerBadge.js.map +1 -0
  91. package/dist/nodes/ui/NodeVitalsDialog.d.ts +11 -1
  92. package/dist/nodes/ui/NodeVitalsDialog.d.ts.map +1 -1
  93. package/dist/nodes/ui/NodeVitalsDialog.js +14 -5
  94. package/dist/nodes/ui/NodeVitalsDialog.js.map +1 -1
  95. package/dist/nodes/ui/WorkersPage.d.ts.map +1 -1
  96. package/dist/nodes/ui/WorkersPage.js +2 -1
  97. package/dist/nodes/ui/WorkersPage.js.map +1 -1
  98. package/dist/nodes/ui/workerVitals.d.ts +17 -1
  99. package/dist/nodes/ui/workerVitals.d.ts.map +1 -1
  100. package/dist/nodes/ui/workerVitals.js +43 -0
  101. package/dist/nodes/ui/workerVitals.js.map +1 -1
  102. package/dist/nodes/ui/workersTable.d.ts.map +1 -1
  103. package/dist/nodes/ui/workersTable.js +2 -1
  104. package/dist/nodes/ui/workersTable.js.map +1 -1
  105. package/dist/telemetry/headless/hooks/useTelemetryDashboard.d.ts +1 -1
  106. package/dist/telemetry/ui/components/dashboard/metrics/MetricSections.d.ts +11 -0
  107. package/dist/telemetry/ui/components/dashboard/metrics/MetricSections.d.ts.map +1 -1
  108. package/dist/telemetry/ui/components/dashboard/metrics/MetricSections.js +17 -2
  109. package/dist/telemetry/ui/components/dashboard/metrics/MetricSections.js.map +1 -1
  110. package/dist/webhooks/headless/client.d.ts +101 -0
  111. package/dist/webhooks/headless/client.d.ts.map +1 -0
  112. package/dist/webhooks/headless/client.js +105 -0
  113. package/dist/webhooks/headless/client.js.map +1 -0
  114. package/dist/webhooks/headless/event-selection.d.ts +119 -0
  115. package/dist/webhooks/headless/event-selection.d.ts.map +1 -0
  116. package/dist/webhooks/headless/event-selection.js +225 -0
  117. package/dist/webhooks/headless/event-selection.js.map +1 -0
  118. package/dist/webhooks/headless/format.d.ts +84 -0
  119. package/dist/webhooks/headless/format.d.ts.map +1 -0
  120. package/dist/webhooks/headless/format.js +142 -0
  121. package/dist/webhooks/headless/format.js.map +1 -0
  122. package/dist/webhooks/headless/hooks.d.ts +199 -0
  123. package/dist/webhooks/headless/hooks.d.ts.map +1 -0
  124. package/dist/webhooks/headless/hooks.js +249 -0
  125. package/dist/webhooks/headless/hooks.js.map +1 -0
  126. package/dist/webhooks/headless/index.d.ts +9 -0
  127. package/dist/webhooks/headless/index.d.ts.map +1 -0
  128. package/dist/webhooks/headless/index.js +9 -0
  129. package/dist/webhooks/headless/index.js.map +1 -0
  130. package/dist/webhooks/ui/WebhookDeliveryDrawer.d.ts +32 -0
  131. package/dist/webhooks/ui/WebhookDeliveryDrawer.d.ts.map +1 -0
  132. package/dist/webhooks/ui/WebhookDeliveryDrawer.js +64 -0
  133. package/dist/webhooks/ui/WebhookDeliveryDrawer.js.map +1 -0
  134. package/dist/webhooks/ui/WebhookEndpointDetail.d.ts +21 -0
  135. package/dist/webhooks/ui/WebhookEndpointDetail.d.ts.map +1 -0
  136. package/dist/webhooks/ui/WebhookEndpointDetail.js +96 -0
  137. package/dist/webhooks/ui/WebhookEndpointDetail.js.map +1 -0
  138. package/dist/webhooks/ui/WebhookEndpointDialog.d.ts +39 -0
  139. package/dist/webhooks/ui/WebhookEndpointDialog.d.ts.map +1 -0
  140. package/dist/webhooks/ui/WebhookEndpointDialog.js +79 -0
  141. package/dist/webhooks/ui/WebhookEndpointDialog.js.map +1 -0
  142. package/dist/webhooks/ui/WebhookEventPicker.d.ts +30 -0
  143. package/dist/webhooks/ui/WebhookEventPicker.d.ts.map +1 -0
  144. package/dist/webhooks/ui/WebhookEventPicker.js +33 -0
  145. package/dist/webhooks/ui/WebhookEventPicker.js.map +1 -0
  146. package/dist/webhooks/ui/WebhookSecretDialog.d.ts +27 -0
  147. package/dist/webhooks/ui/WebhookSecretDialog.d.ts.map +1 -0
  148. package/dist/webhooks/ui/WebhookSecretDialog.js +52 -0
  149. package/dist/webhooks/ui/WebhookSecretDialog.js.map +1 -0
  150. package/dist/webhooks/ui/WebhookSignatureHelp.d.ts +18 -0
  151. package/dist/webhooks/ui/WebhookSignatureHelp.d.ts.map +1 -0
  152. package/dist/webhooks/ui/WebhookSignatureHelp.js +40 -0
  153. package/dist/webhooks/ui/WebhookSignatureHelp.js.map +1 -0
  154. package/dist/webhooks/ui/WebhooksPage.d.ts +47 -0
  155. package/dist/webhooks/ui/WebhooksPage.d.ts.map +1 -0
  156. package/dist/webhooks/ui/WebhooksPage.js +172 -0
  157. package/dist/webhooks/ui/WebhooksPage.js.map +1 -0
  158. package/dist/webhooks/ui/copy.d.ts +24 -0
  159. package/dist/webhooks/ui/copy.d.ts.map +1 -0
  160. package/dist/webhooks/ui/copy.js +34 -0
  161. package/dist/webhooks/ui/copy.js.map +1 -0
  162. package/dist/webhooks/ui/index.d.ts +15 -0
  163. package/dist/webhooks/ui/index.d.ts.map +1 -0
  164. package/dist/webhooks/ui/index.js +12 -0
  165. package/dist/webhooks/ui/index.js.map +1 -0
  166. package/dist/webhooks/ui/parts.d.ts +25 -0
  167. package/dist/webhooks/ui/parts.d.ts.map +1 -0
  168. package/dist/webhooks/ui/parts.js +28 -0
  169. package/dist/webhooks/ui/parts.js.map +1 -0
  170. package/dist/webhooks/ui/settings.d.ts +58 -0
  171. package/dist/webhooks/ui/settings.d.ts.map +1 -0
  172. package/dist/webhooks/ui/settings.js +79 -0
  173. package/dist/webhooks/ui/settings.js.map +1 -0
  174. package/package.json +18 -2
@@ -0,0 +1,28 @@
1
+ import type { ReactElement } from 'react';
2
+ /**
3
+ * Props of {@link FiringAlertsBanner}.
4
+ *
5
+ * @stability experimental
6
+ */
7
+ export interface FiringAlertsBannerProps {
8
+ /** Where "View incidents" goes; default the Alerts page's Incidents tab. */
9
+ to?: string;
10
+ /** The poll interval in milliseconds; default 30 000. */
11
+ intervalMs?: number;
12
+ }
13
+ /**
14
+ * The number of firing alerts by severity, with a link to the incidents.
15
+ *
16
+ * @param props - see {@link FiringAlertsBannerProps}.
17
+ * @returns the banner, or `null` when nothing is firing.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * <TelemetryDashboardPage slots={{ BeforeContent: () => <FiringAlertsBanner /> }} />
22
+ * ```
23
+ *
24
+ * @extensionPoint component
25
+ * @stability experimental
26
+ */
27
+ export declare function FiringAlertsBanner({ to, intervalMs }?: FiringAlertsBannerProps): ReactElement | null;
28
+ //# sourceMappingURL=FiringAlertsBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FiringAlertsBanner.d.ts","sourceRoot":"","sources":["../../../src/alerts/ui/FiringAlertsBanner.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAU1C;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAA6C,EAAE,UAAU,EAAE,GAAE,uBAA4B,GAAG,YAAY,GAAG,IAAI,CAgCnJ"}
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // The firing-alerts banner (issue #1047): how many alerts are firing now, by
3
+ // severity, linking to the Alerts page's incidents. Built for the telemetry
4
+ // dashboard's `BeforeContent` slot (the app passes it; telemetry does not
5
+ // depend on alerts), and usable on any page. Draws nothing while nothing is
6
+ // firing, before the first answer, or for a viewer without `alerts:read`.
7
+ import { Alert, AlertTitle, Button, Stack } from '@mui/material';
8
+ import { Link as RouterLink } from 'react-router-dom';
9
+ import { ALERT_PERMISSIONS, ALERT_SEVERITIES } from '@marinoscar/platform-contract/alerts';
10
+ import { usePlatformViewer } from '../../core/index.js';
11
+ import { ALERT_SEVERITY_LABELS, alertFiringTotal, alertTopSeverity, useAlertSummary } from '../headless/index.js';
12
+ import { ALERTS_PAGE_COPY } from './copy.js';
13
+ import { SeverityChip } from './parts.js';
14
+ const ALERT_SEVERITY_FOR = {
15
+ critical: 'error',
16
+ warning: 'warning',
17
+ info: 'info',
18
+ };
19
+ /**
20
+ * The number of firing alerts by severity, with a link to the incidents.
21
+ *
22
+ * @param props - see {@link FiringAlertsBannerProps}.
23
+ * @returns the banner, or `null` when nothing is firing.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * <TelemetryDashboardPage slots={{ BeforeContent: () => <FiringAlertsBanner /> }} />
28
+ * ```
29
+ *
30
+ * @extensionPoint component
31
+ * @stability experimental
32
+ */
33
+ export function FiringAlertsBanner({ to = `${ALERTS_PAGE_COPY.path}?tab=incidents`, intervalMs } = {}) {
34
+ const viewer = usePlatformViewer();
35
+ const allowed = viewer.hasPermission(ALERT_PERMISSIONS.READ);
36
+ const { summary } = useAlertSummary({ enabled: allowed, ...(intervalMs === undefined ? {} : { intervalMs }) });
37
+ const total = alertFiringTotal(summary);
38
+ const top = alertTopSeverity(summary);
39
+ if (!allowed || !summary || total === 0 || !top)
40
+ return null;
41
+ return (_jsxs(Alert, { severity: ALERT_SEVERITY_FOR[top] ?? 'warning', sx: { mb: 2 }, "data-testid": "firing-alerts-banner", action: _jsx(Button, { component: RouterLink, to: to, color: "inherit", size: "small", sx: { minHeight: 44 }, children: "View incidents" }), children: [_jsx(AlertTitle, { children: total === 1 ? '1 alert is firing' : `${total} alerts are firing` }), _jsx(Stack, { direction: "row", spacing: 1, useFlexGap: true, sx: { flexWrap: 'wrap' }, children: ALERT_SEVERITIES.filter((severity) => summary.firing[severity] > 0)
42
+ .reverse()
43
+ .map((severity) => (_jsx(SeverityChip, { severity: severity, label: `${summary.firing[severity]} ${ALERT_SEVERITY_LABELS[severity].toLowerCase()}` }, severity))) })] }));
44
+ }
45
+ //# sourceMappingURL=FiringAlertsBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FiringAlertsBanner.js","sourceRoot":"","sources":["../../../src/alerts/ui/FiringAlertsBanner.tsx"],"names":[],"mappings":";AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,4EAA4E;AAC5E,0EAA0E;AAE1E,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAE3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAc1C,MAAM,kBAAkB,GAA2D;IACjF,QAAQ,EAAE,OAAO;IACjB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,MAAM;CACb,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAE,EAAE,GAAG,GAAG,gBAAgB,CAAC,IAAI,gBAAgB,EAAE,UAAU,KAA8B,EAAE;IAC5H,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/G,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAC7D,OAAO,CACL,MAAC,KAAK,IACJ,QAAQ,EAAE,kBAAkB,CAAC,GAAG,CAAC,IAAI,SAAS,EAC9C,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,iBACD,sBAAsB,EAClC,MAAM,EACJ,KAAC,MAAM,IAAC,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAC,SAAS,EAAC,IAAI,EAAC,OAAO,EAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,+BAEhF,aAGX,KAAC,UAAU,cAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,KAAK,oBAAoB,GAAc,EAC3F,KAAC,KAAK,IAAC,SAAS,EAAC,KAAK,EAAC,OAAO,EAAE,CAAC,EAAE,UAAU,QAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,YACnE,gBAAgB,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;qBACjE,OAAO,EAAE;qBACT,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CACjB,KAAC,YAAY,IAEX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,qBAAqB,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,IAFhF,QAAQ,CAGb,CACH,CAAC,GACE,IACF,CACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The title, description and route of the Alerts page: the registry card's
3
+ * text and the page's heading.
4
+ *
5
+ * @stability experimental
6
+ */
7
+ export declare const ALERTS_PAGE_COPY: Readonly<{
8
+ /** The card title and the page heading. */
9
+ readonly title: string;
10
+ /** The card text and the page lead. */
11
+ readonly description: string;
12
+ /** The route of the page. */
13
+ readonly path: string;
14
+ }>;
15
+ //# sourceMappingURL=copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../src/alerts/ui/copy.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC;IACtC,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAKC,CAAC"}
@@ -0,0 +1,14 @@
1
+ // The alerts UI's copy (issue #1047), in one place so a fork rewords it once.
2
+ // The card text and the page heading are the same words.
3
+ /**
4
+ * The title, description and route of the Alerts page: the registry card's
5
+ * text and the page's heading.
6
+ *
7
+ * @stability experimental
8
+ */
9
+ export const ALERTS_PAGE_COPY = Object.freeze({
10
+ title: 'Alerts',
11
+ description: 'Get told when something needs attention: metric thresholds, worker node events, offline nodes and the dashboard verdict, with the incidents they raised.',
12
+ path: '/admin/settings/alerts',
13
+ });
14
+ //# sourceMappingURL=copy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.js","sourceRoot":"","sources":["../../../src/alerts/ui/copy.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yDAAyD;AAEzD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAOxB,MAAM,CAAC,MAAM,CAAC;IACjB,KAAK,EAAE,QAAQ;IACf,WAAW,EACT,0JAA0J;IAC5J,IAAI,EAAE,wBAAwB;CAC/B,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { ALERTS_PAGE_COPY } from './copy.js';
2
+ export { alertsAdminCards } from './settings.js';
3
+ export type { AlertsAdminCard } from './settings.js';
4
+ export { AlertIncidentDrawer } from './AlertIncidentDrawer.js';
5
+ export type { AlertIncidentDrawerProps } from './AlertIncidentDrawer.js';
6
+ export { AlertRuleDialog } from './AlertRuleDialog.js';
7
+ export type { AlertRuleDialogProps } from './AlertRuleDialog.js';
8
+ export { AlertRuleTestResult } from './AlertRuleTestResult.js';
9
+ export type { AlertRuleTestResultProps } from './AlertRuleTestResult.js';
10
+ export { AlertsPage } from './AlertsPage.js';
11
+ export type { AlertsPageProps, AlertsPageSlots } from './AlertsPage.js';
12
+ export { FiringAlertsBanner } from './FiringAlertsBanner.js';
13
+ export type { FiringAlertsBannerProps } from './FiringAlertsBanner.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/alerts/ui/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,12 @@
1
+ // `@marinoscar/platform-web/alerts/ui`: the Alerts page (Rules and Incidents
2
+ // tabs), the rule editor, the dry-run result, the incident drawer, the firing
3
+ // banner for the telemetry dashboard and the admin card as data, built on
4
+ // `/alerts/headless` (issue #1047). Documented in ../README.md.
5
+ export { ALERTS_PAGE_COPY } from './copy.js';
6
+ export { alertsAdminCards } from './settings.js';
7
+ export { AlertIncidentDrawer } from './AlertIncidentDrawer.js';
8
+ export { AlertRuleDialog } from './AlertRuleDialog.js';
9
+ export { AlertRuleTestResult } from './AlertRuleTestResult.js';
10
+ export { AlertsPage } from './AlertsPage.js';
11
+ export { FiringAlertsBanner } from './FiringAlertsBanner.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/alerts/ui/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,0EAA0E;AAC1E,gEAAgE;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import type { AlertIncidentState, AlertSeverity } from '@marinoscar/platform-contract/alerts';
3
+ /** A severity as a labelled chip (the words carry the meaning, not the colour). */
4
+ export declare function SeverityChip({ severity, label }: {
5
+ severity: AlertSeverity;
6
+ label?: string;
7
+ }): ReactElement;
8
+ /** An incident state as a labelled chip. */
9
+ export declare function StateChip({ state }: {
10
+ state: AlertIncidentState;
11
+ }): ReactElement;
12
+ /** A timestamp in the display zone, or a dash. */
13
+ export declare function when(iso: string | null | undefined): string;
14
+ export interface ConfirmDialogProps {
15
+ open: boolean;
16
+ title: string;
17
+ children: ReactNode;
18
+ confirmLabel: string;
19
+ destructive?: boolean;
20
+ busy?: boolean;
21
+ onConfirm: () => void;
22
+ onClose: () => void;
23
+ }
24
+ /** A yes/no dialog whose text says what will happen. */
25
+ export declare function ConfirmDialog({ open, title, children, confirmLabel, destructive, busy, onConfirm, onClose }: ConfirmDialogProps): ReactElement;
26
+ //# sourceMappingURL=parts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../../../src/alerts/ui/parts.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAe9F,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAE3G;AAED,4CAA4C;AAC5C,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,kBAAkB,CAAA;CAAE,GAAG,YAAY,CAGhF;AAED,kDAAkD;AAClD,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAE3D;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,kBAAkB,GAAG,YAAY,CAiB9I"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Small building blocks of the alerts UI (issue #1047): the severity and state
3
+ // chips, the confirm dialog and the date text. Internal to the slice.
4
+ import { Button, Chip, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from '@mui/material';
5
+ import { formatDateTime } from '../../core/index.js';
6
+ import { ALERT_SEVERITY_LABELS, ALERT_SEVERITY_TONES, ALERT_STATE_LABELS, ALERT_STATE_TONES, } from '../headless/index.js';
7
+ function chipColor(tone) {
8
+ return tone;
9
+ }
10
+ /** A severity as a labelled chip (the words carry the meaning, not the colour). */
11
+ export function SeverityChip({ severity, label }) {
12
+ return _jsx(Chip, { size: "small", label: label ?? ALERT_SEVERITY_LABELS[severity], color: chipColor(ALERT_SEVERITY_TONES[severity]) });
13
+ }
14
+ /** An incident state as a labelled chip. */
15
+ export function StateChip({ state }) {
16
+ const tone = ALERT_STATE_TONES[state];
17
+ return _jsx(Chip, { size: "small", label: ALERT_STATE_LABELS[state], color: chipColor(tone), variant: state === 'resolved' ? 'outlined' : 'filled' });
18
+ }
19
+ /** A timestamp in the display zone, or a dash. */
20
+ export function when(iso) {
21
+ return iso ? formatDateTime(iso) : '—';
22
+ }
23
+ /** A yes/no dialog whose text says what will happen. */
24
+ export function ConfirmDialog({ open, title, children, confirmLabel, destructive, busy, onConfirm, onClose }) {
25
+ return (_jsxs(Dialog, { open: open, onClose: onClose, maxWidth: "xs", fullWidth: true, "aria-labelledby": "alerts-confirm-title", children: [_jsx(DialogTitle, { id: "alerts-confirm-title", children: title }), _jsx(DialogContent, { children: _jsx(DialogContentText, { component: "div", children: children }) }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: onClose, sx: { minHeight: 44 }, children: "Cancel" }), _jsx(Button, { variant: "contained", color: destructive ? 'error' : 'primary', onClick: onConfirm, disabled: busy, sx: { minHeight: 44 }, children: confirmLabel })] })] }));
26
+ }
27
+ //# sourceMappingURL=parts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parts.js","sourceRoot":"","sources":["../../../src/alerts/ui/parts.tsx"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,sEAAsE;AAEtE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAKnH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAElB,MAAM,sBAAsB,CAAC;AAE9B,SAAS,SAAS,CAAC,IAAe;IAChC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,EAA+C;IAC3F,OAAO,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAE,KAAK,IAAI,qBAAqB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,GAAI,CAAC;AAClI,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,SAAS,CAAC,EAAE,KAAK,EAAiC;IAChE,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,GAAI,CAAC;AAChJ,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,IAAI,CAAC,GAA8B;IACjD,OAAO,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACzC,CAAC;AAaD,wDAAwD;AACxD,MAAM,UAAU,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAsB;IAC9H,OAAO,CACL,MAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAC,IAAI,EAAC,SAAS,2BAAiB,sBAAsB,aAClG,KAAC,WAAW,IAAC,EAAE,EAAC,sBAAsB,YAAE,KAAK,GAAe,EAC5D,KAAC,aAAa,cACZ,KAAC,iBAAiB,IAAC,SAAS,EAAC,KAAK,YAAE,QAAQ,GAAqB,GACnD,EAChB,MAAC,aAAa,eACZ,KAAC,MAAM,IAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,uBAEtC,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,YAC5H,YAAY,GACN,IACK,IACT,CACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { PlatformSettingsPage } from '../../core/index.js';
2
+ /**
3
+ * One alerts registry card: the `PlatformSettingsPage` card shape plus its
4
+ * icon, structurally a `SettingsCardDef` of the reference app.
5
+ *
6
+ * @stability experimental
7
+ */
8
+ export type AlertsAdminCard = PlatformSettingsPage<never>['card'] & {
9
+ /** The card and rail icon (an MUI SvgIcon). */
10
+ Icon: PlatformSettingsPage['Icon'];
11
+ };
12
+ /**
13
+ * The Observability card of the alerts slice: `Alerts`
14
+ * (`/admin/settings/alerts`, `alerts:read`, no `feature`). Route it to
15
+ * `<AlertsPage />`.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // apps/web/src/config/adminSections.tsx, the Observability section
20
+ * cards: [...telemetryAdminCards, doctorCard, ...alertsAdminCards],
21
+ * ```
22
+ *
23
+ * @extensionPoint component
24
+ * @stability experimental
25
+ */
26
+ export declare const alertsAdminCards: readonly AlertsAdminCard[];
27
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/alerts/ui/settings.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG;IAClE,+CAA+C;IAC/C,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,eAAe,EAQrD,CAAC"}
@@ -0,0 +1,37 @@
1
+ // The alerts slice's admin registry card (issue #1047). DATA, not a new
2
+ // registry: the app declares every card in its own `ADMIN_SECTIONS` and
3
+ // spreads this one where it belongs (the Observability section). No page
4
+ // component is referenced here, so importing the card never pulls the page
5
+ // into the app's main chunk.
6
+ //
7
+ // `alerts:read` is the exact string every read route of the packaged
8
+ // `/api/admin/alerts` controller enforces (`ALERT_PERMISSIONS.READ` of
9
+ // `@marinoscar/platform-contract/alerts`); writes (`alerts:write`) are gated
10
+ // inside the page. NO `feature`: node rules work with telemetry switched off.
11
+ import NotificationImportantOutlinedIcon from '@mui/icons-material/NotificationImportantOutlined';
12
+ import { ALERT_PERMISSIONS } from '@marinoscar/platform-contract/alerts';
13
+ import { ALERTS_PAGE_COPY } from './copy.js';
14
+ /**
15
+ * The Observability card of the alerts slice: `Alerts`
16
+ * (`/admin/settings/alerts`, `alerts:read`, no `feature`). Route it to
17
+ * `<AlertsPage />`.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * // apps/web/src/config/adminSections.tsx, the Observability section
22
+ * cards: [...telemetryAdminCards, doctorCard, ...alertsAdminCards],
23
+ * ```
24
+ *
25
+ * @extensionPoint component
26
+ * @stability experimental
27
+ */
28
+ export const alertsAdminCards = Object.freeze([
29
+ {
30
+ title: ALERTS_PAGE_COPY.title,
31
+ description: ALERTS_PAGE_COPY.description,
32
+ path: ALERTS_PAGE_COPY.path,
33
+ Icon: NotificationImportantOutlinedIcon,
34
+ permission: ALERT_PERMISSIONS.READ,
35
+ },
36
+ ]);
37
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/alerts/ui/settings.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,wEAAwE;AACxE,yEAAyE;AACzE,2EAA2E;AAC3E,6BAA6B;AAC7B,EAAE;AACF,qEAAqE;AACrE,uEAAuE;AACvE,6EAA6E;AAC7E,8EAA8E;AAE9E,OAAO,iCAAiC,MAAM,mDAAmD,CAAC;AAClG,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAGzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAa7C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA+B,MAAM,CAAC,MAAM,CAAC;IACxE;QACE,KAAK,EAAE,gBAAgB,CAAC,KAAK;QAC7B,WAAW,EAAE,gBAAgB,CAAC,WAAW;QACzC,IAAI,EAAE,gBAAgB,CAAC,IAAI;QAC3B,IAAI,EAAE,iCAAiC;QACvC,UAAU,EAAE,iBAAiB,CAAC,IAAI;KACnC;CACF,CAAC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { PlatformApiClient } from '../../core/index.js';
2
- import type { CreateNodeCredentialInput, NodeCredential, NodeCredentialCreated, WorkerNode } from './types.js';
2
+ import type { CreateNodeCredentialInput, NodeCredential, NodeCredentialCreated, NodeEventsQuery, WorkerNode, WorkerNodeEventList } from './types.js';
3
3
  /**
4
4
  * Every call the worker-node page and hooks make. `createNodesApi` builds one
5
5
  * over the app's transport; a test or an app with its own client implements it.
@@ -20,6 +20,8 @@ export interface NodesApi {
20
20
  createNodeCredential(input: CreateNodeCredentialInput): Promise<NodeCredentialCreated>;
21
21
  /** `DELETE /admin/nodes/credentials/:id`: effective on the node's next request; one-way. */
22
22
  revokeNodeCredential(id: string): Promise<void>;
23
+ /** `GET /admin/nodes/:id/events`: a page of the node's events, newest first (`nodes:read`). */
24
+ listNodeEvents(nodeId: string, query?: NodeEventsQuery): Promise<WorkerNodeEventList>;
23
25
  }
24
26
  /**
25
27
  * The worker-node client over the app's transport.
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/nodes/headless/api.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE/G;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,8EAA8E;IAC9E,cAAc,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACxC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,yGAAyG;IACzG,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,6FAA6F;IAC7F,kBAAkB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAChD,kFAAkF;IAClF,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvF,4FAA4F;IAC5F,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,QAAQ,CAiBlE"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/nodes/headless/api.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,8EAA8E;IAC9E,cAAc,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACxC,6DAA6D;IAC7D,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,yGAAyG;IACzG,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,6FAA6F;IAC7F,kBAAkB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAChD,kFAAkF;IAClF,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvF,4FAA4F;IAC5F,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,+FAA+F;IAC/F,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACvF;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,QAAQ,CAmBlE"}
@@ -16,7 +16,28 @@
16
16
  //
17
17
  // `GET /admin/nodes` returns the whole fleet as a bare array, not a page: a
18
18
  // fleet is tens of machines, and the page tallies its health verdicts.
19
+ //
20
+ // A node's events (#1045) ARE paged (`GET /admin/nodes/:id/events`): a laptop node
21
+ // on battery reports a change every few minutes, and a timeline only ever
22
+ // needs the newest screenful.
19
23
  // =============================================================================
24
+ /**
25
+ * `GET /admin/nodes/:id/events`'s query string: only the members that are set, in a
26
+ * fixed order (page, pageSize, type, severity), so a request is byte-stable.
27
+ */
28
+ function nodeEventsQueryString(query) {
29
+ const params = new URLSearchParams();
30
+ if (query.page !== undefined)
31
+ params.set('page', String(query.page));
32
+ if (query.pageSize !== undefined)
33
+ params.set('pageSize', String(query.pageSize));
34
+ if (query.type)
35
+ params.set('type', query.type);
36
+ if (query.severity)
37
+ params.set('severity', query.severity);
38
+ const text = params.toString();
39
+ return text ? `?${text}` : '';
40
+ }
20
41
  /**
21
42
  * The worker-node client over the app's transport.
22
43
  *
@@ -48,6 +69,7 @@ export function createNodesApi(client) {
48
69
  revokeNodeCredential: async (id) => {
49
70
  await client.delete(`/admin/nodes/credentials/${id}`);
50
71
  },
72
+ listNodeEvents: (nodeId, query = {}) => client.get(`/admin/nodes/${encodeURIComponent(nodeId)}/events${nodeEventsQueryString(query)}`),
51
73
  };
52
74
  }
53
75
  //# sourceMappingURL=api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/nodes/headless/api.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4CAA4C;AAC5C,gFAAgF;AAChF,EAAE;AACF,gFAAgF;AAChF,2EAA2E;AAC3E,8EAA8E;AAC9E,wDAAwD;AACxD,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,iEAAiE;AACjE,6EAA6E;AAC7E,SAAS;AACT,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,gFAAgF;AA2BhF;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB;IACtD,OAAO;QACL,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAe,cAAc,CAAC;QAC9D,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAa,gBAAgB,EAAE,EAAE,CAAC;QACnE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC7B,MAAM,MAAM,CAAC,MAAM,CAAO,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,kBAAkB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAmB,0BAA0B,CAAC;QAClF,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE;YAC9B,MAAM,IAAI,GAA8B,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7D,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;gBAAE,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;YAChF,OAAO,MAAM,CAAC,IAAI,CAAwB,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;QACD,oBAAoB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACjC,MAAM,MAAM,CAAC,MAAM,CAAO,4BAA4B,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/nodes/headless/api.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,4CAA4C;AAC5C,gFAAgF;AAChF,EAAE;AACF,gFAAgF;AAChF,2EAA2E;AAC3E,8EAA8E;AAC9E,wDAAwD;AACxD,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,4EAA4E;AAC5E,iEAAiE;AACjE,6EAA6E;AAC7E,SAAS;AACT,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,EAAE;AACF,mFAAmF;AACnF,0EAA0E;AAC1E,8BAA8B;AAC9B,gFAAgF;AAoChF;;;GAGG;AACH,SAAS,qBAAqB,CAAC,KAAsB;IACnD,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjF,IAAI,KAAK,CAAC,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,KAAK,CAAC,QAAQ;QAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC/B,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAChC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB;IACtD,OAAO;QACL,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAe,cAAc,CAAC;QAC9D,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAa,gBAAgB,EAAE,EAAE,CAAC;QACnE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC7B,MAAM,MAAM,CAAC,MAAM,CAAO,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,kBAAkB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAmB,0BAA0B,CAAC;QAClF,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE;YAC9B,MAAM,IAAI,GAA8B,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7D,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS;gBAAE,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;YAChF,OAAO,MAAM,CAAC,IAAI,CAAwB,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;QACD,oBAAoB,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACjC,MAAM,MAAM,CAAC,MAAM,CAAO,4BAA4B,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,cAAc,EAAE,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,CACrC,MAAM,CAAC,GAAG,CAAsB,gBAAgB,kBAAkB,CAAC,MAAM,CAAC,UAAU,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;KACtH,CAAC;AACJ,CAAC"}
@@ -1,7 +1,12 @@
1
1
  export { createNodesApi } from './api.js';
2
2
  export type { NodesApi } from './api.js';
3
- export { MAX_NODE_CREDENTIAL_DAYS, MAX_NODE_CREDENTIAL_NAME_LENGTH, NODE_HEALTHS, NODE_STATUSES, nodeCredentialStatus, } from './types.js';
4
- export type { CreateNodeCredentialInput, NodeCredential, NodeCredentialCreated, NodeCredentialStatus, NodeHealth, NodeJobCounts, NodeOwner, NodeStatus, NodeVitals, NodeVitalsCounters, WorkerNode, } from './types.js';
3
+ export { MAX_NODE_CREDENTIAL_DAYS, MAX_NODE_CREDENTIAL_NAME_LENGTH, NODE_EVENT_TYPES, NODE_HEALTHS, NODE_STATUSES, nodeCredentialStatus, } from './types.js';
4
+ export type { CreateNodeCredentialInput, NodeCredential, NodeCredentialCreated, NodeCredentialStatus, NodeEventSeverity, NodeEventsQuery, NodeHealth, NodeHostVitals, NodeJobCounts, NodeOwner, NodePower, NodeStatus, NodeVitals, NodeVitalsCounters, WorkerNode, WorkerNodeEvent, WorkerNodeEventList, } from './types.js';
5
+ export { MAX_NODE_EVENT_SUMMARY_ATTRS, humanizeNodeEventType, nodeEventLabel, nodeEventSummary } from './node-events.js';
6
+ export { NODE_BATTERY_CRITICAL_PERCENT, NODE_BATTERY_WARNING_PERCENT, describeNodePower } from './power.js';
7
+ export type { NodePowerDescription } from './power.js';
8
+ export { useNodeEvents } from './use-node-events.js';
9
+ export type { UseNodeEventsResult } from './use-node-events.js';
5
10
  export { formatDateTime, formatDuration, shortId } from './format.js';
6
11
  export { formatNodeVital, nodeVitalFor, nodeVitalRows, registerNodeVital, registeredNodeVitals } from './node-vitals.js';
7
12
  export type { NodeVitalDef, NodeVitalRow, NodeVitalUnit } from './node-vitals.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/nodes/headless/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,YAAY,EACZ,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACzH,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7G,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACzE,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,EAC7B,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/nodes/headless/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,YAAY,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,cAAc,EACd,aAAa,EACb,SAAS,EACT,SAAS,EACT,UAAU,EACV,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzH,OAAO,EAAE,6BAA6B,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC5G,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACzH,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7G,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACzE,YAAY,EACV,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,6BAA6B,EAC7B,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC"}
@@ -4,7 +4,10 @@
4
4
  // the data hooks, the visible-tab poll, the adapters and the formatting
5
5
  // helpers. Documented in ../README.md. Explicit named exports only.
6
6
  export { createNodesApi } from './api.js';
7
- export { MAX_NODE_CREDENTIAL_DAYS, MAX_NODE_CREDENTIAL_NAME_LENGTH, NODE_HEALTHS, NODE_STATUSES, nodeCredentialStatus, } from './types.js';
7
+ export { MAX_NODE_CREDENTIAL_DAYS, MAX_NODE_CREDENTIAL_NAME_LENGTH, NODE_EVENT_TYPES, NODE_HEALTHS, NODE_STATUSES, nodeCredentialStatus, } from './types.js';
8
+ export { MAX_NODE_EVENT_SUMMARY_ATTRS, humanizeNodeEventType, nodeEventLabel, nodeEventSummary } from './node-events.js';
9
+ export { NODE_BATTERY_CRITICAL_PERCENT, NODE_BATTERY_WARNING_PERCENT, describeNodePower } from './power.js';
10
+ export { useNodeEvents } from './use-node-events.js';
8
11
  export { formatDateTime, formatDuration, shortId } from './format.js';
9
12
  export { formatNodeVital, nodeVitalFor, nodeVitalRows, registerNodeVital, registeredNodeVitals } from './node-vitals.js';
10
13
  export { MAX_CAPABILITY_TEXT_LENGTH, MAX_LISTED_CAPABILITIES, nodeCapabilityItems } from './capabilities.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/nodes/headless/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,4EAA4E;AAC5E,wFAAwF;AACxF,wEAAwE;AACxE,oEAAoE;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,YAAY,EACZ,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAcpB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEzH,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7G,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAc3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/nodes/headless/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,4EAA4E;AAC5E,wFAAwF;AACxF,wEAAwE;AACxE,oEAAoE;AAEpE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAoBpB,OAAO,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzH,OAAO,EAAE,6BAA6B,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5G,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEzH,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7G,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAc3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { WorkerNodeEvent } from './types.js';
2
+ /**
3
+ * Most attributes a summary of an unknown event prints.
4
+ *
5
+ * @stability experimental
6
+ */
7
+ export declare const MAX_NODE_EVENT_SUMMARY_ATTRS = 4;
8
+ /**
9
+ * A dotted event type as words: the last segment is the event, the ones before
10
+ * it its area (`transcode.queue_full` to "Transcode: queue full").
11
+ *
12
+ * @param type - the event's dotted type.
13
+ * @returns the humanized text; the input itself when it has no segments.
14
+ *
15
+ * @stability experimental
16
+ */
17
+ export declare function humanizeNodeEventType(type: string): string;
18
+ /**
19
+ * How an event type reads: the platform's label for a `NODE_EVENT_TYPES` name,
20
+ * else {@link humanizeNodeEventType}.
21
+ *
22
+ * @param type - the event's dotted type.
23
+ * @returns the label.
24
+ *
25
+ * @stability experimental
26
+ */
27
+ export declare function nodeEventLabel(type: string): string;
28
+ /**
29
+ * One line that says what an event's attributes mean, or `null` when it has
30
+ * none worth printing.
31
+ *
32
+ * Known types read as a sentence fragment ("AC → Battery (64%)", "12% (threshold
33
+ * 20%)", "Asleep for 2h 03m", "4.5% free (1.2 GB)"); an unknown type, or a known
34
+ * one missing the attributes its fragment needs, reads as `key: value` pairs, at
35
+ * most {@link MAX_NODE_EVENT_SUMMARY_ATTRS} of them, sorted by key.
36
+ *
37
+ * @param event - the event (its `type` and `attrs`).
38
+ * @returns the summary, or `null`.
39
+ *
40
+ * @stability experimental
41
+ */
42
+ export declare function nodeEventSummary(event: Pick<WorkerNodeEvent, 'type' | 'attrs'>): string | null;
43
+ //# sourceMappingURL=node-events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-events.d.ts","sourceRoot":"","sources":["../../../src/nodes/headless/node-events.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAYlD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAU9C;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CA4C9F"}
@@ -0,0 +1,150 @@
1
+ // =============================================================================
2
+ // Node events: how the Worker Nodes page words one (issue #1045)
3
+ // =============================================================================
4
+ //
5
+ // A node reports what it observed about itself on its heartbeat (a power
6
+ // change, a low battery, a wake from sleep, a low disk); the API stores each one
7
+ // and serves them at `GET /api/admin/nodes/:id/events`. These helpers turn one into
8
+ // text: a label for its type and a one-line summary of its attributes.
9
+ //
10
+ // The type is an OPEN dotted string: an app's node may report its own. A known
11
+ // type (`NODE_EVENT_TYPES`) reads by its label; an unknown one is still shown,
12
+ // humanized from its dotted name (`transcode.queue_full` -> "Transcode: queue
13
+ // full"), never hidden. Attributes are self-reported scalars; they are printed
14
+ // as plain text, bounded, and never turned into a verdict.
15
+ //
16
+ // Pure functions, no markup, so they live in the headless entry.
17
+ // =============================================================================
18
+ import { NODE_EVENT_TYPES } from '@marinoscar/platform-contract/nodes';
19
+ import { formatBytes } from '../internal/format-bytes.js';
20
+ import { formatDuration } from './format.js';
21
+ /** The platform's own event types, as an operator reads them. */
22
+ const NODE_EVENT_LABELS = Object.freeze({
23
+ [NODE_EVENT_TYPES.POWER_SOURCE_CHANGED]: 'Power source changed',
24
+ [NODE_EVENT_TYPES.BATTERY_LOW]: 'Battery low',
25
+ [NODE_EVENT_TYPES.BATTERY_CRITICAL]: 'Battery critical',
26
+ [NODE_EVENT_TYPES.BATTERY_RECOVERED]: 'Battery recovered',
27
+ [NODE_EVENT_TYPES.SLEEP_RESUMED]: 'Resumed from sleep',
28
+ [NODE_EVENT_TYPES.DISK_LOW]: 'Disk space low',
29
+ });
30
+ /**
31
+ * Most attributes a summary of an unknown event prints.
32
+ *
33
+ * @stability experimental
34
+ */
35
+ export const MAX_NODE_EVENT_SUMMARY_ATTRS = 4;
36
+ /** Longest attribute value a summary prints before an ellipsis. */
37
+ const MAX_ATTR_TEXT = 64;
38
+ function sentenceCase(text) {
39
+ const spaced = text.replace(/_/g, ' ').trim();
40
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
41
+ }
42
+ /**
43
+ * A dotted event type as words: the last segment is the event, the ones before
44
+ * it its area (`transcode.queue_full` to "Transcode: queue full").
45
+ *
46
+ * @param type - the event's dotted type.
47
+ * @returns the humanized text; the input itself when it has no segments.
48
+ *
49
+ * @stability experimental
50
+ */
51
+ export function humanizeNodeEventType(type) {
52
+ const segments = type.split('.').filter((segment) => segment !== '');
53
+ if (segments.length === 0)
54
+ return type;
55
+ if (segments.length === 1)
56
+ return sentenceCase(segments[0]);
57
+ const last = segments[segments.length - 1];
58
+ const area = segments.slice(0, -1).map(sentenceCase).join(' ');
59
+ return `${area}: ${last.replace(/_/g, ' ')}`;
60
+ }
61
+ /**
62
+ * How an event type reads: the platform's label for a `NODE_EVENT_TYPES` name,
63
+ * else {@link humanizeNodeEventType}.
64
+ *
65
+ * @param type - the event's dotted type.
66
+ * @returns the label.
67
+ *
68
+ * @stability experimental
69
+ */
70
+ export function nodeEventLabel(type) {
71
+ return NODE_EVENT_LABELS[type] ?? humanizeNodeEventType(type);
72
+ }
73
+ function attrNumber(attrs, key) {
74
+ const value = attrs[key];
75
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
76
+ }
77
+ function percent(value) {
78
+ return `${Math.round(value * 10) / 10}%`;
79
+ }
80
+ const POWER_SOURCE_WORDS = Object.freeze({ ac: 'AC', battery: 'Battery', unknown: 'Unknown' });
81
+ function powerSourceWord(value) {
82
+ if (typeof value !== 'string' || value === '')
83
+ return '?';
84
+ return POWER_SOURCE_WORDS[value] ?? value;
85
+ }
86
+ function plainAttr(value) {
87
+ const text = typeof value === 'number' ? value.toLocaleString(undefined, { maximumFractionDigits: 2 }) : String(value);
88
+ return text.length > MAX_ATTR_TEXT ? `${text.slice(0, MAX_ATTR_TEXT - 1)}…` : text;
89
+ }
90
+ /**
91
+ * One line that says what an event's attributes mean, or `null` when it has
92
+ * none worth printing.
93
+ *
94
+ * Known types read as a sentence fragment ("AC → Battery (64%)", "12% (threshold
95
+ * 20%)", "Asleep for 2h 03m", "4.5% free (1.2 GB)"); an unknown type, or a known
96
+ * one missing the attributes its fragment needs, reads as `key: value` pairs, at
97
+ * most {@link MAX_NODE_EVENT_SUMMARY_ATTRS} of them, sorted by key.
98
+ *
99
+ * @param event - the event (its `type` and `attrs`).
100
+ * @returns the summary, or `null`.
101
+ *
102
+ * @stability experimental
103
+ */
104
+ export function nodeEventSummary(event) {
105
+ const attrs = event.attrs && typeof event.attrs === 'object' ? event.attrs : {};
106
+ const battery = attrNumber(attrs, 'batteryPercent');
107
+ const threshold = attrNumber(attrs, 'threshold');
108
+ switch (event.type) {
109
+ case NODE_EVENT_TYPES.POWER_SOURCE_CHANGED:
110
+ if (attrs.from !== undefined || attrs.to !== undefined) {
111
+ const change = `${powerSourceWord(attrs.from)} → ${powerSourceWord(attrs.to)}`;
112
+ return battery !== undefined ? `${change} (${percent(battery)})` : change;
113
+ }
114
+ break;
115
+ case NODE_EVENT_TYPES.BATTERY_LOW:
116
+ case NODE_EVENT_TYPES.BATTERY_CRITICAL:
117
+ case NODE_EVENT_TYPES.BATTERY_RECOVERED:
118
+ if (battery !== undefined) {
119
+ return threshold !== undefined ? `${percent(battery)} (threshold ${percent(threshold)})` : percent(battery);
120
+ }
121
+ break;
122
+ case NODE_EVENT_TYPES.SLEEP_RESUMED: {
123
+ const gap = attrNumber(attrs, 'gapSeconds');
124
+ if (gap !== undefined)
125
+ return `Asleep for ${formatDuration(gap * 1000)}`;
126
+ break;
127
+ }
128
+ case NODE_EVENT_TYPES.DISK_LOW: {
129
+ const freePercent = attrNumber(attrs, 'freePercent');
130
+ const freeBytes = attrNumber(attrs, 'freeBytes');
131
+ if (freePercent !== undefined) {
132
+ return freeBytes !== undefined ? `${percent(freePercent)} free (${formatBytes(freeBytes)})` : `${percent(freePercent)} free`;
133
+ }
134
+ if (freeBytes !== undefined)
135
+ return `${formatBytes(freeBytes)} free`;
136
+ break;
137
+ }
138
+ default:
139
+ break;
140
+ }
141
+ const entries = Object.entries(attrs)
142
+ .filter(([, value]) => typeof value === 'string' || typeof value === 'boolean' || (typeof value === 'number' && Number.isFinite(value)))
143
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
144
+ if (entries.length === 0)
145
+ return null;
146
+ const shown = entries.slice(0, MAX_NODE_EVENT_SUMMARY_ATTRS).map(([key, value]) => `${key}: ${plainAttr(value)}`);
147
+ const rest = entries.length - shown.length;
148
+ return rest > 0 ? `${shown.join(', ')} (+${rest} more)` : shown.join(', ');
149
+ }
150
+ //# sourceMappingURL=node-events.js.map