@gravitee/gamma-lib-observability 6.2.1 → 6.3.0-feat-obs-170-consistent-failure-states.1f5f951

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 (128) hide show
  1. package/INTEGRATION.md +66 -3
  2. package/USAGE_GUIDE.md +1 -0
  3. package/dist/components/AccessDeniedState.d.ts +29 -0
  4. package/dist/components/AccessDeniedState.d.ts.map +1 -0
  5. package/dist/components/FailureCard.d.ts +16 -0
  6. package/dist/components/FailureCard.d.ts.map +1 -0
  7. package/dist/components/FailureDetailsSheet.d.ts +13 -0
  8. package/dist/components/FailureDetailsSheet.d.ts.map +1 -0
  9. package/dist/components/FailureGhost.d.ts +14 -0
  10. package/dist/components/FailureGhost.d.ts.map +1 -0
  11. package/dist/components/FailureOverlay.d.ts +32 -0
  12. package/dist/components/FailureOverlay.d.ts.map +1 -0
  13. package/dist/components/LoadFailedState.d.ts +47 -0
  14. package/dist/components/LoadFailedState.d.ts.map +1 -0
  15. package/dist/components/QueryErrorBanner.d.ts +5 -3
  16. package/dist/components/QueryErrorBanner.d.ts.map +1 -1
  17. package/dist/components/UnavailableState.d.ts +16 -0
  18. package/dist/components/UnavailableState.d.ts.map +1 -0
  19. package/dist/components/failure-wording.d.ts +47 -0
  20. package/dist/components/failure-wording.d.ts.map +1 -0
  21. package/dist/components/index.d.ts +6 -0
  22. package/dist/components/index.d.ts.map +1 -1
  23. package/dist/components/refusal-wording.d.ts +18 -0
  24. package/dist/components/refusal-wording.d.ts.map +1 -0
  25. package/dist/dashboard-access-provider.js +129 -96
  26. package/dist/dashboards/DashboardView.d.ts +7 -1
  27. package/dist/dashboards/DashboardView.d.ts.map +1 -1
  28. package/dist/dashboards/analytics-table/use-analytics-table-query.d.ts +5 -0
  29. package/dist/dashboards/analytics-table/use-analytics-table-query.d.ts.map +1 -1
  30. package/dist/dashboards/index.d.ts +3 -0
  31. package/dist/dashboards/index.d.ts.map +1 -1
  32. package/dist/dashboards/renderers/BarWidgetRenderer.d.ts.map +1 -1
  33. package/dist/dashboards/renderers/BreakdownWidgetRenderer.d.ts.map +1 -1
  34. package/dist/dashboards/renderers/CartesianWidgetRenderer.d.ts.map +1 -1
  35. package/dist/dashboards/renderers/DoughnutWidgetRenderer.d.ts.map +1 -1
  36. package/dist/dashboards/renderers/MetricGroupWidgetRenderer.d.ts.map +1 -1
  37. package/dist/dashboards/renderers/MetricWidgetRenderer.d.ts.map +1 -1
  38. package/dist/dashboards/renderers/TableWidgetRenderer.d.ts.map +1 -1
  39. package/dist/dashboards/renderers/WidgetAccessDenied.d.ts +14 -0
  40. package/dist/dashboards/renderers/WidgetAccessDenied.d.ts.map +1 -0
  41. package/dist/dashboards/renderers/WidgetLoadFailed.d.ts +26 -0
  42. package/dist/dashboards/renderers/WidgetLoadFailed.d.ts.map +1 -0
  43. package/dist/dashboards/renderers/widget-question.d.ts +9 -0
  44. package/dist/dashboards/renderers/widget-question.d.ts.map +1 -0
  45. package/dist/dashboards/renderers/widget-trouble.d.ts +37 -0
  46. package/dist/dashboards/renderers/widget-trouble.d.ts.map +1 -0
  47. package/dist/data-sources/dashboard-errors.d.ts.map +1 -1
  48. package/dist/data-sources/http-data-source.d.ts.map +1 -1
  49. package/dist/data-sources/http-errors.d.ts +38 -0
  50. package/dist/data-sources/http-errors.d.ts.map +1 -0
  51. package/dist/data-sources/http-filter-source.d.ts.map +1 -1
  52. package/dist/data-sources/http-logs-source.d.ts.map +1 -1
  53. package/dist/data-sources/http-traces-filter-source.d.ts.map +1 -1
  54. package/dist/data-sources/http-traces-source.d.ts.map +1 -1
  55. package/dist/data-sources/index.d.ts +1 -0
  56. package/dist/data-sources/index.d.ts.map +1 -1
  57. package/dist/filters/FilterBar.d.ts.map +1 -1
  58. package/dist/filters/filter-providers-context.d.ts +17 -1
  59. package/dist/filters/filter-providers-context.d.ts.map +1 -1
  60. package/dist/filters/index.d.ts +1 -1
  61. package/dist/filters/index.d.ts.map +1 -1
  62. package/dist/hooks/retry-policy.d.ts +16 -0
  63. package/dist/hooks/retry-policy.d.ts.map +1 -0
  64. package/dist/hooks/use-custom-dashboards.d.ts.map +1 -1
  65. package/dist/hooks/use-facets-query.d.ts.map +1 -1
  66. package/dist/hooks/use-infinite-options.d.ts +8 -0
  67. package/dist/hooks/use-infinite-options.d.ts.map +1 -1
  68. package/dist/hooks/use-kept-answer.d.ts +44 -0
  69. package/dist/hooks/use-kept-answer.d.ts.map +1 -0
  70. package/dist/hooks/use-log-detail-query.d.ts +2 -0
  71. package/dist/hooks/use-log-detail-query.d.ts.map +1 -1
  72. package/dist/hooks/use-logs-paged-query.d.ts +3 -0
  73. package/dist/hooks/use-logs-paged-query.d.ts.map +1 -1
  74. package/dist/hooks/use-logs-query.d.ts.map +1 -1
  75. package/dist/hooks/use-measures-query.d.ts.map +1 -1
  76. package/dist/hooks/use-resolve-filter-labels.d.ts.map +1 -1
  77. package/dist/hooks/use-retry-failed-queries.d.ts +8 -0
  78. package/dist/hooks/use-retry-failed-queries.d.ts.map +1 -0
  79. package/dist/hooks/use-time-series-query.d.ts.map +1 -1
  80. package/dist/hooks/use-trace-detail-query.d.ts +2 -0
  81. package/dist/hooks/use-trace-detail-query.d.ts.map +1 -1
  82. package/dist/hooks/use-traces-paged-query.d.ts +3 -0
  83. package/dist/hooks/use-traces-paged-query.d.ts.map +1 -1
  84. package/dist/index.d.ts +6 -5
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +4331 -3407
  87. package/dist/live/LiveIndicator.d.ts +4 -0
  88. package/dist/live/LiveIndicator.d.ts.map +1 -1
  89. package/dist/live/use-live-retry-countdown.d.ts +12 -0
  90. package/dist/live/use-live-retry-countdown.d.ts.map +1 -0
  91. package/dist/logs/LogTable.d.ts +3 -1
  92. package/dist/logs/LogTable.d.ts.map +1 -1
  93. package/dist/logs/LogsExplorerPage.d.ts.map +1 -1
  94. package/dist/logs/detail/components/LogDetailContextChart.d.ts.map +1 -1
  95. package/dist/logs/detail/components/LogDetailDrawer.d.ts.map +1 -1
  96. package/dist/logs/detail/components/LogDetailError.d.ts +12 -0
  97. package/dist/logs/detail/components/LogDetailError.d.ts.map +1 -0
  98. package/dist/logs/detail/components/LogDetailPage.d.ts.map +1 -1
  99. package/dist/logs/detail/presets/message-log-preset.d.ts.map +1 -1
  100. package/dist/providers/live-refresh-provider.d.ts +17 -0
  101. package/dist/providers/live-refresh-provider.d.ts.map +1 -1
  102. package/dist/routing/ObservabilityDashboardPage.d.ts.map +1 -1
  103. package/dist/routing/ObservabilityRoutes.d.ts.map +1 -1
  104. package/dist/routing/TracingFilterProvider.d.ts.map +1 -1
  105. package/dist/routing/TracingScreen.d.ts.map +1 -1
  106. package/dist/routing/define-observability-features.d.ts.map +1 -1
  107. package/dist/routing/feature-capabilities.d.ts +8 -0
  108. package/dist/routing/feature-capabilities.d.ts.map +1 -0
  109. package/dist/routing/types.d.ts +10 -1
  110. package/dist/routing/types.d.ts.map +1 -1
  111. package/dist/styles/observability.css +1 -1
  112. package/dist/testing/graphene-core-icons-mock.d.ts +1 -0
  113. package/dist/testing/graphene-core-icons-mock.d.ts.map +1 -1
  114. package/dist/testing/graphene-core-mock.d.ts +2 -0
  115. package/dist/testing/graphene-core-mock.d.ts.map +1 -1
  116. package/dist/testing.js +10 -10
  117. package/dist/traces/TraceExplorerPage.d.ts.map +1 -1
  118. package/dist/traces/TraceTable.d.ts +4 -1
  119. package/dist/traces/TraceTable.d.ts.map +1 -1
  120. package/dist/traces/TracingApiSelector.d.ts +4 -1
  121. package/dist/traces/TracingApiSelector.d.ts.map +1 -1
  122. package/dist/traces/detail/TraceDetailDrawer.d.ts.map +1 -1
  123. package/dist/traces/detail/TraceDetailPage.d.ts.map +1 -1
  124. package/dist/traces/detail/TraceDetailStates.d.ts +7 -1
  125. package/dist/traces/detail/TraceDetailStates.d.ts.map +1 -1
  126. package/dist/traces/use-tracing-api-paginated-options.d.ts +7 -1
  127. package/dist/traces/use-tracing-api-paginated-options.d.ts.map +1 -1
  128. package/package.json +1 -1
