@localstack/appinspector-ui 1.0.0-dev-3f04a06e → 1.0.0-dev-a1ff335f

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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/pages/spans-list-page.tsx
2
- import { Box as Box5 } from "@mui/material";
3
- import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
2
+ import { Box as Box6 } from "@mui/material";
3
+ import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
4
4
  import { useNavigate } from "react-router-dom";
5
5
 
6
6
  // src/api/use-api.tsx
@@ -2845,24 +2845,298 @@ var SpansList = (props) => {
2845
2845
  ] });
2846
2846
  };
2847
2847
 
2848
- // src/context.tsx
2849
- import { createContext as createContext2, useContext as useContext2 } from "react";
2850
- import { useCallback as useCallback2, useMemo as useMemo3 } from "react";
2848
+ // src/components/status-message/status-message.tsx
2849
+ import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
2850
+ import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
2851
+ import { Alert as Alert2, AlertTitle, Box as Box5, Button as Button3, Link, Typography as Typography3 } from "@mui/material";
2852
+
2853
+ // src/api/errors.ts
2854
+ var AppInspectorNotFoundError = class extends Error {
2855
+ constructor(message, cause) {
2856
+ super(message);
2857
+ this.name = "AppInspectorNotFoundError";
2858
+ this.cause = cause;
2859
+ }
2860
+ };
2861
+ var ConnectionError = class extends Error {
2862
+ constructor(message, cause) {
2863
+ super(message);
2864
+ this.name = "ConnectionError";
2865
+ this.cause = cause;
2866
+ }
2867
+ };
2851
2868
 
2852
2869
  // src/config.ts
2853
2870
  var APPINSPECTOR_API_PREFIX = "/_localstack/appinspector";
2854
2871
  var API_VERSION = "v1";
2855
2872
  var API_ENDPOINTS = {
2873
+ ROOT: "/",
2856
2874
  SPANS: "/traces/*/spans",
2875
+ STATUS: "/status",
2857
2876
  TRACES: "/traces"
2858
2877
  };
