@gravitee/gamma-lib-observability 3.1.1 → 3.2.0

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 (90) hide show
  1. package/QUERYING.md +58 -7
  2. package/USAGE_GUIDE.md +42 -6
  3. package/dist/dashboards/DashboardView.d.ts +8 -1
  4. package/dist/dashboards/DashboardView.d.ts.map +1 -1
  5. package/dist/dashboards/WidgetGroup.d.ts +7 -1
  6. package/dist/dashboards/WidgetGroup.d.ts.map +1 -1
  7. package/dist/dashboards/WidgetInteractionContext.d.ts +31 -0
  8. package/dist/dashboards/WidgetInteractionContext.d.ts.map +1 -0
  9. package/dist/dashboards/WidgetItem.d.ts +7 -3
  10. package/dist/dashboards/WidgetItem.d.ts.map +1 -1
  11. package/dist/dashboards/analytics-table/AnalyticsTable.d.ts +54 -0
  12. package/dist/dashboards/analytics-table/AnalyticsTable.d.ts.map +1 -0
  13. package/dist/dashboards/analytics-table/analytics-table-model.d.ts +73 -0
  14. package/dist/dashboards/analytics-table/analytics-table-model.d.ts.map +1 -0
  15. package/dist/dashboards/analytics-table/format-table-value.d.ts +31 -0
  16. package/dist/dashboards/analytics-table/format-table-value.d.ts.map +1 -0
  17. package/dist/dashboards/analytics-table/index.d.ts +6 -0
  18. package/dist/dashboards/analytics-table/index.d.ts.map +1 -0
  19. package/dist/dashboards/analytics-table/plan-columns.d.ts +102 -0
  20. package/dist/dashboards/analytics-table/plan-columns.d.ts.map +1 -0
  21. package/dist/dashboards/analytics-table/row-color.d.ts +11 -0
  22. package/dist/dashboards/analytics-table/row-color.d.ts.map +1 -0
  23. package/dist/dashboards/analytics-table/use-analytics-table-query.d.ts +46 -0
  24. package/dist/dashboards/analytics-table/use-analytics-table-query.d.ts.map +1 -0
  25. package/dist/dashboards/editor/TableColumnsEditor.d.ts +26 -0
  26. package/dist/dashboards/editor/TableColumnsEditor.d.ts.map +1 -0
  27. package/dist/dashboards/editor/TableDisplayFields.d.ts +13 -0
  28. package/dist/dashboards/editor/TableDisplayFields.d.ts.map +1 -0
  29. package/dist/dashboards/editor/TableQueryFields.d.ts +15 -0
  30. package/dist/dashboards/editor/TableQueryFields.d.ts.map +1 -0
  31. package/dist/dashboards/editor/VisualizationTypePicker.d.ts.map +1 -1
  32. package/dist/dashboards/editor/WidgetConfigForm.d.ts.map +1 -1
  33. package/dist/dashboards/editor/WidgetEditorPanel.d.ts.map +1 -1
  34. package/dist/dashboards/editor/WidgetPreview.d.ts +5 -0
  35. package/dist/dashboards/editor/WidgetPreview.d.ts.map +1 -1
  36. package/dist/dashboards/editor/convert-widget-type.d.ts +0 -4
  37. package/dist/dashboards/editor/convert-widget-type.d.ts.map +1 -1
  38. package/dist/dashboards/editor/dashboard-editor-state.d.ts +8 -0
  39. package/dist/dashboards/editor/dashboard-editor-state.d.ts.map +1 -1
  40. package/dist/dashboards/editor/facet-display-cols.d.ts +2 -0
  41. package/dist/dashboards/editor/facet-display-cols.d.ts.map +1 -1
  42. package/dist/dashboards/editor/suggest-widget-title.d.ts.map +1 -1
  43. package/dist/dashboards/editor/widget-auto-scope.d.ts.map +1 -1
  44. package/dist/dashboards/index.d.ts +4 -1
  45. package/dist/dashboards/index.d.ts.map +1 -1
  46. package/dist/dashboards/register-default-renderers.d.ts +1 -1
  47. package/dist/dashboards/register-default-renderers.d.ts.map +1 -1
  48. package/dist/dashboards/renderers/TablePresentation.d.ts +20 -0
  49. package/dist/dashboards/renderers/TablePresentation.d.ts.map +1 -0
  50. package/dist/dashboards/renderers/TableWidgetRenderer.d.ts +4 -0
  51. package/dist/dashboards/renderers/TableWidgetRenderer.d.ts.map +1 -0
  52. package/dist/dashboards/renderers/index.d.ts +1 -0
  53. package/dist/dashboards/renderers/index.d.ts.map +1 -1
  54. package/dist/dashboards/widget-data.d.ts +29 -2
  55. package/dist/dashboards/widget-data.d.ts.map +1 -1
  56. package/dist/dashboards/widget-renderer-registry.d.ts +8 -0
  57. package/dist/dashboards/widget-renderer-registry.d.ts.map +1 -1
  58. package/dist/data-sources/http-data-source.d.ts.map +1 -1
  59. package/dist/hooks/use-facets-query.d.ts +7 -0
  60. package/dist/hooks/use-facets-query.d.ts.map +1 -1
  61. package/dist/index.d.ts +4 -4
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +4705 -3151
  64. package/dist/lib/use-element-size.d.ts +21 -0
  65. package/dist/lib/use-element-size.d.ts.map +1 -0
  66. package/dist/routing/ObservabilityDashboardPage.d.ts +16 -0
  67. package/dist/routing/ObservabilityDashboardPage.d.ts.map +1 -1
  68. package/dist/routing/ObservabilityRoutes.d.ts.map +1 -1
  69. package/dist/routing/detail-filter.d.ts +9 -4
  70. package/dist/routing/detail-filter.d.ts.map +1 -1
  71. package/dist/shared/ExplorerTable.d.ts +34 -2
  72. package/dist/shared/ExplorerTable.d.ts.map +1 -1
  73. package/dist/styles/observability.css +1 -1
  74. package/dist/testing/graphene-core-icons-mock.d.ts +6 -0
  75. package/dist/testing/graphene-core-icons-mock.d.ts.map +1 -1
  76. package/dist/testing/graphene-core-mock.d.ts +18 -6
  77. package/dist/testing/graphene-core-mock.d.ts.map +1 -1
  78. package/dist/testing/index.d.ts +9 -0
  79. package/dist/testing/index.d.ts.map +1 -1
  80. package/dist/testing/mock-metrics-data-source.d.ts.map +1 -1
  81. package/dist/testing.js +16 -1
  82. package/dist/types/domain.d.ts +105 -1
  83. package/dist/types/domain.d.ts.map +1 -1
  84. package/dist/types/guards.d.ts +2 -1
  85. package/dist/types/guards.d.ts.map +1 -1
  86. package/dist/types/index.d.ts +2 -2
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/responses.d.ts +18 -0
  89. package/dist/types/responses.d.ts.map +1 -1
  90. package/package.json +1 -1
