index.tsx 2.7 KB

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