index.tsx 5.5 KB

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