package/QUERYING.md CHANGED
@@ -74,13 +74,14 @@ the same metric/range) dedupe.
74
74
 
75
75
  ## 4. Widget → request mapping
76
76
 
77
- | Widget | Endpoint | Mapping |
78
- | -------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
79
- | `metric` | measures | `{ metric, measure }` → one `MetricRequest`. Widget `filters` → top-level filters. |
80
- | `metric-group` | measures | each `items[]` → one `MetricRequest` (`metric`, `measure`, per-item `filters`). Identical (metric+filters) items are deduped. |
81
- | `cartesian` | time-series | each `series[]` → one query. `metric`/`measure` → `metrics[0]`; `by` → `by[]`; `filters`/`sorts`/`ranges`/`limit` forwarded. Results are merged on the shared time bucket (`category`) before rendering. |
82
- | `doughnut` | facets | `by` → `by[]`; `metric`/`measure`/`sorts` → `metrics[0]`; `ranges`/`limit` forwarded. |
83
- | `bar` | facets | same as `doughnut`, plus `barLayout`. |
77
+ | Widget | Endpoint | Mapping |
78
+ | -------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
79
+ | `metric` | measures | `{ metric, measure }` → one `MetricRequest`. Widget `filters` → top-level filters. |
80
+ | `metric-group` | measures | each `items[]` → one `MetricRequest` (`metric`, `measure`, per-item `filters`). Identical (metric+filters) items are deduped. |
81
+ | `cartesian` | time-series | each `series[]` → one query. `metric`/`measure` → `metrics[0]`; `by` → `by[]`; `filters`/`sorts`/`ranges`/`limit` forwarded. Results are merged on the shared time bucket (`category`) before rendering. |
82
+ | `doughnut` | facets | `by` → `by[]`; `metric`/`measure`/`sorts` → `metrics[0]`; `ranges`/`limit` forwarded. |
83
+ | `bar` | facets | same as `doughnut`, plus `barLayout`. |
84
+ | `table` | facets | `by` → `by[]`; `columns[]` grouped by distinct `metric` → one `metrics[]` entry each, measures de-duplicated; `sorts` goes on **exactly one** metric, the one owning the sort column; `ranges`/`limit` forwarded. With `showTotals` or a `share` column, one extra measures request with the same filters and range. |
84
85
 
85
86
  **Presentation-only fields** (not sent to analytics; consumed by `CartesianPresentation` / graphene-charts):
86
87
 
@@ -109,6 +110,11 @@ chart total.
109
110
  sent to the backend but flattened onto the first level.
110
111
  - Distinct visual series for several measures of one metric are best expressed as one `series[]` entry
111
112
  per measure (e.g. P90/P95/P99), which the renderer keys apart by measure.
113
+ - `table` rows come from the metric carrying `sorts`; the other metrics are joined on the bucket key.
114
+ The backend aggregates each metric separately, so a sort on anything but a count can leave a row
115
+ without a value for another column: the cell renders `—` and the widget reports how many rows are
116
+ incomplete. A single-column table issues exactly the request a top list on the same query issues, and
117
+ shares its cache entry.
112
118
 
113
119
  ---
114
120
 
@@ -224,6 +230,51 @@ series to keep a single left axis (backward compatible).
224
230
 
225
231
  ---
226
232
 
233
+ ### 5.7 Multi-metric table (one facets request, sort on one metric)
234
+
235
+ ```json
236
+ {
237
+ "type": "table",
238
+ "by": ["API"],
239
+ "columns": [
240
+ { "metric": "HTTP_REQUESTS", "measure": "COUNT", "share": true },
241
+ {
242
+ "metric": "HTTP_ERROR_RATE",
243
+ "measure": "PERCENTAGE",
244
+ "thresholds": [{ "color": "red", "op": "gte", "value": 5 }]
245
+ },
246
+ { "metric": "HTTP_GATEWAY_RESPONSE_TIME", "measure": "P95", "pinned": true }
247
+ ],
248
+ "sort": { "columnId": "HTTP_GATEWAY_RESPONSE_TIME:P95", "order": "DESC" },
249
+ "limit": 10,
250
+ "showTotals": true
251
+ }
252
+ ```
253
+
254
+ Facets request (`sorts` on the P95 metric only, the others unordered):
255
+
256
+ ```json
257
+ {
258
+ "by": ["API"],
259
+ "limit": 10,
260
+ "metrics": [
261
+ { "name": "HTTP_REQUESTS", "measures": ["COUNT"] },
262
+ { "name": "HTTP_ERROR_RATE", "measures": ["PERCENTAGE"] },
263
+ { "name": "HTTP_GATEWAY_RESPONSE_TIME", "measures": ["P95"], "sorts": [{ "measure": "P95", "order": "DESC" }] }
264
+ ]
265
+ }
266
+ ```
267
+
268
+ Plus, because `showTotals` is on, one measures request for the same three metrics under the same
269
+ filters and range. A column's id is `metric:measure` unless it declares an `id`; the sort refers to it.
270
+ A threshold is an alert tier: `{ color, op, value, basis? }` paints the cell `color` (`red`, `amber`
271
+ or `green`) when it crosses `value`, `op` being `gte` (at or above) or `lte` (at or below) and `basis`
272
+ what is compared: the cell's own value (default) or its share of the column total in percent
273
+ (`"basis": "share"`, which also triggers the measures request for the total). Thresholds are ordered rules: the first one a cell matches decides its colour, so the author's
274
+ order is the priority.
275
+
276
+ ---
277
+
227
278
  ## 6. Filter semantics