2859
- var getApiEndpoint = (endpoint) => {
2878
+ var getApiV1Endpoint = (endpoint) => {
2860
2879
  return `/${API_VERSION}${endpoint}`;
2861
2880
  };
2881
+ var getApiEndpoint = (endpoint) => {
2882
+ if (endpoint === API_ENDPOINTS.ROOT || endpoint === API_ENDPOINTS.STATUS) {
2883
+ return endpoint;
2884
+ }
2885
+ return getApiV1Endpoint(endpoint);
2886
+ };
2862
2887
  var getAppInspectorApiUrl = (localstackEndpoint, endpoint) => {
2863
2888
  return `${localstackEndpoint}${APPINSPECTOR_API_PREFIX}${getApiEndpoint(endpoint)}`;
2864
2889
  };
2865
2890
 
2891
+ // src/components/status-message/status-message.tsx
2892
+ import { jsx as jsx126, jsxs as jsxs122 } from "react/jsx-runtime";
2893
+ var StatusMessage = ({
2894
+ error,
2895
+ onRetry,
2896
+ status
2897
+ }) => {
2898
+ if (error instanceof AppInspectorNotFoundError) {
2899
+ return /* @__PURE__ */ jsx126(
2900
+ Box5,
2901
+ {
2902
+ sx: {
2903
+ alignItems: "center",
2904
+ display: "flex",
2905
+ flexDirection: "column",
2906
+ gap: 2,
2907
+ justifyContent: "center",
2908
+ p: 4
2909
+ },
2910
+ children: /* @__PURE__ */ jsxs122(
2911
+ Alert2,
2912
+ {
2913
+ icon: /* @__PURE__ */ jsx126(ErrorOutlineIcon, { fontSize: "large" }),
2914
+ severity: "error",
2915
+ sx: { maxWidth: 600, width: "100%" },
2916
+ children: [
2917
+ /* @__PURE__ */ jsx126(AlertTitle, { sx: { fontWeight: "bold" }, children: "App Inspector Not Available" }),
2918
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 2 }, variant: "body2", children: "The App Inspector extension is not licensed or not enabled in LocalStack." }),
2919
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1 }, variant: "body2", children: /* @__PURE__ */ jsx126("strong", { children: "To enable App Inspector:" }) }),
2920
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1 }, variant: "body2", children: "Set the environment variable and restart LocalStack:" }),
2921
+ /* @__PURE__ */ jsx126(
2922
+ Box5,
2923
+ {
2924
+ component: "pre",
2925
+ sx: {
2926
+ backgroundColor: "rgba(0, 0, 0, 0.05)",
2927
+ borderRadius: 1,
2928
+ fontSize: "0.875rem",
2929
+ p: 1
2930
+ },
2931
+ children: "APPINSPECTOR=1"
2932
+ }
2933
+ ),
2934
+ /* @__PURE__ */ jsxs122(Typography3, { sx: { fontStyle: "italic", mb: 1, mt: 2 }, variant: "body2", children: [
2935
+ "Runtime changes can be made via endpoint",
2936
+ " ",
2937
+ /* @__PURE__ */ jsxs122("code", { children: [
2938
+ APPINSPECTOR_API_PREFIX,
2939
+ "/status"
2940
+ ] }),
2941
+ ". For persistent default state across restarts, adjust the",
2942
+ /* @__PURE__ */ jsx126("code", { children: "APPINSPECTOR" }),
2943
+ " ",
2944
+ "environment variable."
2945
+ ] }),
2946
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1, mt: 2 }, variant: "body2", children: /* @__PURE__ */ jsx126("strong", { children: "For more information:" }) }),
2947
+ /* @__PURE__ */ jsx126(
2948
+ Link,
2949
+ {
2950
+ href: "https://docs.localstack.cloud/user-guide/tools/application-inspector/",
2951
+ rel: "noopener noreferrer",
2952
+ target: "_blank",
2953
+ children: "App Inspector Documentation"
2954
+ }
2955
+ ),
2956
+ onRetry && /* @__PURE__ */ jsx126(Box5, { sx: { display: "flex", justifyContent: "flex-start", mt: 2 }, children: /* @__PURE__ */ jsx126(
2957
+ Button3,
2958
+ {
2959
+ "aria-label": "Check App Inspector status again",
2960
+ onClick: onRetry,
2961
+ variant: "outlined",
2962
+ children: "Check Again"
2963
+ }
2964
+ ) })
2965
+ ]
2966
+ }
2967
+ )
2968
+ }
2969
+ );
2970
+ }
2971
+ if (error instanceof ConnectionError) {
2972
+ return /* @__PURE__ */ jsx126(
2973
+ Box5,
2974
+ {
2975
+ sx: {
2976
+ alignItems: "center",
2977
+ display: "flex",
2978
+ flexDirection: "column",
2979
+ gap: 2,
2980
+ justifyContent: "center",
2981
+ p: 4
2982
+ },
2983
+ children: /* @__PURE__ */ jsxs122(
2984
+ Alert2,
2985
+ {
2986
+ icon: /* @__PURE__ */ jsx126(ErrorOutlineIcon, { fontSize: "large" }),
2987
+ severity: "error",
2988
+ sx: { maxWidth: 600, width: "100%" },
2989
+ children: [
2990
+ /* @__PURE__ */ jsx126(AlertTitle, { sx: { fontWeight: "bold" }, children: "Connection Error" }),
2991
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 2 }, variant: "body2", children: "Failed to connect to LocalStack. Please ensure LocalStack is running and accessible." }),
2992
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1 }, variant: "body2", children: /* @__PURE__ */ jsx126("strong", { children: "To start LocalStack:" }) }),
2993
+ /* @__PURE__ */ jsx126(
2994
+ Box5,
2995
+ {
2996
+ component: "pre",
2997
+ sx: {
2998
+ backgroundColor: "rgba(0, 0, 0, 0.05)",
2999
+ borderRadius: 1,
3000
+ fontSize: "0.875rem",
3001
+ p: 1
3002
+ },
3003
+ children: "localstack start"
3004
+ }
3005
+ ),
3006
+ onRetry && /* @__PURE__ */ jsx126(Box5, { sx: { display: "flex", justifyContent: "flex-start", mt: 2 }, children: /* @__PURE__ */ jsx126(
3007
+ Button3,
3008
+ {
3009
+ "aria-label": "Retry connection to LocalStack",
3010
+ onClick: onRetry,
3011
+ variant: "outlined",
3012
+ children: "Retry Connection"
3013
+ }
3014
+ ) })
3015
+ ]
3016
+ }
3017
+ )
3018
+ }
3019
+ );
3020
+ }
3021
+ if (status?.status === "DISABLED") {
3022
+ return /* @__PURE__ */ jsx126(
3023
+ Box5,
3024
+ {
3025
+ sx: {
3026
+ alignItems: "center",
3027
+ display: "flex",
3028
+ flexDirection: "column",
3029
+ gap: 2,
3030
+ justifyContent: "center",
3031
+ p: 4
3032
+ },
3033
+ children: /* @__PURE__ */ jsxs122(
3034
+ Alert2,
3035
+ {
3036
+ icon: /* @__PURE__ */ jsx126(InfoOutlinedIcon, { fontSize: "large" }),
3037
+ severity: "warning",
3038
+ sx: { maxWidth: 600, width: "100%" },
3039
+ children: [
3040
+ /* @__PURE__ */ jsx126(AlertTitle, { sx: { fontWeight: "bold" }, children: "App Inspector is Disabled" }),
3041
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 2 }, variant: "body2", children: "App Inspector is currently disabled. Please enable it to view traces and spans." }),
3042
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1 }, variant: "body2", children: /* @__PURE__ */ jsx126("strong", { children: "To enable App Inspector at runtime:" }) }),
3043
+ /* @__PURE__ */ jsx126(
3044
+ Box5,
3045
+ {
3046
+ component: "pre",
3047
+ sx: {
3048
+ backgroundColor: "rgba(0, 0, 0, 0.05)",
3049
+ borderRadius: 1,
3050
+ fontSize: "0.875rem",
3051
+ overflowX: "auto",
3052
+ p: 1
3053
+ },
3054
+ children: `curl -X PUT http://localhost:4566${APPINSPECTOR_API_PREFIX}/status \\
3055
+ -H "Content-Type: application/json" \\
3056
+ -d '{"status": "ENABLED"}'`
3057
+ }
3058
+ ),
3059
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1, mt: 2 }, variant: "body2", children: /* @__PURE__ */ jsx126("strong", { children: "To enable App Inspector persistently across restarts:" }) }),
3060
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 1 }, variant: "body2", children: "Set the environment variable:" }),
3061
+ /* @__PURE__ */ jsx126(
3062
+ Box5,
3063
+ {
3064
+ component: "pre",
3065
+ sx: {
3066
+ backgroundColor: "rgba(0, 0, 0, 0.05)",
3067
+ borderRadius: 1,
3068
+ fontSize: "0.875rem",
3069
+ p: 1
3070
+ },
3071
+ children: "APPINSPECTOR=1"
3072
+ }
3073
+ ),
3074
+ Boolean(status.note) && /* @__PURE__ */ jsx126(Typography3, { sx: { display: "block", fontStyle: "italic", mt: 2 }, variant: "caption", children: status.note }),
3075
+ onRetry && /* @__PURE__ */ jsx126(Box5, { sx: { display: "flex", justifyContent: "flex-start", mt: 2 }, children: /* @__PURE__ */ jsx126(
3076
+ Button3,
3077
+ {
3078
+ "aria-label": "Check if App Inspector is enabled",
3079
+ onClick: onRetry,
3080
+ variant: "outlined",
3081
+ children: "Check Status Again"
3082
+ }
3083
+ ) })
3084
+ ]
3085
+ }
3086
+ )
3087
+ }
3088
+ );
3089
+ }
3090
+ if (error) {
3091
+ return /* @__PURE__ */ jsx126(
3092
+ Box5,
3093
+ {
3094
+ sx: {
3095
+ alignItems: "center",
3096
+ display: "flex",
3097
+ flexDirection: "column",
3098
+ gap: 2,
3099
+ justifyContent: "center",
3100
+ p: 4
3101
+ },
3102
+ children: /* @__PURE__ */ jsxs122(
3103
+ Alert2,
3104
+ {
3105
+ icon: /* @__PURE__ */ jsx126(ErrorOutlineIcon, { fontSize: "large" }),
3106
+ severity: "error",
3107
+ sx: { maxWidth: 600, width: "100%" },
3108
+ children: [
3109
+ /* @__PURE__ */ jsx126(AlertTitle, { sx: { fontWeight: "bold" }, children: "Error" }),
3110
+ /* @__PURE__ */ jsx126(Typography3, { sx: { mb: 2 }, variant: "body2", children: error.message }),
3111
+ onRetry && /* @__PURE__ */ jsx126(Box5, { sx: { display: "flex", justifyContent: "flex-start", mt: 2 }, children: /* @__PURE__ */ jsx126(
3112
+ Button3,
3113
+ {
3114
+ "aria-label": "Retry operation",
3115
+ onClick: onRetry,
3116
+ variant: "outlined",
3117
+ children: "Retry"
3118
+ }
3119
+ ) })
3120
+ ]
3121
+ }
3122
+ )
3123
+ }
3124
+ );
3125
+ }
3126
+ return;
3127
+ };
3128
+
3129
+ // src/context.tsx
3130
+ import { createContext as createContext2, useContext as useContext2 } from "react";
3131
+ import { useCallback as useCallback2, useMemo as useMemo3 } from "react";
3132
+
3133
+ // src/constants/error-messages.ts
3134
+ var ERROR_MESSAGES = {
3135
+ APP_INSPECTOR_DISABLED: "App Inspector is currently disabled.",
3136
+ APP_INSPECTOR_NOT_FOUND: "App Inspector extension not found. Please ensure App Inspector is licensed and enabled.",
3137
+ CONNECTION_FAILED: "Failed to connect to LocalStack. Please ensure LocalStack is running and accessible."
3138
+ };
3139
+
2866
3140
  // src/api/client.ts
2867
3141
  var apiLogger = createScopedLogger("API");
2868
3142
  var makeRequest = async (options) => {
@@ -2876,10 +3150,23 @@ var makeRequest = async (options) => {
2876
3150
  headers
2877
3151
  });
2878
3152
  if (!response.ok) {
3153
+ if (response.status === 404) {
3154
+ throw new AppInspectorNotFoundError(
3155
+ ERROR_MESSAGES.APP_INSPECTOR_NOT_FOUND,
3156
+ new Error(`404 from ${url}: ${response.statusText}`)
3157
+ );
3158
+ }
2879
3159
  throw new Error(`API request failed: ${response.status.toString()} ${response.statusText}`);
2880
3160
  }
