Просмотр исходного кода

feat(issue-details): Format number values in structured data (#66098)

Formats numbers with the same color used in syntax highlighting.

For Python variables, the values are strings but can safely be assumed
to be numbers in they look like one. Other SDKs are not implemented
because it's harder to know if something is a string or a number.

Also applies formatting by default when the value is an actual number.
Malachi Willey 1 год назад
Родитель
Сommit
e0f4358d03

+ 8 - 0
static/app/components/events/interfaces/frame/frameVariables.spec.tsx

@@ -107,6 +107,7 @@ describe('Frame Variables', function () {
           null: 'None',
           bool: 'True',
           str: "'string'",
+          number: '123.45',
           other: '<Class at 0x12345>',
         }}
         platform="python"
@@ -122,6 +123,9 @@ describe('Frame Variables', function () {
     expect(
       within(screen.getByTestId('value-string')).getByText('"string"')
     ).toBeInTheDocument();
+    expect(
+      within(screen.getByTestId('value-number')).getByText('123.45')
+    ).toBeInTheDocument();
     expect(
       within(screen.getByTestId('value-unformatted')).getByText('<Class at 0x12345>')
     ).toBeInTheDocument();
@@ -134,6 +138,7 @@ describe('Frame Variables', function () {
           null: '<null>',
           undefined: '<undefined>',
           bool: true,
+          number: 123.45,
           str: 'string',
         }}
         platform="node"
@@ -147,6 +152,9 @@ describe('Frame Variables', function () {
     expect(
       within(screen.getByTestId('value-boolean')).getByText('true')
     ).toBeInTheDocument();
+    expect(
+      within(screen.getByTestId('value-number')).getByText('123.45')
+    ).toBeInTheDocument();
     expect(
       within(screen.getByTestId('value-unformatted')).getByText('string')
     ).toBeInTheDocument();

+ 7 - 0
static/app/components/events/interfaces/frame/frameVariables.tsx

@@ -13,6 +13,7 @@ type Props = {
 };
 
 const PYTHON_STRING_REGEX = /^['"](.*)['"]$/;
+const NUMERIC_STRING_REGEX = /^-?\d+(\.\d+)?$/;
 
 const renderPythonBoolean = (value: unknown) => {
   if (typeof value === 'string') {
@@ -47,8 +48,14 @@ const getStructuredDataConfig = ({
         isNull: value => value === null || value === 'None',
         renderBoolean: renderPythonBoolean,
         renderNull: () => 'None',
+        // Python SDK wraps string values in single quotes
         isString: value => typeof value === 'string' && PYTHON_STRING_REGEX.test(value),
+        // Strip single quotes from python strings for display purposes
         renderString: value => value.replace(PYTHON_STRING_REGEX, '$1'),
+        // Python SDK returns numbers as strings, but we can assume they are numbers if they look like one
+        isNumber: value =>
+          typeof value === 'number' ||
+          (typeof value === 'string' && NUMERIC_STRING_REGEX.test(value)),
       };
     case 'ruby':
       return {

+ 13 - 10
static/app/components/structuredEventData/index.tsx

@@ -1,6 +1,5 @@
 import {Fragment, isValidElement} from 'react';
 import styled from '@emotion/styled';
-import isNumber from 'lodash/isNumber';
 
 import {AnnotatedText} from 'sentry/components/events/meta/annotatedText';
 import ExternalLink from 'sentry/components/links/externalLink';
@@ -18,6 +17,7 @@ import {
 export type StructedEventDataConfig = {
   isBoolean?: (value: unknown) => boolean;
   isNull?: (value: unknown) => boolean;
+  isNumber?: (value: unknown) => boolean;
   isString?: (value: unknown) => boolean;
   renderBoolean?: (value: unknown) => React.ReactNode;
   renderNull?: (value: unknown) => React.ReactNode;
@@ -114,6 +114,14 @@ function StructuredData({
     );
   }
 
+  if (typeof value === 'number' || config?.isNumber?.(value)) {
+    return (
+      <ValueNumber data-test-id="value-number">
+        <AnnotatedValue value={value} meta={meta} withAnnotatedText={withAnnotatedText} />
+      </ValueNumber>
+    );
+  }
+
   if (typeof value === 'string') {
     if (config?.isString?.(value)) {
       const stringValue = config.renderString?.(value) ?? value;
@@ -158,15 +166,6 @@ function StructuredData({
     );
   }
 
-  if (isNumber(value)) {
-    const valueToBeReturned =
-      withAnnotatedText && meta ? (
-        <AnnotatedValue value={value} meta={meta} withAnnotatedText={withAnnotatedText} />
-      ) : (
-        value
-      );
-    return <span>{valueToBeReturned}</span>;
-  }
   if (Array.isArray(value)) {
     for (i = 0; i < value.length; i++) {
       children.push(
@@ -284,6 +283,10 @@ const ValueStrippedString = styled('span')`
   color: var(--prism-keyword);
 `;
 
+const ValueNumber = styled('span')`
+  color: var(--prism-property);
+`;
+
 const ValueObjectKey = styled('span')`
   color: var(--prism-keyword);
 `;