package/INTEGRATION.md CHANGED
@@ -227,7 +227,7 @@ The lib is a **contributor**: it ships routes, nav and route metadata; the host
227
227
  - [ ] **Query client** — wrap the app in a single `QueryClientProvider` (shared singleton under Module Federation).
228
228
  - [ ] **Authenticated HTTP** — pass the `http` prop (or an `HttpProvider`) once so every internal source is authenticated (see [Authenticated HTTP](#authenticated-http-http-prop)).
229
229
  - [ ] **Mount routes** — `<Route path="observe/*" element={<observability.Routes … />} />`.
230
- - [ ] **Register navigation** — add `observability.navGroup` to your sidenav groups.
230
+ - [ ] **Register navigation** — add `observability.navGroup` to your sidenav groups, or `observability.navGroupFor(capabilities)` once you know the user's capabilities (see [Sidebar navigation](#sidebar-navigation)).
231
231
  - [ ] **Active nav key** — resolve it with `observability.resolveRouteKey(pathname)` (see [Active nav key detection](#active-nav-key-detection)).
232
232
  - [ ] **Breadcrumbs** — build them from `observability.breadcrumbSegments(activeNavKey)` (see [Breadcrumbs](#breadcrumbs)).
233
233
  - [ ] **Merge route keys / routes** — spread `observability.routeKeys` / `observability.routes` into the module's own (see [Merging route keys and routes](#merging-route-keys-and-routes)).
@@ -943,6 +943,12 @@ const { navGroup } = observability;
943
943
 
944
944
  Only enabled features appear in `navGroup.items`.
945
945
 
946
+ A host that knows its user's capabilities lists `navGroupFor(capabilities)` instead: the same group, without the sections the user may not read. It reads the same keys the routes mount on (`observability.dashboards.read`, `observability.logs.read`, `observability.traces.read`), so a section is never in the nav without being on screen. `navGroup` itself is unchanged and still lists every enabled feature.
947
+
948
+ ```ts
949
+ const navGroup = observability.navGroupFor(capabilities);
950
+ ```
951
+
946
952
  Override titles and icons via `nav.overrides`:
947
953
 
948
954
  ```ts
@@ -1071,13 +1077,13 @@ const capabilities: DashboardCapabilities = {
1071
1077
  | `observability.logs.read` | Shows the logs explorer and log detail routes, when logs are enabled. |
1072
1078
  | `observability.traces.read` | Shows the traces explorer and trace detail routes, when tracing is enabled. |
1073
1079
 
1074
- Every declared key is enforced: a section is on screen when its feature flag **and** its read capability both hold, and the catch-all redirect only targets sections that are actually mounted. Capabilities gate `ObservabilityRoutes`; components imported and mounted directly (`DashboardView`, `WidgetItem`, `LogsExplorerPage`, `TracingScreen`, …) are the host's own composition and are not gated, except where a prop says so (`DashboardView`'s `editable` requires the write capability).
1080
+ Every declared key is enforced: a section is on screen when its feature flag **and** its read capability both hold, and the catch-all redirect only targets sections that are actually mounted. A link to a section the host enabled but the reader may not read (a shared link, a bookmark) shows "No access to logs" (or traces, or dashboards) with "Ask an administrator for access." and a button to the first section they can read, instead of redirecting without a word; nothing is asked of the server. When no enabled section is readable at all, the page says "No access to observability". A link to a section the host did not enable, or to an unknown path, still redirects to the first readable section. Capabilities gate `ObservabilityRoutes`; components imported and mounted directly (`DashboardView`, `WidgetItem`, `LogsExplorerPage`, `TracingScreen`, …) are the host's own composition and are not gated, except where a prop says so (`DashboardView`'s `editable` requires the write capability).
1075
1081
 
1076
1082
  **Default behavior:** When no `CapabilityProvider` is present, all capabilities default to `false` (secure default). For initial integration without RBAC, pass all relevant capabilities as `true`.
1077
1083
 
1078
1084
  > **Migration note (breaking, v3).** Before v3, `observability.logs.read` and `observability.dashboards.read` were declared and documented but never read as route gates: the logs and dashboards sections were mounted on their feature flags alone. They now gate their routes exactly as `observability.traces.read` always has. A host that enables these features without declaring the read capabilities (or without any `CapabilityProvider`) loses the sections on upgrade — declare the keys `true` to keep the previous behavior. Capabilities describe what the host allows; per-user backend refusals are handled separately, see [Backend refusals](#backend-refusals-403).
1079
1085
  >
1080
- > The sidebar entries from `defineObservabilityFeatures().navGroup` are built from the feature config alone — capabilities live in React context and are not visible there. A host that disables a capability should filter the matching nav item itself; a link left in place degrades safely (it lands on the first visible section).
1086
+ > The sidebar entries from `defineObservabilityFeatures().navGroup` are built from the feature config alone — capabilities live in React context and are not visible there. A host that knows its user's capabilities lists `navGroupFor(capabilities)` instead, which leaves out the sections the routes would not mount (see [Sidebar navigation](#sidebar-navigation)); a link left in place says the reader has no access to that section, with a way to one they can read.
1081
1087
 
1082
1088
  ---
1083
1089
 
@@ -1275,6 +1281,63 @@ Refusals are remembered **per verb family** (read, write), not per operation: on
1275
1281
 
1276
1282
  A store that enforces permissions must reject with `DashboardForbiddenError` (or a `status: 403` error) for the degradation to engage — see the port's documentation. Only a 403 earns the quiet degradation: any other listing failure is a fault, not a designed experience (its current silence on the list is a known gap).
1277
1283
 
1284
+ #### Refused data (logs, traces, analytics, filters)
1285
+
1286
+ The same rule holds for the data behind the screens. The built-in HTTP sources reject a failed call with an `ObservabilityHttpError` that keeps the HTTP `status`; `isForbiddenError(error)` tells a refusal from any other failure, reading the status from the shape so a host source's own errors (anything with `status: 403`) count too. A refusal is named where it happened, never offered a retry, and never shown as "no data". Every refusal uses the same component, `AccessDeniedState`, so the reader is guided the same way everywhere: the title names the data, and the description is always "Ask an administrator for access." Its `compact` variant (a chart's area, dashboard tiles) drops the description by itself when its box is too short; its `inline` variant fits next to a control.
1287
+
1288
+ | Where | On a refusal | On any other failure |
1289
+ | ------------------------------ | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
1290
+ | Logs page, logs table | Headers kept; "No access to logs" where "No logs found" would be | "Couldn't load logs" in the empty rows |
1291
+ | Logs page, chart | "No access to analytics" in the chart's area, at its height | "Couldn't load analytics" in its area |
1292
+ | Logs page, both refused | One "No access to logs and analytics" for the page, in place of chart and table; no filters or time range | Both failed: one card over the faint page, with Try again |
1293
+ | Log detail chart | "No access to analytics" in the chart's place | "Couldn't load analytics" in its place |
1294
+ | Traces table | Headers kept; "No access to traces" in the empty rows; no filters or time range | "Couldn't load traces" with Try again |
1295
+ | Log and trace detail | "No access to this log" / "No access to this trace" | "Couldn't load this log" with Try again |
1296
+ | A dashboard widget | "No access to analytics" (or logs, traces) in that tile only, when the dashboard is mixed | "Couldn't load analytics" in that tile |
1297
+ | A whole dashboard | One state named after the refused kinds, in place of the widget grid; title kept, no filters or time range | All failed: one card over the faint grid, with Try again |
1298
+ | Filter bar (both filter lists) | "No access to filters." inline, next to the disabled "Add filter" | "Couldn't load filters." with Try again |
1299
+ | Tracing API picker (paginated) | "No access to APIs." inline, next to the field | "Couldn't load APIs." with Try again |
1300
+ | Filter values | Falls back to typing the value, as for any listing failure | Same (unchanged) |
1301
+
1302
+ **404 that may stand for a refusal.** The trace search, trace detail and log detail endpoints answer 404 for an API the reader may not see, so that its existence does not leak. These three screens keep that promise: on a 404 (`isNotFoundError`), and on a log detail the source reports as missing, they show "API not found, or you don't have access" (in the traces table), "Trace not found, …" or "Log not found, …", with "Check the link, or ask an administrator for access.", and no retry. A 404 anywhere else keeps its existing handling.
1303
+
1304
+ **Wording.** Every state names the kind of data refused, "No access to analytics", "No access to logs" or "No access to traces", and lists every kind when several are refused at once ("No access to logs and analytics"), so the reader asks for each access they lack. Analytics (`API_ANALYTICS`) and logs (`API_LOG`) are separate rights, as the analytics and logs filter catalogs are. On the Logs page the chart and the table each render from their own query, so one can be refused, or cover more APIs, without the other: the refused part says so in its own place and the other shows as usual. When both are refused the whole feature is, and the page shows a single state instead of two. Dashboards follow the same rule: a widget is refused only when the reader lacks a whole data kind (an API they may not read is narrowed out and shows as empty, so its existence does not leak), so a dashboard whose every widget is refused shows one state in place of its grid, and a mixed one shows a state in each refused tile. While editing, each widget keeps its own state, so the dashboard can still be laid out. A page with nothing left to show (Logs with both refused, Traces, a whole dashboard) also drops its filters and time range: a refusal does not depend on them, and controls that change nothing suggest the data could appear. The title, the dashboard's actions and the host's links stay. `DashboardView`'s `onWholeRefusedChange` tells a host page of its own when to do the same. A host widget backed by logs or traces names its kind through `WidgetAccessDenied`'s `dataKind`.
1305
+
1306
+ An empty answer is not a refusal: a reader whose APIs have no traffic in range, or who may read none of them, gets the usual empty states. Sections are never hidden because a request was refused; which sections exist is decided by capabilities alone.
1307
+
1308
+ **Retries.** The library's queries run on the host's `QueryClient`, and its `retry` setting still applies to failures (5xx, network). A 4xx answer is never retried: the server answered on purpose, so the screen says so at once instead of showing skeletons through every retry.
1309
+
1310
+ ### Load failures (5xx, network)
1311
+
1312
+ A failure that is not a refusal (a 5xx, a network error, a host source's own error) is shown the same way everywhere, with `LoadFailedState`, the sibling of `AccessDeniedState`: same variants, a discreet icon, nothing in red, and in the data's own place, so a failure never reads as an empty answer and never sits above one. The table above lists where. "No data" and "No logs found" are for empty answers only.
1313
+
1314
+ - **The page keeps its layout.** A failure is drawn over the faint shape of the data it stands in for (`ghost`: bars for a chart, lines for a table's rows, a number for a metric, a detail's sections, a dashboard's tiles), so it reads as data that is late, on the page the reader knows. When a whole page failed (the logs page with both parts failed, a dashboard whose every widget failed), the page itself stays in place, faint and out of reach (`inert`), each part drawing its ghost, under one card. A refusal does not do this: no data is on its way.
1315
+
1316
+ - **Wording.** The title names the data: "Couldn't load logs", "Couldn't load analytics", "Couldn't load traces", "Couldn't load this log", "Couldn't load this trace". A compact state (a tile, a chart's area) shows the title alone. While Live is on, a state whose data follows the Live window (`followsLive`) counts down to the refresh that loads it again: "Trying again in 42 seconds.", and a page-level state's button reads "Try now". Otherwise (Live paused, an absolute range, a log or trace opened by id) a page-level state says "Something went wrong. Try again in a moment." with "Try again".
1317
+ - **No flicker between two failures.** While the same question is asked again (the next Live refresh, "Try again"), the failure stays on screen until an answer comes back, rather than flashing a loading state; the details stay open.
1318
+ - **One retry per page.** One part of a page failing (a widget tile, the logs chart or the logs table, the log detail's chart) gets no retry: the rest of the page still works and the next refresh asks again. A page whose every part failed gets exactly one "Try again", which re-runs every failed query on screen: the traces page, a log or trace detail (a drawer included), the logs page with both parts failed (one state, "Couldn't load logs and analytics"), the logs page without a chart, a dashboard whose every widget failed. The filter bar, the tracing API picker and the message list of a log detail keep their own inline "Try again": Live mode refreshes the data, never those lists.
1319
+ - **One state for a page.** A dashboard shows one state for all of it only when every widget has the same outcome, all refused (in place of its grid) or all failed (one card over its faint grid). Any mix, a refused widget next to a failed one included, keeps a state per tile. On the Logs page, a refusal on one side and a failure on the other stay each in place. Unlike a refusal, a failure keeps the filters and the time range: it may depend on them.
1320
+ - **Details on demand.** A state's "View details" opens a side panel with each failed call: its status, the call and when it failed, and "Copy for support", which copies it all as text. A compact or inline state shows the same text in a tooltip on its icon. There is no request id: the sources read no response headers. `ObservabilityHttpError` carries the `call` for this; a host source's error with a `status` and a `call` is described the same way. The `[gamma-lib-observability]` prefix of the error message stays in console logs.
1321
+ - **A failed refresh keeps the data.** Live mode refetches every minute by moving the window forward, and switching Paused back to Live refetches at once, on every page. When a refresh fails with data on screen, the data stays and the Live pill says so: an amber dot, and "Couldn't refresh at HH:MM. Showing earlier data." in its tooltip. That is the page's one signal of stale data, never a failure state over good data. A change of filters or time range is a new question: if it fails, the failure is shown, never the old data. A refusal never keeps old data either.
1322
+ - **Host widgets.** A host widget renderer shows its failure with `WidgetLoadFailed` (`error`, `failedAt`, `dataKind` for logs or traces, and `ghost`: `chart`, `rows` or `metric`), which also lets the dashboard show one card when every widget failed. Pass the query's own `error`: the same object from one render to the next.
1323
+
1324
+ `QueryErrorBanner` stays exported for hosts that render it, but the library's pages no longer use it.
1325
+
1326
+ **Try it.** The Storybook story `Routing/Permissions › Playground` renders every observability page through the real routes against mock sources. Its controls reach each case above without code, and default to everything allowed. Changing a right refreshes the page you are on, and navigating in the story's sidebar moves the Page control along:
1327
+
1328
+ | Control | Values | What it drives |
1329
+ | --------------------------------------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
1330
+ | Page | Home, Dashboard, Logs, Log detail, Tracing, Trace detail | The page the reader opens (Home: the section root) |
1331
+ | Analytics | Allowed, Refused (403), Failing (500), Partly failing | Dashboard widgets, the logs histogram, the log detail chart; partly: the breakdowns fail, time series and totals load |
1332
+ | Failed refresh | on / off | Data loads, then every refresh fails: the Live pill turns amber |
1333
+ | Logs | Allowed, Refused (403), Failing (500) | The logs table, a log detail, the dashboard's logs widget |
1334
+ | Traces | Allowed, Refused (403), Failing (500) | The traces table and a trace detail |
1335
+ | API the reader may not see | on / off | The deliberate 404 on the tracing page, a trace detail and a log detail |
1336
+ | Filter lists | Allowed, Refused (403), Failing (500) | The filter bar's filter lists (analytics and tracing) |
1337
+ | Tracing API list | Allowed, Refused (403), Failing (500) | The tracing API picker |
1338
+ | Capability: dashboards.read, dashboards.write, logs.read, traces.read | on / off | The host's capabilities: which sections exist, in the nav and the routes |
1339
+ | Dashboard with a logs widget | on / off | Adds a host widget backed by logs, for a dashboard mixing data kinds |
1340
+
1278
1341
  **Concurrent edits.** `DashboardConflictError` carries `currentDashboard`, the dashboard as it now stands in the store, and the editor renders it from there rather than fetching again. The author then picks one of three resolutions, and each comes back to this port:
1279
1342
 
1280
1343
  - _Overwrite_ calls `updateDashboard(dashboard, signal, { force: true })`, which must apply the write over whatever revision is current, in one request. The HTTP adapter sends `If-Match: *`. The dashboard must still exist, so an overwrite never resurrects a deleted one.
package/USAGE_GUIDE.md CHANGED
@@ -768,6 +768,7 @@ It returns an `ObservabilityFeatures` object with the following members:
768
768
  | -------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------- |
769
769
  | `Routes` | `(props: ObservabilityRoutesProps) => ReactNode` | Route tree to mount under `observe/*`. |
770
770
  | `navGroup` | `NavGroup` | `{ label, items }` descriptor for the sidenav. Only enabled features appear in `items`. |
771
+ | `navGroupFor` | `(capabilities: DashboardCapabilities) => NavGroup` | `navGroup` without the sections these capabilities cannot read. |
771
772
  | `routeKeys` | `readonly string[]` | Composite keys for enabled features, e.g. `['observe/dashboards', 'observe/logs']`. |
772
773
  | `routes` | `Record<string, { path; label }>` | Per-feature `{ path, label }` keyed by composite route key. |
773
774
  | `resolveRouteKey` | `(pathname: string) => string \| null` | Reparses a host pathname into the matching composite route key. See below. |
@@ -0,0 +1,29 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * - `default`: a page or a table's empty rows.
4
+ * - `compact`: a box with little room, such as a chart's area or a dashboard tile.
5
+ * - `inline`: one line next to a control, such as the filter bar or a picker.
6
+ */
7
+ export type AccessDeniedStateVariant = 'default' | 'compact' | 'inline';
8
+ export interface AccessDeniedStateProps {
9
+ /** What the reader may not see, naming the data: "No access to logs". */
10
+ readonly title: string;
11
+ /** How the reader gets access. Defaults to asking an administrator, the same everywhere. */
12
+ readonly description?: string;
13
+ /** Rendered under the text, e.g. a way back. Not shown inline. */
14
+ readonly action?: ReactNode;
15
+ /** @default 'default' */
16
+ readonly variant?: AccessDeniedStateVariant;
17
+ /** Replaces the lock, e.g. for a state that must not say whether access was the reason. */
18
+ readonly icon?: ReactNode;
19
+ readonly className?: string;
20
+ }
21
+ /**
22
+ * What a screen shows in place of data the reader may not see. Every refusal
23
+ * in the library uses it, so a reader is guided the same way everywhere: the
24
+ * title names the data, the description says how to get access. Deliberately
25
+ * not an error: nothing failed, so there is no retry and nothing in red. A
26
+ * refusal is about the reader, and retrying would get the same answer.
27
+ */
28
+ export declare function AccessDeniedState({ title, description, action, variant, icon, className, }: AccessDeniedStateProps): import("react/jsx-runtime").JSX.Element;
29
+ //# sourceMappingURL=AccessDeniedState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccessDeniedState.d.ts","sourceRoot":"","sources":["../../src/components/AccessDeniedState.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,yBAAyB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAC5C,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAID;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,WAAiC,EACjC,MAAM,EACN,OAAmB,EACnB,IAAsC,EACtC,SAAS,GACV,EAAE,sBAAsB,2CA8BxB"}
@@ -0,0 +1,16 @@
1
+ import { LoadFailure } from './failure-wording';
2
+ export interface FailureCardProps {
3
+ readonly title: string;
4
+ readonly failures?: readonly LoadFailure[];
5
+ readonly onRetry?: () => void;
6
+ /** The data loads again on its own at each Live refresh: the card counts down to the next one. */
7
+ readonly followsLive?: boolean;
8
+ readonly className?: string;
9
+ }
10
+ /**
11
+ * The card a page-level or part-of-a-page failure shows over the faint shape
12
+ * of its data: what did not load, when it loads again on its own if it does,
13
+ * the page's one retry, and the details one step away in a side panel.
14
+ */
15
+ export declare function FailureCard({ title, failures, onRetry, followsLive, className }: FailureCardProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=FailureCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FailureCard.d.ts","sourceRoot":"","sources":["../../src/components/FailureCard.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEvF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,kGAAkG;IAClG,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAmB,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CAmDzG"}
@@ -0,0 +1,13 @@
1
+ import { LoadFailure } from './failure-wording';
2
+ export interface FailureDetailsSheetProps {
3
+ readonly failures: readonly LoadFailure[];
4
+ readonly open: boolean;
5
+ readonly onOpenChange: (open: boolean) => void;
6
+ }
7
+ /**
8
+ * The technical side of a failure, one step away from the page: each failed
9
+ * call with its status, the call and when it failed, and a copy of it all as
10
+ * text for a support ticket.
11
+ */
12
+ export declare function FailureDetailsSheet({ failures, open, onOpenChange }: FailureDetailsSheetProps): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=FailureDetailsSheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FailureDetailsSheet.d.ts","sourceRoot":"","sources":["../../src/components/FailureDetailsSheet.tsx"],"names":[],"mappings":"AAYA,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAChD;AAcD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,wBAAwB,2CA6B7F"}
@@ -0,0 +1,14 @@
1
+ /** The shape of the data a failure stands in for. */
2
+ export type FailureGhostKind = 'chart' | 'rows' | 'metric' | 'detail' | 'tiles';
3
+ export interface FailureGhostProps {
4
+ readonly kind: FailureGhostKind;
5
+ readonly className?: string;
6
+ }
7
+ /**
8
+ * The faint shape of the data a failure stands in for: bars for a chart, lines
9
+ * for a table's rows, a number for a metric. Drawn behind a failure state, it
10
+ * keeps the page's layout, so a failure reads as data that is late rather than
11
+ * as a different page. Decorative: hidden from assistive technology.
12
+ */
13
+ export declare function FailureGhost({ kind, className }: FailureGhostProps): import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=FailureGhost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FailureGhost.d.ts","sourceRoot":"","sources":["../../src/components/FailureGhost.tsx"],"names":[],"mappings":"AAGA,qDAAqD;AACrD,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AA8FD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,iBAAiB,2CAOlE"}
@@ -0,0 +1,32 @@
1
+ import { ReactNode } from 'react';
2
+ import { LoadFailure } from './failure-wording';
3
+ /**
4
+ * Whether this part of a page sits under a `FailureOverlay` that shows the
5
+ * failure for all of it: a failure state then draws only the faint shape of
6
+ * its data, and leaves the words to the overlay's one card.
7
+ */
8
+ export declare function useUnderFailureOverlay(): boolean;
9
+ /** The failure that holds a whole area: what the overlay's card says. */
10
+ export interface AreaFailure {
11
+ readonly title: string;
12
+ readonly failures: readonly LoadFailure[];
13
+ readonly onRetry?: () => void;
14
+ /** The data loads again on its own at each Live refresh. */
15
+ readonly followsLive?: boolean;
16
+ }
17
+ export interface FailureOverlayProps {
18
+ /** The failure that holds the whole area, or `undefined` while it shows its content as usual. */
19
+ readonly failure: AreaFailure | undefined;
20
+ readonly children: ReactNode;
21
+ }
22
+ /**
23
+ * Keeps a page's layout when everything in it failed: its content stays in
24
+ * place, faint and out of reach, each part drawing the shape of its data, and
25
+ * one card over it says what failed. A failure then reads as data that is
26
+ * late, on the page the reader knows, rather than as a different page.
27
+ *
28
+ * The content keeps its place in the tree whether the area failed or not: the
29
+ * queries inside are what tell the page it failed, and when the data is back.
30
+ */
31
+ export declare function FailureOverlay({ failure, children }: FailureOverlayProps): import("react/jsx-runtime").JSX.Element;
32
+ //# sourceMappingURL=FailureOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FailureOverlay.d.ts","sourceRoot":"","sources":["../../src/components/FailureOverlay.tsx"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,iGAAiG;IACjG,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAuBxE"}
@@ -0,0 +1,47 @@
1
+ import { AccessDeniedStateVariant } from './AccessDeniedState';
2
+ import { FailureGhostKind } from './FailureGhost';
3
+ import { LoadFailure } from './failure-wording';
4
+ /** The same three as a refusal: a page or a table's rows, a small box, one line next to a control. */
5
+ export type LoadFailedStateVariant = AccessDeniedStateVariant;
6
+ export interface LoadFailedStateProps {
7
+ /** What did not load, naming the data: "Couldn't load logs". */
8
+ readonly title: string;
9
+ /** The failures behind it, described on demand for support. */
10
+ readonly failures?: readonly LoadFailure[];
11
+ /**
12
+ * Given to a page-level state only: re-runs the page's failed loads, and
13
+ * adds the guidance that goes with it. One part of a page failing gets no
14
+ * retry: the next refresh asks again, and the rest of the page still works.
15
+ */
16
+ readonly onRetry?: () => void;
17
+ /**
18
+ * The faint shape of the data the state stands in for, drawn behind it: bars
19
+ * for a chart, lines for a table's rows. Keeps the page's layout, so the
20
+ * failure reads as data that is late. Not drawn by the inline form.
21
+ */
22
+ readonly ghost?: FailureGhostKind;
23
+ /**
24
+ * The data loads again on its own at each Live refresh (a query built on the
25
+ * Live window): the state counts down to the next one while Live is on.
26
+ * Leave it off for data Live never reloads, such as a log opened by id.
27
+ * @default false
28
+ */
29
+ readonly followsLive?: boolean;
30
+ /** @default 'default' */
31
+ readonly variant?: LoadFailedStateVariant;
32
+ readonly className?: string;
33
+ }
34
+ /**
35
+ * What a screen shows in place of data that failed to load (5xx, network).
36
+ * Every failure in the library uses it, in the data's own place, so a failure
37
+ * never reads as an empty answer. The sibling of `AccessDeniedState`, with the
38
+ * same variants: a card over the faint shape of the data for a page or a part
39
+ * of one, a title over it for a tile, one line next to a control. Neutral,
40
+ * nothing in red, the technical details one step away (a side panel, or a
41
+ * tooltip on the icon of a small state) rather than in the text.
42
+ *
43
+ * Under a `FailureOverlay` that shows the failure for a whole area, it draws
44
+ * only the shape of its data: the overlay's card speaks for all of it.
45
+ */
46
+ export declare function LoadFailedState({ title, failures, onRetry, ghost, followsLive, variant, className, }: LoadFailedStateProps): import("react/jsx-runtime").JSX.Element | null;
47
+ //# sourceMappingURL=LoadFailedState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadFailedState.d.ts","sourceRoot":"","sources":["../../src/components/LoadFailedState.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEvE,sGAAsG;AACtG,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,yBAAyB;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,OAAO,EACP,KAAK,EACL,WAAmB,EACnB,OAAmB,EACnB,SAAS,GACV,EAAE,oBAAoB,kDAsCtB"}
@@ -7,9 +7,11 @@ export interface QueryErrorBannerProps {
7
7
  }
8
8
  /**
9
9
  * Inline error banner for a failed data query. Exposed with `role="alert"` so
10
- * assistive technologies announce the failure as soon as it renders. Shared by
11
- * the observability explorer pages so logs and traces surface query errors
12
- * identically.
10
+ * assistive technologies announce the failure as soon as it renders.
11
+ *
12
+ * The library's own pages no longer use it: they show `LoadFailedState` in the
13
+ * data's own place, so a failure never sits above an empty table. Kept for
14
+ * hosts that still render it.
13
15
  */
14
16
  export declare function QueryErrorBanner({ message, onRetry, className }: QueryErrorBannerProps): import("react/jsx-runtime").JSX.Element;
15
17
  //# sourceMappingURL=QueryErrorBanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QueryErrorBanner.d.ts","sourceRoot":"","sources":["../../src/components/QueryErrorBanner.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,qBAAqB,2CAiBtF"}
1
+ {"version":3,"file":"QueryErrorBanner.d.ts","sourceRoot":"","sources":["../../src/components/QueryErrorBanner.tsx"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,qBAAqB,2CAiBtF"}
@@ -0,0 +1,16 @@
1
+ import { ReactNode } from 'react';
2
+ export interface UnavailableStateProps {
3
+ /** What was asked for, named in the title: "API", "Trace", "Log". */
4
+ readonly subject: string;
5
+ /** Rendered under the text, e.g. a way back. */
6
+ readonly action?: ReactNode;
7
+ readonly className?: string;
8
+ }
9
+ /**
10
+ * What a screen shows for a 404 that may stand for a refusal. Some endpoints
11
+ * answer "not found" for what the reader may not see, so that its existence
12
+ * does not leak; this state keeps that promise by never saying which of the
13
+ * two it is, and offers no retry since asking again gets the same answer.
14
+ */
15
+ export declare function UnavailableState({ subject, action, className }: UnavailableStateProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=UnavailableState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnavailableState.d.ts","sourceRoot":"","sources":["../../src/components/UnavailableState.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,qBAAqB,2CAUrF"}
@@ -0,0 +1,47 @@
1
+ import { DataKind } from './refusal-wording';
2
+ /** A failed load, with when it failed: what a failure state's details describe. */
3
+ export interface LoadFailure {
4
+ readonly error: unknown;
5
+ /** When the load failed, in epoch milliseconds, when known. */
6
+ readonly at?: number;
7
+ }
8
+ /**
9
+ * What a page-level failure state says under its title, next to its one "Try
10
+ * again", when nothing will load the data again on its own.
11
+ */
12
+ export declare const FAILURE_GUIDANCE = "Something went wrong. Try again in a moment.";
13
+ /**
14
+ * The title of a failure, naming what did not load: "Couldn't load analytics",
15
+ * or every kind once when several parts failed, "Couldn't load logs and
16
+ * analytics".
17
+ */
18
+ export declare function failureTitle(kinds: Iterable<DataKind>): string;
19
+ /** "10:42", local time: the Live pill's refresh time. */
20
+ export declare function formatClock(at: number): string;
21
+ /** What is known of one failed call, for the details. */
22
+ export interface FailureFacts {
23
+ /** The HTTP status, absent when no response came back. */
24
+ readonly status?: number;
25
+ /** The call that failed, "POST /observability/logs/search", when known. */
26
+ readonly call?: string;
27
+ /** The error's own message, kept only without a status: a network failure or a host source's error. */
28
+ readonly message?: string;
29
+ readonly at?: number;
30
+ }
31
+ /**
32
+ * Each distinct failed call, the latest when the same call failed several
33
+ * times. No request id: the sources read no response headers.
34
+ */
35
+ export declare function failureFacts(failures: readonly LoadFailure[]): FailureFacts[];
36
+ /** "HTTP 500", or "No response" when nothing came back. */
37
+ export declare function failureStatusLabel(status: number | undefined): string;
38
+ /** "Today, 10:42:13", or the date as well on another day. */
39
+ export declare function formatFailureTime(at: number, now?: number): string;
40
+ /**
41
+ * The technical details of one or several failures as text, for a support
42
+ * ticket: the status, the call and the time of each distinct failed call.
43
+ */
44
+ export declare function describeFailures(failures: readonly LoadFailure[]): string;
45
+ /** What a failure state says while Live mode is about to load the data again. */
46
+ export declare function retryCountdown(seconds: number): string;
47
+ //# sourceMappingURL=failure-wording.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-wording.d.ts","sourceRoot":"","sources":["../../src/components/failure-wording.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEjE,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,iDAAiD,CAAC;AAE/E;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,MAAM,CAE9D;AASD,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG9C;AASD,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,uGAAuG;IACvG,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACtB;AAkBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,YAAY,EAAE,CAQ7E;AAED,2DAA2D;AAC3D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAErE;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,MAAM,CAI9E;AAUD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAEzE;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtD"}
@@ -1,3 +1,9 @@
1
+ export { AccessDeniedState } from './AccessDeniedState';
2
+ export type { AccessDeniedStateProps, AccessDeniedStateVariant } from './AccessDeniedState';
3
+ export { LoadFailedState } from './LoadFailedState';
4
+ export type { LoadFailedStateProps, LoadFailedStateVariant } from './LoadFailedState';
5
+ export type { FailureGhostKind } from './FailureGhost';
6
+ export type { LoadFailure } from './failure-wording';
1
7
  export { QueryErrorBanner } from './QueryErrorBanner';
2
8
  export type { QueryErrorBannerProps } from './QueryErrorBanner';
3
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACtF,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The kinds of data a screen reads, one per right: analytics
3
+ * (`API_ANALYTICS`), logs and traces (`API_LOG`). A refusal or a failure
4
+ * names the kind, so the reader knows which access to ask for, or what is
5
+ * missing from the screen.
6
+ */
7
+ export type DataKind = 'logs' | 'traces' | 'analytics';
8
+ /** The kinds of data a reader may be refused. */
9
+ export type RefusedDataKind = DataKind;
10
+ /** Every kind once, in a stable order: "logs, traces and analytics". */
11
+ export declare function listDataKinds(kinds: Iterable<DataKind>): string;
12
+ /**
13
+ * The title of a refusal: "No access to analytics", or every refused kind once,
14
+ * "No access to logs and analytics", so asking for one of them is not mistaken
15
+ * for enough.
16
+ */
17
+ export declare function refusalTitle(kinds: Iterable<RefusedDataKind>): string;
18
+ //# sourceMappingURL=refusal-wording.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal-wording.d.ts","sourceRoot":"","sources":["../../src/components/refusal-wording.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEvD,iDAAiD;AACjD,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;AAKvC,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,MAAM,CAK/D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,MAAM,CAErE"}