2881
3161
  return await response.json();
2882
3162
  } catch (error) {
3163
+ if (error instanceof TypeError) {
3164
+ const message = error.message.toLowerCase();
3165
+ const isNetworkError = message.includes("fetch") || message.includes("network") || message.includes("failed to fetch");
3166
+ if (isNetworkError) {
3167
+ throw new ConnectionError(ERROR_MESSAGES.CONNECTION_FAILED, error);
3168
+ }
3169
+ }
2883
3170
  if (error instanceof Error) {
2884
3171
  throw error;
2885
3172
  }
@@ -2919,12 +3206,18 @@ var createApiClient = ({ localstackEndpoint }) => {
2919
3206
  getSpans: async (request) => {
2920
3207
  const endpoint = buildSpansEndpoint(request);
2921
3208
  return makeRequest({ endpoint, localstackEndpoint });
3209
+ },
3210
+ getStatus: async () => {
3211
+ return makeRequest({
3212
+ endpoint: API_ENDPOINTS.STATUS,
3213
+ localstackEndpoint
3214
+ });
2922
3215
  }
2923
3216
  };
2924
3217
  };
2925
3218
 
2926
3219
  // src/context.tsx
2927
- import { jsx as jsx126 } from "react/jsx-runtime";
3220
+ import { jsx as jsx127 } from "react/jsx-runtime";
2928
3221
  var AppInspectorContext = createContext2(void 0);
