index.tsx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import {Location} from 'history';
  2. import {t} from 'sentry/locale';
  3. import {Organization, Project} from 'sentry/types';
  4. import EventView from 'sentry/utils/discover/eventView';
  5. import {isAggregateField, WebVital} from 'sentry/utils/discover/fields';
  6. import {WEB_VITAL_DETAILS} from 'sentry/utils/performance/vitals/constants';
  7. import {decodeScalar} from 'sentry/utils/queryString';
  8. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  9. import withOrganization from 'sentry/utils/withOrganization';
  10. import withProjects from 'sentry/utils/withProjects';
  11. import PageLayout from '../pageLayout';
  12. import Tab from '../tabs';
  13. import {PERCENTILE, VITAL_GROUPS} from './constants';
  14. import VitalsContent from './content';
  15. type Props = {
  16. location: Location;
  17. organization: Organization;
  18. projects: Project[];
  19. };
  20. function TransactionVitals(props: Props) {
  21. const {location, organization, projects} = props;
  22. return (
  23. <PageLayout
  24. location={location}
  25. organization={organization}
  26. projects={projects}
  27. tab={Tab.WebVitals}
  28. getDocumentTitle={getDocumentTitle}
  29. generateEventView={generateEventView}
  30. childComponent={VitalsContent}
  31. />
  32. );
  33. }
  34. function getDocumentTitle(transactionName: string): string {
  35. const hasTransactionName =
  36. typeof transactionName === 'string' && String(transactionName).trim().length > 0;
  37. if (hasTransactionName) {
  38. return [String(transactionName).trim(), t('Vitals')].join(' \u2014 ');
  39. }
  40. return [t('Summary'), t('Vitals')].join(' \u2014 ');
  41. }
  42. function generateEventView({
  43. location,
  44. transactionName,
  45. }: {
  46. location: Location;
  47. transactionName: string;
  48. }): EventView {
  49. const query = decodeScalar(location.query.query, '');
  50. const conditions = new MutableSearch(query);
  51. conditions.setFilterValues('event.type', ['transaction']);
  52. conditions.setFilterValues('transaction', [transactionName]);
  53. Object.keys(conditions.filters).forEach(field => {
  54. if (isAggregateField(field)) {
  55. conditions.removeFilter(field);
  56. }
  57. });
  58. const vitals = VITAL_GROUPS.reduce((allVitals: WebVital[], group) => {
  59. return allVitals.concat(group.vitals);
  60. }, []);
  61. return EventView.fromNewQueryWithLocation(
  62. {
  63. id: undefined,
  64. version: 2,
  65. name: transactionName,
  66. fields: [
  67. ...vitals.map(vital => `percentile(${vital}, ${PERCENTILE})`),
  68. ...vitals.map(vital => `count_at_least(${vital}, 0)`),
  69. ...vitals.map(
  70. vital => `count_at_least(${vital}, ${WEB_VITAL_DETAILS[vital].poorThreshold})`
  71. ),
  72. ],
  73. query: conditions.formatString(),
  74. projects: [],
  75. },
  76. location
  77. );
  78. }
  79. export default withProjects(withOrganization(TransactionVitals));