@localstack/appinspector-ui 1.0.143 → 1.0.145

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
@@ -2422,7 +2422,7 @@ var init_event_streams = __esm({
2422
2422
 
2423
2423
  // src/pages/spans-list-page.tsx
2424
2424
  import { Box as Box19 } from "@mui/material";
2425
- import { useCallback as useCallback11, useEffect as useEffect22, useRef as useRef16, useState as useState18 } from "react";
2425
+ import { useCallback as useCallback11, useEffect as useEffect22, useRef as useRef16, useState as useState19 } from "react";
2426
2426
 
2427
2427
  // src/api/errors.ts
2428
2428
  var AppInspectorDisabledError = class extends Error {
@@ -2476,6 +2476,9 @@ var SPANS_LIST_PAGE_TEST_ID = "spans-list-page";
2476
2476
  var TRACE_GRAPH_PAGE_TEST_ID = "trace-graph-page";
2477
2477
  var VIEW_SPAN_DETAILS_TEST_ID = "view-span-details";
2478
2478
  var SPANS_DATA_GRID_ROW_TEST_ID = "spans-data-grid-row";
2479
+ var SPANS_SEARCH_INPUT_TEST_ID = "spans-search-input";
2480
+ var SPANS_SEARCH_CLEAR_TEST_ID = "spans-search-clear";
2481
+ var SPANS_SEARCH_NO_MATCH_TEST_ID = "spans-search-no-match";
2479
2482
  var EVENT_DETAILS_SECTION_BASIC_INFORMATION_TEST_ID = "event-details-section-basic-information";
2480
2483
  var EVENT_DETAILS_SERVICE_NAME_TEST_ID = "event-details-service-name";
2481
2484
  var EVENT_DETAILS_OPERATION_NAME_TEST_ID = "event-details-operation-name";
@@ -2508,6 +2511,7 @@ var EMULATOR_VERSION_BANNER_TEST_ID = "emulator-version-banner";
2508
2511
  // src/utils/emulator-version.ts
2509
2512
  var import_semver = __toESM(require_semver2(), 1);
2510
2513
  var MINIMUM_EMULATOR_VERSION = "2026.4.0";
2514
+ var MIN_EMULATOR_VERSION_FOR_SEARCH = "2026.6.0";
2511
2515
  function checkEmulatorVersion(version, now = /* @__PURE__ */ new Date()) {
2512
2516
  if (!version) return "error";
2513
2517
  const coerced = import_semver.default.coerce(version);
@@ -2518,6 +2522,13 @@ function checkEmulatorVersion(version, now = /* @__PURE__ */ new Date()) {
2518
2522
  if (ageInMonths >= 3) return "warning";
2519
2523
  return "ok";
2520
2524
  }
2525
+ function emulatorSupportsSearch(version) {
2526
+ if (!version) return false;
2527
+ const coerced = import_semver.default.coerce(version);
2528
+ const minimum = import_semver.default.coerce(MIN_EMULATOR_VERSION_FOR_SEARCH);
2529
+ if (!coerced || !minimum) return false;
2530
+ return import_semver.default.gte(coerced, minimum);
2531
+ }
2521
2532
  function getVersionAgeInMonths(year, month, now = /* @__PURE__ */ new Date()) {
2522
2533
  const versionDate = new Date(year, month - 1, 1);
2523
2534
  return (now.getTime() - versionDate.getTime()) / (1e3 * 60 * 60 * 24 * 30.44);
@@ -2586,13 +2597,15 @@ var EmulatorVersionBanner = ({
2586
2597
  import { Alert as Alert2, Box as Box5, Button as Button3 } from "@mui/material";
2587
2598
 
2588
2599
  // src/components/spans-list/spans-data-grid.tsx
2589
- import { DeleteForeverOutlined } from "@mui/icons-material";
2600
+ import { Close, DeleteForeverOutlined, Search } from "@mui/icons-material";
2590
2601
  import {
2591
2602
  Box as Box4,
2592
2603
  Button as Button2,
2593
2604
  CircularProgress,
2594
2605
  FormControlLabel,
2595
2606
  Grid,
2607
+ IconButton as IconButton2,
2608
+ InputAdornment,
2596
2609
  Paper,
2597
2610
  Table,
2598
2611
  TableBody,
@@ -2601,6 +2614,7 @@ import {
2601
2614
  TableHead,
2602
2615
  TableRow,
2603
2616
  TableSortLabel,
2617
+ TextField,
2604
2618
  Tooltip as Tooltip4,
2605
2619
  Typography as Typography4,
2606
2620
  useTheme as useTheme2
@@ -13061,7 +13075,7 @@ var motion = /* @__PURE__ */ createMotionProxy(function(Component, config) {
13061
13075
  });
13062
13076
 
13063
13077
  // src/components/spans-list/spans-data-grid.tsx
13064
- import { memo as memo8, useCallback as useCallback2, useEffect as useEffect11, useLayoutEffect as useLayoutEffect3, useMemo as useMemo4, useRef as useRef6 } from "react";
13078
+ import { memo as memo8, useCallback as useCallback2, useEffect as useEffect11, useLayoutEffect as useLayoutEffect3, useMemo as useMemo4, useRef as useRef6, useState as useState5 } from "react";
13065
13079
 
13066
13080
  // src/components/cells/responsive-timestamp-cell.tsx
13067
13081
  import { memo as memo3 } from "react";
@@ -15286,13 +15300,14 @@ function parseIAMEvent(payloadString) {
15286
15300
 
15287
15301
  // src/components/cells/status-cell.tsx
15288
15302
  import { Fragment as Fragment2, jsx as jsx124, jsxs as jsxs119 } from "react/jsx-runtime";
15289
- var StatusIcon = ({ errorLevel, spanStatusCode }) => {
15303
+ var StatusIcon = ({ errorLevel, operationStatus, spanStatusCode }) => {
15290
15304
  switch (errorLevel) {
15291
15305
  case ErrorLevel.ERROR: {
15292
15306
  return /* @__PURE__ */ jsx124(Cancel, { sx: { color: "red" } });
15293
15307
  }
15294
15308
  case ErrorLevel.IAM_PERMISSION: {
15295
- return /* @__PURE__ */ jsx124(GppBad, { sx: { color: spanStatusCode === 2 ? "red" : "warning.main" } });
15309
+ const isDenial = operationStatus ? operationStatus === "iam_explicit_deny" || operationStatus === "iam_implicit_deny" : spanStatusCode === 2;
15310
+ return /* @__PURE__ */ jsx124(GppBad, { sx: { color: isDenial ? "red" : "warning.main" } });
15296
15311
  }
15297
15312
  case ErrorLevel.WARNING: {
15298
15313
  return /* @__PURE__ */ jsx124(Error2, { sx: { color: "orange" } });
@@ -15303,6 +15318,22 @@ var StatusIcon = ({ errorLevel, spanStatusCode }) => {
15303
15318
  }
15304
15319
  };
15305
15320
  var calculateHighestErrorLevel = (span) => {
15321
+ if (span.operation_status) {
15322
+ switch (span.operation_status) {
15323
+ case "error": {
15324
+ return ErrorLevel.ERROR;
15325
+ }
15326
+ case "iam_explicit_deny":
15327
+ case "iam_explicit_warn":
15328
+ case "iam_implicit_deny":
15329
+ case "iam_implicit_warn": {
15330
+ return ErrorLevel.IAM_PERMISSION;
15331
+ }
15332
+ default: {
15333
+ return ErrorLevel.OK;
15334
+ }
15335
+ }
15336
+ }
15306
15337
  const hasIamDenial = span.events.some((event) => {
15307
15338
  if (!event.event_type?.toLowerCase().includes("iam")) return false;
15308
15339
  if (typeof event.attributes?.payload !== "string") return false;
@@ -15346,7 +15377,7 @@ var buildTooltipContent = (span) => {
15346
15377
  var StatusIconWithTooltip = ({ span }) => {
15347
15378
  const errorLevel = calculateHighestErrorLevel(span);
15348
15379
  if (errorLevel !== ErrorLevel.ERROR && errorLevel !== ErrorLevel.IAM_PERMISSION) return /* @__PURE__ */ jsx124(Fragment2, {});
15349
- return /* @__PURE__ */ jsx124(Tooltip2, { title: buildTooltipContent(span), children: /* @__PURE__ */ jsx124(Box2, { sx: { alignItems: "center", cursor: "default", display: "flex" }, children: /* @__PURE__ */ jsx124(StatusIcon, { errorLevel, spanStatusCode: span.status_code }) }) });
15380
+ return /* @__PURE__ */ jsx124(Tooltip2, { title: buildTooltipContent(span), children: /* @__PURE__ */ jsx124(Box2, { sx: { alignItems: "center", cursor: "default", display: "flex" }, children: /* @__PURE__ */ jsx124(StatusIcon, { errorLevel, operationStatus: span.operation_status, spanStatusCode: span.status_code }) }) });
15350
15381
  };
15351
15382
 
15352
15383
  // src/components/spans-list/span-count-badge.tsx
@@ -15370,7 +15401,7 @@ var StatRow = ({ label, value }) => /* @__PURE__ */ jsxs120(Box3, { sx: { alignI
15370
15401
  /* @__PURE__ */ jsx125(Typography3, { color: "text.secondary", sx: { mr: 4 }, variant: "caption", children: label }),
15371
15402
  /* @__PURE__ */ jsx125(Typography3, { fontWeight: 600, variant: "body2", children: fmtLimit(value) })
15372
15403
  ] });
15373
- var SpanCountBadge = ({ licenseLimit, systemLimit, totalCount, visibleCount }) => {
15404
+ var SpanCountBadge = ({ licenseLimit, searchActive = false, systemLimit, totalCount, visibleCount }) => {
15374
15405
  const [anchorElement, setAnchorElement] = useState4();
15375
15406
  const bindingLimit = resolveBindingLimit(systemLimit, licenseLimit);
15376
15407
  if (totalCount === void 0 && bindingLimit === void 0) {
@@ -15385,7 +15416,7 @@ var SpanCountBadge = ({ licenseLimit, systemLimit, totalCount, visibleCount }) =
15385
15416
  isLoading ? /* @__PURE__ */ jsx125(Skeleton, { sx: { minWidth: 120 } }) : /* @__PURE__ */ jsxs120(Box3, { sx: { alignItems: "baseline", display: "flex", gap: 0.5 }, children: [
15386
15417
  /* @__PURE__ */ jsx125(Typography3, { color: "text.secondary", variant: "caption", children: "Showing" }),
15387
15418
  /* @__PURE__ */ jsx125(Typography3, { variant: "body2", children: visibleCount === void 0 ? "\u2014" : fmt(visibleCount) }),
15388
- /* @__PURE__ */ jsx125(Typography3, { color: "text.secondary", variant: "caption", children: `of ${totalCount === void 0 ? "-" : fmt(totalCount)} operations` })
15419
+ /* @__PURE__ */ jsx125(Typography3, { color: "text.secondary", variant: "caption", children: `of ${totalCount === void 0 ? "-" : fmt(totalCount)} ${searchActive ? "matches" : "operations"}` })
15389
15420
  ] }),
15390
15421
  /* @__PURE__ */ jsx125(Tooltip3, { title: "Operation count details", children: /* @__PURE__ */ jsx125(
15391
15422
  IconButton,
@@ -15424,7 +15455,7 @@ var SpanCountBadge = ({ licenseLimit, systemLimit, totalCount, visibleCount }) =
15424
15455
  /* @__PURE__ */ jsx125(
15425
15456
  StatRow,
15426
15457
  {
15427
- label: /* @__PURE__ */ jsx125(Tooltip3, { placement: "left", title: "The total number of operations stored on the server.", children: /* @__PURE__ */ jsx125(Box3, { component: "span", sx: { borderBottom: "1px dashed", borderColor: "text.secondary", cursor: "help" }, children: "Total stored" }) }),
15458
+ label: /* @__PURE__ */ jsx125(Tooltip3, { placement: "left", title: searchActive ? "The total number of operations matching the search." : "The total number of operations stored on the server.", children: /* @__PURE__ */ jsx125(Box3, { component: "span", sx: { borderBottom: "1px dashed", borderColor: "text.secondary", cursor: "help" }, children: searchActive ? "Total matches" : "Total stored" }) }),
15428
15459
  value: totalCount
15429
15460
  }
15430
15461
  )
@@ -15491,9 +15522,55 @@ var newSpanBackgroundColor = {
15491
15522
  var LABEL_BEGINNING_OF_STREAM = "This is the beginning of the stream";
15492
15523
  var LABEL_END_OF_STREAM = "This is the end of the stream";
15493
15524
  var LABEL_NO_SPANS = "There are no operations";
15525
+ var SEARCH_MAX_LENGTH = 512;
15526
+ var SEARCH_DEBOUNCE_MS = 300;
15494
15527
  var STICK_TO_EDGE_THRESHOLD_PX = 4;
15495
15528
  var StreamBoundaryRow = ({ colSpan, label }) => /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan, sx: { fontStyle: "italic", textAlign: "center" }, children: /* @__PURE__ */ jsx126("span", { children: label }) }) });
15496
15529
  var LoadingRow = ({ colSpan }) => /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan, sx: { textAlign: "center" }, children: /* @__PURE__ */ jsx126(CircularProgress, { size: 24, sx: { m: 2 } }) }) });
15530
+ var NoMatchRow = ({
15531
+ colSpan,
15532
+ onClearSearch,
15533
+ term
15534
+ }) => /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan, "data-testid": SPANS_SEARCH_NO_MATCH_TEST_ID, sx: { textAlign: "center" }, children: /* @__PURE__ */ jsxs121(Box4, { sx: { alignItems: "center", display: "flex", flexDirection: "column", gap: 1, py: 3 }, children: [
15535
+ /* @__PURE__ */ jsx126(Typography4, { sx: { fontStyle: "italic" }, variant: "body2", children: `No operations match \u201C${term}\u201D` }),
15536
+ /* @__PURE__ */ jsx126(Button2, { onClick: onClearSearch, size: "small", variant: "text", children: "Clear search" })
15537
+ ] }) }) });
15538
+ var SpansSearchField = ({ onChange, onClear, searchSupported, value }) => {
15539
+ const field = /* @__PURE__ */ jsx126(
15540
+ TextField,
15541
+ {
15542
+ disabled: !searchSupported,
15543
+ inputProps: {
15544
+ "aria-label": "Search operations",
15545
+ "data-testid": SPANS_SEARCH_INPUT_TEST_ID,
15546
+ "maxLength": SEARCH_MAX_LENGTH
15547
+ },
15548
+ InputProps: {
15549
+ endAdornment: value ? /* @__PURE__ */ jsx126(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx126(
15550
+ IconButton2,
15551
+ {
15552
+ "aria-label": "Clear search",
15553
+ "data-testid": SPANS_SEARCH_CLEAR_TEST_ID,
15554
+ edge: "end",
15555
+ onClick: onClear,
15556
+ size: "small",
15557
+ children: /* @__PURE__ */ jsx126(Close, { sx: { fontSize: 16 } })
15558
+ }
15559
+ ) }) : void 0,
15560
+ startAdornment: /* @__PURE__ */ jsx126(InputAdornment, { position: "start", children: /* @__PURE__ */ jsx126(Search, { sx: { fontSize: 18 } }) })
15561
+ },
15562
+ onChange: (event) => {
15563
+ onChange(event.target.value);
15564
+ },
15565
+ placeholder: "Search operations\u2026",
15566
+ size: "small",
15567
+ sx: { minWidth: 260 },
15568
+ value
15569
+ }
15570
+ );
15571
+ if (searchSupported) return field;
15572
+ return /* @__PURE__ */ jsx126(Tooltip4, { title: `Search requires LocalStack \u2265 ${MIN_EMULATOR_VERSION_FOR_SEARCH}`, children: /* @__PURE__ */ jsx126("span", { children: field }) });
15573
+ };
15497
15574
  var SpansDataGridRow = memo8(
15498
15575
  ({ isNew, onSpanClick, row }) => {
15499
15576
  const theme = useTheme2();
@@ -15561,13 +15638,35 @@ var SpansDataGrid = ({
15561
15638
  licenseLimit,
15562
15639
  onClearSpans,
15563
15640
  onOrderChange,
15641
+ onSearchChange,
15564
15642
  onSpanClick,
15565
15643
  order: order2,
15644
+ search,
15645
+ searching,
15646
+ searchSupported,
15566
15647
  spans,
15567
15648
  systemLimit,
15568
15649
  totalCount,
15569
15650
  warningCount
15570
15651
  }) => {
15652
+ const searchActive = search.length > 0;
15653
+ const [searchDraft, setSearchDraft] = useState5(search);
15654
+ useEffect11(() => {
15655
+ const handle = setTimeout(() => {
15656
+ onSearchChange(searchDraft);
15657
+ }, SEARCH_DEBOUNCE_MS);
15658
+ return () => {
15659
+ clearTimeout(handle);
15660
+ };
15661
+ }, [searchDraft, onSearchChange]);
15662
+ const handleClearSearch = useCallback2(() => {
15663
+ setSearchDraft("");
15664
+ onSearchChange("");
15665
+ }, [onSearchChange]);
15666
+ const handleClearSpans = useCallback2(() => {
15667
+ setSearchDraft("");
15668
+ onClearSpans();
15669
+ }, [onClearSpans]);
15571
15670
  const columns = useMemo4(() => [
15572
15671
  columnHelper.accessor("startTime", {
15573
15672
  cell: (props) => /* @__PURE__ */ jsx126(ResponsiveTimestampCell, { date: props.getValue() }),
@@ -15590,7 +15689,13 @@ var SpansDataGrid = ({
15590
15689
  if (!props.row.original.parent_service_name || !props.row.original.parent_resource_name) {
15591
15690
  return /* @__PURE__ */ jsx126(Typography4, { sx: { fontStyle: "italic" }, variant: "body2", children: "External producer" });
15592
15691
  }
15593
- return /* @__PURE__ */ jsx126(ServiceCell, { resource: props.row.original.parent_resource_name, service: props.row.original.parent_service_name });
15692
+ return /* @__PURE__ */ jsx126(
15693
+ ServiceCell,
15694
+ {
15695
+ resource: props.row.original.parent_resource_name,
15696
+ service: props.row.original.parent_service_name
15697
+ }
15698
+ );
15594
15699
  },
15595
15700
  header: "Producer",
15596
15701
  id: "producer",
@@ -15701,14 +15806,40 @@ var SpansDataGrid = ({
15701
15806
  }, [order2, spans?.length, lastSpanId]);
15702
15807
  return /* @__PURE__ */ jsxs121(Fragment4, { children: [
15703
15808
  /* @__PURE__ */ jsx126(Grid, { item: true, xs: 12, children: /* @__PURE__ */ jsxs121(Box4, { sx: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
15704
- /* @__PURE__ */ jsx126(SpanCountBadge, { licenseLimit, systemLimit, totalCount, visibleCount: spans?.length }),
15705
- errorCount !== void 0 && errorCount > 0 && /* @__PURE__ */ jsxs121(Fragment4, { children: [
15809
+ /* @__PURE__ */ jsx126(
15810
+ SpansSearchField,
15811
+ {
15812
+ onChange: setSearchDraft,
15813
+ onClear: handleClearSearch,
15814
+ searchSupported,
15815
+ value: searchDraft
15816
+ }
15817
+ ),
15818
+ /* @__PURE__ */ jsx126(
15819
+ SpanCountBadge,
15820
+ {
15821
+ licenseLimit,
15822
+ searchActive,
15823
+ systemLimit,
15824
+ totalCount,
15825
+ visibleCount: spans?.length
15826
+ }
15827
+ ),
15828
+ !searchActive && errorCount !== void 0 && errorCount > 0 && /* @__PURE__ */ jsxs121(Fragment4, { children: [
15706
15829
  /* @__PURE__ */ jsx126(Typography4, { color: "text.disabled", sx: { mr: 0.5 }, variant: "body2", children: "\u2014" }),
15707
15830
  /* @__PURE__ */ jsx126(Tooltip4, { title: "Number of errors detected across all operations", children: /* @__PURE__ */ jsxs121(
15708
15831
  Box4,
15709
15832
  {
15710
15833
  "data-testid": ERROR_COUNT_TEST_ID,
15711
- sx: { alignItems: "center", borderBottom: "1px dotted", borderColor: "error.main", cursor: "help", display: "flex", gap: 0.5, mb: "-1px" },
15834
+ sx: {
15835
+ alignItems: "center",
15836
+ borderBottom: "1px dotted",
15837
+ borderColor: "error.main",
15838
+ cursor: "help",
15839
+ display: "flex",
15840
+ gap: 0.5,
15841
+ mb: "-1px"
15842
+ },
15712
15843
  children: [
15713
15844
  /* @__PURE__ */ jsx126(Typography4, { color: "error", variant: "body2", children: errorCount.toLocaleString() }),
15714
15845
  /* @__PURE__ */ jsx126(Typography4, { color: "error", variant: "caption", children: errorCount === 1 ? "error" : "errors" })
@@ -15716,13 +15847,21 @@ var SpansDataGrid = ({
15716
15847
  }
15717
15848
  ) })
15718
15849
  ] }),
15719
- warningCount !== void 0 && warningCount > 0 && /* @__PURE__ */ jsxs121(Fragment4, { children: [
15850
+ !searchActive && warningCount !== void 0 && warningCount > 0 && /* @__PURE__ */ jsxs121(Fragment4, { children: [
15720
15851
  /* @__PURE__ */ jsx126(Typography4, { color: "text.disabled", sx: { mr: 0.5 }, variant: "body2", children: "\u2014" }),
15721
15852
  /* @__PURE__ */ jsx126(Tooltip4, { title: "Number of warnings detected across all operations", children: /* @__PURE__ */ jsxs121(
15722
15853
  Box4,
15723
15854
  {
15724
15855
  "data-testid": WARNING_COUNT_TEST_ID,
15725
- sx: { alignItems: "center", borderBottom: "1px dotted", borderColor: "warning.main", cursor: "help", display: "flex", gap: 0.5, mb: "-1px" },
15856
+ sx: {
15857
+ alignItems: "center",
15858
+ borderBottom: "1px dotted",
15859
+ borderColor: "warning.main",
15860
+ cursor: "help",
15861
+ display: "flex",
15862
+ gap: 0.5,
15863
+ mb: "-1px"
15864
+ },
15726
15865
  children: [
15727
15866
  /* @__PURE__ */ jsx126(Typography4, { color: "warning.main", variant: "body2", children: warningCount.toLocaleString() }),
15728
15867
  /* @__PURE__ */ jsx126(Typography4, { color: "warning.main", variant: "caption", children: warningCount === 1 ? "warning" : "warnings" })
@@ -15738,7 +15877,7 @@ var SpansDataGrid = ({
15738
15877
  Button2,
15739
15878
  {
15740
15879
  "data-testid": CLEAR_SPANS_TEST_ID,
15741
- onClick: onClearSpans,
15880
+ onClick: handleClearSpans,
15742
15881
  startIcon: /* @__PURE__ */ jsx126(DeleteForeverOutlined, {}),
15743
15882
  children: "Clear Operations"
15744
15883
  }
@@ -15791,31 +15930,71 @@ var SpansDataGrid = ({
15791
15930
  )) }, headerGroup.id);
15792
15931
  }) }),
15793
15932
  /* @__PURE__ */ jsxs121(TableBody, { children: [
15794
- (spans === void 0 || clearingSpans) && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan: columnCount, sx: { fontStyle: "italic", textAlign: "center" }, children: /* @__PURE__ */ jsx126(CircularProgress, { size: 48, sx: { m: 4 } }) }) }),
15795
- !clearingSpans && spans?.length === 0 && /* @__PURE__ */ jsx126(StreamBoundaryRow, { colSpan: columnCount, label: LABEL_NO_SPANS }),
15933
+ (spans === void 0 || clearingSpans || searching) && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan: columnCount, sx: { fontStyle: "italic", textAlign: "center" }, children: /* @__PURE__ */ jsx126(CircularProgress, { size: 48, sx: { m: 4 } }) }) }),
15934
+ !clearingSpans && !searching && spans?.length === 0 && (searchActive ? /* @__PURE__ */ jsx126(NoMatchRow, { colSpan: columnCount, onClearSearch: handleClearSearch, term: search }) : /* @__PURE__ */ jsx126(StreamBoundaryRow, { colSpan: columnCount, label: LABEL_NO_SPANS })),
15796
15935
  !clearingSpans && order2 === "newest_first" && /* @__PURE__ */ jsxs121(Fragment4, { children: [
15797
15936
  hasRows && hasMoreForward && fetchingForward && /* @__PURE__ */ jsx126(LoadingRow, { colSpan: columnCount }),
15798
15937
  hasRows && !hasMoreForward && /* @__PURE__ */ jsx126(StreamBoundaryRow, { colSpan: columnCount, label: LABEL_END_OF_STREAM }),
15799
- hasRows && paddingTop > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan: columnCount, sx: { border: 0, height: paddingTop, p: 0 } }) }),
15938
+ hasRows && paddingTop > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(
15939
+ TableCell,
15940
+ {
15941
+ colSpan: columnCount,
15942
+ sx: { border: 0, height: paddingTop, p: 0 }
15943
+ }
15944
+ ) }),
15800
15945
  hasRows && virtualItems.map((virtualItem) => {
15801
15946
  const row = displayRows[virtualItem.index];
15802
15947
  const isNew = !(seenSpanIdsRef.current?.has(row.original.span_id) ?? false);
15803
- return /* @__PURE__ */ jsx126(SpansDataGridRow, { isNew, onSpanClick, row }, row.original.span_id);
15948
+ return /* @__PURE__ */ jsx126(
15949
+ SpansDataGridRow,
15950
+ {
15951
+ isNew,
15952
+ onSpanClick,
15953
+ row
15954
+ },
15955
+ row.original.span_id
15956
+ );
15804
15957
  }),
15805
- hasRows && paddingBottom > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan: columnCount, sx: { border: 0, height: paddingBottom, p: 0 } }) }),
15958
+ hasRows && paddingBottom > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(
15959
+ TableCell,
15960
+ {
15961
+ colSpan: columnCount,
15962
+ sx: { border: 0, height: paddingBottom, p: 0 }
15963
+ }
15964
+ ) }),
15806
15965
  hasRows && hasMoreBackward && fetchingBackward && /* @__PURE__ */ jsx126(LoadingRow, { colSpan: columnCount }),
15807
15966
  hasRows && !hasMoreBackward && /* @__PURE__ */ jsx126(StreamBoundaryRow, { colSpan: columnCount, label: LABEL_BEGINNING_OF_STREAM })
15808
15967
  ] }),
15809
15968
  !clearingSpans && order2 === "oldest_first" && /* @__PURE__ */ jsxs121(Fragment4, { children: [
15810
15969
  hasRows && !hasMoreBackward && /* @__PURE__ */ jsx126(StreamBoundaryRow, { colSpan: columnCount, label: LABEL_BEGINNING_OF_STREAM }),
15811
15970
  hasRows && hasMoreBackward && fetchingBackward && /* @__PURE__ */ jsx126(LoadingRow, { colSpan: columnCount }),
15812
- hasRows && paddingTop > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan: columnCount, sx: { border: 0, height: paddingTop, p: 0 } }) }),
15971
+ hasRows && paddingTop > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(
15972
+ TableCell,
15973
+ {
15974
+ colSpan: columnCount,
15975
+ sx: { border: 0, height: paddingTop, p: 0 }
15976
+ }
15977
+ ) }),
15813
15978
  hasRows && virtualItems.map((virtualItem) => {
15814
15979
  const row = displayRows[virtualItem.index];
15815
15980
  const isNew = !(seenSpanIdsRef.current?.has(row.original.span_id) ?? false);
15816
- return /* @__PURE__ */ jsx126(SpansDataGridRow, { isNew, onSpanClick, row }, row.original.span_id);
15981
+ return /* @__PURE__ */ jsx126(
15982
+ SpansDataGridRow,
15983
+ {
15984
+ isNew,
15985
+ onSpanClick,
15986
+ row
15987
+ },
15988
+ row.original.span_id
15989
+ );
15817
15990
  }),
15818
- hasRows && paddingBottom > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(TableCell, { colSpan: columnCount, sx: { border: 0, height: paddingBottom, p: 0 } }) }),
15991
+ hasRows && paddingBottom > 0 && /* @__PURE__ */ jsx126(TableRow, { children: /* @__PURE__ */ jsx126(
15992
+ TableCell,
15993
+ {
15994
+ colSpan: columnCount,
15995
+ sx: { border: 0, height: paddingBottom, p: 0 }
15996
+ }
15997
+ ) }),
15819
15998
  hasRows && hasMoreForward && fetchingForward && /* @__PURE__ */ jsx126(LoadingRow, { colSpan: columnCount }),
15820
15999
  hasRows && !hasMoreForward && /* @__PURE__ */ jsx126(StreamBoundaryRow, { colSpan: columnCount, label: LABEL_END_OF_STREAM })
15821
16000
  ] })
@@ -15856,8 +16035,12 @@ var SpansList = (props) => {
15856
16035
  licenseLimit: props.licenseLimit,
15857
16036
  onClearSpans: props.onClearSpans,
15858
16037
  onOrderChange: props.onOrderChange,
16038
+ onSearchChange: props.onSearchChange,
15859
16039
  onSpanClick: props.onSpanClick,
15860
16040
  order: props.order,
16041
+ search: props.search,
16042
+ searching: props.searching,
16043
+ searchSupported: props.searchSupported,
15861
16044
  spans: props.spans,
15862
16045
  systemLimit: props.systemLimit,
15863
16046
  totalCount: props.totalCount,
@@ -15870,7 +16053,7 @@ var SpansList = (props) => {
15870
16053
  // src/components/status-message/status-message.tsx
15871
16054
  import { ErrorOutline, InfoOutlined as InfoOutlined2 } from "@mui/icons-material";
15872
16055
  import { Alert as Alert3, AlertTitle, Box as Box6, Button as Button4, CircularProgress as CircularProgress2, Link, Typography as Typography5 } from "@mui/material";
15873
- import { useState as useState5 } from "react";
16056
+ import { useState as useState6 } from "react";
15874
16057
  import { Fragment as Fragment5, jsx as jsx128, jsxs as jsxs123 } from "react/jsx-runtime";
15875
16058
  var StatusMessage = ({
15876
16059
  localstackVersion,
@@ -15878,8 +16061,8 @@ var StatusMessage = ({
15878
16061
  onRetry,
15879
16062
  phase
15880
16063
  }) => {
15881
- const [enabling, setEnabling] = useState5(false);
15882
- const [enableError, setEnableError] = useState5();
16064
+ const [enabling, setEnabling] = useState6(false);
16065
+ const [enableError, setEnableError] = useState6();
15883
16066
  const handleEnable = async () => {
15884
16067
  if (!onEnable) return;
15885
16068
  setEnabling(true);
@@ -16082,14 +16265,14 @@ var StatusMessage = ({
16082
16265
  import { createContext as createContext8, useContext as useContext14 } from "react";
16083
16266
 
16084
16267
  // src/hooks/use-connection-state-machine.ts
16085
- import { useCallback as useCallback3, useEffect as useEffect12, useRef as useRef7, useState as useState6 } from "react";
16268
+ import { useCallback as useCallback3, useEffect as useEffect12, useRef as useRef7, useState as useState7 } from "react";
16086
16269
  var POLL_INTERVAL_MS = 5e3;
16087
16270
  function useConnectionStateMachine() {
16088
16271
  const api = useAppInspectorApi();
16089
- const [phase, setPhase] = useState6("CHECKING_STATUS");
16090
- const [checking, setChecking] = useState6(true);
16091
- const [status, setStatus] = useState6();
16092
- const [statusError, setStatusError] = useState6();
16272
+ const [phase, setPhase] = useState7("CHECKING_STATUS");
16273
+ const [checking, setChecking] = useState7(true);
16274
+ const [status, setStatus] = useState7();
16275
+ const [statusError, setStatusError] = useState7();
16093
16276
  const abortControllerRef = useRef7(null);
16094
16277
  const dispatchStatus = useCallback3((result, error) => {
16095
16278
  if (result === void 0) {
@@ -16179,9 +16362,9 @@ var useAppInspectorStatus = () => {
16179
16362
  };
16180
16363
 
16181
16364
  // src/hooks/use-local-storage.tsx
16182
- import { useCallback as useCallback4, useEffect as useEffect13, useState as useState7 } from "react";
16365
+ import { useCallback as useCallback4, useEffect as useEffect13, useState as useState8 } from "react";
16183
16366
  function useLocalStorage(key, initialValue) {
16184
- const [storedValue, setStoredValue] = useState7(() => {
16367
+ const [storedValue, setStoredValue] = useState8(() => {
16185
16368
  try {
16186
16369
  const item = globalThis.localStorage.getItem(key);
16187
16370
  return item ? JSON.parse(item) : initialValue;
@@ -16224,7 +16407,7 @@ function useLocalStorage(key, initialValue) {
16224
16407
  }
16225
16408
 
16226
16409
  // src/hooks/use-spans.ts
16227
- import { useCallback as useCallback7, useEffect as useEffect16, useRef as useRef10, useState as useState9 } from "react";
16410
+ import { useCallback as useCallback7, useEffect as useEffect16, useRef as useRef10, useState as useState10 } from "react";
16228
16411
 
16229
16412
  // src/utils/pagination-buffer.ts
16230
16413
  var insertSorted = (array, item, compareFunction, hint = "back") => {
@@ -16268,6 +16451,7 @@ var createPaginationBuffer = (options) => {
16268
16451
  let hasMoreBackward = void 0;
16269
16452
  let fetchingForward = false;
16270
16453
  let fetchingBackward = false;
16454
+ let abortController;
16271
16455
  const reportDataChange = () => {
16272
16456
  options.onDataChange({
16273
16457
  hasMoreBackward: hasMoreBackward ?? false,
@@ -16291,25 +16475,40 @@ var createPaginationBuffer = (options) => {
16291
16475
  if (hasMoreForward === true) {
16292
16476
  return;
16293
16477
  }
16478
+ const controller = new AbortController();
16479
+ abortController = controller;
16294
16480
  fetchingForward = true;
16295
16481
  reportStatusChange();
16296
16482
  try {
16297
- const newPage = await fetchPage(nextForwardToken);
16483
+ const newPage = await fetchPage(nextForwardToken, controller.signal);
16484
+ if (controller.signal.aborted) {
16485
+ return;
16486
+ }
16298
16487
  hasMoreForward = newPage.items.length > 0;
16299
16488
  reportDataChange();
16300
16489
  } catch (error) {
16490
+ if (controller.signal.aborted) {
16491
+ return;
16492
+ }
16301
16493
  reportError(error instanceof Error ? error : new Error("Failed to fetch forward page", { cause: error }));
16302
16494
  } finally {
16303
- fetchingForward = false;
16304
- reportStatusChange();
16495
+ if (!controller.signal.aborted) {
16496
+ fetchingForward = false;
16497
+ reportStatusChange();
16498
+ runPostFetchActions();
16499
+ }
16305
16500
  }
16306
- runPostFetchActions();
16307
16501
  };
16308
16502
  const fetchForward = async () => {
16503
+ const controller = new AbortController();
16504
+ abortController = controller;
16309
16505
  fetchingForward = true;
16310
16506
  reportStatusChange();
16311
16507
  try {
16312
- const newPage = await fetchPage(nextForwardToken);
16508
+ const newPage = await fetchPage(nextForwardToken, controller.signal);
16509
+ if (controller.signal.aborted) {
16510
+ return;
16511
+ }
16313
16512
  if (options.sortComparator === void 0) {
16314
16513
  items = [...items ?? [], ...newPage.items];
16315
16514
  } else {
@@ -16325,18 +16524,28 @@ var createPaginationBuffer = (options) => {
16325
16524
  nextBackwardToken ??= newPage.nextBackwardToken;
16326
16525
  reportDataChange();
16327
16526
  } catch (error) {
16527
+ if (controller.signal.aborted) {
16528
+ return;
16529
+ }
16328
16530
  reportError(error instanceof Error ? error : new Error("Failed to fetch forward page", { cause: error }));
16329
16531
  } finally {
16330
- fetchingForward = false;
16331
- reportStatusChange();
16532
+ if (!controller.signal.aborted) {
16533
+ fetchingForward = false;
16534
+ reportStatusChange();
16535
+ runPostFetchActions();
16536
+ }
16332
16537
  }
16333
- runPostFetchActions();
16334
16538
  };
16335
16539
  const fetchBackward = async () => {
16540
+ const controller = new AbortController();
16541
+ abortController = controller;
16336
16542
  fetchingBackward = true;
16337
16543
  reportStatusChange();
16338
16544
  try {
16339
- const newPage = await fetchPage(nextBackwardToken);
16545
+ const newPage = await fetchPage(nextBackwardToken, controller.signal);
16546
+ if (controller.signal.aborted) {
16547
+ return;
16548
+ }
16340
16549
  if (options.sortComparator === void 0) {
16341
16550
  items = [...newPage.items, ...items ?? []];
16342
16551
  } else {
@@ -16352,12 +16561,17 @@ var createPaginationBuffer = (options) => {
16352
16561
  nextForwardToken ??= newPage.nextForwardToken;
16353
16562
  reportDataChange();
16354
16563
  } catch (error) {
16564
+ if (controller.signal.aborted) {
16565
+ return;
16566
+ }
16355
16567
  reportError(error instanceof Error ? error : new Error("Failed to fetch forward page", { cause: error }));
16356
16568
  } finally {
16357
- fetchingBackward = false;
16358
- reportStatusChange();
16569
+ if (!controller.signal.aborted) {
16570
+ fetchingBackward = false;
16571
+ reportStatusChange();
16572
+ runPostFetchActions();
16573
+ }
16359
16574
  }
16360
- runPostFetchActions();
16361
16575
  };
16362
16576
  const runPostFetchActions = () => {
16363
16577
  if (fetchBackwardLater) {
@@ -16382,11 +16596,16 @@ var createPaginationBuffer = (options) => {
16382
16596
  void checkIfThereAreMoreItemsForward();
16383
16597
  },
16384
16598
  clear: () => {
16599
+ abortController?.abort();
16600
+ abortController = void 0;
16601
+ fetchingForward = false;
16602
+ fetchingBackward = false;
16385
16603
  items = [];
16386
16604
  hasMoreBackward = void 0;
16387
16605
  nextBackwardToken = void 0;
16388
16606
  hasMoreForward = void 0;
16389
16607
  nextForwardToken = void 0;
16608
+ reportStatusChange();
16390
16609
  reportDataChange();
16391
16610
  },
16392
16611
  fetchBackward: async () => {
@@ -16405,7 +16624,7 @@ var createPaginationBuffer = (options) => {
16405
16624
  };
16406
16625
 
16407
16626
  // src/hooks/use-spans-ws.tsx
16408
- import { useCallback as useCallback6, useEffect as useEffect15, useRef as useRef9, useState as useState8 } from "react";
16627
+ import { useCallback as useCallback6, useEffect as useEffect15, useRef as useRef9, useState as useState9 } from "react";
16409
16628
 
16410
16629
  // src/config.ts
16411
16630
  var APPINSPECTOR_API_PREFIX = "/_localstack/appinspector";
@@ -16622,9 +16841,9 @@ var createApiClient = ({ localstackEndpoint }) => {
16622
16841
  const endpoint = buildEventsEndpoint(iamEventsRequest);
16623
16842
  return makeRequest({ endpoint, localstackEndpoint });
16624
16843
  },
16625
- getSpans: async (request) => {
16844
+ getSpans: async (request, options) => {
16626
16845
  const endpoint = buildSpansEndpoint(request);
16627
- const response = await makeRequest({ endpoint, localstackEndpoint });
16846
+ const response = await makeRequest({ endpoint, localstackEndpoint, request: { signal: options?.signal } });
16628
16847
  return {
16629
16848
  ...response,
16630
16849
  spans: response.spans.map((span) => ({
@@ -18649,7 +18868,7 @@ function useSpansWebSocket(options) {
18649
18868
  useEffect15(() => {
18650
18869
  onCloseRef.current = onClose;
18651
18870
  }, [onClose]);
18652
- const [connected, setConnected] = useState8(false);
18871
+ const [connected, setConnected] = useState9(false);
18653
18872
  const wsRef = useRef9(void 0);
18654
18873
  const { localstackEndpoint } = useAppInspector();
18655
18874
  const connect = useCallback6(() => {
@@ -18710,66 +18929,89 @@ var PAGE_SIZE = 100;
18710
18929
  var useSpans = () => {
18711
18930
  const api = useAppInspectorApi();
18712
18931
  const { onWsClose, onWsOpen, wsEnabled } = useAppInspectorStatus();
18713
- const [spans, setSpans] = useState9();
18714
- const [fetchError, setFetchError] = useState9();
18715
- const [fetchingForward, setFetchingForward] = useState9(false);
18716
- const [fetchingBackward, setFetchingBackward] = useState9(false);
18717
- const paginationBufferRef = useRef10(createPaginationBuffer({
18718
- async fetchPage(token) {
18719
- const response = await api.getSpans({
18720
- limit: PAGE_SIZE,
18721
- pagination_token: token
18722
- });
18723
- setTotalCount(response.pagination.total_count);
18724
- setLicenseLimit(response.limits.span_count_limit_license);
18725
- setSystemLimit(response.limits.span_count_limit_system);
18726
- setErrorCount(response.error_count);
18727
- setWarningCount(response.warning_count);
18728
- return {
18729
- hasMoreBackward: response.pagination.has_prev,
18730
- hasMoreForward: response.pagination.has_next,
18731
- items: response.spans,
18732
- nextBackwardToken: response.pagination.prev_cursor ?? void 0,
18733
- nextForwardToken: response.pagination.next_cursor ?? void 0
18734
- };
18735
- },
18736
- onDataChange: ({ hasMoreBackward: hasMoreBackward2, hasMoreForward: hasMoreForward2, items }) => {
18737
- setFetchError(void 0);
18738
- setSpans(items);
18739
- setHasMoreBackward(hasMoreBackward2);
18740
- setHasMoreForward(hasMoreForward2);
18741
- },
18742
- onError: (error) => {
18743
- setFetchError(error);
18744
- },
18745
- onStatusChange(status) {
18746
- setFetchingBackward(status.fetchingBackward);
18747
- setFetchingForward(status.fetchingForward);
18748
- },
18749
- // The spans endpoint is sorted by span ingestion time, which might differ from
18750
- // the span timestamp. In order to accomodate for this, we will sort the spans
18751
- // in the frontend with the following sort comparator.
18752
- sortComparator(a3, b3) {
18753
- return a3.start_time_unix_nano < b3.start_time_unix_nano ? -1 : 1;
18754
- }
18755
- }));
18756
- const [totalCount, setTotalCount] = useState9();
18757
- const [licenseLimit, setLicenseLimit] = useState9();
18758
- const [systemLimit, setSystemLimit] = useState9();
18759
- const [errorCount, setErrorCount] = useState9();
18760
- const [warningCount, setWarningCount] = useState9();
18761
- const [hasMoreBackward, setHasMoreBackward] = useState9();
18762
- const [hasMoreForward, setHasMoreForward] = useState9();
18932
+ const [spans, setSpans] = useState10();
18933
+ const [fetchError, setFetchError] = useState10();
18934
+ const [fetchingForward, setFetchingForward] = useState10(false);
18935
+ const [fetchingBackward, setFetchingBackward] = useState10(false);
18936
+ const [search, setSearch] = useState10("");
18937
+ const searchRef = useRef10("");
18938
+ const [searching, setSearching] = useState10(false);
18939
+ const searchSeqRef = useRef10(0);
18940
+ const paginationBufferRef = useRef10();
18941
+ const [totalCount, setTotalCount] = useState10();
18942
+ const [licenseLimit, setLicenseLimit] = useState10();
18943
+ const [systemLimit, setSystemLimit] = useState10();
18944
+ const [errorCount, setErrorCount] = useState10();
18945
+ const [warningCount, setWarningCount] = useState10();
18946
+ const [hasMoreBackward, setHasMoreBackward] = useState10();
18947
+ const [hasMoreForward, setHasMoreForward] = useState10();
18763
18948
  const fetchForward = useCallback7(() => {
18764
- void paginationBufferRef.current.fetchForward();
18949
+ void paginationBufferRef.current?.fetchForward();
18765
18950
  }, []);
18766
18951
  const fetchBackward = useCallback7(() => {
18767
- void paginationBufferRef.current.fetchBackward();
18952
+ void paginationBufferRef.current?.fetchBackward();
18953
+ }, []);
18954
+ const applySearch = useCallback7((term) => {
18955
+ const normalized = term.trim();
18956
+ if (normalized === searchRef.current) {
18957
+ return;
18958
+ }
18959
+ searchRef.current = normalized;
18960
+ setSearch(normalized);
18961
+ const seq = ++searchSeqRef.current;
18962
+ setSearching(true);
18963
+ paginationBufferRef.current?.clear();
18964
+ void paginationBufferRef.current?.fetchForward().finally(() => {
18965
+ if (searchSeqRef.current === seq) {
18966
+ setSearching(false);
18967
+ }
18968
+ });
18768
18969
  }, []);
18769
18970
  useEffect16(() => {
18770
- fetchForward();
18771
- }, [fetchForward]);
18772
- const [clearingSpans, setClearingSpans] = useState9(false);
18971
+ const buffer = createPaginationBuffer({
18972
+ async fetchPage(token, signal) {
18973
+ const response = await api.getSpans({
18974
+ limit: PAGE_SIZE,
18975
+ pagination_token: token,
18976
+ search: searchRef.current || void 0
18977
+ }, { signal });
18978
+ setTotalCount(response.pagination.total_count);
18979
+ setLicenseLimit(response.limits.span_count_limit_license);
18980
+ setSystemLimit(response.limits.span_count_limit_system);
18981
+ setErrorCount(response.error_count);
18982
+ setWarningCount(response.warning_count);
18983
+ return {
18984
+ hasMoreBackward: response.pagination.has_prev,
18985
+ hasMoreForward: response.pagination.has_next,
18986
+ items: response.spans,
18987
+ nextBackwardToken: response.pagination.prev_cursor ?? void 0,
18988
+ nextForwardToken: response.pagination.next_cursor ?? void 0
18989
+ };
18990
+ },
18991
+ onDataChange: ({ hasMoreBackward: hasMoreBackward2, hasMoreForward: hasMoreForward2, items }) => {
18992
+ setFetchError(void 0);
18993
+ setSpans(items);
18994
+ setHasMoreBackward(hasMoreBackward2);
18995
+ setHasMoreForward(hasMoreForward2);
18996
+ },
18997
+ onError: (error) => {
18998
+ setFetchError(error);
18999
+ },
19000
+ onStatusChange(status) {
19001
+ setFetchingBackward(status.fetchingBackward);
19002
+ setFetchingForward(status.fetchingForward);
19003
+ },
19004
+ // The spans endpoint is sorted by span ingestion time, which might differ from
19005
+ // the span timestamp. In order to accomodate for this, we will sort the spans
19006
+ // in the frontend with the following sort comparator.
19007
+ sortComparator(a3, b3) {
19008
+ return a3.start_time_unix_nano < b3.start_time_unix_nano ? -1 : 1;
19009
+ }
19010
+ });
19011
+ paginationBufferRef.current = buffer;
19012
+ void buffer.fetchForward();
19013
+ }, [api]);
19014
+ const [clearingSpans, setClearingSpans] = useState10(false);
18773
19015
  const clearSpans = useCallback7(async () => {
18774
19016
  if (clearingSpans) {
18775
19017
  return;
@@ -18778,8 +19020,11 @@ var useSpans = () => {
18778
19020
  try {
18779
19021
  await api.deleteSpans();
18780
19022
  setTotalCount(void 0);
18781
- paginationBufferRef.current.clear();
18782
- await paginationBufferRef.current.fetchForward();
19023
+ searchRef.current = "";
19024
+ setSearch("");
19025
+ setSearching(false);
19026
+ paginationBufferRef.current?.clear();
19027
+ await paginationBufferRef.current?.fetchForward();
18783
19028
  } catch (error) {
18784
19029
  console.error("Failed to delete spans:", error);
18785
19030
  setFetchError(error instanceof Error ? error : new Error("Failed to delete spans", { cause: error }));
@@ -18789,12 +19034,12 @@ var useSpans = () => {
18789
19034
  }, [clearingSpans, api]);
18790
19035
  useEffect16(() => {
18791
19036
  if (hasMoreForward === true && !fetchingForward) {
18792
- void paginationBufferRef.current.fetchForward();
19037
+ void paginationBufferRef.current?.fetchForward();
18793
19038
  }
18794
19039
  }, [hasMoreForward, fetchingForward]);
18795
19040
  useEffect16(() => {
18796
19041
  if (hasMoreBackward === true && !fetchingBackward && !fetchingForward) {
18797
- void paginationBufferRef.current.fetchBackward();
19042
+ void paginationBufferRef.current?.fetchBackward();
18798
19043
  }
18799
19044
  }, [hasMoreBackward, fetchingBackward, fetchingForward]);
18800
19045
  useSpansWebSocket({
@@ -18805,7 +19050,7 @@ var useSpans = () => {
18805
19050
  return;
18806
19051
  }
18807
19052
  if (!hasMoreForward) {
18808
- void paginationBufferRef.current.fetchForward();
19053
+ void paginationBufferRef.current?.fetchForward();
18809
19054
  }
18810
19055
  },
18811
19056
  onOpen: () => {
@@ -18829,6 +19074,9 @@ var useSpans = () => {
18829
19074
  hasMoreBackward,
18830
19075
  hasMoreForward,
18831
19076
  licenseLimit,
19077
+ search,
19078
+ searching,
19079
+ setSearch: applySearch,
18832
19080
  spans,
18833
19081
  systemLimit,
18834
19082
  totalCount,
@@ -18841,12 +19089,12 @@ import { ArrowBack } from "@mui/icons-material";
18841
19089
  import { Box as Box18, Button as Button6, Drawer, Paper as Paper3 } from "@mui/material";
18842
19090
  import { styled } from "@mui/material/styles";
18843
19091
  import { ReactFlowProvider } from "@xyflow/react";
18844
- import { useCallback as useCallback10, useEffect as useEffect21, useRef as useRef15, useState as useState17 } from "react";
19092
+ import { useCallback as useCallback10, useEffect as useEffect21, useRef as useRef15, useState as useState18 } from "react";
18845
19093
 
18846
19094
  // src/components/event-details/event-details.tsx
18847
- import { Close as Close2 } from "@mui/icons-material";
18848
- import { Alert as Alert4, Box as Box15, Chip as Chip3, Divider as Divider3, FormControlLabel as FormControlLabel2, IconButton as IconButton4, Stack as Stack4, Switch, Typography as Typography11 } from "@mui/material";
18849
- import { useMemo as useMemo10, useState as useState15 } from "react";
19095
+ import { Close as Close3 } from "@mui/icons-material";
19096
+ import { Alert as Alert4, Box as Box15, Chip as Chip3, Divider as Divider3, FormControlLabel as FormControlLabel2, IconButton as IconButton5, Stack as Stack4, Switch, Typography as Typography11 } from "@mui/material";
19097
+ import { useMemo as useMemo10, useState as useState16 } from "react";
18850
19098
 
18851
19099
  // src/utils/event-utils.ts
18852
19100
  var iamEventParser = (eventName, attributes) => {
@@ -18958,11 +19206,11 @@ var getEventGroupsByType = (events) => {
18958
19206
 
18959
19207
  // src/components/event-details/copy-button.tsx
18960
19208
  import { Check, ContentCopy } from "@mui/icons-material";
18961
- import { IconButton as IconButton2, Tooltip as Tooltip5 } from "@mui/material";
18962
- import { useCallback as useCallback8, useState as useState10 } from "react";
19209
+ import { IconButton as IconButton3, Tooltip as Tooltip5 } from "@mui/material";
19210
+ import { useCallback as useCallback8, useState as useState11 } from "react";
18963
19211
  import { jsx as jsx131 } from "react/jsx-runtime";
18964
19212
  var CopyButton = ({ value }) => {
18965
- const [copied, setCopied] = useState10(false);
19213
+ const [copied, setCopied] = useState11(false);
18966
19214
  const handleCopy = useCallback8(() => {
18967
19215
  const text2 = typeof value === "string" ? value : JSON.stringify(value, void 0, 2);
18968
19216
  void navigator.clipboard.writeText(text2).then(() => {
@@ -18973,7 +19221,7 @@ var CopyButton = ({ value }) => {
18973
19221
  });
18974
19222
  }, [value]);
18975
19223
  return /* @__PURE__ */ jsx131(Tooltip5, { title: copied ? "Copied!" : "Copy", children: /* @__PURE__ */ jsx131(
18976
- IconButton2,
19224
+ IconButton3,
18977
19225
  {
18978
19226
  className: "copy-btn",
18979
19227
  onClick: handleCopy,
@@ -18986,8 +19234,8 @@ var CopyButton = ({ value }) => {
18986
19234
 
18987
19235
  // src/components/event-details/event-detail.tsx
18988
19236
  import { KeyboardArrowDown, KeyboardArrowRight } from "@mui/icons-material";
18989
- import { Box as Box12, IconButton as IconButton3, Typography as Typography8 } from "@mui/material";
18990
- import { useEffect as useEffect18, useMemo as useMemo8, useRef as useRef12, useState as useState12 } from "react";
19237
+ import { Box as Box12, IconButton as IconButton4, Typography as Typography8 } from "@mui/material";
19238
+ import { useEffect as useEffect18, useMemo as useMemo8, useRef as useRef12, useState as useState13 } from "react";
18991
19239
 
18992
19240
  // src/components/status-icon.tsx
18993
19241
  import { Cancel as Cancel2, CheckCircle, Error as Error3, Info, RemoveCircle } from "@mui/icons-material";
@@ -19153,7 +19401,7 @@ import { Box as Box11, useTheme as useTheme3 } from "@mui/material";
19153
19401
  var import_copy_to_clipboard = __toESM(require_copy_to_clipboard(), 1);
19154
19402
  import { jsx as jsx135, jsxs as jsxs126, Fragment as Fragment7 } from "react/jsx-runtime";
19155
19403
  import { Box as Box10, InputBase, NoSsr, SvgIcon, createTheme, ThemeProvider, Paper as Paper2 } from "@mui/material";
19156
- import { createContext as createContext10, useContext as useContext16, useState as useState11, useRef as useRef11, useCallback as useCallback9, useMemo as useMemo7, useEffect as useEffect17, memo as memo9 } from "react";
19404
+ import { createContext as createContext10, useContext as useContext16, useState as useState12, useRef as useRef11, useCallback as useCallback9, useMemo as useMemo7, useEffect as useEffect17, memo as memo9 } from "react";
19157
19405
  import { create, useStore, createStore } from "zustand";
19158
19406
  function r(e2) {
19159
19407
  var t, f2, n = "";
@@ -19397,7 +19645,7 @@ async function copyString(value) {
19397
19645
  }
19398
19646
  function useClipboard() {
19399
19647
  let { timeout = 2e3 } = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
19400
- const [copied, setCopied] = useState11(false);
19648
+ const [copied, setCopied] = useState12(false);
19401
19649
  const copyTimeout = useRef11(null);
19402
19650
  const handleCopyResult = useCallback9((value) => {
19403
19651
  const current = copyTimeout.current;
@@ -19480,7 +19728,7 @@ function useInspect(path, value, nestedIndex) {
19480
19728
  value,
19481
19729
  setInspectCache
19482
19730
  ]);
19483
- const [inspect, set] = useState11(() => {
19731
+ const [inspect, set] = useState12(() => {
19484
19732
  const shouldInspect = getInspectCache(path, nestedIndex);
19485
19733
  if (shouldInspect !== void 0) {
19486
19734
  return shouldInspect;
@@ -19829,7 +20077,7 @@ var AddBox = "M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.
19829
20077
  var Check2 = "M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z";
19830
20078
  var ChevronRight = "M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z";
19831
20079
  var CircularArrows = "M 12 2 C 10.615 1.998 9.214625 2.2867656 7.890625 2.8847656 L 8.9003906 4.6328125 C 9.9043906 4.2098125 10.957 3.998 12 4 C 15.080783 4 17.738521 5.7633175 19.074219 8.3222656 L 17.125 9 L 21.25 11 L 22.875 7 L 20.998047 7.6523438 C 19.377701 4.3110398 15.95585 2 12 2 z M 6.5097656 4.4882812 L 2.2324219 5.0820312 L 3.734375 6.3808594 C 1.6515335 9.4550558 1.3615962 13.574578 3.3398438 17 C 4.0308437 18.201 4.9801562 19.268234 6.1601562 20.115234 L 7.1699219 18.367188 C 6.3019219 17.710187 5.5922656 16.904 5.0722656 16 C 3.5320014 13.332354 3.729203 10.148679 5.2773438 7.7128906 L 6.8398438 9.0625 L 6.5097656 4.4882812 z M 19.929688 13 C 19.794687 14.08 19.450734 15.098 18.927734 16 C 17.386985 18.668487 14.531361 20.090637 11.646484 19.966797 L 12.035156 17.9375 L 8.2402344 20.511719 L 10.892578 23.917969 L 11.265625 21.966797 C 14.968963 22.233766 18.681899 20.426323 20.660156 17 C 21.355156 15.801 21.805219 14.445 21.949219 13 L 19.929688 13 z";
19832
- var Close = "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z";
20080
+ var Close2 = "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z";
19833
20081
  var ContentCopy2 = "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z";
19834
20082
  var Edit = "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z";
19835
20083
  var ExpandMore = "M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z";
@@ -19860,7 +20108,7 @@ var CircularArrowsIcon = (props) => {
19860
20108
  };
19861
20109
  var CloseIcon = (props) => {
19862
20110
  return /* @__PURE__ */ jsx135(BaseIcon, {
19863
- d: Close,
20111
+ d: Close2,
19864
20112
  ...props
19865
20113
  });
19866
20114
  };
@@ -20011,7 +20259,7 @@ var ObjectType = (props) => {
20011
20259
  const borderColor = useJsonViewerStore((store) => store.colorspace.base02);
20012
20260
  const groupArraysAfterLength = useJsonViewerStore((store) => store.groupArraysAfterLength);
20013
20261
  const isTrap = useIsCycleReference(props.path, props.value);
20014
- const [displayLength, setDisplayLength] = useState11(useJsonViewerStore((store) => store.maxDisplayLength));
20262
+ const [displayLength, setDisplayLength] = useState12(useJsonViewerStore((store) => store.maxDisplayLength));
20015
20263
  const objectSortKeys = useJsonViewerStore((store) => store.objectSortKeys);
20016
20264
  const elements = useMemo7(() => {
20017
20265
  if (!props.inspect) {
@@ -20217,7 +20465,7 @@ var stringType = defineEasyType({
20217
20465
  serialize: (value) => value,
20218
20466
  deserialize: (value) => value,
20219
20467
  Renderer: (props) => {
20220
- const [showRest, setShowRest] = useState11(false);
20468
+ const [showRest, setShowRest] = useState12(false);
20221
20469
  const collapseStringsAfterLength = useJsonViewerStore((store) => store.collapseStringsAfterLength);
20222
20470
  const value = showRest ? props.value : props.value.slice(0, collapseStringsAfterLength);
20223
20471
  const hasRest = props.value.length > collapseStringsAfterLength;
@@ -20371,7 +20619,7 @@ var DataKeyPair = (props) => {
20371
20619
  storeEditable,
20372
20620
  value
20373
20621
  ]);
20374
- const [tempValue, setTempValue] = useState11("");
20622
+ const [tempValue, setTempValue] = useState12("");
20375
20623
  const depth = path.length;
20376
20624
  const key = path[depth - 1];
20377
20625
  const hoverPath = useJsonViewerStore((store) => store.hoverPath);
@@ -20385,7 +20633,7 @@ var DataKeyPair = (props) => {
20385
20633
  const setHover = useJsonViewerStore((store) => store.setHover);
20386
20634
  const root2 = useJsonViewerStore((store) => store.value);
20387
20635
  const [inspect, setInspect] = useInspect(path, value, nestedIndex);
20388
- const [editing, setEditing] = useState11(false);
20636
+ const [editing, setEditing] = useState12(false);
20389
20637
  const onChange = useJsonViewerStore((store) => store.onChange);
20390
20638
  const keyColor = useTextColor();
20391
20639
  const numberKeyColor = useJsonViewerStore((store) => store.colorspace.base0C);
@@ -20770,7 +21018,7 @@ var DataKeyPair = (props) => {
20770
21018
  };
20771
21019
  var query = "(prefers-color-scheme: dark)";
20772
21020
  function useThemeDetector() {
20773
- const [isDark, setIsDark] = useState11(false);
21021
+ const [isDark, setIsDark] = useState12(false);
20774
21022
  useEffect17(() => {
20775
21023
  const listener = (e2) => setIsDark(e2.matches);
20776
21024
  setIsDark(window.matchMedia(query).matches);
@@ -20991,8 +21239,8 @@ var DetailRow2 = ({ content, label }) => /* @__PURE__ */ jsxs127(Box12, { sx: {
20991
21239
  /* @__PURE__ */ jsx137(Box12, { children: typeof content === "string" ? /* @__PURE__ */ jsx137(Typography8, { sx: { color: "text.primary", whiteSpace: "pre-wrap" }, variant: "caption", children: content }) : content })
20992
21240
  ] });
20993
21241
  var EventMessage = ({ event }) => {
20994
- const [isOpen, setIsOpen] = useState12(false);
20995
- const [isOverflowing, setIsOverflowing] = useState12(false);
21242
+ const [isOpen, setIsOpen] = useState13(false);
21243
+ const [isOverflowing, setIsOverflowing] = useState13(false);
20996
21244
  const textReference = useRef12(null);
20997
21245
  const parsedMessage = useMemo8(() => parseEventMessage(event), [event]);
20998
21246
  const isIAMPolicyEvent = useMemo8(
@@ -21023,7 +21271,7 @@ var EventMessage = ({ event }) => {
21023
21271
  return /* @__PURE__ */ jsxs127(Box12, { sx: { display: "flex", flexDirection: "column" }, children: [
21024
21272
  /* @__PURE__ */ jsxs127(Box12, { sx: { alignItems: "center", display: "flex" }, children: [
21025
21273
  Boolean(shouldShowToggle) && /* @__PURE__ */ jsx137(
21026
- IconButton3,
21274
+ IconButton4,
21027
21275
  {
21028
21276
  onClick: () => {
21029
21277
  setIsOpen(!isOpen);
@@ -31055,7 +31303,7 @@ var QueryStatus = {
31055
31303
 
31056
31304
  // src/components/event-details/lambda-invoke-logs-section.tsx
31057
31305
  import { Box as Box13, CircularProgress as CircularProgress3, Stack as Stack3, Typography as Typography9 } from "@mui/material";
31058
- import { useEffect as useEffect19, useMemo as useMemo9, useRef as useRef13, useState as useState13 } from "react";
31306
+ import { useEffect as useEffect19, useMemo as useMemo9, useRef as useRef13, useState as useState14 } from "react";
31059
31307
  import { jsx as jsx138, jsxs as jsxs128 } from "react/jsx-runtime";
31060
31308
  var POLL_INTERVAL_MS2 = 1e3;
31061
31309
  async function pollQueryResults(client, queryId) {
@@ -31084,9 +31332,9 @@ function useCloudWatchLogsClient(region) {
31084
31332
  return client;
31085
31333
  }
31086
31334
  function useLambdaInvokeLogs(functionName2, requestId, region, startTimeNano, endTimeNano) {
31087
- const [loading, setLoading] = useState13(true);
31088
- const [logs, setLogs] = useState13([]);
31089
- const [error, setError] = useState13();
31335
+ const [loading, setLoading] = useState14(true);
31336
+ const [logs, setLogs] = useState14([]);
31337
+ const [error, setError] = useState14();
31090
31338
  const pollTimerRef = useRef13(null);
31091
31339
  const cloudWatchLogs = useCloudWatchLogsClient(region);
31092
31340
  useEffect19(() => {
@@ -31163,10 +31411,10 @@ var LambdaInvokeLogsSection = ({ endTimeNano, functionName: functionName2, regio
31163
31411
  // src/components/event-details/toggle-section.tsx
31164
31412
  import { KeyboardArrowDown as KeyboardArrowDown2, KeyboardArrowRight as KeyboardArrowRight2 } from "@mui/icons-material";
31165
31413
  import { Box as Box14, Typography as Typography10 } from "@mui/material";
31166
- import { useState as useState14 } from "react";
31414
+ import { useState as useState15 } from "react";
31167
31415
  import { jsx as jsx139, jsxs as jsxs129 } from "react/jsx-runtime";
31168
31416
  var ToggleSection = ({ action, children, headline, initialOpen = true }) => {
31169
- const [isOpen, setIsOpen] = useState14(initialOpen);
31417
+ const [isOpen, setIsOpen] = useState15(initialOpen);
31170
31418
  return /* @__PURE__ */ jsxs129(Box14, { sx: { mt: 4 }, children: [
31171
31419
  /* @__PURE__ */ jsxs129(
31172
31420
  Box14,
@@ -31227,7 +31475,7 @@ var EventDetails = ({ onClose, selectedEvent }) => {
31227
31475
  () => getEventGroupsByType(selectedEvent?.events ?? []),
31228
31476
  [selectedEvent?.events]
31229
31477
  );
31230
- const [parseNestedJson, setParseNestedJson] = useState15(true);
31478
+ const [parseNestedJson, setParseNestedJson] = useState16(true);
31231
31479
  if (!selectedEvent) {
31232
31480
  return /* @__PURE__ */ jsx140(Box15, { sx: { p: 3, textAlign: "center" }, children: /* @__PURE__ */ jsx140(Typography11, { color: "text.secondary", variant: "body2", children: "Select an operation to view graph" }) });
31233
31481
  }
@@ -31270,7 +31518,7 @@ var EventDetails = ({ onClose, selectedEvent }) => {
31270
31518
  },
31271
31519
  children: [
31272
31520
  /* @__PURE__ */ jsx140(Box15, { children: /* @__PURE__ */ jsx140(Typography11, { sx: { fontWeight: 600 }, variant: "h6", children: "Operation Details" }) }),
31273
- onClose && /* @__PURE__ */ jsx140(IconButton4, { "data-testid": EVENT_DETAILS_CLOSE_BUTTON_TEST_ID, onClick: onClose, size: "small", children: /* @__PURE__ */ jsx140(Close2, {}) })
31521
+ onClose && /* @__PURE__ */ jsx140(IconButton5, { "data-testid": EVENT_DETAILS_CLOSE_BUTTON_TEST_ID, onClick: onClose, size: "small", children: /* @__PURE__ */ jsx140(Close3, {}) })
31274
31522
  ]
31275
31523
  }
31276
31524
  ),
@@ -31458,7 +31706,7 @@ import { Box as Box16, Divider as Divider4, Stack as Stack5, Tooltip as Tooltip6
31458
31706
  import { Handle, Position } from "@xyflow/react";
31459
31707
  import "@xyflow/react/dist/style.css";
31460
31708
  import "react";
31461
- import { memo as memo11, useMemo as useMemo11, useRef as useRef14, useState as useState16 } from "react";
31709
+ import { memo as memo11, useMemo as useMemo11, useRef as useRef14, useState as useState17 } from "react";
31462
31710
  import { Fragment as Fragment10, jsx as jsx141, jsxs as jsxs131 } from "react/jsx-runtime";
31463
31711
  var handleStyle = {
31464
31712
  backgroundColor: "white",
@@ -31543,16 +31791,18 @@ var NodeContent = ({ event, expanded, hasPermissionEvents, isError, isWarning })
31543
31791
  };
31544
31792
  var ServiceNode = memo11(({ data, selected }) => {
31545
31793
  const theme = useTheme4();
31546
- const [isHovered, setIsHovered] = useState16(false);
31794
+ const [isHovered, setIsHovered] = useState17(false);
31547
31795
  const nodeRef = useRef14(null);
31548
- const isError = data.event.status_code === 2;
31549
- const hasPermissionEvents = useMemo11(
31796
+ const { operation_status } = data.event;
31797
+ const hasPermissionEventsLegacy = useMemo11(
31550
31798
  () => data.event.events.some(
31551
31799
  (event) => event.event_type === "iam.policy_evaluation" && event.name === "iam.policy.denied"
31552
31800
  ),
31553
31801
  [data.event.events]
31554
31802
  );
31555
- const isWarning = !isError && data.event.status_code === 1 && hasPermissionEvents;
31803
+ const isError = operation_status ? operation_status === "error" || operation_status === "iam_explicit_deny" || operation_status === "iam_implicit_deny" : data.event.status_code === 2;
31804
+ const isWarning = operation_status ? operation_status === "iam_explicit_warn" || operation_status === "iam_implicit_warn" : !isError && data.event.status_code === 1 && hasPermissionEventsLegacy;
31805
+ const hasPermissionEvents = operation_status ? operation_status.startsWith("iam_") : hasPermissionEventsLegacy;
31556
31806
  const outlineColor = isError ? theme.palette.error.main : isWarning ? theme.palette.warning.main : void 0;
31557
31807
  const sharedBoxSx = {
31558
31808
  backgroundColor: theme.palette.background.paper,
@@ -31708,7 +31958,7 @@ var getLayoutedNodesAndEdges = (inputNodes, inputEdges) => {
31708
31958
 
31709
31959
  // src/components/trace-graph/xyflow/controls.tsx
31710
31960
  import { Add, FitScreen, Remove } from "@mui/icons-material";
31711
- import { Box as Box17, IconButton as IconButton5 } from "@mui/material";
31961
+ import { Box as Box17, IconButton as IconButton6 } from "@mui/material";
31712
31962
  import { useReactFlow, useStore as useStore2 } from "@xyflow/react";
31713
31963
  import { memo as memo12 } from "react";
31714
31964
  import { shallow } from "zustand/shallow";
@@ -31745,7 +31995,7 @@ var Controls = memo12(() => {
31745
31995
  },
31746
31996
  children: [
31747
31997
  /* @__PURE__ */ jsx142(
31748
- IconButton5,
31998
+ IconButton6,
31749
31999
  {
31750
32000
  className: "react-flow__controls-zoomin",
31751
32001
  disabled: maxZoomReached,
@@ -31755,7 +32005,7 @@ var Controls = memo12(() => {
31755
32005
  }
31756
32006
  ),
31757
32007
  /* @__PURE__ */ jsx142(
31758
- IconButton5,
32008
+ IconButton6,
31759
32009
  {
31760
32010
  className: "react-flow__controls-zoomout",
31761
32011
  disabled: minZoomReached,
@@ -31765,7 +32015,7 @@ var Controls = memo12(() => {
31765
32015
  }
31766
32016
  ),
31767
32017
  /* @__PURE__ */ jsx142(
31768
- IconButton5,
32018
+ IconButton6,
31769
32019
  {
31770
32020
  className: "react-flow__controls-fitview",
31771
32021
  onClick: onFitViewHandler,
@@ -32035,9 +32285,9 @@ async function fetchConnectedTraces(api, traceIds, allSpans = /* @__PURE__ */ ne
32035
32285
  var TraceGraphPage = ({ onClose, spanId, traceId }) => {
32036
32286
  const api = useAppInspectorApi();
32037
32287
  const { headerHeight } = useAppInspector();
32038
- const [spans, setSpans] = useState17();
32039
- const [loading, setLoading] = useState17(false);
32040
- const [fetchError, setFetchError] = useState17();
32288
+ const [spans, setSpans] = useState18();
32289
+ const [loading, setLoading] = useState18(false);
32290
+ const [fetchError, setFetchError] = useState18();
32041
32291
  const fetchSpans = useCallback10(async () => {
32042
32292
  setLoading(true);
32043
32293
  try {
@@ -32054,8 +32304,8 @@ var TraceGraphPage = ({ onClose, spanId, traceId }) => {
32054
32304
  useEffect21(() => {
32055
32305
  void fetchSpans();
32056
32306
  }, [fetchSpans]);
32057
- const [open, setOpen] = useState17(true);
32058
- const [selectedEvent, setSelectedEvent] = useState17(() => spans?.find((span) => span.span_id === spanId));
32307
+ const [open, setOpen] = useState18(true);
32308
+ const [selectedEvent, setSelectedEvent] = useState18(() => spans?.find((span) => span.span_id === spanId));
32059
32309
  const spansReference = useRef15();
32060
32310
  useEffect21(() => {
32061
32311
  if (!spansReference.current && spans) {
@@ -32108,6 +32358,9 @@ var SpansListPage = () => {
32108
32358
  hasMoreBackward,
32109
32359
  hasMoreForward,
32110
32360
  licenseLimit,
32361
+ search,
32362
+ searching,
32363
+ setSearch,
32111
32364
  spans,
32112
32365
  systemLimit,
32113
32366
  totalCount,
@@ -32119,10 +32372,11 @@ var SpansListPage = () => {
32119
32372
  }, [clearSpans]);
32120
32373
  const localstackVersion = status?.localstackVersion ?? (statusError instanceof AppInspectorNotFoundError ? statusError.localstackVersion : void 0);
32121
32374
  const versionCompatibility = checkEmulatorVersion(localstackVersion);
32122
- const [bannerDismissed, setBannerDismissed] = useState18(false);
32375
+ const searchSupported = emulatorSupportsSearch(localstackVersion);
32376
+ const [bannerDismissed, setBannerDismissed] = useState19(false);
32123
32377
  const [order2, setOrder] = useLocalStorage("spans-order", "oldest_first");
32124
- const [selectedTraceId, setSelectedTraceId] = useState18();
32125
- const [selectedSpanId, setSelectedSpanId] = useState18();
32378
+ const [selectedTraceId, setSelectedTraceId] = useState19();
32379
+ const [selectedSpanId, setSelectedSpanId] = useState19();
32126
32380
  const navigateToSpan = useCallback11((span) => {
32127
32381
  setSelectedTraceId(span.trace_id);
32128
32382
  setSelectedSpanId(span.span_id);
@@ -32235,8 +32489,12 @@ var SpansListPage = () => {
32235
32489
  onClearSpans: clearSpansSync,
32236
32490
  onFetchForward: fetchForward,
32237
32491
  onOrderChange: setOrder,
32492
+ onSearchChange: setSearch,
32238
32493
  onSpanClick: navigateToSpan,
32239
32494
  order: order2,
32495
+ search,
32496
+ searching,
32497
+ searchSupported,
32240
32498
  spans,
32241
32499
  systemLimit,
32242
32500
  totalCount,