2929
3222
  var useAppInspector = () => {
2930
3223
  const context = useContext2(AppInspectorContext);
@@ -2937,7 +3230,7 @@ var AppInspectorContextProvider = (props) => {
2937
3230
  const api = useMemo3(() => {
2938
3231
  return false ? createApiClientMock() : createApiClient({ localstackEndpoint: props.localstackEndpoint });
2939
3232
  }, [props.localstackEndpoint]);
2940
- return /* @__PURE__ */ jsx126(ApiProvider, { api, children: /* @__PURE__ */ jsx126(
3233
+ return /* @__PURE__ */ jsx127(ApiProvider, { api, children: /* @__PURE__ */ jsx127(
2941
3234
  AppInspectorContext.Provider,
2942
3235
  {
2943
3236
  value: {
@@ -2961,17 +3254,60 @@ var AppInspectorContextProvider = (props) => {
2961
3254
  ) });
2962
3255
  };
2963
3256
 
3257
+ // src/hooks/use-status.tsx
3258
+ import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
3259
+ var useStatus = () => {
3260
+ const api = useAppInspectorApi();
3261
+ const [checking, setChecking] = useState3(true);
3262
+ const [status, setStatus] = useState3();
3263
+ const [error, setError] = useState3();
3264
+ const hasFetchedReference = useRef2(false);
3265
+ const abortControllerReference = useRef2(null);
3266
+ const checkStatus = useCallback3(async () => {
3267
+ if (abortControllerReference.current) {
3268
+ abortControllerReference.current.abort();
3269
+ }
3270
+ const abortController = new AbortController();
3271
+ abortControllerReference.current = abortController;
3272
+ setChecking(true);
3273
+ try {
3274
+ const response = await api.getStatus();
3275
+ if (!abortController.signal.aborted) {
3276
+ setStatus(response);
3277
+ setError(void 0);
3278
+ }
3279
+ } catch (error_) {
3280
+ if (!abortController.signal.aborted) {
3281
+ setError(error_ instanceof Error ? error_ : new Error("Unknown error"));
3282
+ setStatus(void 0);
3283
+ }
3284
+ } finally {
3285
+ if (!abortController.signal.aborted) {
3286
+ setChecking(false);
3287
+ }
3288
+ }
3289
+ }, [api]);
3290
+ useEffect2(() => {
3291
+ if (!hasFetchedReference.current) {
3292
+ hasFetchedReference.current = true;
3293
+ void checkStatus();
3294
+ }
3295
+ }, [checkStatus]);
3296
+ return { checking, checkStatus, error, status };
3297
+ };
3298
+
2964
3299
  // src/pages/spans-list-page.tsx
2965
- import { jsx as jsx127 } from "react/jsx-runtime";
3300
+ import { jsx as jsx128 } from "react/jsx-runtime";
2966
3301
  var MAX_WIDTH = 1400;
2967
3302
  var SpansListPage = () => {
2968
3303
  const api = useAppInspectorApi();
2969
- const [spans, setSpans] = useState3();
2970
- const [loading, setLoading] = useState3(false);
2971
- const hasFetched = useRef2(false);
2972
- const [filterWriteOperations, setFilterWriteOperations] = useState3(true);
2973
- const [fetchError, setFetchError] = useState3();
2974
- const fetchSpans = useCallback3(async () => {
3304
+ const [spans, setSpans] = useState4();
3305
+ const [loading, setLoading] = useState4(false);
3306
+ const hasFetched = useRef3(false);
3307
+ const [filterWriteOperations, setFilterWriteOperations] = useState4(true);
3308
+ const [fetchError, setFetchError] = useState4();
3309
+ const { checkStatus, error: statusError, status } = useStatus();
3310
+ const fetchSpans = useCallback4(async () => {
2975
3311
  setLoading(true);
2976
3312
  try {
2977
3313
  const response = await api.getSpans({
@@ -2987,25 +3323,26 @@ var SpansListPage = () => {
2987
3323
  setLoading(false);
2988
3324
  }
2989
3325
  }, [api, filterWriteOperations]);
2990
- const fetchSpansSync = useCallback3(() => {
3326
+ const fetchSpansSync = useCallback4(() => {
2991
3327
  void fetchSpans();
2992
3328
  }, [fetchSpans]);
2993
- useEffect2(() => {
3329
+ useEffect3(() => {
2994
3330
  if (hasFetched.current) return;
3331
+ if (status?.status !== "ENABLED") return;
2995
3332
  hasFetched.current = true;
2996
3333
  void fetchSpans();
2997
- }, [fetchSpans]);
2998
- useEffect2(() => {
3334
+ }, [fetchSpans, status]);
3335
+ useEffect3(() => {
2999
3336
  if (!hasFetched.current) return;
3000
3337
  void fetchSpans();
3001
3338
  }, [fetchSpans]);
3002
3339
  const navigate = useNavigate();
3003
3340
  const { resolveLink } = useAppInspector();
3004
- const navigateToSpan = useCallback3((span) => {
3341
+ const navigateToSpan = useCallback4((span) => {
3005
3342
  const url = resolveLink({ to: "trace-graph", traceId: span.trace_id });
3006
3343
  navigate(`${url}?spanId=${span.span_id}`);
3007
3344
  }, [navigate, resolveLink]);
3008
- const clearSpans = useCallback3(async () => {
3345
+ const clearSpans = useCallback4(async () => {
3009
3346
  setLoading(true);
3010
3347
  try {
3011
3348
  await api.deleteSpans();
@@ -3019,8 +3356,12 @@ var SpansListPage = () => {
3019
3356
  setLoading(false);
3020
3357
  }
3021
3358
  }, [api, fetchSpans]);
3022
- return /* @__PURE__ */ jsx127(
3023
- Box5,
3359
+ const handleRetry = useCallback4(() => {
3360
+ void checkStatus();
3361
+ }, [checkStatus]);
3362
+ const shouldShowStatusMessage = Boolean(statusError) || status?.status === "DISABLED";
3363
+ return /* @__PURE__ */ jsx128(
3364
+ Box6,
3024
3365
  {
3025
3366
  "data-testid": "spans-list-page",
3026
3367
  sx: {
@@ -3030,8 +3371,8 @@ var SpansListPage = () => {
3030
3371
  height: "100vh",
3031
3372
  width: "100%"
3032
3373
  },
3033
- children: /* @__PURE__ */ jsx127(
3034
- Box5,
3374
+ children: /* @__PURE__ */ jsx128(
3375
+ Box6,
3035
3376
  {
3036
3377
  sx: {
3037
3378
  display: "flex",
@@ -3040,7 +3381,14 @@ var SpansListPage = () => {
3040
3381
  maxWidth: MAX_WIDTH,
3041
3382
  width: "100%"
3042
3383
  },
3043
- children: /* @__PURE__ */ jsx127(
3384
+ children: shouldShowStatusMessage ? /* @__PURE__ */ jsx128(
3385
+ StatusMessage,
3386
+ {
3387
+ error: statusError,
3388
+ onRetry: handleRetry,
3389
+ status
3390
+ }
3391
+ ) : /* @__PURE__ */ jsx128(
3044
3392
  SpansList,
3045
3393
  {
3046
3394
  filterWriteOperations,
@@ -3070,22 +3418,22 @@ var SpansListPage = () => {
3070
3418
  };
3071
3419
 
3072
3420
  // src/pages/trace-graph.tsx
3073
- import { Box as Box11, Drawer, Paper as Paper2 } from "@mui/material";
3421
+ import { Box as Box12, Drawer, Paper as Paper2 } from "@mui/material";
3074
3422
  import { styled } from "@mui/material/styles";
3075
3423
  import { ReactFlowProvider } from "@xyflow/react";
3076
- import { useCallback as useCallback6, useEffect as useEffect4, useState as useState6 } from "react";
3424
+ import { useCallback as useCallback7, useEffect as useEffect5, useState as useState7 } from "react";
3077
3425
  import { useParams, useSearchParams } from "react-router-dom";
3078
3426
 
3079
3427
  // src/components/event-details/event-details.tsx
3080
- import { Box as Box8, Chip, Divider, Stack, Typography as Typography5 } from "@mui/material";
3428
+ import { Box as Box9, Chip, Divider, Stack, Typography as Typography6 } from "@mui/material";
3081
3429
 
3082
3430
  // src/components/event-details/event-details-header.tsx
3083
3431
  import { Close } from "@mui/icons-material";
3084
- import { Box as Box6, IconButton, Typography as Typography3 } from "@mui/material";
3085
- import { jsx as jsx128, jsxs as jsxs122 } from "react/jsx-runtime";
3432
+ import { Box as Box7, IconButton, Typography as Typography4 } from "@mui/material";
3433
+ import { jsx as jsx129, jsxs as jsxs123 } from "react/jsx-runtime";
3086
3434
  var EventDetailsHeader = ({ event, onClose }) => {
3087
- return /* @__PURE__ */ jsxs122(
3088
- Box6,
3435
+ return /* @__PURE__ */ jsxs123(
3436
+ Box7,
3089
3437
  {
3090
3438
  sx: {
3091
3439
  alignItems: "center",
@@ -3096,16 +3444,16 @@ var EventDetailsHeader = ({ event, onClose }) => {
3096
3444
  p: 2
3097
3445
  },
3098
3446
  children: [
3099
- /* @__PURE__ */ jsxs122(Box6, { children: [
3100
- /* @__PURE__ */ jsx128(Typography3, { sx: { fontWeight: 600 }, variant: "h6", children: "Event Details" }),
3101
- /* @__PURE__ */ jsxs122(Typography3, { color: "text.secondary", variant: "body2", children: [
3447
+ /* @__PURE__ */ jsxs123(Box7, { children: [
3448
+ /* @__PURE__ */ jsx129(Typography4, { sx: { fontWeight: 600 }, variant: "h6", children: "Event Details" }),
3449
+ /* @__PURE__ */ jsxs123(Typography4, { color: "text.secondary", variant: "body2", children: [
3102
3450
  event.service_name,
3103
3451
  " ",
3104
3452
  "-",
3105
3453
  event.operation_name
3106
3454
  ] })
3107
3455
  ] }),
3108
- onClose && /* @__PURE__ */ jsx128(IconButton, { onClick: onClose, size: "small", children: /* @__PURE__ */ jsx128(Close, {}) })
3456
+ onClose && /* @__PURE__ */ jsx129(IconButton, { onClick: onClose, size: "small", children: /* @__PURE__ */ jsx129(Close, {}) })
3109
3457
  ]
3110
3458
  }
3111
3459
  );
@@ -3113,14 +3461,14 @@ var EventDetailsHeader = ({ event, onClose }) => {
3113
3461
 
3114
3462
  // src/components/event-details/toggle-section.tsx
3115
3463
  import { KeyboardArrowDown, KeyboardArrowRight } from "@mui/icons-material";
3116
- import { Box as Box7, Typography as Typography4 } from "@mui/material";
3117
- import { useState as useState4 } from "react";
3118
- import { jsx as jsx129, jsxs as jsxs123 } from "react/jsx-runtime";
3464
+ import { Box as Box8, Typography as Typography5 } from "@mui/material";
3465
+ import { useState as useState5 } from "react";
3466
+ import { jsx as jsx130, jsxs as jsxs124 } from "react/jsx-runtime";
3119
3467
  var ToggleSection = ({ children, headline, initialOpen = true }) => {
3120
- const [isOpen, setIsOpen] = useState4(initialOpen);
3121
- return /* @__PURE__ */ jsxs123(Box7, { sx: { mt: 4 }, children: [
3122
- /* @__PURE__ */ jsx129(
3123
- Box7,
3468
+ const [isOpen, setIsOpen] = useState5(initialOpen);
3469
+ return /* @__PURE__ */ jsxs124(Box8, { sx: { mt: 4 }, children: [
3470
+ /* @__PURE__ */ jsx130(
3471
+ Box8,
3124
3472
  {
3125
3473
  onClick: () => {
3126
3474
  setIsOpen(!isOpen);
@@ -3129,8 +3477,8 @@ var ToggleSection = ({ children, headline, initialOpen = true }) => {
3129
3477
  cursor: "pointer",
3130
3478
  mb: 1
3131
3479
  },
3132
- children: /* @__PURE__ */ jsxs123(
3133
- Box7,
3480
+ children: /* @__PURE__ */ jsxs124(
3481
+ Box8,
3134
3482
  {
3135
3483
  role: "button",
3136
3484
  sx: {
@@ -3139,73 +3487,73 @@ var ToggleSection = ({ children, headline, initialOpen = true }) => {
3139
3487
  gap: 1
3140
3488
  },
3141
3489
  children: [
3142
- /* @__PURE__ */ jsx129(Typography4, { sx: { fontWeight: 600 }, variant: "subtitle2", children: headline }),
3143
- isOpen ? /* @__PURE__ */ jsx129(KeyboardArrowDown, { sx: { color: "text.secondary", height: 20, width: 20 } }) : /* @__PURE__ */ jsx129(KeyboardArrowRight, { sx: { color: "text.secondary", height: 20, width: 20 } })
3490
+ /* @__PURE__ */ jsx130(Typography5, { sx: { fontWeight: 600 }, variant: "subtitle2", children: headline }),
3491
+ isOpen ? /* @__PURE__ */ jsx130(KeyboardArrowDown, { sx: { color: "text.secondary", height: 20, width: 20 } }) : /* @__PURE__ */ jsx130(KeyboardArrowRight, { sx: { color: "text.secondary", height: 20, width: 20 } })
3144
3492
  ]
3145
3493
  }
3146
3494
  )
3147
3495
  }
3148
3496
  ),
3149
- isOpen && /* @__PURE__ */ jsx129(Box7, { children })
3497
+ isOpen && /* @__PURE__ */ jsx130(Box8, { children })
3150
3498
  ] });
3151
3499
  };
3152
3500
 
3153
3501
  // src/components/event-details/event-details.tsx
3154
- import { Fragment as Fragment2, jsx as jsx130, jsxs as jsxs124 } from "react/jsx-runtime";
3502
+ import { Fragment as Fragment2, jsx as jsx131, jsxs as jsxs125 } from "react/jsx-runtime";
3155
3503
  var EventDetails = ({ selectedEvent }) => {
3156
3504
  if (!selectedEvent) {
3157
- return /* @__PURE__ */ jsx130(Box8, { sx: { p: 3, textAlign: "center" }, children: /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "body2", children: "Select an event to view details" }) });
3505
+ return /* @__PURE__ */ jsx131(Box9, { sx: { p: 3, textAlign: "center" }, children: /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "body2", children: "Select an event to view details" }) });
3158
3506
  }
3159
- return /* @__PURE__ */ jsxs124(Box8, { "data-testid": "event-details", sx: { display: "flex", flexDirection: "column", height: "100%" }, children: [
3160
- /* @__PURE__ */ jsx130(EventDetailsHeader, { event: selectedEvent }),
3161
- /* @__PURE__ */ jsx130(Box8, { sx: { flexGrow: 1, overflow: "auto", p: 2 }, children: /* @__PURE__ */ jsxs124(Stack, { spacing: 2, children: [
3162
- /* @__PURE__ */ jsx130(ToggleSection, { headline: "Basic Information", children: /* @__PURE__ */ jsxs124(Stack, { spacing: 1, children: [
3163
- /* @__PURE__ */ jsxs124(Box8, { children: [
3164
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Span ID" }),
3165
- /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: selectedEvent.span_id })
3507
+ return /* @__PURE__ */ jsxs125(Box9, { "data-testid": "event-details", sx: { display: "flex", flexDirection: "column", height: "100%" }, children: [
3508
+ /* @__PURE__ */ jsx131(EventDetailsHeader, { event: selectedEvent }),
3509
+ /* @__PURE__ */ jsx131(Box9, { sx: { flexGrow: 1, overflow: "auto", p: 2 }, children: /* @__PURE__ */ jsxs125(Stack, { spacing: 2, children: [
3510
+ /* @__PURE__ */ jsx131(ToggleSection, { headline: "Basic Information", children: /* @__PURE__ */ jsxs125(Stack, { spacing: 1, children: [
3511
+ /* @__PURE__ */ jsxs125(Box9, { children: [
3512
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Span ID" }),
3513
+ /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: selectedEvent.span_id })
3166
3514
  ] }),
3167
- /* @__PURE__ */ jsxs124(Box8, { children: [
3168
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Trace ID" }),
3169
- /* @__PURE__ */ jsx130(Typography5, { sx: { fontFamily: "monospace", fontSize: "0.85rem" }, variant: "body2", children: selectedEvent.trace_id })
3515
+ /* @__PURE__ */ jsxs125(Box9, { children: [
3516
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Trace ID" }),
3517
+ /* @__PURE__ */ jsx131(Typography6, { sx: { fontFamily: "monospace", fontSize: "0.85rem" }, variant: "body2", children: selectedEvent.trace_id })
3170
3518
  ] }),
3171
- /* @__PURE__ */ jsxs124(Box8, { children: [
3172
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Operation" }),
3173
- /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: selectedEvent.operation_name })
3519
+ /* @__PURE__ */ jsxs125(Box9, { children: [
3520
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Operation" }),
3521
+ /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: selectedEvent.operation_name })
3174
3522
  ] })
3175
3523
  ] }) }),
3176
- /* @__PURE__ */ jsx130(Divider, {}),
3177
- /* @__PURE__ */ jsx130(ToggleSection, { headline: "Service Information", children: /* @__PURE__ */ jsxs124(Stack, { spacing: 1, children: [
3178
- /* @__PURE__ */ jsxs124(Box8, { children: [
3179
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Service" }),
3180
- /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: selectedEvent.service_name })
3524
+ /* @__PURE__ */ jsx131(Divider, {}),
3525
+ /* @__PURE__ */ jsx131(ToggleSection, { headline: "Service Information", children: /* @__PURE__ */ jsxs125(Stack, { spacing: 1, children: [
3526
+ /* @__PURE__ */ jsxs125(Box9, { children: [
3527
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Service" }),
3528
+ /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: selectedEvent.service_name })
3181
3529
  ] }),
3182
- /* @__PURE__ */ jsxs124(Box8, { children: [
3183
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Resource" }),
3184
- /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: selectedEvent.resource_name })
3530
+ /* @__PURE__ */ jsxs125(Box9, { children: [
3531
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Resource" }),
3532
+ /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: selectedEvent.resource_name })
3185
3533
  ] }),
3186
- selectedEvent.region && /* @__PURE__ */ jsxs124(Box8, { children: [
3187
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Region" }),
3188
- /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: selectedEvent.region })
3534
+ selectedEvent.region && /* @__PURE__ */ jsxs125(Box9, { children: [
3535
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Region" }),
3536
+ /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: selectedEvent.region })
3189
3537
  ] })
3190
3538
  ] }) }),
3191
- /* @__PURE__ */ jsx130(Divider, {}),
3192
- /* @__PURE__ */ jsx130(ToggleSection, { headline: "Timing", children: /* @__PURE__ */ jsxs124(Stack, { spacing: 1, children: [
3193
- /* @__PURE__ */ jsxs124(Box8, { children: [
3194
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Start Time" }),
3195
- /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: unixNanoToDate(selectedEvent.start_time_unix_nano)?.toISOString() })
3539
+ /* @__PURE__ */ jsx131(Divider, {}),
3540
+ /* @__PURE__ */ jsx131(ToggleSection, { headline: "Timing", children: /* @__PURE__ */ jsxs125(Stack, { spacing: 1, children: [
3541
+ /* @__PURE__ */ jsxs125(Box9, { children: [
3542
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Start Time" }),
3543
+ /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: unixNanoToDate(selectedEvent.start_time_unix_nano)?.toISOString() })
3196
3544
  ] }),
3197
- selectedEvent.end_time_unix_nano && /* @__PURE__ */ jsxs124(Box8, { children: [
3198
- /* @__PURE__ */ jsx130(Typography5, { color: "text.secondary", variant: "caption", children: "Duration" }),
3199
- /* @__PURE__ */ jsxs124(Typography5, { variant: "body2", children: [
3545
+ selectedEvent.end_time_unix_nano && /* @__PURE__ */ jsxs125(Box9, { children: [
3546
+ /* @__PURE__ */ jsx131(Typography6, { color: "text.secondary", variant: "caption", children: "Duration" }),
3547
+ /* @__PURE__ */ jsxs125(Typography6, { variant: "body2", children: [
3200
3548
  ((BigInt(selectedEvent.end_time_unix_nano) - BigInt(selectedEvent.start_time_unix_nano)) / BigInt("1000000")).toString(),
3201
3549
  " ",
3202
3550
  "ms"
3203
3551
  ] })
3204
3552
  ] })
3205
3553
  ] }) }),
3206
- /* @__PURE__ */ jsx130(Divider, {}),
3207
- /* @__PURE__ */ jsx130(ToggleSection, { headline: "Status", children: /* @__PURE__ */ jsxs124(Stack, { direction: "row", spacing: 1, children: [
3208
- /* @__PURE__ */ jsx130(
3554
+ /* @__PURE__ */ jsx131(Divider, {}),
3555
+ /* @__PURE__ */ jsx131(ToggleSection, { headline: "Status", children: /* @__PURE__ */ jsxs125(Stack, { direction: "row", spacing: 1, children: [
3556
+ /* @__PURE__ */ jsx131(
3209
3557
  Chip,
3210
3558
  {
3211
3559
  color: selectedEvent.status_code === 0 ? "success" : "error",
@@ -3213,11 +3561,11 @@ var EventDetails = ({ selectedEvent }) => {
3213
3561
  size: "small"
3214
3562
  }
3215
3563
  ),
3216
- selectedEvent.status_message && /* @__PURE__ */ jsx130(Typography5, { variant: "body2", children: selectedEvent.status_message })
3564
+ selectedEvent.status_message && /* @__PURE__ */ jsx131(Typography6, { variant: "body2", children: selectedEvent.status_message })
3217
3565
  ] }) }),
3218
- selectedEvent.attributes && Object.keys(selectedEvent.attributes).length > 0 && /* @__PURE__ */ jsxs124(Fragment2, { children: [
3219
- /* @__PURE__ */ jsx130(Divider, {}),
3220
- /* @__PURE__ */ jsx130(ToggleSection, { headline: "Attributes", children: /* @__PURE__ */ jsx130(Box8, { sx: { backgroundColor: "#f5f5f5", borderRadius: 1, p: 1 }, children: /* @__PURE__ */ jsx130("pre", { style: { fontSize: "0.85rem", margin: 0, overflow: "auto" }, children: JSON.stringify(selectedEvent.attributes, void 0, 2) }) }) })
3566
+ selectedEvent.attributes && Object.keys(selectedEvent.attributes).length > 0 && /* @__PURE__ */ jsxs125(Fragment2, { children: [
3567
+ /* @__PURE__ */ jsx131(Divider, {}),
3568
+ /* @__PURE__ */ jsx131(ToggleSection, { headline: "Attributes", children: /* @__PURE__ */ jsx131(Box9, { sx: { backgroundColor: "#f5f5f5", borderRadius: 1, p: 1 }, children: /* @__PURE__ */ jsx131("pre", { style: { fontSize: "0.85rem", margin: 0, overflow: "auto" }, children: JSON.stringify(selectedEvent.attributes, void 0, 2) }) }) })
3221
3569
  ] })
3222
3570
  ] }) })
3223
3571
  ] });
@@ -3225,32 +3573,32 @@ var EventDetails = ({ selectedEvent }) => {
3225
3573
 
3226
3574
  // src/components/trace-graph/trace-graph.tsx
3227
3575
  import "@xyflow/react/dist/base.css";
3228
- import { Alert as Alert2, Button as Button3 } from "@mui/material";
3576
+ import { Alert as Alert3, Button as Button4 } from "@mui/material";
3229
3577
  import { Background, Controls, ReactFlow, useReactFlow, useStoreApi } from "@xyflow/react";
3230
- import { useCallback as useCallback5, useEffect as useEffect3, useState as useState5 } from "react";
3578
+ import { useCallback as useCallback6, useEffect as useEffect4, useState as useState6 } from "react";
3231
3579
 
3232
3580
  // src/components/trace-graph/service-node.tsx
3233
- import { Box as Box10, Stack as Stack2, Typography as Typography6 } from "@mui/material";
3581
+ import { Box as Box11, Stack as Stack2, Typography as Typography7 } from "@mui/material";
3234
3582
  import "@xyflow/react/dist/style.css";
3235
3583
  import { Handle, Position } from "@xyflow/react";
3236
- import { memo, useCallback as useCallback4 } from "react";
3584
+ import { memo, useCallback as useCallback5 } from "react";
3237
3585
 
3238
3586
  // src/components/trace-graph/problem-indicator.tsx
3239
3587
  import { Error as ErrorIcon, Info, Warning } from "@mui/icons-material";
3240
- import { Box as Box9, Tooltip as Tooltip2 } from "@mui/material";
3588
+ import { Box as Box10, Tooltip as Tooltip2 } from "@mui/material";
3241
3589
  import { useMemo as useMemo4 } from "react";
3242
- import { jsx as jsx131 } from "react/jsx-runtime";
3590
+ import { jsx as jsx132 } from "react/jsx-runtime";
3243
3591
  var ProblemIndicator = ({ error }) => {
3244
3592
  const icon = useMemo4(() => {
3245
3593
  switch (error.level) {
3246
3594
  case "error": {
3247
- return /* @__PURE__ */ jsx131(ErrorIcon, { sx: { color: "#d32f2f", fontSize: "14px" } });
3595
+ return /* @__PURE__ */ jsx132(ErrorIcon, { sx: { color: "#d32f2f", fontSize: "14px" } });
3248
3596
  }
3249
3597
  case "warning": {
3250
- return /* @__PURE__ */ jsx131(Warning, { sx: { color: "#ff9800", fontSize: "14px" } });
3598
+ return /* @__PURE__ */ jsx132(Warning, { sx: { color: "#ff9800", fontSize: "14px" } });
3251
3599
  }
3252
3600
  default: {
3253
- return /* @__PURE__ */ jsx131(Info, { sx: { color: "#2196f3", fontSize: "14px" } });
3601
+ return /* @__PURE__ */ jsx132(Info, { sx: { color: "#2196f3", fontSize: "14px" } });
3254
3602
  }
3255
3603
  }
3256
3604
  }, [error.level]);
@@ -3267,8 +3615,8 @@ var ProblemIndicator = ({ error }) => {
3267
3615
  }
3268
3616
  }
3269
3617
  }, [error.level]);
3270
- return /* @__PURE__ */ jsx131(Tooltip2, { arrow: true, title: error.message ?? "Issue detected", children: /* @__PURE__ */ jsx131(
3271
- Box9,
3618
+ return /* @__PURE__ */ jsx132(Tooltip2, { arrow: true, title: error.message ?? "Issue detected", children: /* @__PURE__ */ jsx132(
3619
+ Box10,
3272
3620
  {
3273
3621
  sx: {
3274
3622
  alignItems: "center",
@@ -3287,17 +3635,17 @@ var ProblemIndicator = ({ error }) => {
3287
3635
  };
3288
3636
 
3289
3637
  // src/components/trace-graph/service-node.tsx
3290
- import { jsx as jsx132, jsxs as jsxs125 } from "react/jsx-runtime";
3638
+ import { jsx as jsx133, jsxs as jsxs126 } from "react/jsx-runtime";
3291
3639
  var handleStyle = {
3292
3640
  backgroundColor: "white",
3293
3641
  borderColor: "lightgray",
3294
3642
  opacity: 0
3295
3643
  };
3296
3644
  var ServiceNode = memo(function ServiceNode2({ data, selected }) {
3297
- const handleClick = useCallback4(() => {
3645
+ const handleClick = useCallback5(() => {
3298
3646
  data.onEventSelect(data.event);
3299
3647
  }, [data]);
3300
- const handleKeyPress = useCallback4(
3648
+ const handleKeyPress = useCallback5(
3301
3649
  (event) => {
3302
3650
  if (event.key === "Enter" || event.key === " ") {
3303
3651
  handleClick();
@@ -3306,9 +3654,9 @@ var ServiceNode = memo(function ServiceNode2({ data, selected }) {
3306
3654
  [handleClick]
3307
3655
  );
3308
3656
  const hasErrors = (data.event.errors && data.event.errors.length > 0) ?? false;
3309
- return /* @__PURE__ */ jsxs125(Box10, { sx: { maxWidth: 200 }, children: [
3310
- /* @__PURE__ */ jsxs125(
3311
- Box10,
3657
+ return /* @__PURE__ */ jsxs126(Box11, { sx: { maxWidth: 200 }, children: [
3658
+ /* @__PURE__ */ jsxs126(
3659
+ Box11,
3312
3660
  {
3313
3661
  onClick: handleClick,
3314
3662
  onKeyPress: handleKeyPress,
@@ -3330,9 +3678,9 @@ var ServiceNode = memo(function ServiceNode2({ data, selected }) {
3330
3678
  },
3331
3679
  tabIndex: 0,
3332
3680
  children: [
3333
- /* @__PURE__ */ jsx132(Handle, { position: Position.Left, style: handleStyle, type: "target" }),
3334
- /* @__PURE__ */ jsx132(Handle, { position: Position.Right, style: handleStyle, type: "source" }),
3335
- /* @__PURE__ */ jsx132(
3681
+ /* @__PURE__ */ jsx133(Handle, { position: Position.Left, style: handleStyle, type: "target" }),
3682
+ /* @__PURE__ */ jsx133(Handle, { position: Position.Right, style: handleStyle, type: "source" }),
3683
+ /* @__PURE__ */ jsx133(
3336
3684
  ServiceCell,
3337
3685
  {
3338
3686
  borderColor: selected ? "black" : "lightgray",
@@ -3346,7 +3694,7 @@ var ServiceNode = memo(function ServiceNode2({ data, selected }) {
3346
3694
  ]
3347
3695
  }
3348
3696
  ),
3349
- /* @__PURE__ */ jsxs125(
3697
+ /* @__PURE__ */ jsxs126(
3350
3698
  Stack2,
3351
3699
  {
3352
3700
  alignItems: "center",
@@ -3357,7 +3705,7 @@ var ServiceNode = memo(function ServiceNode2({ data, selected }) {
3357
3705
  mt: 0.5
3358
3706
  },
3359
3707
  children: [
3360
- hasErrors && /* @__PURE__ */ jsx132(
3708
+ hasErrors && /* @__PURE__ */ jsx133(
3361
3709
  Stack2,
3362
3710
  {
3363
3711
  direction: "row",
@@ -3366,11 +3714,11 @@ var ServiceNode = memo(function ServiceNode2({ data, selected }) {
3366
3714
  flexWrap: "wrap",
3367
3715
  gap: "2px"
3368
3716
  },
3369
- children: data.event.errors?.map((error) => /* @__PURE__ */ jsx132(ProblemIndicator, { error }, error.span_id))
3717
+ children: data.event.errors?.map((error) => /* @__PURE__ */ jsx133(ProblemIndicator, { error }, error.span_id))
3370
3718
  }
3371
3719
  ),
3372
- /* @__PURE__ */ jsx132(
3373
- Typography6,
3720
+ /* @__PURE__ */ jsx133(
3721
+ Typography7,
3374
3722
  {
3375
3723
  sx: {
3376
3724
  fontSize: "0.9rem",
@@ -3483,7 +3831,7 @@ var calculateCenterX = (focusNodeX, viewPortPixelWidth, minX, maxX) => {
3483
3831
  };
3484
3832
 
3485
3833
  // src/components/trace-graph/trace-graph.tsx
3486
- import { Fragment as Fragment3, jsx as jsx133, jsxs as jsxs126 } from "react/jsx-runtime";
3834
+ import { Fragment as Fragment3, jsx as jsx134, jsxs as jsxs127 } from "react/jsx-runtime";
3487
3835
  var nodeTypes = {
3488
3836
  service: ServiceNode
3489
3837
  };
@@ -3493,15 +3841,15 @@ var TraceGraph = ({
3493
3841
  traceId,
3494
3842
  viewPortPixelWidth
3495
3843
  }) => {
3496
- const [nodes, setNodes] = useState5([]);
3497
- const [edges, setEdges] = useState5([]);
3498
- const [isLoading, setIsLoading] = useState5(true);
3499
- const [initialViewSet, setInitialViewSet] = useState5(false);
3844
+ const [nodes, setNodes] = useState6([]);
3845
+ const [edges, setEdges] = useState6([]);
3846
+ const [isLoading, setIsLoading] = useState6(true);
3847
+ const [initialViewSet, setInitialViewSet] = useState6(false);
3500
3848
  const { fitView, setCenter } = useReactFlow();
3501
3849
  const store = useStoreApi();
3502
3850
  const api = useAppInspectorApi();
3503
- const [fetchError, setFetchError] = useState5();
3504
- const updateSelectedNode = useCallback5(
3851
+ const [fetchError, setFetchError] = useState6();
3852
+ const updateSelectedNode = useCallback6(
3505
3853
  (nodeId) => {
3506
3854
  const { addSelectedNodes } = store.getState();
3507
3855
  if (nodeId) {
@@ -3513,7 +3861,7 @@ var TraceGraph = ({
3513
3861
  },
3514
3862
  [nodes, store]
3515
3863
  );
3516
- const fetchTrace = useCallback5(async () => {
3864
+ const fetchTrace = useCallback6(async () => {
3517
3865
  setIsLoading(true);
3518
3866
  try {
3519
3867
  const response = await api.getSpans({ trace_id: traceId });
@@ -3556,13 +3904,13 @@ var TraceGraph = ({
3556
3904
  setIsLoading(false);
3557
3905
  }
3558
3906
  }, [api, traceId, onEventSelect]);
3559
- const fetchTraceSync = useCallback5(() => {
3907
+ const fetchTraceSync = useCallback6(() => {
3560
3908
  void fetchTrace();
3561
3909
  }, [fetchTrace]);
3562
- useEffect3(() => {
3910
+ useEffect4(() => {
3563
3911
  fetchTraceSync();
3564
3912
  }, [fetchTraceSync]);
3565
- useEffect3(() => {
3913
+ useEffect4(() => {
3566
3914
  const shouldSetInitialView = !isLoading && nodes.length > 0 && !initialViewSet;
3567
3915
  if (shouldSetInitialView) {
3568
3916
  if (initialFocusEventId) {
@@ -3582,20 +3930,20 @@ var TraceGraph = ({
3582
3930
  setInitialViewSet(true);
3583
3931
  }
3584
3932
  }, [isLoading, nodes, initialFocusEventId, viewPortPixelWidth, setCenter, fitView, onEventSelect, initialViewSet]);
3585
- useEffect3(() => {
3933
+ useEffect4(() => {
3586
3934
  if (initialFocusEventId) {
3587
3935
  updateSelectedNode(initialFocusEventId);
3588
3936
  }
3589
3937
  }, [initialFocusEventId, updateSelectedNode]);
3590
- const onNodeClick = useCallback5((_event, node) => {
3938
+ const onNodeClick = useCallback6((_event, node) => {
3591
3939
  onEventSelect(node.data.event);
3592
3940
  updateSelectedNode(node.id);
3593
3941
  }, [onEventSelect, updateSelectedNode]);
3594
- return /* @__PURE__ */ jsxs126(Fragment3, { children: [
3595
- fetchError && /* @__PURE__ */ jsxs126(
3596
- Alert2,
3942
+ return /* @__PURE__ */ jsxs127(Fragment3, { children: [
3943
+ fetchError && /* @__PURE__ */ jsxs127(
3944
+ Alert3,
3597
3945
  {
3598
- action: /* @__PURE__ */ jsx133(Button3, { onClick: fetchTraceSync, children: "Retry" }),
3946
+ action: /* @__PURE__ */ jsx134(Button4, { onClick: fetchTraceSync, children: "Retry" }),
3599
3947
  severity: "error",
3600
3948
  children: [
3601
3949
  "Unexpected error:",
@@ -3604,7 +3952,7 @@ var TraceGraph = ({
3604
3952
  ]
3605
3953
  }
3606
3954
  ),
3607
- /* @__PURE__ */ jsxs126(
3955
+ /* @__PURE__ */ jsxs127(
3608
3956
  ReactFlow,
3609
3957
  {
3610
3958
  "data-testid": "trace-graph",
@@ -3618,8 +3966,8 @@ var TraceGraph = ({
3618
3966
  onNodeClick,
3619
3967
  selectNodesOnDrag: false,
3620
3968
  children: [
3621
- /* @__PURE__ */ jsx133(Controls, { showInteractive: false }),
3622
- /* @__PURE__ */ jsx133(Background, {})
3969
+ /* @__PURE__ */ jsx134(Controls, { showInteractive: false }),
3970
+ /* @__PURE__ */ jsx134(Background, {})
3623
3971
  ]
3624
3972
  }
3625
3973
  )
@@ -3627,7 +3975,7 @@ var TraceGraph = ({
3627
3975
  };
3628
3976
 
3629
3977
  // src/pages/trace-graph.tsx
3630
- import { jsx as jsx134, jsxs as jsxs127 } from "react/jsx-runtime";
3978
+ import { Fragment as Fragment4, jsx as jsx135, jsxs as jsxs128 } from "react/jsx-runtime";
3631
3979
  var HEADER_HEIGHT = 56;
3632
3980
  var DRAWER_WIDTH = "35%";
3633
3981
  var Main = styled("main", { shouldForwardProp: (property) => property !== "open" })(({ open, theme }) => ({
@@ -3663,10 +4011,11 @@ var TraceGraphPage = () => {
3663
4011
  const { traceId } = useParams();
3664
4012
  const [searchParameters] = useSearchParams();
3665
4013
  const spanId = searchParameters.get("spanId");
3666
- const [open, setOpen] = useState6(true);
3667
- const [selectedEvent, setSelectedEvent] = useState6();
3668
- const [viewPortPixelWidth, setViewPortPixelWidth] = useState6(0);
3669
- const calculateDrawerWidth = useCallback6(() => {
4014
+ const [open, setOpen] = useState7(true);
4015
+ const [selectedEvent, setSelectedEvent] = useState7();
4016
+ const [viewPortPixelWidth, setViewPortPixelWidth] = useState7(0);
4017
+ const { checkStatus, error: statusError, status } = useStatus();
4018
+ const calculateDrawerWidth = useCallback7(() => {
3670
4019
  const percentageMatch = /(\d+)%/.exec(DRAWER_WIDTH);
3671
4020
  if (percentageMatch && open) {
3672
4021
  const percentage = Number.parseInt(percentageMatch[1], 10);
@@ -3674,7 +4023,7 @@ var TraceGraphPage = () => {
3674
4023
  }
3675
4024
  return 0;
3676
4025
  }, [open]);
3677
- useEffect4(() => {
4026
+ useEffect5(() => {
3678
4027
  const updateViewportWidth = () => {
3679
4028
  const totalWidth = window.innerWidth;
3680
4029
  const drawerPixelWidth = open ? calculateDrawerWidth() : 0;
@@ -3688,12 +4037,16 @@ var TraceGraphPage = () => {
3688
4037
  clearTimeout(timeoutId);
3689
4038
  };
3690
4039
  }, [open, calculateDrawerWidth]);
3691
- const handleEventSelect = useCallback6((event) => {
4040
+ const handleEventSelect = useCallback7((event) => {
3692
4041
  setSelectedEvent(event);
3693
4042
  setOpen(true);
3694
4043
  }, []);
3695
- return /* @__PURE__ */ jsx134(
3696
- Box11,
4044
+ const handleRetry = useCallback7(() => {
4045
+ void checkStatus();
4046
+ }, [checkStatus]);
4047
+ const shouldShowStatusMessage = Boolean(statusError) || status?.status === "DISABLED";
4048
+ return /* @__PURE__ */ jsx135(
4049
+ Box12,
3697
4050
  {
3698
4051
  "data-testid": "trace-graph-page",
3699
4052
  sx: {
@@ -3703,7 +4056,7 @@ var TraceGraphPage = () => {
3703
4056
  height: "100vh",
3704
4057
  overflow: "hidden"
3705
4058
  },
3706
- children: /* @__PURE__ */ jsxs127(
4059
+ children: /* @__PURE__ */ jsx135(
3707
4060
  Paper2,
3708
4061
  {
3709
4062
  sx: {
@@ -3713,15 +4066,22 @@ var TraceGraphPage = () => {
3713
4066
  position: "relative",
3714
4067
  width: "100%"
3715
4068
  },
3716
- children: [
3717
- /* @__PURE__ */ jsx134(Main, { open, children: /* @__PURE__ */ jsx134(
3718
- Box11,
4069
+ children: shouldShowStatusMessage ? /* @__PURE__ */ jsx135(
4070
+ StatusMessage,
4071
+ {
4072
+ error: statusError,
4073
+ onRetry: handleRetry,
4074
+ status
4075
+ }
4076
+ ) : /* @__PURE__ */ jsxs128(Fragment4, { children: [
4077
+ /* @__PURE__ */ jsx135(Main, { open, children: /* @__PURE__ */ jsx135(
4078
+ Box12,
3719
4079
  {
3720
4080
  sx: {
3721
4081
  height: "100%",
3722
4082
  overflow: "auto"
3723
4083
  },
3724
- children: traceId !== void 0 && /* @__PURE__ */ jsx134(ReactFlowProvider, { children: /* @__PURE__ */ jsx134(
4084
+ children: traceId !== void 0 && /* @__PURE__ */ jsx135(ReactFlowProvider, { children: /* @__PURE__ */ jsx135(
3725
4085
  TraceGraph,
3726
4086
  {
3727
4087
  initialFocusEventId: spanId,
@@ -3732,8 +4092,8 @@ var TraceGraphPage = () => {
3732
4092
  ) })
3733
4093
  }
3734
4094
  ) }),
3735
- /* @__PURE__ */ jsx134(StyledDrawer, { anchor: "right", open, variant: "persistent", children: /* @__PURE__ */ jsx134(EventDetails, { selectedEvent }) })
3736
- ]
4095
+ /* @__PURE__ */ jsx135(StyledDrawer, { anchor: "right", open, variant: "persistent", children: /* @__PURE__ */ jsx135(EventDetails, { selectedEvent }) })
4096
+ ] })
3737
4097
  }
3738
4098
  )
3739
4099
  }