@localstack/appinspector-ui 1.0.29 → 1.0.31

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
2
  import { Box as Box7 } from "@mui/material";
3
- import { useCallback as useCallback5, useEffect as useEffect4, useMemo as useMemo4, useRef as useRef3, useState as useState5 } from "react";
3
+ import { useCallback as useCallback6, useEffect as useEffect4, useMemo as useMemo5, useRef as useRef3, useState as useState5 } from "react";
4
4
  import { useNavigate } from "react-router-dom";
5
5
 
6
6
  // src/api/use-api.tsx
@@ -3476,6 +3476,28 @@ var useStatus = () => {
3476
3476
  return { checking, checkStatus, error, status };
3477
3477
  };
3478
3478
 
3479
+ // src/utils/use-search-param-codec.ts
3480
+ import { useCallback as useCallback5, useMemo as useMemo4 } from "react";
3481
+ import { useSearchParams } from "react-router-dom";
3482
+ var useSearchParamCodec = (key, codec) => {
3483
+ const [searchParams, setSearchParams] = useSearchParams();
3484
+ const raw = searchParams.get(key) ?? void 0;
3485
+ const value = useMemo4(() => {
3486
+ return codec.decode(raw);
3487
+ }, [raw, codec]);
3488
+ const setValue = useCallback5(
3489
+ (next) => {
3490
+ setSearchParams((previous) => {
3491
+ const nextParams = new URLSearchParams(previous);
3492
+ nextParams.set(key, codec.encode(next));
3493
+ return nextParams;
3494
+ });
3495
+ },
3496
+ [key, codec, setSearchParams]
3497
+ );
3498
+ return [value, setValue];
3499
+ };
3500
+
3479
3501
  // src/pages/spans-list-page.tsx
3480
3502
  import { jsx as jsx130 } from "react/jsx-runtime";
3481
3503
  var spansPerPageOptions = [25, 50, 100];
