@localstack/appinspector-ui 1.0.185 → 1.0.186

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.cjs CHANGED
@@ -13103,7 +13103,7 @@ var ResponsiveTimestampCell = (0, import_react31.memo)(({ date }) => {
13103
13103
 
13104
13104
  // src/dev-settings.tsx
13105
13105
  var React5 = __toESM(require("react"), 1);
13106
- var DEFAULT_DEV_SETTINGS = { requestTerms: "on", waterfallIssueBackgrounds: "on", waterfallLayout: "tree", waterfallStatusIcons: "first column" };
13106
+ var DEFAULT_DEV_SETTINGS = { requestTerms: "on", warningIcon: "iam shield", waterfallIssueBackgrounds: "on", waterfallLayout: "tree", waterfallStatusIcons: "first column" };
13107
13107
  var DevSettingsContext = React5.createContext(DEFAULT_DEV_SETTINGS);
13108
13108
  var useDevSettings = () => React5.useContext(DevSettingsContext);
13109
13109
 
@@ -15355,22 +15355,6 @@ ServiceCell.displayName = "ServiceCell";
15355
15355
  var import_icons_material2 = require("@mui/icons-material");
15356
15356
  var import_material5 = require("@mui/material");
15357
15357
 
15358
- // src/types/error-levels.ts
15359
- var ErrorLevel = {
15360
- ERROR: 3,
15361
- // General error
15362
- IAM_PERMISSION: 5,
15363
- // IAM permission issues
15364
- OK: 2,
15365
- // OK
15366
- // Standard OTEL status codes
15367
- UNSET: 1,
15368
- // Unset
15369
- // Extended custom levels
15370
- WARNING: 4
15371
- // Warning
15372
- };
15373
-
15374
15358
  // src/utils/iam-utils.ts
15375
15359
  function determinePermissionStatus(payload) {
15376
15360
  if (payload.explicit_deny_count && payload.explicit_deny_count > 0) {
@@ -15469,58 +15453,40 @@ var getIamSummary = (span) => {
15469
15453
  return { denials, level: void 0 };
15470
15454
  };
15471
15455
 
15472
- // src/utils/error-level.ts
15473
- var calculateHighestErrorLevel = (span) => {
15474
- if (span.operation_status) {
15475
- switch (span.operation_status) {
15476
- case "error": {
15477
- return ErrorLevel.ERROR;
15478
- }
15479
- case "iam_explicit_deny":
15480
- case "iam_explicit_warn":
15481
- case "iam_implicit_deny":
15482
- case "iam_implicit_warn": {
15483
- return ErrorLevel.IAM_PERMISSION;
15484
- }
15485
- default: {
15486
- return ErrorLevel.OK;
15487
- }
15488
- }
15456
+ // src/utils/span-issues.ts
15457
+ var firstText = (...values) => values.find((value) => !!value) ?? void 0;
15458
+ var OTEL_STATUS_ERROR = 2;
15459
+ var getIamDenials = (span) => span.events.flatMap((event) => {
15460
+ if (!event.event_type?.toLowerCase().includes("iam") || typeof event.attributes?.payload !== "string") {
15461
+ return [];
15489
15462
  }
15490
- const hasIamDenial = span.events.some((event) => {
15491
- if (!event.event_type?.toLowerCase().includes("iam")) return false;
15492
- if (typeof event.attributes?.payload !== "string") return false;
15493
- const parsed = parseIAMEvent(event.attributes.payload);
15494
- return parsed?.permission === "explicitly_denied" || parsed?.permission === "implicitly_denied";
15495
- });
15496
- if (hasIamDenial) return ErrorLevel.IAM_PERMISSION;
15497
- if (span.status_code === 2) return ErrorLevel.ERROR;
15498
- const hasErrorInErrors = span.errors?.some((error) => error.level === "error");
15499
- if (hasErrorInErrors) return ErrorLevel.ERROR;
15500
- const hasWarning = span.errors?.some((error) => error.level === "warning");
15501
- if (hasWarning) return ErrorLevel.WARNING;
15502
- return span.status_code || ErrorLevel.UNSET;
15463
+ const permission = parseIAMEvent(event.attributes.payload)?.permission;
15464
+ if (permission === "explicitly_denied") return ["explicit"];
15465
+ if (permission === "implicitly_denied") return ["implicit"];
15466
+ return [];
15467
+ });
15468
+ var getSpanIssues = (span) => {
15469
+ const status = span.operation_status;
15470
+ const iamDenied = status === "iam_explicit_deny" || status === "iam_implicit_deny";
15471
+ const iamWarned = status === "iam_explicit_warn" || status === "iam_implicit_warn";
15472
+ const errorMessages = (span.errors ?? []).filter((item) => item.level === "error");
15473
+ const warningMessages = (span.errors ?? []).filter((item) => item.level === "warning");
15474
+ const denials = getIamDenials(span);
15475
+ const unenforcedDenial = !iamDenied && (denials.length > 0 || span.attributes?.["localstack.has_iam_deny_event"] === true);
15476
+ const error = status === "error" || iamDenied || span.status_code === OTEL_STATUS_ERROR || errorMessages.length > 0;
15477
+ const warning2 = iamWarned || warningMessages.length > 0 || unenforcedDenial;
15478
+ const denialCount = unenforcedDenial ? Math.max(1, denials.length) : 0;
15479
+ return {
15480
+ error,
15481
+ errorType: error ? firstText(span.status_message, errorMessages[0]?.message) ?? (iamDenied ? "AccessDenied" : "Error") : void 0,
15482
+ warning: warning2,
15483
+ warningCount: warning2 ? Math.max(1, warningMessages.length + denialCount) : 0,
15484
+ warningType: warning2 ? firstText(warningMessages[0]?.message) ?? (unenforcedDenial ? `IAM ${denials[0] ?? "implicit"} deny` : iamWarned ? "IAM permission warning" : "Warning") : void 0
15485
+ };
15503
15486
  };
15504
15487
 
15505
15488
  // src/components/cells/status-cell.tsx
15506
15489
  var import_jsx_runtime125 = require("react/jsx-runtime");
15507
- var StatusIcon = ({ errorLevel, operationStatus, spanStatusCode }) => {
15508
- switch (errorLevel) {
15509
- case ErrorLevel.ERROR: {
15510
- return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.Cancel, { sx: { color: "red" } });
15511
- }
15512
- case ErrorLevel.IAM_PERMISSION: {
15513
- const isDenial = operationStatus ? operationStatus === "iam_explicit_deny" || operationStatus === "iam_implicit_deny" : spanStatusCode === 2;
15514
- return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.GppBad, { sx: { color: isDenial ? "red" : "warning.main" } });
15515
- }
15516
- case ErrorLevel.WARNING: {
15517
- return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.Error, { sx: { color: "orange" } });
15518
- }
15519
- default: {
15520
- return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_jsx_runtime125.Fragment, {});
15521
- }
15522
- }
15523
- };
15524
15490
  var SPAN_STATUS_LABELS = {
15525
15491
  0: "Unset",
15526
15492
  1: "OK",
@@ -15548,9 +15514,14 @@ var buildTooltipContent = (span) => {
15548
15514
  ] });
15549
15515
  };
