index.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import {browserHistory} from 'react-router';
  2. import styled from '@emotion/styled';
  3. import Breadcrumbs from 'sentry/components/breadcrumbs';
  4. import DatePageFilter from 'sentry/components/datePageFilter';
  5. import FeatureBadge from 'sentry/components/featureBadge';
  6. import SelectControl, {
  7. ControlProps,
  8. } from 'sentry/components/forms/controls/selectControl';
  9. import * as Layout from 'sentry/components/layouts/thirds';
  10. import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
  11. import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter';
  12. import {t} from 'sentry/locale';
  13. import {space} from 'sentry/styles/space';
  14. import {useLocation} from 'sentry/utils/useLocation';
  15. import useOrganization from 'sentry/utils/useOrganization';
  16. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  17. import {ResourceSidebar} from 'sentry/views/performance/browser/resources/resourceSidebar';
  18. import ResourceTable from 'sentry/views/performance/browser/resources/resourceTable';
  19. import {
  20. BrowserStarfishFields,
  21. useResourceModuleFilters,
  22. } from 'sentry/views/performance/browser/resources/utils/useResourceFilters';
  23. import {useResourceSort} from 'sentry/views/performance/browser/resources/utils/useResourceSort';
  24. import {ModulePageProviders} from 'sentry/views/performance/database/modulePageProviders';
  25. const {RESOURCE_TYPE, DOMAIN, PAGE, DESCRIPTION} = BrowserStarfishFields;
  26. type Option = {
  27. label: string;
  28. value: string;
  29. };
  30. function ResourcesLandingPage() {
  31. const organization = useOrganization();
  32. const filters = useResourceModuleFilters();
  33. const sort = useResourceSort();
  34. return (
  35. <ModulePageProviders title={[t('Performance'), t('Resources')].join(' — ')}>
  36. <Layout.Header>
  37. <Layout.HeaderContent>
  38. <Breadcrumbs
  39. crumbs={[
  40. {
  41. label: 'Performance',
  42. to: normalizeUrl(`/organizations/${organization.slug}/performance/`),
  43. preservePageFilters: true,
  44. },
  45. {
  46. label: 'Resources',
  47. },
  48. ]}
  49. />
  50. <Layout.Title>
  51. {t('Resources')}
  52. <FeatureBadge type="alpha" />
  53. </Layout.Title>
  54. </Layout.HeaderContent>
  55. </Layout.Header>
  56. <Layout.Body>
  57. <Layout.Main fullWidth>
  58. <PaddedContainer>
  59. <PageFilterBar condensed>
  60. <ProjectPageFilter />
  61. <DatePageFilter alignDropdown="left" />
  62. </PageFilterBar>
  63. </PaddedContainer>
  64. <FilterOptionsContainer>
  65. <DomainSelector value={filters[DOMAIN] || ''} />
  66. <ResourceTypeSelector value={filters[RESOURCE_TYPE] || ''} />
  67. <PageSelector value={filters[PAGE] || ''} />
  68. </FilterOptionsContainer>
  69. <ResourceTable sort={sort} />
  70. <ResourceSidebar groupId={filters[DESCRIPTION]} />
  71. </Layout.Main>
  72. </Layout.Body>
  73. </ModulePageProviders>
  74. );
  75. }
  76. function DomainSelector({value}: {value?: string}) {
  77. const location = useLocation();
  78. const options: Option[] = [
  79. {value: '', label: 'All'},
  80. {value: 'https://s1.sentry-cdn.com', label: 'https://s1.sentry-cdn.com'},
  81. {value: 'https://s2.sentry-cdn.com', label: 'https://s2.sentry-cdn.com'},
  82. {value: 'https://cdn.pendo.io', label: 'https://cdn.pendo.io'},
  83. ];
  84. return (
  85. <SelectControlWithProps
  86. inFieldLabel={`${t('Domain')}:`}
  87. options={options}
  88. value={value}
  89. onChange={newValue => {
  90. browserHistory.push({
  91. ...location,
  92. query: {
  93. ...location.query,
  94. [DOMAIN]: newValue?.value,
  95. },
  96. });
  97. }}
  98. />
  99. );
  100. }
  101. function ResourceTypeSelector({value}: {value?: string}) {
  102. const location = useLocation();
  103. const options: Option[] = [
  104. {value: '', label: 'All'},
  105. {value: 'resource.script', label: `${t('JavaScript')} (.js)`},
  106. {value: '.css', label: `${t('Stylesheet')} (.css)`},
  107. {value: 'resource.img', label: `${t('Images')} (.png, .jpg, .jpeg, .gif, etc)`},
  108. ];
  109. return (
  110. <SelectControlWithProps
  111. inFieldLabel={`${t('Type')}:`}
  112. options={options}
  113. value={value}
  114. onChange={newValue => {
  115. browserHistory.push({
  116. ...location,
  117. query: {
  118. ...location.query,
  119. [RESOURCE_TYPE]: newValue?.value,
  120. },
  121. });
  122. }}
  123. />
  124. );
  125. }
  126. function PageSelector({value}: {value?: string}) {
  127. const location = useLocation();
  128. const options: Option[] = [
  129. {value: '', label: 'All'},
  130. {value: '/performance', label: '/performance'},
  131. {value: '/profiling', label: '/profiling'},
  132. {value: '/starfish', label: '/starfish'},
  133. ];
  134. return (
  135. <SelectControlWithProps
  136. inFieldLabel={`${t('Page')}:`}
  137. options={options}
  138. value={value}
  139. onChange={newValue => {
  140. browserHistory.push({
  141. ...location,
  142. query: {
  143. ...location.query,
  144. [PAGE]: newValue?.value,
  145. },
  146. });
  147. }}
  148. />
  149. );
  150. }
  151. function SelectControlWithProps(props: ControlProps & {options: Option[]}) {
  152. return <SelectControl {...props} />;
  153. }
  154. export const PaddedContainer = styled('div')`
  155. margin-bottom: ${space(2)};
  156. `;
  157. const FilterOptionsContainer = styled('div')`
  158. display: grid;
  159. grid-template-columns: repeat(3, 1fr);
  160. gap: ${space(2)};
  161. margin-bottom: ${space(2)};
  162. max-width: 800px;
  163. `;
  164. export default ResourcesLandingPage;