@datalayer/core 1.0.3 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/lib/api/constants.d.ts +3 -0
  2. package/lib/api/constants.js +3 -0
  3. package/lib/api/runtimes/checkpoints.d.ts +122 -0
  4. package/lib/api/runtimes/checkpoints.js +118 -0
  5. package/lib/api/runtimes/index.d.ts +1 -0
  6. package/lib/api/runtimes/index.js +1 -0
  7. package/lib/api/runtimes/runtimes.d.ts +84 -0
  8. package/lib/api/runtimes/runtimes.js +50 -0
  9. package/lib/components/auth/Login.js +1 -1
  10. package/lib/components/display/BusyDots.d.ts +9 -0
  11. package/lib/components/display/BusyDots.js +31 -0
  12. package/lib/components/display/LiveRelativeTime.d.ts +10 -0
  13. package/lib/components/display/LiveRelativeTime.js +21 -0
  14. package/lib/components/display/index.d.ts +2 -0
  15. package/lib/components/display/index.js +2 -0
  16. package/lib/components/flashes/FlashSurveys.js +1 -1
  17. package/lib/components/index.d.ts +1 -0
  18. package/lib/components/index.js +1 -0
  19. package/lib/components/navbar/SubdomainNavBar.js +1 -1
  20. package/lib/components/progress/ConsumptionBar.js +6 -7
  21. package/lib/components/progress/CreditsIndicator.js +2 -2
  22. package/lib/components/progress/consumption.d.ts +12 -0
  23. package/lib/components/progress/consumption.js +31 -0
  24. package/lib/components/progress/index.d.ts +1 -0
  25. package/lib/components/progress/index.js +1 -0
  26. package/lib/components/sparklines/Sparklines.d.ts +16 -0
  27. package/lib/components/sparklines/Sparklines.js +65 -0
  28. package/lib/components/sparklines/SparklinesLine.d.ts +8 -0
  29. package/lib/components/sparklines/SparklinesLine.js +37 -0
  30. package/lib/components/sparklines/dataProcessing.d.ts +25 -0
  31. package/lib/components/sparklines/dataProcessing.js +35 -0
  32. package/lib/components/sparklines/index.d.ts +4 -0
  33. package/lib/components/sparklines/index.js +7 -0
  34. package/lib/components/sparklines/types.d.ts +36 -0
  35. package/lib/components/sparklines/types.js +5 -0
  36. package/lib/components/storage/ContentsBrowser.js +17 -1
  37. package/lib/components/subnav/SubNav.js +1 -1
  38. package/lib/hooks/useCache.d.ts +5 -67
  39. package/lib/hooks/useCache.js +15 -213
  40. package/lib/hooks/useProjects.d.ts +1 -1
  41. package/lib/models/ItemDTO.js +1 -1
  42. package/lib/models/RolesPlatform.js +2 -2
  43. package/lib/models/User.d.ts +2 -0
  44. package/lib/models/User.js +4 -1
  45. package/lib/otel/client/OtelClient.d.ts +93 -0
  46. package/lib/otel/client/OtelClient.js +232 -0
  47. package/lib/otel/client/index.d.ts +2 -0
  48. package/lib/otel/client/index.js +5 -0
  49. package/lib/otel/{hooks.d.ts → hooks/index.d.ts} +15 -1
  50. package/lib/otel/{hooks.js → hooks/index.js} +58 -16
  51. package/lib/otel/index.d.ts +29 -20
  52. package/lib/otel/index.js +19 -15
  53. package/lib/otel/{OtelLive.d.ts → views/OtelLive.d.ts} +1 -1
  54. package/lib/otel/{OtelLive.js → views/OtelLive.js} +22 -4
  55. package/lib/otel/{OtelLogsList.d.ts → views/OtelLogsList.d.ts} +1 -1
  56. package/lib/otel/{OtelLogsList.js → views/OtelLogsList.js} +1 -1
  57. package/lib/otel/{OtelMetricsChart.d.ts → views/OtelMetricsChart.d.ts} +1 -1
  58. package/lib/otel/{OtelMetricsList.d.ts → views/OtelMetricsList.d.ts} +1 -1
  59. package/lib/otel/{OtelMetricsList.js → views/OtelMetricsList.js} +1 -1
  60. package/lib/otel/{OtelSearchBar.d.ts → views/OtelSearchBar.d.ts} +1 -1
  61. package/lib/otel/{OtelSpanDetail.d.ts → views/OtelSpanDetail.d.ts} +1 -1
  62. package/lib/otel/{OtelSpanDetail.js → views/OtelSpanDetail.js} +1 -1
  63. package/lib/otel/{OtelSpanTree.d.ts → views/OtelSpanTree.d.ts} +1 -1
  64. package/lib/otel/{OtelSpanTree.js → views/OtelSpanTree.js} +1 -1
  65. package/lib/otel/{OtelSqlView.js → views/OtelSqlView.js} +1 -1
  66. package/lib/otel/{OtelSystemView.js → views/OtelSystemView.js} +1 -1
  67. package/lib/otel/{OtelTimeline.d.ts → views/OtelTimeline.d.ts} +1 -1
  68. package/lib/otel/{OtelTimeline.js → views/OtelTimeline.js} +1 -1
  69. package/lib/otel/{OtelTimelineRangeSlider.d.ts → views/OtelTimelineRangeSlider.d.ts} +1 -1
  70. package/lib/otel/{OtelTracesList.d.ts → views/OtelTracesList.d.ts} +1 -1
  71. package/lib/otel/{OtelTracesList.js → views/OtelTracesList.js} +1 -1
  72. package/lib/otel/views/index.d.ts +20 -0
  73. package/lib/otel/views/index.js +21 -0
  74. package/lib/state/substates/CoreState.js +6 -6
  75. package/lib/utils/Date.d.ts +6 -0
  76. package/lib/utils/Date.js +37 -0
  77. package/lib/views/iam/SignInSimple.d.ts +5 -0
  78. package/lib/views/iam/SignInSimple.js +39 -6
  79. package/lib/views/iam-tokens/IAMTokenEdit.d.ts +5 -1
  80. package/lib/views/iam-tokens/IAMTokenEdit.js +3 -3
  81. package/lib/views/iam-tokens/IAMTokenNew.js +2 -2
  82. package/lib/views/iam-tokens/IAMTokens.d.ts +4 -2
  83. package/lib/views/iam-tokens/IAMTokens.js +4 -4
  84. package/lib/views/index.d.ts +1 -0
  85. package/lib/views/index.js +1 -0
  86. package/lib/views/otel/DashboardView.d.ts +16 -0
  87. package/lib/views/otel/DashboardView.js +4 -0
  88. package/lib/views/otel/LogsView.d.ts +12 -0
  89. package/lib/views/otel/LogsView.js +4 -0
  90. package/lib/views/otel/MetricsView.d.ts +12 -0
  91. package/lib/views/otel/MetricsView.js +4 -0
  92. package/lib/views/otel/OtelHeader.d.ts +33 -0
  93. package/lib/views/otel/OtelHeader.js +105 -0
  94. package/lib/views/otel/SqlView.d.ts +9 -0
  95. package/lib/views/otel/SqlView.js +4 -0
  96. package/lib/views/otel/SystemView.d.ts +9 -0
  97. package/lib/views/otel/SystemView.js +4 -0
  98. package/lib/views/otel/TracesView.d.ts +12 -0
  99. package/lib/views/otel/TracesView.js +4 -0
  100. package/lib/views/otel/index.d.ts +16 -0
  101. package/lib/views/otel/index.js +12 -0
  102. package/lib/views/otel/simpleAuthStore.d.ts +21 -0
  103. package/lib/views/otel/simpleAuthStore.js +22 -0
  104. package/lib/views/profile/UserBadge.d.ts +2 -0
  105. package/lib/views/profile/UserBadge.js +3 -3
  106. package/package.json +1 -26
  107. /package/lib/otel/{OtelMetricsChart.js → views/OtelMetricsChart.js} +0 -0
  108. /package/lib/otel/{OtelSearchBar.js → views/OtelSearchBar.js} +0 -0
  109. /package/lib/otel/{OtelSqlView.d.ts → views/OtelSqlView.d.ts} +0 -0
  110. /package/lib/otel/{OtelSystemView.d.ts → views/OtelSystemView.d.ts} +0 -0
  111. /package/lib/otel/{OtelTimelineRangeSlider.js → views/OtelTimelineRangeSlider.js} +0 -0