15550
15516
  var StatusIconWithTooltip = ({ span }) => {
15551
- const errorLevel = calculateHighestErrorLevel(span);
15552
- if (errorLevel !== ErrorLevel.ERROR && errorLevel !== ErrorLevel.IAM_PERMISSION) return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_jsx_runtime125.Fragment, {});
15553
- return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_material5.Tooltip, { title: buildTooltipContent(span), children: /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_material5.Box, { sx: { alignItems: "center", cursor: "default", display: "flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(StatusIcon, { errorLevel, operationStatus: span.operation_status, spanStatusCode: span.status_code }) }) });
15517
+ const { warningIcon } = useDevSettings();
15518
+ const { error, warning: warning2 } = getSpanIssues(span);
15519
+ if (!error && !warning2) return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_jsx_runtime125.Fragment, {});
15520
+ const iamLevel = getIamSummary(span).level;
15521
+ return /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_material5.Tooltip, { title: buildTooltipContent(span), children: /* @__PURE__ */ (0, import_jsx_runtime125.jsxs)(import_material5.Box, { sx: { alignItems: "center", cursor: "default", display: "flex" }, children: [
15522
+ error && /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_material5.Box, { "aria-label": "Error", role: "img", sx: { display: "flex" }, children: iamLevel === "error" ? /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.GppBad, { sx: { color: "error.main" } }) : /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.Cancel, { sx: { color: "error.main" } }) }),
15523
+ warning2 && /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_material5.Box, { "aria-label": "Warning", role: "img", sx: { display: "flex" }, children: iamLevel === "warning" && warningIcon === "iam shield" ? /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.GppBad, { sx: { color: "warning.main" } }) : /* @__PURE__ */ (0, import_jsx_runtime125.jsx)(import_icons_material2.Error, { sx: { color: "warning.main" } }) })
15524
+ ] }) });
15554
15525
  };
15555
15526
 
15556
15527
  // src/components/spans-list/span-count-badge.tsx
@@ -16754,38 +16725,6 @@ var getEventGroupsByType = (events) => {
16754
16725
  return groups;
16755
16726
  };