228
279
 
229
280
  Filters merge in this order, later layers win on a field conflict:
package/USAGE_GUIDE.md CHANGED
@@ -492,6 +492,8 @@ import { MetricPresentation, BarPresentation } from '@gravitee/gamma-lib-observa
492
492
  | Manual | `CartesianWidget` | `CartesianWidgetData` |
493
493
  | Manual | `BarWidget` | `BarWidgetData` |
494
494
  | Manual | `DoughnutWidget` | `DoughnutWidgetData` |
495
+ | Manual | `BreakdownWidget` | `BreakdownWidgetData` |
496
+ | Manual | `TableWidget` | `TableWidgetData` |
495
497
 
496
498
  Shared props (available in all modes):
497
499
 
@@ -504,12 +506,46 @@ Shared props (available in all modes):
504
506
 
505
507
  #### `WidgetGroupProps`
506
508
 
507
- | Prop | Type | Required | Default | Description |
508
- | ----------- | ---------------------------- | -------- | ----------- | --------------------------------------------------------- |
509
- | `timeRange` | `TimeRange` | Yes | | Time range propagated to all nested `WidgetItem`s |
510
- | `filters` | `readonly FilterCondition[]` | No | `[]` | Filters propagated to all nested `WidgetItem`s |
511
- | `align` | `WidgetGroupAlign` | No | `'stretch'` | Cross-axis alignment: `stretch`, `center`, `start`, `end` |
512
- | `children` | `ReactNode` | Yes | | `WidgetItem` children |
509
+ | Prop | Type | Required | Default | Description |
510
+ | ------------- | ------------------------------- | -------- | ----------- | ---------------------------------------------------------- |
511
+ | `timeRange` | `TimeRange` | Yes | | Time range propagated to all nested `WidgetItem`s |
512
+ | `filters` | `readonly FilterCondition[]` | No | `[]` | Filters propagated to all nested `WidgetItem`s |
513
+ | `align` | `WidgetGroupAlign` | No | `'stretch'` | Cross-axis alignment: `stretch`, `center`, `start`, `end` |
514
+ | `interaction` | `WidgetInteractionContextValue` | No | | Receives what a reader acts on inside a widget (see below) |
515
+ | `children` | `ReactNode` | Yes | | `WidgetItem` children |
516
+
517
+ #### Widget interactions (row drill-down)
518
+
519
+ A widget can send a value the reader acted on back to the page — a table row, today — through a
520
+ `WidgetInteraction { kind, field, value, label? }`. `DashboardView` and `WidgetGroup` both take an
521
+ `interaction` prop; `ObservabilityDashboardPage` wires it for you (a row click adds a filter chip on
522
+ the widget's dimension, clicking the same row again clears it, a locked dashboard filter is never
523
+ overridden). When embedding widgets yourself:
524
+
525
+ ```tsx
526
+ <WidgetGroup
527
+ timeRange={timeRange}
528
+ filters={filters}
529
+ interaction={{
530
+ onInteract: ({ kind, field, value }) => {
531
+ if (kind === 'filter') setFilters(upsertFilterCondition(filters, field, value));
532
+ },
533
+ // Optional: which kinds the page can act on, per field. Only `filter` is
534
+ // offered when omitted; `exclude` needs the field's provider to advertise
535
+ // `not_in`, `view-logs` / `view-traces` / `open-entity` need a route.
536
+ supports: (kind) => kind === 'filter',
537
+ }}
538
+ >
539
+ <WidgetItem widget={topApisTable} />
540
+ </WidgetGroup>
541
+ ```
542
+
543
+ Widgets rendered without an `interaction` upstream show no row affordance at all rather than a dead
544
+ one. The built-in dashboard page offers **View logs** / **View traces** only for a sibling screen the
545
+ host enabled in `defineObservabilityFeatures` (and the reader may read), and **View traces** only on
546
+ the `API` dimension, since the tracing screen is per API (`tracing/:apiId`). A layout may declare `minCols` / `minRows`, which `DashboardView` forwards to the grid; no
547
+ widget type sets them by default. A table that gets too small degrades in steps instead: compact
548
+ numbers, collapsed columns, a top list, then an explicit "Enlarge the widget" state.
513
549
 
514
550
  ---
515
551
 
@@ -1,5 +1,6 @@
1
1
  import { BreakpointCols } from '@gravitee/graphene-charts/dashboard-grid';
2
2
  import { Dashboard, FilterCondition, TimeRange, Widget, WidgetLayout } from '../types/domain';