@@ -1,4 +1,18 @@
1
- import type { OtelSpan, OtelLog, OtelMetric, OtelQueryRow } from './types';
1
+ import type { OtelSpan, OtelLog, OtelMetric, OtelQueryRow } from '../types';
2
+ /**
3
+ * Register a callback invoked whenever an OTEL API call receives a
4
+ * **401 Unauthorized** response. Typically used to clear auth state
5
+ * (i.e. log the user out) when the token has expired.
6
+ *
7
+ * Pass `null` to unregister.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { setOtelOnUnauthorized } from '@datalayer/core/lib/otel';
12
+ * setOtelOnUnauthorized(() => authStore.getState().clearAuth());
13
+ * ```
14
+ */
15
+ export declare function setOtelOnUnauthorized(cb: (() => void) | null): void;
2
16
  /** Fetch a list of traces / spans from the OTEL service. */
3
17
  export declare function useOtelTraces(options: {
4
18
  token?: string;
@@ -8,9 +8,32 @@
8
8
  * @module otel/hooks
9
9
  */
10
10
  import { useCallback, useEffect, useRef, useState } from 'react';
11
+ import { coreStore } from '../../state/substates/CoreState';
12
+ // ── Global 401 handler ──────────────────────────────────────────────
13
+ let _onUnauthorized = null;
14
+ /**
15
+ * Register a callback invoked whenever an OTEL API call receives a
16
+ * **401 Unauthorized** response. Typically used to clear auth state
17
+ * (i.e. log the user out) when the token has expired.
18
+ *
19
+ * Pass `null` to unregister.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { setOtelOnUnauthorized } from '@datalayer/core/lib/otel';
24
+ * setOtelOnUnauthorized(() => authStore.getState().clearAuth());
25
+ * ```
26
+ */
27
+ export function setOtelOnUnauthorized(cb) {
28
+ _onUnauthorized = cb;
29
+ }
11
30
  /**
12
31
  * Lightweight fetch helper for OTEL API calls.
13
32
  * Uses plain `fetch` to avoid pulling in `@jupyterlab/coreutils` / axios.
33
+ *
34
+ * If the response is **401 Unauthorized** and a global `onUnauthorized`
35
+ * handler has been registered via {@link setOtelOnUnauthorized}, the
36
+ * handler is called before the error is thrown.
14
37
  */
15
38
  async function otelFetch(url, token, options) {
16
39
  const headers = {
@@ -33,6 +56,9 @@ async function otelFetch(url, token, options) {
33
56
  : undefined,
34
57
  });
35
58
  if (!res.ok) {
59
+ if (res.status === 401 && _onUnauthorized) {
60
+ _onUnauthorized();
61
+ }
36
62
  throw new Error(`HTTP ${res.status} ${res.statusText}`);
37
63
  }
38
64
  return res.json();
@@ -162,7 +188,7 @@ function normalizeMetric(raw) {
162
188
  // ── useOtelTraces ───────────────────────────────────────────────────
163
189
  /** Fetch a list of traces / spans from the OTEL service. */
164
190
  export function useOtelTraces(options) {
165
- const { token, baseUrl = '', serviceName, limit = 50, autoRefreshMs, } = options;
191
+ const { token, baseUrl = coreStore.getState().configuration.otelRunUrl, serviceName, limit = 50, autoRefreshMs, } = options;
166
192
  const [traces, setTraces] = useState([]);
167
193
  const [loading, setLoading] = useState(true);
168
194
  const [error, setError] = useState(null);
@@ -219,7 +245,7 @@ export function useOtelTrace(options) {
219
245
  // ── useOtelLogs ─────────────────────────────────────────────────────
220
246
  /** Fetch log records from the OTEL service. */
221
247
  export function useOtelLogs(options) {
222
- const { token, baseUrl = '', serviceName, severity, traceId, limit = 100, autoRefreshMs, } = options;
248
+ const { token, baseUrl = coreStore.getState().configuration.otelRunUrl, serviceName, severity, traceId, limit = 100, autoRefreshMs, } = options;
223
249
  const [logs, setLogs] = useState([]);
224
250
  const [loading, setLoading] = useState(true);
225
251
  const [error, setError] = useState(null);
@@ -256,7 +282,7 @@ export function useOtelLogs(options) {
256
282
  // ── useOtelMetrics ──────────────────────────────────────────────────
257
283
  /** Fetch metrics from the OTEL service. */
258
284
  export function useOtelMetrics(options) {
259
- const { token, baseUrl = '', serviceName, metricName, limit = 50, autoRefreshMs, } = options;
285
+ const { token, baseUrl = coreStore.getState().configuration.otelRunUrl, serviceName, metricName, limit = 50, autoRefreshMs, } = options;
260
286
  const [metrics, setMetrics] = useState([]);
261
287
  const [loading, setLoading] = useState(true);
262
288
  const [error, setError] = useState(null);
@@ -291,22 +317,38 @@ export function useOtelMetrics(options) {
291
317
  // ── useOtelServices ─────────────────────────────────────────────────
292
318
  /** Fetch list of observed service names. */
293
319
  export function useOtelServices(options) {
294
- const { token, baseUrl = '' } = options;
320
+ const { token, baseUrl = coreStore.getState().configuration.otelRunUrl } = options;
295
321
  const [services, setServices] = useState([]);
296
322
  const [loading, setLoading] = useState(true);
297
323
  useEffect(() => {
298
- otelFetch(`${baseUrl}/api/otel/v1/traces/services/list`, token)
324
+ otelFetch(`${baseUrl}/api/otel/v1/traces/services/list/`, token)
299
325
  .then(data => {
300
- // Handle various response shapes:
301
- // { services: ["a","b"] } | { data: [{service_name:"a"},...] } | ["a","b"]
302
- let raw = data.services ?? data.data ?? data;
303
- if (Array.isArray(raw) &&
304
- raw.length > 0 &&
305
- typeof raw[0] === 'object' &&
306
- raw[0] !== null) {
307
- raw = raw.map(r => (r.service_name ?? r.name ?? ''));
308
- }
309
- setServices(Array.isArray(raw) ? raw : []);
326
+ // Accept multiple backend response shapes and normalize to unique names.
327
+ // Examples:
328
+ // { services: ["a","b"] }
329
+ // { data: [{ service_name: "a" }] }
330
+ // { data: [{ service: "a" }] }
331
+ // ["a", "b"]
332
+ // [{ serviceName: "a" }]
333
+ const raw = data.services ?? data.data ?? data;
334
+ const rows = Array.isArray(raw) ? raw : [];
335
+ const names = rows
336
+ .map(row => {
337
+ if (typeof row === 'string') {
338
+ return row.trim();
339
+ }
340
+ if (row && typeof row === 'object') {
341
+ const record = row;
342
+ const value = record.service_name ??
343
+ record.serviceName ??
344
+ record.service ??
345
+ record.name;
346
+ return value == null ? '' : String(value).trim();
347
+ }
348
+ return '';
349
+ })
350
+ .filter(Boolean);
351
+ setServices(Array.from(new Set(names)).sort((a, b) => a.localeCompare(b)));
310
352
  })
311
353
  .catch(() => { })
312
354
  .finally(() => setLoading(false));
@@ -394,7 +436,7 @@ export function useOtelQuery(options) {
394
436
  * @returns `{ connected, error, close }` – reactive connection state.
395
437
  */
396
438
  export function useOtelWebSocket(options) {
397
- const { baseUrl = '', token, autoReconnect = true, reconnectDelayMs = 3000, callbacks, } = options;
439
+ const { baseUrl = coreStore.getState().configuration.otelRunUrl, token, autoReconnect = true, reconnectDelayMs = 3000, callbacks, } = options;
398
440
  const [connected, setConnected] = useState(false);
399
441
  const [error, setError] = useState(null);
400
442
  const wsRef = useRef(null);
@@ -1,25 +1,34 @@
1
1
  /**
2
- * OTEL React components for visualizing OpenTelemetry signals
3
- * (traces, logs, metrics) in a Logfire-inspired Live view.
2
+ * OTEL React components, hooks, and client for visualizing OpenTelemetry
3
+ * signals (traces, logs, metrics) in a Logfire-inspired Live view.
4
+ *
5
+ * Structure:
6
+ * - `types` – shared TypeScript types
7
+ * - `utils` – pure helpers (formatDuration, buildSpanTree, …)
8
+ * - `hooks/` – React hooks that read from Datalayer config by default
9
+ * - `client/`– Typed HTTP client (non-React, reads Datalayer config by default)
10
+ * - `views/` – React view components
4
11
  *
5
12
  * @module otel
6
13
  */
7
14
  export type { OtelSpan, OtelLog, OtelMetric, OtelSpanEvent, OtelSpanLink, SignalType, OtelLiveProps, OtelTracesListProps, OtelSpanDetailProps, OtelTimelineProps, OtelLogsListProps, OtelMetricsListProps, OtelSpanTreeProps, OtelSearchBarProps, OtelTimelineRangeSliderProps, OtelQueryRow, OtelQueryResult, } from './types';
8
- export { useOtelTraces, useOtelTrace, useOtelLogs, useOtelMetrics, useOtelServices, useOtelStats, useOtelQuery, useOtelSystem, useOtelWebSocket, } from './hooks';
9
- export type { OtelWsMessage, OtelWsCallbacks } from './hooks';
10
- export { OtelTimeline } from './OtelTimeline';
11
- export { OtelTracesList } from './OtelTracesList';
12
- export { OtelSpanDetail } from './OtelSpanDetail';
13
- export { OtelSpanTree } from './OtelSpanTree';
14
- export { OtelLogsList } from './OtelLogsList';
15
- export { OtelSearchBar } from './OtelSearchBar';
16
- export { OtelMetricsList } from './OtelMetricsList';
17
- export { OtelMetricsChart } from './OtelMetricsChart';
18
- export type { OtelMetricsChartProps } from './OtelMetricsChart';
19
- export { OtelLive } from './OtelLive';
20
- export { OtelTimelineRangeSlider } from './OtelTimelineRangeSlider';
21
- export { OtelSqlView } from './OtelSqlView';
22
- export type { OtelSqlViewProps } from './OtelSqlView';
23
- export { OtelSystemView } from './OtelSystemView';
24
- export type { OtelSystemViewProps } from './OtelSystemView';
25
- export type { OtelSystemData, OtelSystemProcess, OtelSystemDisk, OtelSystemTable, } from './hooks';
15
+ export { toMs, formatDuration, formatTime, serviceColor, kindColor, severityColor, severityVariant, buildSpanTree, flattenSpanTree, } from './utils';
16
+ export { useOtelTraces, useOtelTrace, useOtelLogs, useOtelMetrics, useOtelServices, useOtelStats, useOtelQuery, useOtelSystem, useOtelWebSocket, setOtelOnUnauthorized, } from './hooks';
17
+ export type { OtelWsMessage, OtelWsCallbacks, OtelSystemData, OtelSystemProcess, OtelSystemDisk, OtelSystemTable, } from './hooks';
18
+ export { OtelClient, createOtelClient } from './client';
19
+ export type { OtelClientOptions, FetchTracesOptions, FetchLogsOptions, FetchMetricsOptions, FetchMetricTotalOptions, } from './client';
20
+ export { OtelLive } from './views';
21
+ export { OtelTracesList } from './views';
22
+ export { OtelSpanDetail } from './views';
23
+ export { OtelSpanTree } from './views';
24
+ export { OtelLogsList } from './views';
25
+ export { OtelSearchBar } from './views';
26
+ export { OtelMetricsList } from './views';
27
+ export { OtelMetricsChart } from './views';
28
+ export type { OtelMetricsChartProps } from './views';
29
+ export { OtelTimeline } from './views';
30
+ export { OtelTimelineRangeSlider } from './views';
31
+ export { OtelSqlView } from './views';
32
+ export type { OtelSqlViewProps } from './views';
33
+ export { OtelSystemView } from './views';
34
+ export type { OtelSystemViewProps } from './views';
package/lib/otel/index.js CHANGED
@@ -2,18 +2,22 @@
2
2
  * Copyright (c) 2023-2025 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- // Hooks
6
- export { useOtelTraces, useOtelTrace, useOtelLogs, useOtelMetrics, useOtelServices, useOtelStats, useOtelQuery, useOtelSystem, useOtelWebSocket, } from './hooks';
7
- // Components
8
- export { OtelTimeline } from './OtelTimeline';
9
- export { OtelTracesList } from './OtelTracesList';
10
- export { OtelSpanDetail } from './OtelSpanDetail';
11
- export { OtelSpanTree } from './OtelSpanTree';
12
- export { OtelLogsList } from './OtelLogsList';
13
- export { OtelSearchBar } from './OtelSearchBar';
14
- export { OtelMetricsList } from './OtelMetricsList';
15
- export { OtelMetricsChart } from './OtelMetricsChart';
16
- export { OtelLive } from './OtelLive';
17
- export { OtelTimelineRangeSlider } from './OtelTimelineRangeSlider';
18
- export { OtelSqlView } from './OtelSqlView';
19
- export { OtelSystemView } from './OtelSystemView';
5
+ // ── Utils ─────────────────────────────────────────────────────────────────────
6
+ export { toMs, formatDuration, formatTime, serviceColor, kindColor, severityColor, severityVariant, buildSpanTree, flattenSpanTree, } from './utils';
7
+ // ── Hooks ─────────────────────────────────────────────────────────────────────
8
+ export { useOtelTraces, useOtelTrace, useOtelLogs, useOtelMetrics, useOtelServices, useOtelStats, useOtelQuery, useOtelSystem, useOtelWebSocket, setOtelOnUnauthorized, } from './hooks';
9
+ // ── Client ────────────────────────────────────────────────────────────────────
10
+ export { OtelClient, createOtelClient } from './client';
11
+ // ── Views ─────────────────────────────────────────────────────────────────────
12
+ export { OtelLive } from './views';
13
+ export { OtelTracesList } from './views';
14
+ export { OtelSpanDetail } from './views';
15
+ export { OtelSpanTree } from './views';
16
+ export { OtelLogsList } from './views';
17
+ export { OtelSearchBar } from './views';
18
+ export { OtelMetricsList } from './views';
19
+ export { OtelMetricsChart } from './views';
20
+ export { OtelTimeline } from './views';
21
+ export { OtelTimelineRangeSlider } from './views';
22
+ export { OtelSqlView } from './views';
23
+ export { OtelSystemView } from './views';
@@ -8,5 +8,5 @@
8
8
  * @module otel/OtelLive
9
9
  */
10
10
  import React from 'react';
11
- import type { OtelLiveProps } from './types';
11
+ import type { OtelLiveProps } from '../types';
12
12
  export declare const OtelLive: React.FC<OtelLiveProps>;
@@ -15,8 +15,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
15
15
  import { useState, useCallback, useMemo, useEffect, useRef, } from 'react';
16
16
  import { Box, Text, Button, Label } from '@primer/react';
17
17
  import { GitBranchIcon, ClockIcon } from '@primer/octicons-react';
18
- import { coreStore } from '../state/substates/CoreState';
19
- import { useOtelTraces, useOtelTrace, useOtelLogs, useOtelMetrics, useOtelServices, useOtelWebSocket, } from './hooks';
18
+ import { coreStore } from '../../state/substates/CoreState';
19
+ import { useOtelTraces, useOtelTrace, useOtelLogs, useOtelMetrics, useOtelServices, useOtelWebSocket, } from '../hooks';
20
20
  import { OtelSearchBar } from './OtelSearchBar';
21
21
  import { OtelTimelineRangeSlider } from './OtelTimelineRangeSlider';
22
22
  import { OtelTracesList } from './OtelTracesList';
@@ -25,7 +25,7 @@ import { OtelMetricsList } from './OtelMetricsList';
25
25
  import { OtelSpanDetail } from './OtelSpanDetail';
26
26
  import { OtelTimeline } from './OtelTimeline';
27
27
  import { OtelSpanTree } from './OtelSpanTree';
28
- import { buildSpanTree } from './utils';
28
+ import { buildSpanTree } from '../utils';
29
29
  // ── Helpers ─────────────────────────────────────────────────────────
30
30
  const BOTTOM_PANE_VIEWS = ['timeline', 'tree'];
31
31
  const HISTOGRAM_BUCKETS = 60;
@@ -116,6 +116,24 @@ export const OtelLive = ({ baseUrl = coreStore.getState().configuration.otelRunU
116
116
  autoRefreshMs,
117
117
  });
118
118
  const { services } = useOtelServices({ baseUrl, token });
119
+ const effectiveServices = useMemo(() => {
120
+ const fromApi = (services ?? []).map(s => s.trim()).filter(Boolean);
121
+ const fromTraces = (traces ?? [])
122
+ .map(s => (s.service_name ?? '').trim())
123
+ .filter(Boolean);
124
+ const fromLogs = (logs ?? [])
125
+ .map(l => (l.service_name ?? '').trim())
126
+ .filter(Boolean);
127
+ const fromMetrics = (metrics ?? [])
128
+ .map(m => (m.service_name ?? '').trim())
129
+ .filter(Boolean);
130
+ const fromSignal = signal === 'traces'
131
+ ? fromTraces
132
+ : signal === 'logs'
133
+ ? fromLogs
134
+ : fromMetrics;
135
+ return Array.from(new Set([...fromApi, ...fromSignal])).sort((a, b) => a.localeCompare(b));
136
+ }, [services, traces, logs, metrics, signal]);
119
137
  // ── WebSocket live updates ──
120
138
  // When a WS message arrives for a signal, refetch the corresponding hook
121
139
  // so the data stays fresh without polling.
@@ -281,7 +299,7 @@ export const OtelLive = ({ baseUrl = coreStore.getState().configuration.otelRunU
281
299
  borderColor: 'border.default',
282
300
  borderRadius: 2,
283
301
  overflow: 'hidden',
284
- }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0 }, children: [_jsx(Box, { sx: { flex: 1 }, children: _jsx(OtelSearchBar, { signal: signal, onSignalChange: setSignal, services: services ?? [], selectedService: service, onServiceChange: setService, query: query, onQueryChange: setQuery, onRefresh: handleRefresh, loading: signal === 'traces'
302
+ }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0 }, children: [_jsx(Box, { sx: { flex: 1 }, children: _jsx(OtelSearchBar, { signal: signal, onSignalChange: setSignal, services: effectiveServices, selectedService: service, onServiceChange: setService, query: query, onQueryChange: setQuery, onRefresh: handleRefresh, loading: signal === 'traces'
285
303
  ? tracesLoading
286
304
  : signal === 'logs'
287
305
  ? logsLoading
@@ -7,5 +7,5 @@
7
7
  * @module otel/OtelLogsList
8
8
  */
9
9
  import React from 'react';
10
- import type { OtelLogsListProps } from './types';
10
+ import type { OtelLogsListProps } from '../types';
11
11
  export declare const OtelLogsList: React.FC<OtelLogsListProps>;
@@ -15,7 +15,7 @@ import React, { useState } from 'react';
15
15
  import { Box, Text, Label, Spinner } from '@primer/react';
16
16
  import { Blankslate } from '@primer/react/experimental';
17
17
  import { LogIcon } from '@primer/octicons-react';
18
- import { formatTime, severityVariant } from './utils';
18
+ import { formatTime, severityVariant } from '../utils';
19
19
  // ── helpers ─────────────────────────────────────────────────────────
20
20
  /** Severity badge using Primer Label, centered in its grid cell. */
21
21
  const Severity = ({ text }) => (_jsx(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: _jsx(Label, { size: "small", variant: severityVariant(text), children: text }) }));
@@ -12,7 +12,7 @@
12
12
  * @module otel/OtelMetricsChart
13
13
  */
14
14
  import React from 'react';
15
- import type { OtelMetric } from './types';
15
+ import type { OtelMetric } from '../types';
16
16
  export interface OtelMetricsChartProps {
17
17
  metrics: OtelMetric[];
18
18
  /** Height per chart panel in px. Default 240. */
@@ -7,7 +7,7 @@
7
7
  * @module otel/OtelMetricsList
8
8
  */
9
9
  import React from 'react';
10
- import type { OtelMetric } from './types';
10
+ import type { OtelMetric } from '../types';
11
11
  export interface OtelMetricsListProps {
12
12
  metrics: OtelMetric[];
13
13
  loading?: boolean;
@@ -15,7 +15,7 @@ import { useMemo, useState } from 'react';
15
15
  import { Box, Text, Label, Spinner, CounterLabel, SegmentedControl, } from '@primer/react';
16
16
  import { Blankslate } from '@primer/react/experimental';
17
17
  import { MeterIcon, ChevronDownIcon, ChevronRightIcon, GraphIcon, TableIcon, } from '@primer/octicons-react';
18
- import { formatTime } from './utils';
18
+ import { formatTime } from '../utils';
19
19
  import { OtelMetricsChart } from './OtelMetricsChart';
20
20
  // ── Helpers ─────────────────────────────────────────────────────────
21
21
  /** Group metrics by metric_name. */
@@ -7,5 +7,5 @@
7
7
  * @module otel/OtelSearchBar
8
8
  */
9
9
  import React from 'react';
10
- import type { OtelSearchBarProps } from './types';
10
+ import type { OtelSearchBarProps } from '../types';
11
11
  export declare const OtelSearchBar: React.FC<OtelSearchBarProps>;
@@ -7,5 +7,5 @@
7
7
  * @module otel/OtelSpanDetail
8
8
  */
9
9
  import React from 'react';
10
- import type { OtelSpanDetailProps } from './types';
10
+ import type { OtelSpanDetailProps } from '../types';
11
11
  export declare const OtelSpanDetail: React.FC<OtelSpanDetailProps>;
@@ -14,7 +14,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  import { useState } from 'react';
15
15
  import { Box, Text, IconButton, UnderlineNav, CounterLabel, Label, } from '@primer/react';
16
16
  import { XIcon, ChevronDownIcon, ChevronRightIcon, } from '@primer/octicons-react';
17
- import { formatDuration, buildSpanTree } from './utils';
17
+ import { formatDuration, buildSpanTree } from '../utils';
18
18
  import { OtelSpanTree } from './OtelSpanTree';
19
19
  // ── Helpers ─────────────────────────────────────────────────────────
20
20
  /** Single key–value metadata row. */
@@ -7,5 +7,5 @@
7
7
  * @module otel/OtelSpanTree
8
8
  */
9
9
  import React from 'react';
10
- import type { OtelSpanTreeProps } from './types';
10
+ import type { OtelSpanTreeProps } from '../types';
11
11
  export declare const OtelSpanTree: React.FC<OtelSpanTreeProps>;
@@ -14,7 +14,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
14
14
  import { useState, useMemo, useCallback } from 'react';
15
15
  import { Box, Text } from '@primer/react';
16
16
  import { ChevronDownIcon, ChevronRightIcon } from '@primer/octicons-react';
17
- import { formatDuration, serviceColor, toMs } from './utils';
17
+ import { formatDuration, serviceColor, toMs } from '../utils';
18
18
  const INDENT_PX = 20;
19
19
  const SpanNode = ({ span, depth, selectedSpanId, onSelectSpan, expandedIds, toggleExpanded, traceMinTime, traceDuration, }) => {
20
20
  const hasChildren = (span.children?.length ?? 0) > 0;
@@ -16,7 +16,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
16
  import { useState, useCallback } from 'react';
17
17
  import { ActionList, ActionMenu, Box, Button, Text, Textarea, Spinner, } from '@primer/react';
18
18
  import { HistoryIcon, TableIcon, XCircleIcon, DownloadIcon, } from '@primer/octicons-react';
19
- import { useOtelQuery } from './hooks';
19
+ import { useOtelQuery } from '../hooks';
20
20
  // ── Cookie helpers ────────────────────────────────────────────────
21
21
  const HISTORY_COOKIE = 'otel_sql_history';
22
22
  const HISTORY_MAX = 10;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Box, Button, Spinner, Text } from '@primer/react';
3
3
  import { SyncIcon } from '@primer/octicons-react';
4
- import { useOtelSystem } from './hooks';
4
+ import { useOtelSystem } from '../hooks';
5
5
  // ── Helpers ───────────────────────────────────────────────────────
6
6
  function fmtBytes(bytes) {
7
7
  if (bytes >= 1024 ** 3)
@@ -7,5 +7,5 @@
7
7
  * @module otel/OtelTimeline
8
8
  */
9
9
  import React from 'react';
10
- import type { OtelTimelineProps } from './types';
10
+ import type { OtelTimelineProps } from '../types';
11
11
  export declare const OtelTimeline: React.FC<OtelTimelineProps>;
@@ -13,7 +13,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  */
14
14
  import { useMemo } from 'react';
15
15
  import { Box, Text } from '@primer/react';
16
- import { toMs, formatDuration, serviceColor } from './utils';
16
+ import { toMs, formatDuration, serviceColor } from '../utils';
17
17
  export const OtelTimeline = ({ spans, barHeight = 24, selectedSpanId, onSelectSpan, }) => {
18
18
  const { minTime, maxTime, sortedSpans } = useMemo(() => {
19
19
  if (spans.length === 0)
@@ -12,5 +12,5 @@
12
12
  * @module otel/OtelTimelineRangeSlider
13
13
  */
14
14
  import React from 'react';
15
- import type { OtelTimelineRangeSliderProps } from './types';
15
+ import type { OtelTimelineRangeSliderProps } from '../types';
16
16
  export declare const OtelTimelineRangeSlider: React.FC<OtelTimelineRangeSliderProps>;
@@ -9,5 +9,5 @@
9
9
  * @module otel/OtelTracesList
10
10
  */
11
11
  import React from 'react';
12
- import type { OtelTracesListProps } from './types';
12
+ import type { OtelTracesListProps } from '../types';
13
13
  export declare const OtelTracesList: React.FC<OtelTracesListProps>;
@@ -17,7 +17,7 @@ import { useMemo, useCallback, useState } from 'react';
17
17
  import { Box, Text, Label, Spinner } from '@primer/react';
18
18
  import { Blankslate } from '@primer/react/experimental';
19
19
  import { TelescopeIcon, ChevronRightIcon, ChevronDownIcon, } from '@primer/octicons-react';
20
- import { formatDuration, formatTime, buildSpanTree } from './utils';
20
+ import { formatDuration, formatTime, buildSpanTree } from '../utils';
21
21
  const GRID_COLS = '140px 1fr 160px 90px';
22
22
  // ── Helpers ─────────────────────────────────────────────────────────
23
23
  /** Extract gen_ai token counts from span attributes. */
@@ -0,0 +1,20 @@
1
+ /**
2
+ * OTEL view components.
3
+ *
4
+ * @module otel/views
5
+ */
6
+ export { OtelLive } from './OtelLive';
7
+ export { OtelTracesList } from './OtelTracesList';
8
+ export { OtelLogsList } from './OtelLogsList';
9
+ export { OtelMetricsList } from './OtelMetricsList';
10
+ export { OtelMetricsChart } from './OtelMetricsChart';
11
+ export type { OtelMetricsChartProps } from './OtelMetricsChart';
12
+ export { OtelSearchBar } from './OtelSearchBar';
13
+ export { OtelSpanDetail } from './OtelSpanDetail';
14
+ export { OtelSpanTree } from './OtelSpanTree';
15
+ export { OtelTimeline } from './OtelTimeline';
16
+ export { OtelTimelineRangeSlider } from './OtelTimelineRangeSlider';
17
+ export { OtelSqlView } from './OtelSqlView';
18
+ export type { OtelSqlViewProps } from './OtelSqlView';
19
+ export { OtelSystemView } from './OtelSystemView';
20
+ export type { OtelSystemViewProps } from './OtelSystemView';
@@ -0,0 +1,21 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * OTEL view components.
7
+ *
8
+ * @module otel/views
9
+ */
10
+ export { OtelLive } from './OtelLive';
11
+ export { OtelTracesList } from './OtelTracesList';
12
+ export { OtelLogsList } from './OtelLogsList';
13
+ export { OtelMetricsList } from './OtelMetricsList';
14
+ export { OtelMetricsChart } from './OtelMetricsChart';
15
+ export { OtelSearchBar } from './OtelSearchBar';
16
+ export { OtelSpanDetail } from './OtelSpanDetail';
17
+ export { OtelSpanTree } from './OtelSpanTree';
18
+ export { OtelTimeline } from './OtelTimeline';
19
+ export { OtelTimelineRangeSlider } from './OtelTimelineRangeSlider';
20
+ export { OtelSqlView } from './OtelSqlView';
21
+ export { OtelSystemView } from './OtelSystemView';
@@ -17,7 +17,7 @@ let initialConfiguration = {
17
17
  loadConfigurationFromServer: true,
18
18
  jupyterServerless: false,
19
19
  iamRunUrl: 'https://prod1.datalayer.run',
20
- runtimesRunUrl: 'https://prod1.datalayer.run',
20
+ runtimesRunUrl: 'https://r1.datalayer.run',
21
21
  libraryRunUrl: 'https://prod1.datalayer.run',
22
22
  spacerRunUrl: 'https://prod1.datalayer.run',
23
23
  aiagentsRunUrl: 'https://prod1.datalayer.run',
@@ -40,11 +40,11 @@ let initialConfiguration = {
40
40
  logoUrl: 'https://assets.datalayer.tech/datalayer-25.svg',
41
41
  logoSquareUrl: 'https://assets.datalayer.tech/datalayer-square.png',
42
42
  copyright: '© 2025 Datalayer, Inc',
43
- docsUrl: 'https://docs.datalayer.app',
44
- supportUrl: 'https://datalayer.app/support',
45
- termsUrl: 'https://datalayer.app/terms',
46
- pricingUrl: 'https://datalayer.app/pricing',
47
- privacyUrl: 'https://datalayer.app/privacy',
43
+ docsUrl: 'https://docs.datalayer.ai',
44
+ supportUrl: 'https://datalayer.ai/support',
45
+ termsUrl: 'https://datalayer.ai/terms',
46
+ pricingUrl: 'https://datalayer.ai/pricing',
47
+ privacyUrl: 'https://datalayer.ai/privacy',
48
48
  },
49
49
  };
50
50
  // Try loading initial state from datalayer-config-data element
@@ -1,2 +1,8 @@
1
1
  export declare const getRelativeTime: (d1: Date, d2?: Date) => string;
2
2
  export declare const timeSince: (date: Date) => string;
3
+ /**
4
+ * Format a timestamp into a compact relative string.
5
+ *
6
+ * Examples: "just now", "15m ago", "3h ago", "2d ago", "4w ago", "1y ago".
7
+ */
8
+ export declare const formatRelativeTime: (value?: Date | string | number, now?: Date) => string | undefined;
package/lib/utils/Date.js CHANGED
@@ -58,3 +58,40 @@ export const timeSince = (date) => {
58
58
  const i = Math.floor(interval);
59
59
  return i + ` second${p(i)}`;
60
60
  };
61
+ /**
62
+ * Format a timestamp into a compact relative string.
63
+ *
64
+ * Examples: "just now", "15m ago", "3h ago", "2d ago", "4w ago", "1y ago".
65
+ */
66
+ export const formatRelativeTime = (value, now = new Date()) => {
67
+ if (value === undefined || value === null) {
68
+ return undefined;
69
+ }
70
+ const date = value instanceof Date
71
+ ? value
72
+ : typeof value === 'number'
73
+ ? new Date(value)
74
+ : new Date(value);
75
+ const ts = date.getTime();
76
+ if (Number.isNaN(ts)) {
77
+ return typeof value === 'string' ? value : undefined;
78
+ }
79
+ const diffMs = Math.max(0, now.getTime() - ts);
80
+ const seconds = Math.floor(diffMs / 1000);
81
+ if (seconds < 60)
82
+ return 'just now';
83
+ const minutes = Math.floor(seconds / 60);
84
+ if (minutes < 60)
85
+ return `${minutes}m ago`;
86
+ const hours = Math.floor(minutes / 60);
87
+ if (hours < 24)
88
+ return `${hours}h ago`;
89
+ const days = Math.floor(hours / 24);
90
+ if (days < 7)
91
+ return `${days}d ago`;
92
+ const weeks = Math.floor(days / 7);
93
+ if (weeks < 52)
94
+ return `${weeks}w ago`;
95
+ const years = Math.floor(days / 365);
96
+ return `${years}y ago`;
97
+ };
@@ -14,6 +14,11 @@ export interface SignInSimpleProps {
14
14
  * Typically used to store credentials in a Zustand / context store.
15
15
  */
16
16
  onSignIn: (token: string, handle: string) => void;
17
+ /**
18
+ * Called when the user authenticates with an API key.
19
+ * If not provided the "Sign in with API Key" button is hidden.
20
+ */
21
+ onApiKeySignIn?: (apiKey: string) => void;
17
22
  /**
18
23
  * Login endpoint. Defaults to `/api/iam/v1/login`.
19
24
  * The endpoint must accept `POST { handle, password }` and return