16756
16727
 
16757
- // src/utils/span-issues.ts
16758
- var firstText = (...values) => values.find((value) => !!value) ?? void 0;
16759
- var OTEL_STATUS_ERROR = 2;
16760
- var getIamDenials = (span) => span.events.flatMap((event) => {
16761
- if (!event.event_type?.toLowerCase().includes("iam") || typeof event.attributes?.payload !== "string") {
16762
- return [];
16763
- }
16764
- const permission = parseIAMEvent(event.attributes.payload)?.permission;
16765
- if (permission === "explicitly_denied") return ["explicit"];
16766
- if (permission === "implicitly_denied") return ["implicit"];
16767
- return [];
16768
- });
16769
- var getSpanIssues = (span) => {
16770
- const status = span.operation_status;
16771
- const iamDenied = status === "iam_explicit_deny" || status === "iam_implicit_deny";
16772
- const iamWarned = status === "iam_explicit_warn" || status === "iam_implicit_warn";
16773
- const errorMessages = (span.errors ?? []).filter((item) => item.level === "error");
16774
- const warningMessages = (span.errors ?? []).filter((item) => item.level === "warning");
16775
- const denials = getIamDenials(span);
16776
- const unenforcedDenial = !iamDenied && (denials.length > 0 || span.attributes?.["localstack.has_iam_deny_event"] === true);
16777
- const error = status === "error" || iamDenied || span.status_code === OTEL_STATUS_ERROR || errorMessages.length > 0;
16778
- const warning2 = iamWarned || warningMessages.length > 0 || unenforcedDenial;
16779
- const denialCount = unenforcedDenial ? Math.max(1, denials.length) : 0;
16780
- return {
16781
- error,
16782
- errorType: error ? firstText(span.status_message, errorMessages[0]?.message) ?? (iamDenied ? "AccessDenied" : "Error") : void 0,
16783
- warning: warning2,
16784
- warningCount: warning2 ? Math.max(1, warningMessages.length + denialCount) : 0,
16785
- warningType: warning2 ? firstText(warningMessages[0]?.message) ?? (unenforcedDenial ? `IAM ${denials[0] ?? "implicit"} deny` : iamWarned ? "IAM permission warning" : "Warning") : void 0
16786
- };
16787
- };
16788
-
16789
16728
  // src/utils/time.ts
16790
16729
  function unixNanoToDate(unixNanoString) {
16791
16730
  const milliseconds = unixNanoToMilliseconds(unixNanoString);
@@ -16834,7 +16773,7 @@ var import_react44 = require("react");
16834
16773
  var import_icons_material8 = require("@mui/icons-material");
16835
16774
  var import_material12 = require("@mui/material");
16836
16775
  var import_jsx_runtime132 = require("react/jsx-runtime");
16837
- var StatusIcon2 = ({ errorLevel }) => {
16776
+ var StatusIcon = ({ errorLevel }) => {
16838
16777
  switch (errorLevel) {
16839
16778
  case EventLevel.LevelError: {
16840
16779
  return /* @__PURE__ */ (0, import_jsx_runtime132.jsx)(import_icons_material8.Cancel, { sx: { color: "red" } });
@@ -18935,7 +18874,7 @@ var EventDetail = ({
18935
18874
  const eventLevel = getEventLevelFromGroup(type);
18936
18875
  return /* @__PURE__ */ (0, import_jsx_runtime137.jsxs)(import_material17.Box, { children: [
18937
18876
  /* @__PURE__ */ (0, import_jsx_runtime137.jsxs)(import_material17.Box, { sx: { alignItems: "center", display: "flex", mb: 0.5 }, children: [
18938
- /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(StatusIcon2, { errorLevel: eventLevel }),
18877
+ /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(StatusIcon, { errorLevel: eventLevel }),
18939
18878
  /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(import_material17.Typography, { color: "text.secondary", sx: { fontWeight: 600, ml: 0.5 }, variant: "caption", children: displayText })
18940
18879
  ] }),
18941
18880
  /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(import_material17.Box, { children: events.map((event) => /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(import_material17.Box, { sx: { maxWidth: "100%", mb: 0.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime137.jsx)(EventMessage, { event }) }, `${event.span_id}-${event.event_id}`)) })
@@ -31584,8 +31523,9 @@ var handleStyle = {
31584
31523
  borderColor: "lightgray",
31585
31524
  opacity: 0
31586
31525
  };
31587
- var NodeContent = ({ event, expanded, hasPermissionEvents, isError, isWarning }) => {
31526
+ var NodeContent = ({ event, expanded, iamLevel, issues }) => {
31588
31527
  const theme = (0, import_material20.useTheme)();
31528
+ const { warningIcon } = useDevSettings();
31589
31529
  return /* @__PURE__ */ (0, import_jsx_runtime143.jsxs)(import_jsx_runtime143.Fragment, { children: [
31590
31530
  /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_react52.Handle, { position: import_react52.Position.Left, style: handleStyle, type: "target" }),
31591
31531
  /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_react52.Handle, { position: import_react52.Position.Right, style: handleStyle, type: "source" }),
@@ -31640,8 +31580,8 @@ var NodeContent = ({ event, expanded, hasPermissionEvents, isError, isWarning })
31640
31580
  width: "38px"
31641
31581
  },
31642
31582
  children: [
31643
- (isError || isWarning) && hasPermissionEvents && /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_material20.Tooltip, { arrow: true, title: "Permission denied", children: /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_icons_material12.GppBad, { sx: { color: isError ? theme.palette.error.main : theme.palette.warning.main, fontSize: "16px" } }) }),
31644
- isError && !hasPermissionEvents && /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_material20.Tooltip, { arrow: true, title: "Error", children: /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_icons_material12.Cancel, { sx: { color: theme.palette.error.main, fontSize: "16px" } }) })
31583
+ issues.error && /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_material20.Tooltip, { arrow: true, title: issues.errorType, children: /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_material20.Box, { "aria-label": "Error", role: "img", sx: { display: "flex" }, children: iamLevel === "error" ? /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_icons_material12.GppBad, { sx: { color: theme.palette.error.main, fontSize: "16px" } }) : /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_icons_material12.Cancel, { sx: { color: theme.palette.error.main, fontSize: "16px" } }) }) }),
31584
+ issues.warning && /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_material20.Tooltip, { arrow: true, title: issues.warningType, children: /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_material20.Box, { "aria-label": "Warning", role: "img", sx: { display: "flex" }, children: iamLevel === "warning" && warningIcon === "iam shield" ? /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_icons_material12.GppBad, { sx: { color: theme.palette.warning.main, fontSize: "16px" } }) : /* @__PURE__ */ (0, import_jsx_runtime143.jsx)(import_icons_material12.Error, { sx: { color: theme.palette.warning.main, fontSize: "16px" } }) }) })
31645
31585
  ]
31646
31586
  }