3
+ import { WidgetInteractionContextValue } from './WidgetInteractionContext';
3
4
  export interface DashboardViewProps {
4
5
  readonly dashboard: Dashboard;
5
6
  readonly timeRange: TimeRange;
@@ -28,6 +29,12 @@ export interface DashboardViewProps {
28
29
  * user knows the grid copy will be replaced on save.
29
30
  */
30
31
  readonly highlightedWidgetId?: string;
32
+ /**
33
+ * Receives what a reader acted on inside a widget — a table row, say — so the
34
+ * page can turn it into a dashboard filter or a navigation. Left out, widgets
35
+ * render without the affordance rather than with a dead one.
36
+ */
37
+ readonly interaction?: WidgetInteractionContextValue;
31
38
  }
32
- export declare function DashboardView({ dashboard, timeRange, filters, editable, rowHeight, breakpointCols, onLayoutChange, widgetActions, highlightedWidgetId, }: DashboardViewProps): import("react/jsx-runtime").JSX.Element;
39
+ export declare function DashboardView({ dashboard, timeRange, filters, editable, rowHeight, breakpointCols, onLayoutChange, widgetActions, highlightedWidgetId, interaction, }: DashboardViewProps): import("react/jsx-runtime").JSX.Element;
33
40
  //# sourceMappingURL=DashboardView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardView.d.ts","sourceRoot":"","sources":["../../src/dashboards/DashboardView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,0CAA0C,CAAC;AAIrG,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAgCnG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,iIAAiI;IACjI,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,2DAA2D;IAC3D,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,KAAK,IAAI,CAAC;IAC/E;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7D;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,SAAS,EACT,OAAuB,EACvB,QAAgB,EAChB,SAAS,EACT,cAAwC,EACxC,cAAc,EACd,aAAa,EACb,mBAAmB,GACpB,EAAE,kBAAkB,2CA2EpB"}
1
+ {"version":3,"file":"DashboardView.d.ts","sourceRoot":"","sources":["../../src/dashboards/DashboardView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,0CAA0C,CAAC;AAIrG,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEnG,OAAO,EAA6B,KAAK,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AA+B3G,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,iIAAiI;IACjI,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,2DAA2D;IAC3D,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,KAAK,IAAI,CAAC;IAC/E;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7D;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,6BAA6B,CAAC;CACtD;AAED,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,SAAS,EACT,OAAuB,EACvB,QAAgB,EAChB,SAAS,EACT,cAAwC,EACxC,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,WAAW,GACZ,EAAE,kBAAkB,2CAoFpB"}
@@ -1,10 +1,16 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { FilterCondition, TimeRange } from '../types/domain';
3
+ import { WidgetInteractionContextValue } from './WidgetInteractionContext';
3
4
  export type WidgetGroupAlign = 'stretch' | 'center' | 'start' | 'end';
4
5
  export interface WidgetGroupProps {
5
6
  readonly timeRange: TimeRange;
6
7
  readonly filters?: readonly FilterCondition[];
7
8
  readonly align?: WidgetGroupAlign;
9
+ /**
10
+ * Receives what a reader acted on inside a widget. Same contract as on
11
+ * `DashboardView`, so an embedded group behaves like a dashboard does.
12
+ */
13
+ readonly interaction?: WidgetInteractionContextValue;
8
14
  readonly children: ReactNode;
9
15
  }
10
16
  /**
@@ -12,5 +18,5 @@ export interface WidgetGroupProps {
12
18
  * `filters` context. Renders children in a responsive flex layout where
13
19
  * each child takes equal width.
14
20
  */
15
- export declare function WidgetGroup({ timeRange, filters, align, children }: WidgetGroupProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function WidgetGroup({ timeRange, filters, align, interaction, children, }: WidgetGroupProps): import("react/jsx-runtime").JSX.Element;
16
22
  //# sourceMappingURL=WidgetGroup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetGroup.d.ts","sourceRoot":"","sources":["../../src/dashboards/WidgetGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGlE,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AASD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,OAAuB,EAAE,KAAiB,EAAE,QAAQ,EAAE,EAAE,gBAAgB,2CAQhH"}
1
+ {"version":3,"file":"WidgetGroup.d.ts","sourceRoot":"","sources":["../../src/dashboards/WidgetGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAA6B,KAAK,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAE3G,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,6BAA6B,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AASD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,OAAuB,EACvB,KAAiB,EACjB,WAAW,EACX,QAAQ,GACT,EAAE,gBAAgB,2CAYlB"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * What a widget can ask the page to do with one of its values.
3
+ *
4
+ * `filter` and `exclude` are the drill-down proper. The three navigation kinds
5
+ * exist because the widget cannot build those links itself: the library
6
+ * contributes routes but never owns them, so only the page knows its base path
7
+ * and, for `open-entity`, what a value even points at. The widget offers the
8
+ * affordance; the page decides what it means.
9
+ */
10
+ export type WidgetInteractionKind = 'filter' | 'exclude' | 'view-logs' | 'view-traces' | 'open-entity';
11
+ export interface WidgetInteraction {
12
+ readonly kind: WidgetInteractionKind;
13
+ /** Dimension the value belongs to, which is also its filter field. */
14
+ readonly field: string;
15
+ readonly value: string;
16
+ /** Human-readable form of `value`, when the data source resolved one. */
17
+ readonly label?: string;
18
+ }
19
+ export type WidgetInteractionHandler = (interaction: WidgetInteraction) => void;
20
+ export interface WidgetInteractionContextValue {
21
+ readonly onInteract: WidgetInteractionHandler;
22
+ /**
23
+ * Whether the page can act on a kind for a given field. A widget offers only
24
+ * what the page answers for: an entry that silently does nothing is worse
25
+ * than no entry at all. Everything is offered when this is omitted.
26
+ */
27
+ readonly supports?: (kind: WidgetInteractionKind, field: string) => boolean;
28
+ }
29
+ export declare const WidgetInteractionProvider: import('react').Provider<WidgetInteractionContextValue | null>;
30
+ export declare function useWidgetInteractionContext(): WidgetInteractionContextValue | null;
31
+ //# sourceMappingURL=WidgetInteractionContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WidgetInteractionContext.d.ts","sourceRoot":"","sources":["../../src/dashboards/WidgetInteractionContext.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;AAEvG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,wBAAwB,GAAG,CAAC,WAAW,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAEhF,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CAC7E;AAUD,eAAO,MAAM,yBAAyB,gEAAoC,CAAC;AAE3E,wBAAgB,2BAA2B,IAAI,6BAA6B,GAAG,IAAI,CAElF"}
@@ -1,5 +1,5 @@
1
- import { BarWidget, BreakdownWidget, CartesianWidget, DoughnutWidget, FilterCondition, MetricGroupWidget, MetricWidget, TimeRange, Widget } from '../types/domain';
2
- import { BarWidgetData, BreakdownWidgetData, CartesianWidgetData, DoughnutWidgetData, MetricGroupWidgetData, MetricWidgetData } from './widget-data';
1
+ import { BarWidget, BreakdownWidget, CartesianWidget, DoughnutWidget, FilterCondition, MetricGroupWidget, MetricWidget, TableWidget, TimeRange, Widget } from '../types/domain';
2
+ import { BarWidgetData, BreakdownWidgetData, CartesianWidgetData, DoughnutWidgetData, MetricGroupWidgetData, MetricWidgetData, TableWidgetData } from './widget-data';
3
3
  interface WidgetItemBaseProps {
4
4
  readonly timeRange?: TimeRange;
5
5
  readonly filters?: readonly FilterCondition[];
@@ -32,11 +32,15 @@ interface WidgetItemManualBreakdownProps extends WidgetItemBaseProps {
32
32
  readonly widget: BreakdownWidget;
33
33
  readonly data: BreakdownWidgetData;
34
34
  }
35
+ interface WidgetItemManualTableProps extends WidgetItemBaseProps {
36
+ readonly widget: TableWidget;
37
+ readonly data: TableWidgetData;
38
+ }
35
39
  /**
36
40
  * Props for `WidgetItem`. The union ensures that when `data` is provided,
37
41
  * `data.type` is paired with the correct `widget` subtype at compile time.
38
42
  */
39
- export type WidgetItemProps = WidgetItemAutoProps | WidgetItemManualMetricProps | WidgetItemManualMetricGroupProps | WidgetItemManualCartesianProps | WidgetItemManualBarProps | WidgetItemManualDoughnutProps | WidgetItemManualBreakdownProps;
43
+ export type WidgetItemProps = WidgetItemAutoProps | WidgetItemManualMetricProps | WidgetItemManualMetricGroupProps | WidgetItemManualCartesianProps | WidgetItemManualBarProps | WidgetItemManualDoughnutProps | WidgetItemManualBreakdownProps | WidgetItemManualTableProps;
40
44
  /**
41
45
  * Standalone widget that resolves a renderer from the widget registry.
42
46
  *
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetItem.d.ts","sourceRoot":"","sources":["../../src/dashboards/WidgetItem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,eAAe,EACf,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,MAAM,EACP,MAAM,iBAAiB,CAAC;AAUzB,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAEjB,MAAM,eAAe,CAAC;AAKvB,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;AAED,UAAU,mBAAoB,SAAQ,mBAAmB;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B;AAED,UAAU,2BAA4B,SAAQ,mBAAmB;IAC/D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,UAAU,gCAAiC,SAAQ,mBAAmB;IACpE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;CACtC;AAED,UAAU,8BAA+B,SAAQ,mBAAmB;IAClE,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED,UAAU,wBAAyB,SAAQ,mBAAmB;IAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B;AAED,UAAU,6BAA8B,SAAQ,mBAAmB;IACjE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;CACnC;AAED,UAAU,8BAA+B,SAAQ,mBAAmB;IAClE,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,2BAA2B,GAC3B,gCAAgC,GAChC,8BAA8B,GAC9B,wBAAwB,GACxB,6BAA6B,GAC7B,8BAA8B,CAAC;AAEnC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CAMhD"}
1
+ {"version":3,"file":"WidgetItem.d.ts","sourceRoot":"","sources":["../../src/dashboards/WidgetItem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,eAAe,EACf,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,SAAS,EACT,MAAM,EACP,MAAM,iBAAiB,CAAC;AAazB,OAAO,KAAK,EACV,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,eAAe,EAEhB,MAAM,eAAe,CAAC;AAKvB,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;CAC/C;AAED,UAAU,mBAAoB,SAAQ,mBAAmB;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;CAC3B;AAED,UAAU,2BAA4B,SAAQ,mBAAmB;IAC/D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,UAAU,gCAAiC,SAAQ,mBAAmB;IACpE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;CACtC;AAED,UAAU,8BAA+B,SAAQ,mBAAmB;IAClE,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED,UAAU,wBAAyB,SAAQ,mBAAmB;IAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B;AAED,UAAU,6BAA8B,SAAQ,mBAAmB;IACjE,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;CACnC;AAED,UAAU,8BAA+B,SAAQ,mBAAmB;IAClE,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED,UAAU,0BAA2B,SAAQ,mBAAmB;IAC9D,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,2BAA2B,GAC3B,gCAAgC,GAChC,8BAA8B,GAC9B,wBAAwB,GACxB,6BAA6B,GAC7B,8BAA8B,GAC9B,0BAA0B,CAAC;AAE/B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CAMhD"}
@@ -0,0 +1,54 @@
1
+ import { ChartState } from '@gravitee/graphene-charts';
2
+ import { ReactNode } from 'react';
3
+ import { TableRowMarker, TableSort } from '../../types/domain';
4
+ import { AnalyticsTableRow, ResolvedTableColumn } from './analytics-table-model';
5
+ import { RowColorResolver } from './row-color';
6
+ /** Key of the synthetic totals row. Never a real dimension value. */
7
+ export declare const TOTALS_ROW_KEY = "__totals__";
8
+ export declare function isTotalsRow(row: AnalyticsTableRow): boolean;
9
+ export interface AnalyticsTableProps {
10
+ readonly columns: readonly ResolvedTableColumn[];
11
+ readonly rows: readonly AnalyticsTableRow[];
12
+ /** Header of the label column, e.g. `API`. */
13
+ readonly dimensionLabel: string;
14
+ readonly state: ChartState;
15
+ /** Active sort when controlled; the initial sort otherwise. */
16
+ readonly sort: TableSort | undefined;
17
+ /**
18
+ * Makes the sort controlled. Left out — in manual mode, or in a story — the
19
+ * table sorts itself over the rows it was handed, which is the only thing it
20
+ * can do without a query to re-issue.
21
+ */
22
+ readonly onSortChange?: (sort: TableSort) => void;
23
+ /** Overall metric totals, keyed by column id. Also the share denominator. */
24
+ readonly totals?: Readonly<Record<string, number>>;
25
+ readonly showTotals?: boolean;
26
+ /** How many rows the response could not fill completely. */
27
+ readonly partialRows?: number;
28
+ /** Ceiling on the rows shown per page; the height decides the rest. */
29
+ readonly pageSize?: number;
30
+ readonly rowMarker?: TableRowMarker;
31
+ /** Colour of a row's swatch when the dimension has semantic colours. */
32
+ readonly rowColorFor?: RowColorResolver;
33
+ readonly onRowSelect?: (row: AnalyticsTableRow) => void;
34
+ /** Extra entries for the per-row menu. The menu only exists when this is set. */
35
+ readonly renderRowMenuItems?: (row: AnalyticsTableRow) => ReactNode;
36
+ /**
37
+ * Ranked-list rendering used when the widget is too narrow for even one value
38
+ * column. Supplied by the caller so the fallback is the real top-list
39
+ * presentation rather than a second implementation of it.
40
+ */
41
+ readonly renderTopList?: (sortColumn: ResolvedTableColumn) => ReactNode;
42
+ readonly emptyMessage?: ReactNode;
43
+ }
44
+ /**
45
+ * The table itself: sorting, paging, totals and degradation, over data someone
46
+ * else fetched.
47
+ *
48
+ * It measures its own body and adapts in discrete steps — compact numbers, then
49
+ * collapsed columns, then a top list, then an explicit "too small" state. It
50
+ * never scales and never scrolls: the widget lives in a box the grid clips, so
51
+ * anything that does not fit has to be decided about, not pushed out of view.
52
+ */
53
+ export declare function AnalyticsTable({ columns, rows, dimensionLabel, state, sort, onSortChange, totals, showTotals, partialRows, pageSize, rowMarker, rowColorFor, onRowSelect, renderRowMenuItems, renderTopList, emptyMessage, }: AnalyticsTableProps): import("react/jsx-runtime").JSX.Element;
54
+ //# sourceMappingURL=AnalyticsTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyticsTable.d.ts","sourceRoot":"","sources":["../../../src/dashboards/analytics-table/AnalyticsTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAe5D,OAAO,EAAkC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,qEAAqE;AACrE,eAAO,MAAM,cAAc,eAAe,CAAC;AAM3C,wBAAgB,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAE3D;AAyGD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5C,8CAA8C;IAC9C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAClD,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACxD,iFAAiF;IACjF,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,SAAS,CAAC;IACpE;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,mBAAmB,KAAK,SAAS,CAAC;IACxE,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,cAAc,EACd,KAAK,EACL,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,UAAkB,EAClB,WAAe,EACf,QAAQ,EACR,SAAS,EACT,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,aAAa,EACb,YAAyC,GAC1C,EAAE,mBAAmB,2CAgPrB"}
@@ -0,0 +1,73 @@
1
+ import { SortOrder, TableColumn, TableColumnFormat, TableSort, TableThreshold } from '../../types/domain';
2
+ import { FacetBucket } from '../../types/responses';
3
+ /**
4
+ * A column with every default resolved: the identity used for sorting and for
5
+ * the collapse plan, the label and unit taken from the metric catalog when the
6
+ * author did not override them, and the flags turned into plain booleans.
7
+ *
8
+ * Resolution happens at render time, never at save time, so a table follows the
9
+ * catalog as it is corrected or extended instead of freezing a copy of it into
10
+ * the dashboard (see OBS-73 / OBS-81).
11
+ */
12
+ export interface ResolvedTableColumn {
13
+ readonly id: string;
14
+ readonly metric: string;
15
+ readonly measure: string;
16
+ readonly label: string;
17
+ readonly unit?: string;
18
+ readonly format: TableColumnFormat;
19
+ readonly thresholds: readonly TableThreshold[];
20
+ readonly share: boolean;
21
+ readonly pinned: boolean;
22
+ }
23
+ export interface AnalyticsTableRow {
24
+ /** Bucket key — the value a row click filters on. */
25
+ readonly key: string;
26
+ readonly label: string;
27
+ /**
28
+ * Column id to value. A missing entry is a cell the response did not carry,
29
+ * which renders as "—" rather than as a zero: the two mean different things
30
+ * and reading "0 errors" where the backend said nothing is a lie.
31
+ */
32
+ readonly values: Readonly<Record<string, number>>;
33
+ }
34
+ export interface AnalyticsTableModel {
35
+ readonly rows: readonly AnalyticsTableRow[];
36
+ /** Rows missing at least one column's value. */
37
+ readonly partialRows: number;
38
+ }
39
+ /** A column's identity is its metric/measure pair unless the author named it. */
40
+ export declare function tableColumnId(column: TableColumn): string;
41
+ export declare function resolveTableColumn(column: TableColumn): ResolvedTableColumn;
42
+ export declare function resolveTableColumns(columns: readonly TableColumn[]): ResolvedTableColumn[];
43
+ /**
44
+ * The sort the widget actually applies: the author's when it still names a
45
+ * column, otherwise the first column descending. A saved sort pointing at a
46
+ * column that has since been removed must not leave the table unordered.
47
+ */
48
+ export declare function resolveTableSort(columns: readonly ResolvedTableColumn[], sort: TableSort | undefined): TableSort | undefined;
49
+ /**
50
+ * Joins the buckets of several metrics into one row per dimension value.
51
+ *
52
+ * The row list — and its order — comes from the metric that carries the sort,
53
+ * because that is the only aggregation the backend ordered. Every other metric
54
+ * is looked up by key, and a key it does not carry leaves a hole: with one
55
+ * `terms` aggregation per metric, a sort on something other than a count lets
56
+ * the other aggregations return a different top-N. Holes are counted so the
57
+ * widget can say how much of the table is incomplete rather than passing off a
58
+ * partial join as a full one.
59
+ */
60
+ export declare function buildTableModel(buckets: readonly FacetBucket[], columns: readonly ResolvedTableColumn[], sortMetric: string): AnalyticsTableModel;
61
+ /**
62
+ * Denominator for a share column: the metric's overall total when totals were
63
+ * fetched, otherwise the sum of what is on screen. The two answer different
64
+ * questions ("share of all traffic" vs "share of the top N"), so which one is
65
+ * in play has to reach the cell — hence the flag rather than a bare number.
66
+ */
67
+ export declare function resolveShareBase(column: ResolvedTableColumn, rows: readonly AnalyticsTableRow[], totals: Readonly<Record<string, number>> | undefined): {
68
+ readonly base: number;
69
+ readonly ofTotal: boolean;
70
+ };
71
+ /** Client-side ordering over the top-N the backend returned. */
72
+ export declare function sortTableRows(rows: readonly AnalyticsTableRow[], columnId: string, order: SortOrder): AnalyticsTableRow[];
73
+ //# sourceMappingURL=analytics-table-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-table-model.d.ts","sourceRoot":"","sources":["../../../src/dashboards/analytics-table/analytics-table-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC/G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIzD;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5C,gDAAgD;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEzD;AAaD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,mBAAmB,CAc3E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,mBAAmB,EAAE,CAE1F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,IAAI,EAAE,SAAS,GAAG,SAAS,GAC1B,SAAS,GAAG,SAAS,CAKvB;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,OAAO,EAAE,SAAS,mBAAmB,EAAE,EACvC,UAAU,EAAE,MAAM,GACjB,mBAAmB,CAmCrB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAE,SAAS,iBAAiB,EAAE,EAClC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAKtD;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAC3B,IAAI,EAAE,SAAS,iBAAiB,EAAE,EAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,SAAS,GACf,iBAAiB,EAAE,CAWrB"}
@@ -0,0 +1,31 @@
1
+ import { TableColumnFormat, TableThreshold, TableTierColor } from '../../types/domain';
2
+ import { ResolvedTableColumn } from './analytics-table-model';
3
+ import { TableDensity } from './plan-columns';
4
+ /** What an absent cell reads as. Never a zero — see `AnalyticsTableRow.values`. */
5
+ export declare const MISSING_CELL = "\u2014";
6
+ export interface FormatTableValueOptions {
7
+ readonly format: TableColumnFormat;
8
+ readonly unit?: string;
9
+ /** Compact density switches plain numbers to `1.28M`. @default 'comfortable' */
10
+ readonly density?: TableDensity;
11
+ }
12
+ /**
13
+ * Formats one cell. The unit suffix is only appended to plain numbers: a
14
+ * percentage, a duration and a byte size all carry their own, and repeating it
15
+ * gives "2.3% %".
16
+ */
17
+ export declare function formatTableValue(value: number, options: FormatTableValueOptions): string;
18
+ /** Formats a cell of a resolved column, or the placeholder when it has no value. */
19
+ export declare function formatColumnValue(value: number | undefined, column: ResolvedTableColumn, density: TableDensity): string;
20
+ /**
21
+ * The colour a cell takes, or none. Thresholds are ordered rules and **the
22
+ * first one that matches wins**, the way conditional formatting works in
23
+ * Datadog, Metabase or a spreadsheet: the author's order is the priority, and
24
+ * a later rule never overrides an earlier one. Each rule is checked against
25
+ * what it asks for: the cell's value, or its share of the column total (a
26
+ * ratio here, a percentage in the rule).
27
+ */
28
+ export declare function resolveThresholdColor(value: number | undefined, share: number | undefined, thresholds: readonly TableThreshold[]): TableTierColor | undefined;
29
+ /** Design-system tokens, so both themes are covered without a theme branch. */
30
+ export declare const THRESHOLD_TEXT_CLASS: Record<TableTierColor, string>;
31
+ //# sourceMappingURL=format-table-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-table-value.d.ts","sourceRoot":"","sources":["../../../src/dashboards/analytics-table/format-table-value.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,mFAAmF;AACnF,eAAO,MAAM,YAAY,WAAM,CAAC;AAuBhC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAkBxF;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,YAAY,GACpB,MAAM,CAOR;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,UAAU,EAAE,SAAS,cAAc,EAAE,GACpC,cAAc,GAAG,SAAS,CAU5B;AAED,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAI/D,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { AnalyticsTable, TOTALS_ROW_KEY, isTotalsRow, type AnalyticsTableProps } from './AnalyticsTable';
2
+ export { buildTableModel, resolveShareBase, resolveTableColumn, resolveTableColumns, resolveTableSort, sortTableRows, tableColumnId, type AnalyticsTableModel, type AnalyticsTableRow, type ResolvedTableColumn, } from './analytics-table-model';
3
+ export { MISSING_CELL, formatColumnValue, formatTableValue, resolveThresholdColor, type FormatTableValueOptions, } from './format-table-value';
4
+ export { planColumns, resolveRowsPerPage, type ColumnPlan, type PageSizePlan, type PlanColumnsOptions, type TableDensity, type TableLayoutMode, } from './plan-columns';
5
+ export { buildTableMetrics, useAnalyticsTableQuery, type AnalyticsTableQueryResult, type UseAnalyticsTableQueryParams, } from './use-analytics-table-query';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dashboards/analytics-table/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzG,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,GAClC,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,102 @@
1
+ import { TableRowMarker } from '../../types/domain';
2
+ import { ResolvedTableColumn } from './analytics-table-model';
3
+ /**
4
+ * Intrinsic minimum widths, in pixels, for each kind of cell. They are what the
5
+ * content needs to stay readable, not a share of the widget: an API name needs
6
+ * room for more than an ellipsis, and a number needs room for its unit.
7
+ */
8
+ export declare const LABEL_COLUMN_MIN_WIDTH = 140;
9
+ export declare const VALUE_COLUMN_MIN_WIDTH = 88;
10
+ /** A value column drawing a share bar next to its number. */
11
+ export declare const SHARE_COLUMN_MIN_WIDTH = 120;
12
+ export declare const ROW_MENU_WIDTH = 28;
13
+ /** Room the row marker takes in front of the label, gap included. */
14
+ export declare const ROW_MARKER_WIDTH: Readonly<Record<TableRowMarker, number>>;
15
+ /**
16
+ * Below either of these nothing legible fits at all, so the widget says so
17
+ * instead of drawing a table nobody can read — the same call `MetricGroup`
18
+ * makes with its own emergency threshold.
19
+ */
20
+ export declare const EMERGENCY_WIDTH = 180;
21
+ export declare const EMERGENCY_HEIGHT = 90;
22
+ export declare const TABLE_ROW_HEIGHT = 36;
23
+ export declare const TABLE_HEADER_HEIGHT = 40;
24
+ export declare const TABLE_PAGINATION_HEIGHT = 36;
25
+ export type TableDensity = 'comfortable' | 'compact';
26
+ /**
27
+ * - `table` — the visualization the author asked for, possibly with columns
28
+ * collapsed away.
29
+ * - `top-list` — not even one value column fits next to the labels, so the
30
+ * widget falls back to the ranked-list presentation on the sort column.
31
+ * - `emergency` — too small for either.
32
+ */
33
+ export type TableLayoutMode = 'table' | 'top-list' | 'emergency';
34
+ export interface ColumnPlan {
35
+ readonly mode: TableLayoutMode;
36
+ readonly density: TableDensity;
37
+ /** Column ids to render, in author order. */
38
+ readonly visible: readonly string[];
39
+ /** Column ids collapsed away, in author order. */
40
+ readonly hidden: readonly string[];
41
+ /**
42
+ * Pixels left to the label column once the visible value columns and the
43
+ * row menu have taken theirs, marker included. The table caps the labels at
44
+ * this so a long value truncates instead of widening its column: table
45
+ * layout gives a cell what its text asks for, and one long label would push
46
+ * the last value column out of the widget. Zero outside `table` mode.
47
+ */
48
+ readonly labelWidth: number;
49
+ }
50
+ export interface PlanColumnsOptions {
51
+ readonly width: number;
52
+ readonly height: number;
53
+ readonly columns: readonly ResolvedTableColumn[];
54
+ /** The column ordering the rows. Never collapsed while a table is rendered. */
55
+ readonly sortColumnId: string | undefined;
56
+ /** Reserves room for the per-row actions button. @default false */
57
+ readonly hasRowMenu?: boolean;
58
+ /** Header of the label column, so a long dimension name is budgeted for. */
59
+ readonly labelHeader?: string;
60
+ readonly rowMarker?: TableRowMarker;
61
+ }
62
+ /**
63
+ * Room a header needs to stay on one line. An estimate, not a measurement:
64
+ * the plan runs before anything is laid out, and a per-character average is
65
+ * within a few pixels of the truth for the labels a catalog produces. Without
66
+ * it a column budgeted at its numeric minimum would be handed a header wider
67
+ * than that, and the table layout would take the missing pixels from a
68
+ * neighbour — folding "300 req 99%" onto two lines while the plan swears
69
+ * everything fits.
70
+ */
71
+ export declare function estimateHeaderWidth(label: string): number;
72
+ /**
73
+ * Decides which columns fit the measured width, and how tightly they draw.
74
+ *
75
+ * Pure, and separate from the component, because it is the whole of the
76
+ * degradation contract: hide in reverse author order, keep the label, the sort
77
+ * column and the pinned ones, fall back to a top list rather than clip. A
78
+ * pinned column is dropped only when the alternative is losing the table
79
+ * altogether — pinning asks for priority, and priority cannot conjure pixels.
80
+ */
81
+ export declare function planColumns({ width, height, columns, sortColumnId, hasRowMenu, labelHeader, rowMarker, }: PlanColumnsOptions): ColumnPlan;
82
+ export interface PageSizePlan {
83
+ readonly rowsPerPage: number;
84
+ readonly paginated: boolean;
85
+ }
86
+ /**
87
+ * Rows per page derived from the height that is actually available, capped by
88
+ * the author's `pageSize`.
89
+ *
90
+ * Derived rather than fixed because the widget must never clip: a table asked
91
+ * for ten rows in a box that holds four has to show four and page, not four and
92
+ * a half. The author's number is therefore a ceiling — it can ask for fewer
93
+ * rows than fit, never for more.
94
+ *
95
+ * Two passes, because the pagination bar only exists if there is something to
96
+ * page through, and it costs a row's worth of height when it does.
97
+ */
98
+ export declare function resolveRowsPerPage(height: number, totalRows: number, options?: {
99
+ readonly showTotals?: boolean;
100
+ readonly pageSize?: number;
101
+ }): PageSizePlan;
102
+ //# sourceMappingURL=plan-columns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-columns.d.ts","sourceRoot":"","sources":["../../../src/dashboards/analytics-table/plan-columns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,6DAA6D;AAC7D,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAA6B,CAAC;AAEpG;;;;GAIG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAE1C,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,SAAS,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;AAEjE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACjD,+EAA+E;IAC/E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,mEAAmE;IACnE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;CACrC;AAOD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAOD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,MAAM,EACN,OAAO,EACP,YAAY,EACZ,UAAkB,EAClB,WAAgB,EAChB,SAAS,GACV,EAAE,kBAAkB,GAAG,UAAU,CAsDjC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1E,YAAY,CASd"}
@@ -0,0 +1,11 @@
1
+ import { AnalyticsTableRow } from './analytics-table-model';
2
+ /** CSS colour for a row's swatch, or `undefined` to let the index palette decide. */
3
+ export type RowColorResolver = (row: AnalyticsTableRow) => string | undefined;
4
+ /**
5
+ * Rows of a status dimension keep their semantic colours (2XX green, 5XX red),
6
+ * the same `status-palette` every other widget applies to that dimension, so a
7
+ * table and a bar chart of the same values never disagree. Any other dimension
8
+ * gets no resolver: its rows follow the index palette, like the top list.
9
+ */
10
+ export declare function rowColorResolver(dimension: string | undefined): RowColorResolver | undefined;
11
+ //# sourceMappingURL=row-color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"row-color.d.ts","sourceRoot":"","sources":["../../../src/dashboards/analytics-table/row-color.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,qFAAqF;AACrF,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,MAAM,GAAG,SAAS,CAAC;AAE9E;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,gBAAgB,GAAG,SAAS,CAG5F"}