pageLayout.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import {useState} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import styled from '@emotion/styled';
  4. import {Location} from 'history';
  5. import Feature from 'sentry/components/acl/feature';
  6. import {Alert} from 'sentry/components/alert';
  7. import * as Layout from 'sentry/components/layouts/thirds';
  8. import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
  9. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  10. import {Tabs} from 'sentry/components/tabs';
  11. import {t} from 'sentry/locale';
  12. import {Organization, Project} from 'sentry/types';
  13. import {defined} from 'sentry/utils';
  14. import EventView from 'sentry/utils/discover/eventView';
  15. import {useMetricsCardinalityContext} from 'sentry/utils/performance/contexts/metricsCardinality';
  16. import {PerformanceEventViewProvider} from 'sentry/utils/performance/contexts/performanceEventViewContext';
  17. import {decodeScalar} from 'sentry/utils/queryString';
  18. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  19. import {getTransactionName} from '../utils';
  20. import PageLayout from './pageLayout/pageLayout';
  21. import Tab from './pageLayout/tabs';
  22. import usePageTabs from './pageLayout/usePageTabs';
  23. import TransactionHeader from './header';
  24. import {TransactionThresholdMetric} from './transactionThresholdModal';
  25. export type ChildProps = {
  26. eventView: EventView;
  27. location: Location;
  28. organization: Organization;
  29. projectId: string;
  30. projects: Project[];
  31. setError: React.Dispatch<React.SetStateAction<string | undefined>>;
  32. transactionName: string;
  33. // These are used to trigger a reload when the threshold/metric changes.
  34. transactionThreshold?: number;
  35. transactionThresholdMetric?: TransactionThresholdMetric;
  36. };
  37. type Props = {
  38. childComponent: (props: ChildProps) => JSX.Element;
  39. generateEventView: (props: {
  40. location: Location;
  41. organization: Organization;
  42. transactionName: string;
  43. }) => EventView;
  44. getDocumentTitle: (name: string) => string;
  45. location: Location;
  46. organization: Organization;
  47. projects: Project[];
  48. tab: Tab;
  49. features?: string[];
  50. };
  51. function Page(props: Props) {
  52. const {
  53. location,
  54. organization,
  55. projects,
  56. tab,
  57. getDocumentTitle,
  58. generateEventView,
  59. childComponent: ChildComponent,
  60. features = [],
  61. } = props;
  62. const projectId = decodeScalar(location.query.project);
  63. const transactionName = getTransactionName(location);
  64. const [error, setError] = useState<string | undefined>();
  65. const metricsCardinality = useMetricsCardinalityContext();
  66. const [transactionThreshold, setTransactionThreshold] = useState<number | undefined>();
  67. const [transactionThresholdMetric, setTransactionThresholdMetric] = useState<
  68. TransactionThresholdMetric | undefined
  69. >();
  70. const {onTabChange} = usePageTabs({
  71. location,
  72. organization,
  73. projectId,
  74. projects,
  75. tab,
  76. transactionName,
  77. });
  78. if (!defined(projectId) || !defined(transactionName)) {
  79. redirectToPerformanceHomepage(organization, location);
  80. return null;
  81. }
  82. const project = projects.find(p => p.id === projectId);
  83. const eventView = generateEventView({location, transactionName, organization});
  84. return (
  85. <PageLayout
  86. title={getDocumentTitle(transactionName)}
  87. organization={organization}
  88. tab={tab}
  89. project={project}
  90. >
  91. <ChildComponent
  92. location={location}
  93. organization={organization}
  94. projects={projects}
  95. eventView={eventView}
  96. projectId={projectId}
  97. transactionName={transactionName}
  98. setError={setError}
  99. transactionThreshold={transactionThreshold}
  100. transactionThresholdMetric={transactionThresholdMetric}
  101. />
  102. </PageLayout>
  103. );
  104. // return (
  105. // <SentryDocumentTitle
  106. // title={getDocumentTitle(transactionName)}
  107. // orgSlug={organization.slug}
  108. // projectSlug={project?.slug}
  109. // >
  110. // <Feature
  111. // features={['performance-view', ...features]}
  112. // organization={organization}
  113. // renderDisabled={NoAccess}
  114. // >
  115. // <PerformanceEventViewProvider value={{eventView}}>
  116. // <PageFiltersContainer
  117. // shouldForceProject={defined(project)}
  118. // forceProject={project}
  119. // specificProjectSlugs={defined(project) ? [project.slug] : []}
  120. // >
  121. // <Tabs value={tab} onChange={onTabChange}>
  122. // <Layout.Page>
  123. // <TransactionHeader
  124. // eventView={eventView}
  125. // location={location}
  126. // organization={organization}
  127. // projects={projects}
  128. // projectId={projectId}
  129. // transactionName={transactionName}
  130. // currentTab={tab}
  131. // hasWebVitals={tab === Tab.WebVitals ? 'yes' : 'maybe'}
  132. // onChangeThreshold={(threshold, metric) => {
  133. // setTransactionThreshold(threshold);
  134. // setTransactionThresholdMetric(metric);
  135. // }}
  136. // metricsCardinality={metricsCardinality}
  137. // />
  138. // <Layout.Body>
  139. // {defined(error) && (
  140. // <StyledAlert type="error" showIcon>
  141. // {error}
  142. // </StyledAlert>
  143. // )}
  144. // <ChildComponent
  145. // location={location}
  146. // organization={organization}
  147. // projects={projects}
  148. // eventView={eventView}
  149. // projectId={projectId}
  150. // transactionName={transactionName}
  151. // setError={setError}
  152. // transactionThreshold={transactionThreshold}
  153. // transactionThresholdMetric={transactionThresholdMetric}
  154. // />
  155. // </Layout.Body>
  156. // </Layout.Page>
  157. // </Tabs>
  158. // </PageFiltersContainer>
  159. // </PerformanceEventViewProvider>
  160. // </Feature>
  161. // </SentryDocumentTitle>
  162. // );
  163. }
  164. export function NoAccess() {
  165. return <Alert type="warning">{t("You don't have access to this feature")}</Alert>;
  166. }
  167. // const StyledAlert = styled(Alert)`
  168. // grid-column: 1/3;
  169. // margin: 0;
  170. // `;
  171. export function redirectToPerformanceHomepage(
  172. organization: Organization,
  173. location: Location
  174. ) {
  175. // If there is no transaction name, redirect to the Performance landing page
  176. browserHistory.replace(
  177. normalizeUrl({
  178. pathname: `/organizations/${organization.slug}/performance/`,
  179. query: {
  180. ...location.query,
  181. },
  182. })
  183. );
  184. }
  185. export default Page;