31647
31587
  ),
@@ -31664,17 +31604,9 @@ var ServiceNode = (0, import_react53.memo)(({ data, selected }) => {
31664
31604
  const theme = (0, import_material20.useTheme)();
31665
31605
  const [isHovered, setIsHovered] = (0, import_react53.useState)(false);
31666
31606
  const nodeRef = (0, import_react53.useRef)(null);
31667
- const { operation_status } = data.event;
31668
- const hasPermissionEventsLegacy = (0, import_react53.useMemo)(
31669
- () => data.event.events.some(
31670
- (event) => event.event_type === "iam.policy_evaluation" && event.name === "iam.policy.denied"
31671
- ),
31672
- [data.event.events]
31673
- );
31674
- const isError = operation_status ? operation_status === "error" || operation_status === "iam_explicit_deny" || operation_status === "iam_implicit_deny" : data.event.status_code === 2;
31675
- const isWarning = operation_status ? operation_status === "iam_explicit_warn" || operation_status === "iam_implicit_warn" : !isError && data.event.status_code === 1 && hasPermissionEventsLegacy;
31676
- const hasPermissionEvents = operation_status ? operation_status.startsWith("iam_") : hasPermissionEventsLegacy;
31677
- const outlineColor = isError ? theme.palette.error.main : isWarning ? theme.palette.warning.main : void 0;
31607
+ const issues = getSpanIssues(data.event);
31608
+ const iamLevel = getIamSummary(data.event).level;
31609
+ const outlineColor = issues.error ? theme.palette.error.main : issues.warning ? theme.palette.warning.main : void 0;
31678
31610
  const sharedBoxSx = {
31679
31611
  backgroundColor: theme.palette.background.paper,
31680
31612
  borderLeft: `3px solid ${outlineColor ?? "transparent"}`,
@@ -31683,7 +31615,7 @@ var ServiceNode = (0, import_react53.memo)(({ data, selected }) => {
31683
31615
  minWidth: 140,
31684
31616
  outline: selected ? `2px solid ${outlineColor ?? theme.palette.primary.main}` : `1px solid ${theme.palette.divider}`
31685
31617
  };
31686
- const contentProps = { event: data.event, hasPermissionEvents, isError, isWarning };
31618
+ const contentProps = { event: data.event, iamLevel, issues };
31687
31619
  const handleMouseEnter = () => {
31688
31620
  setIsHovered(true);
31689
31621
  const xyNode = nodeRef.current?.closest(".react-flow__node");