@@ -3486,10 +3508,30 @@ var SpansListPage = () => {
3486
3508
  const hasFetched = useRef3(false);
3487
3509
  const [filterWriteOperations, setFilterWriteOperations] = useLocalStorage("filterWriteOperations", true);
3488
3510
  const mapPageToNextCursor = useRef3({});
3489
- const [page, setPage] = useState5(0);
3490
- const [pageSize, setPageSize] = useState5(100);
3511
+ const [page, setPage] = useSearchParamCodec("page", {
3512
+ decode: (raw) => {
3513
+ const defaultPage = 0;
3514
+ if (!raw) {
3515
+ return defaultPage;
3516
+ }
3517
+ const parsed = Number.parseInt(raw, 10);
3518
+ return Number.isNaN(parsed) || parsed < 0 ? defaultPage : parsed;
3519
+ },
3520
+ encode: (value) => value.toString()
3521
+ });
3522
+ const [pageSize, setPageSize] = useSearchParamCodec("pageSize", {
3523
+ decode: (raw) => {
3524
+ const defaultPageSize = 100;
3525
+ if (!raw) {
3526
+ return defaultPageSize;
3527
+ }
3528
+ const parsed = Number.parseInt(raw, 10);
3529
+ return spansPerPageOptions.includes(parsed) ? parsed : defaultPageSize;
3530
+ },
3531
+ encode: (value) => value.toString()
3532
+ });
3491
3533
  const [spanCount, setSpanCount] = useState5(0);
3492
- const queryOptions = useMemo4(() => {
3534
+ const queryOptions = useMemo5(() => {
3493
3535
  return {
3494
3536
  is_write_operation: filterWriteOperations ? true : void 0,
3495
3537
  limit: pageSize,
@@ -3498,7 +3540,7 @@ var SpansListPage = () => {
3498
3540
  }, [filterWriteOperations, pageSize, page]);
3499
3541
  const [fetchError, setFetchError] = useState5();
3500
3542
  const { checkStatus, error: statusError, status } = useStatus();
3501
- const fetchSpans = useCallback5(async () => {
3543
+ const fetchSpans = useCallback6(async () => {
3502
3544
  setLoading(true);
3503
3545
  try {
3504
3546
  const response = await api.getSpans(queryOptions);
@@ -3515,7 +3557,7 @@ var SpansListPage = () => {
3515
3557
  setLoading(false);
3516
3558
  }
3517
3559
  }, [api, page, queryOptions]);
3518
- const fetchSpansSync = useCallback5(() => {
3560
+ const fetchSpansSync = useCallback6(() => {
3519
3561
  void fetchSpans();
3520
3562
  }, [fetchSpans]);
3521
3563
  useEffect4(() => {
@@ -3530,11 +3572,16 @@ var SpansListPage = () => {
3530
3572
  }, [fetchSpans]);
3531
3573
  const navigate = useNavigate();
3532
3574
  const { resolveLink } = useAppInspector();
3533
- const navigateToSpan = useCallback5((span) => {
3575
+ const navigateToSpan = useCallback6((span) => {
3534
3576
  const url = resolveLink({ to: "trace-graph", traceId: span.trace_id });
3535
- navigate(`${url}?spanId=${span.span_id}`);
3536
- }, [navigate, resolveLink]);
3537
- const clearSpans = useCallback5(async () => {
3577
+ const searchParams = new URLSearchParams({
3578
+ page: String(page),
3579
+ pageSize: String(pageSize),
3580
+ spanId: span.span_id
3581
+ });
3582
+ navigate(`${url}?${searchParams.toString()}`);
3583
+ }, [navigate, resolveLink, page, pageSize]);
3584
+ const clearSpans = useCallback6(async () => {
3538
3585
  setLoading(true);
3539
3586
  try {
3540
3587
  await api.deleteSpans();
@@ -3548,7 +3595,7 @@ var SpansListPage = () => {
3548
3595
  setLoading(false);
3549
3596
  }
3550
3597
  }, [api, fetchSpans]);
3551
- const handleRetry = useCallback5(() => {
3598
+ const handleRetry = useCallback6(() => {
3552
3599
  void checkStatus();
3553
3600
  }, [checkStatus]);
3554
3601
  const shouldShowStatusMessage = Boolean(statusError) || status?.status === "DISABLED";
@@ -3608,12 +3655,12 @@ import { ArrowBack } from "@mui/icons-material";
3608
3655
  import { Box as Box19, Button as Button5, Drawer, Paper as Paper2 } from "@mui/material";
3609
3656
  import { styled } from "@mui/material/styles";
3610
3657
  import { ReactFlowProvider } from "@xyflow/react";
3611
- import { useCallback as useCallback7, useEffect as useEffect7, useState as useState10 } from "react";
3612
- import { useNavigate as useNavigate2, useParams, useSearchParams } from "react-router-dom";
3658
+ import { useCallback as useCallback8, useEffect as useEffect7, useState as useState10 } from "react";
3659
+ import { useNavigate as useNavigate2, useParams, useSearchParams as useSearchParams2 } from "react-router-dom";
3613
3660
 
3614
3661
  // src/components/event-details/event-details.tsx
3615
3662
  import { Box as Box15, Chip as Chip3, Divider as Divider2, Stack as Stack2, Typography as Typography9 } from "@mui/material";
3616
- import { useMemo as useMemo7 } from "react";
3663
+ import { useMemo as useMemo8 } from "react";
3617
3664
 
3618
3665
  // src/utils/iam-utils.ts
3619
3666
  function determinePermissionStatus(payload) {
@@ -3847,7 +3894,7 @@ import { Box as Box14 } from "@mui/material";
3847
3894
  // src/components/event-details/event-detail.tsx
3848
3895
  import { KeyboardArrowDown as KeyboardArrowDown2, KeyboardArrowRight as KeyboardArrowRight2 } from "@mui/icons-material";
3849
3896
  import { Box as Box12, Grid as Grid3, IconButton as IconButton3, Typography as Typography7 } from "@mui/material";
3850
- import { useEffect as useEffect5, useMemo as useMemo6, useRef as useRef4, useState as useState7 } from "react";
3897
+ import { useEffect as useEffect5, useMemo as useMemo7, useRef as useRef4, useState as useState7 } from "react";
3851
3898
 
3852
3899
  // src/components/status-icon.tsx
3853
3900
  import { Cancel, CheckCircle, Error as Error2, Info, RemoveCircle } from "@mui/icons-material";
@@ -3998,7 +4045,7 @@ var IAMEventDetail = ({ event }) => {
3998
4045
  // src/components/event-details/iam-permission-detail.tsx
3999
4046
  import { KeyboardArrowDown, KeyboardArrowRight } from "@mui/icons-material";
4000
4047
  import { Box as Box11, Chip as Chip2, IconButton as IconButton2, Typography as Typography6 } from "@mui/material";
4001
- import { useMemo as useMemo5, useState as useState6 } from "react";
4048
+ import { useMemo as useMemo6, useState as useState6 } from "react";
4002
4049
  import { jsx as jsx134, jsxs as jsxs125 } from "react/jsx-runtime";
4003
4050
  var getChipColors = (status) => {
4004
4051
  const isAllowed = status === "explicitly_allowed" || status === "implicitly_allowed";
@@ -4009,7 +4056,7 @@ var getChipColors = (status) => {
4009
4056
  };
4010
4057
  var IAMPermissionItem = ({ event }) => {
4011
4058
  const [isOpen, setIsOpen] = useState6(false);
4012
- const parsedData = useMemo5(() => {
4059
+ const parsedData = useMemo6(() => {
4013
4060
  const payloadString = event.attributes?.payload;
4014
4061
  if (!payloadString) {
4015
4062
  return;
@@ -4082,8 +4129,8 @@ var EventMessage = ({ event }) => {
4082
4129
  const [isOpen, setIsOpen] = useState7(false);
4083
4130
  const [isOverflowing, setIsOverflowing] = useState7(false);
4084
4131
  const textReference = useRef4(null);
4085
- const parsedMessage = useMemo6(() => parseEventMessage(event), [event]);
4086
- const isIAMPolicyEvent = useMemo6(
4132
+ const parsedMessage = useMemo7(() => parseEventMessage(event), [event]);
4133
+ const isIAMPolicyEvent = useMemo7(
4087
4134
  () => event.event_type === "iam.policy_evaluation" && event.attributes?.payload && typeof event.attributes.payload === "string",
4088
4135
  [event]
4089
4136
  );
@@ -4100,11 +4147,11 @@ var EventMessage = ({ event }) => {
4100
4147
  window.removeEventListener("resize", checkOverflow);
4101
4148
  };
4102
4149
  }, [parsedMessage.headline]);
4103
- const hasAdditionalContent = useMemo6(
4150
+ const hasAdditionalContent = useMemo7(
4104
4151
  () => parsedMessage.message || parsedMessage.details || isIAMPolicyEvent,
4105
4152
  [parsedMessage.message, parsedMessage.details, isIAMPolicyEvent]
4106
4153
  );
4107
- const shouldShowToggle = useMemo6(
4154
+ const shouldShowToggle = useMemo7(
4108
4155
  () => isOverflowing || hasAdditionalContent,
4109
4156
  [isOverflowing, hasAdditionalContent]
4110
4157
  );
@@ -4325,7 +4372,7 @@ var EventSection = ({
4325
4372
  // src/components/event-details/event-details.tsx
4326
4373
  import { Fragment as Fragment6, jsx as jsx138, jsxs as jsxs129 } from "react/jsx-runtime";
4327
4374
  var EventDetails = ({ onClose, selectedEvent }) => {
4328
- const attributes = useMemo7(() => {
4375
+ const attributes = useMemo8(() => {
4329
4376
  const attributes2 = Object.entries(selectedEvent?.attributes ?? {});
4330
4377
  return attributes2.filter(([key]) => key !== "localstack.aws.account_id" && key !== "localstack.aws.service");
4331
4378
  }, [selectedEvent?.attributes]);
@@ -4425,7 +4472,7 @@ function renderKeyValue(key, value) {
4425
4472
  import "@xyflow/react/dist/base.css";
4426
4473
  import { Alert as Alert3, Button as Button4, useTheme as useTheme2 } from "@mui/material";
4427
4474
  import { Background, ReactFlow, useReactFlow as useReactFlow2 } from "@xyflow/react";
4428
- import { useCallback as useCallback6, useEffect as useEffect6, useState as useState9 } from "react";
4475
+ import { useCallback as useCallback7, useEffect as useEffect6, useState as useState9 } from "react";
4429
4476
 
4430
4477
  // src/components/trace-graph/service-node.tsx
4431
4478
  import { Box as Box17, Stack as Stack3, Typography as Typography10 } from "@mui/material";
@@ -4436,10 +4483,10 @@ import { memo as memo2 } from "react";
4436
4483
  // src/components/trace-graph/problem-indicator.tsx
4437
4484
  import { Error as ErrorIcon2, Info as Info2, Warning as Warning2 } from "@mui/icons-material";
4438
4485
  import { Box as Box16, Tooltip as Tooltip4 } from "@mui/material";
4439
- import { useMemo as useMemo8 } from "react";
4486
+ import { useMemo as useMemo9 } from "react";
4440
4487
  import { jsx as jsx139 } from "react/jsx-runtime";
4441
4488
  var ProblemIndicator = ({ error }) => {
4442
- const icon = useMemo8(() => {
4489
+ const icon = useMemo9(() => {
4443
4490
  switch (error.level) {
4444
4491
  case "error": {
4445
4492
  return /* @__PURE__ */ jsx139(ErrorIcon2, { sx: { color: "#d32f2f", fontSize: "14px" } });
@@ -4452,7 +4499,7 @@ var ProblemIndicator = ({ error }) => {
4452
4499
  }
4453
4500
  }
4454
4501
  }, [error.level]);
4455
- const color = useMemo8(() => {
4502
+ const color = useMemo9(() => {
4456
4503
  switch (error.level) {
4457
4504
  case "error": {
4458
4505
  return "#d32f2f";
@@ -4795,7 +4842,7 @@ var TraceGraph = ({
4795
4842
  const [edges, setEdges] = useState9([]);
4796
4843
  const [initialViewSet, setInitialViewSet] = useState9(false);
4797
4844
  const { fitView, setCenter } = useReactFlow2();
4798
- const updateSelectedNode = useCallback6((nodeId) => {
4845
+ const updateSelectedNode = useCallback7((nodeId) => {
4799
4846
  const toSelect = new Set(nodeId ? [nodeId] : []);
4800
4847
  setNodes((previousNodes) => {
4801
4848
  return previousNodes.map((node) => ({ ...node, selected: toSelect.has(node.id) }));
@@ -4861,7 +4908,7 @@ var TraceGraph = ({
4861
4908
  updateSelectedNode(initialFocusEventId);
4862
4909
  }
4863
4910
  }, [initialFocusEventId, updateSelectedNode]);
4864
- const onNodeClick = useCallback6((_event, node) => {
4911
+ const onNodeClick = useCallback7((_event, node) => {
4865
4912
  onEventSelect(node.data.event);
4866
4913
  updateSelectedNode(node.id);
4867
4914
  }, [onEventSelect, updateSelectedNode]);
@@ -5031,13 +5078,13 @@ var TraceGraphView = ({
5031
5078
  };
5032
5079
  var TraceGraphPage = () => {
5033
5080
  const { traceId } = useParams();
5034
- const [searchParameters] = useSearchParams();
5081
+ const [searchParameters] = useSearchParams2();
5035
5082
  const spanId = searchParameters.get("spanId");
5036
5083
  const api = useAppInspectorApi();
5037
5084
  const [spans, setSpans] = useState10();
5038
5085
  const [loading, setLoading] = useState10(false);
5039
5086
  const [fetchError, setFetchError] = useState10();
5040
- const fetchSpans = useCallback7(async () => {
5087
+ const fetchSpans = useCallback8(async () => {
5041
5088
  setLoading(true);
5042
5089
  try {
5043
5090
  const response = await api.getSpans({
@@ -5059,7 +5106,7 @@ var TraceGraphPage = () => {
5059
5106
  const [selectedEvent, setSelectedEvent] = useState10();
5060
5107
  const [viewPortPixelWidth, setViewPortPixelWidth] = useState10(0);
5061
5108
  const { checkStatus, error: statusError, status } = useStatus();
5062
- const calculateDrawerWidth = useCallback7(() => {
5109
+ const calculateDrawerWidth = useCallback8(() => {
5063
5110
  const percentageMatch = /(\d+)%/.exec(DRAWER_WIDTH);
5064
5111
  if (percentageMatch && open) {
5065
5112
  const percentage = Number.parseInt(percentageMatch[1], 10);
@@ -5081,19 +5128,23 @@ var TraceGraphPage = () => {
5081
5128
  clearTimeout(timeoutId);
5082
5129
  };
5083
5130
  }, [open, calculateDrawerWidth]);
5084
- const handleEventSelect = useCallback7((event) => {
5131
+ const handleEventSelect = useCallback8((event) => {
5085
5132
  setSelectedEvent(event);
5086
5133
  setOpen(true);
5087
5134
  }, []);
5088
- const handleRetry = useCallback7(() => {
5135
+ const handleRetry = useCallback8(() => {
5089
5136
  void checkStatus();
5090
5137
  }, [checkStatus]);
5091
5138
  const navigate = useNavigate2();
5092
5139
  const { resolveLink } = useAppInspector();
5093
- const navigateToSpansList = useCallback7(() => {
5140
+ const navigateToSpansList = useCallback8(() => {
5094
5141
  const url = resolveLink({ to: "spans-list" });
5095
- navigate(url);
5096
- }, [navigate, resolveLink]);
5142
+ const searchParams = new URLSearchParams({
5143
+ page: searchParameters.get("page") ?? "",
5144
+ pageSize: searchParameters.get("pageSize") ?? ""
5145
+ });
5146
+ navigate(`${url}?${searchParams.toString()}`);
5147
+ }, [navigate, resolveLink, searchParameters]);
5097
5148
  return /* @__PURE__ */ jsx143(
5098
5149
  TraceGraphView,
5099
5150
  {