deadClickList.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import {browserHistory, RouteComponentProps} from 'react-router';
  2. import styled from '@emotion/styled';
  3. import Alert from 'sentry/components/alert';
  4. import DatePageFilter from 'sentry/components/datePageFilter';
  5. import EnvironmentPageFilter from 'sentry/components/environmentPageFilter';
  6. import * as Layout from 'sentry/components/layouts/thirds';
  7. import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
  8. import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
  9. import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip';
  10. import Pagination from 'sentry/components/pagination';
  11. import ProjectPageFilter from 'sentry/components/projectPageFilter';
  12. import {hydratedSelectorData} from 'sentry/components/replays/utils';
  13. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  14. import {t} from 'sentry/locale';
  15. import {space} from 'sentry/styles/space';
  16. import useDeadRageSelectors from 'sentry/utils/replays/hooks/useDeadRageSelectors';
  17. import useOrganization from 'sentry/utils/useOrganization';
  18. import SelectorTable from 'sentry/views/replays/deadRageClick/selectorTable';
  19. import {DeadRageSelectorQueryParams} from 'sentry/views/replays/types';
  20. interface Props extends RouteComponentProps<{}, {}, DeadRageSelectorQueryParams> {}
  21. export default function DeadClickList({location}: Props) {
  22. const organization = useOrganization();
  23. const hasDeadClickFeature = organization.features.includes(
  24. 'session-replay-rage-dead-selectors'
  25. );
  26. const {isLoading, isError, data, pageLinks} = useDeadRageSelectors({
  27. per_page: 50,
  28. sort: '-count_dead_clicks',
  29. });
  30. if (!hasDeadClickFeature) {
  31. return (
  32. <Layout.Page withPadding>
  33. <Alert type="warning">{t("You don't have access to this feature")}</Alert>
  34. </Layout.Page>
  35. );
  36. }
  37. return (
  38. <SentryDocumentTitle
  39. title={t('Top Selectors with Dead Clicks')}
  40. orgSlug={organization.slug}
  41. >
  42. <Layout.Header>
  43. <Layout.HeaderContent>
  44. <Layout.Title>
  45. {t('Top Selectors with Dead Clicks')}
  46. <PageHeadingQuestionTooltip
  47. title={t('See the top selectors your users have dead clicked on.')}
  48. docsUrl="https://docs.sentry.io/product/session-replay/replay-page-and-filters/"
  49. />
  50. </Layout.Title>
  51. </Layout.HeaderContent>
  52. </Layout.Header>
  53. <PageFiltersContainer>
  54. <Layout.Body>
  55. <Layout.Main fullWidth>
  56. <LayoutGap>
  57. <PageFilterBar condensed>
  58. <ProjectPageFilter resetParamsOnChange={['cursor']} />
  59. <EnvironmentPageFilter resetParamsOnChange={['cursor']} />
  60. <DatePageFilter alignDropdown="left" resetParamsOnChange={['cursor']} />
  61. </PageFilterBar>
  62. <SelectorTable
  63. data={hydratedSelectorData(data, 'count_dead_clicks')}
  64. isError={isError}
  65. isLoading={isLoading}
  66. location={location}
  67. clickCountColumn={{key: 'count_dead_clicks', name: 'dead clicks'}}
  68. />
  69. </LayoutGap>
  70. <PaginationNoMargin
  71. pageLinks={pageLinks}
  72. onCursor={(cursor, path, searchQuery) => {
  73. browserHistory.push({
  74. pathname: path,
  75. query: {...searchQuery, cursor},
  76. });
  77. }}
  78. />
  79. </Layout.Main>
  80. </Layout.Body>
  81. </PageFiltersContainer>
  82. </SentryDocumentTitle>
  83. );
  84. }
  85. const LayoutGap = styled('div')`
  86. display: grid;
  87. gap: ${space(2)};
  88. `;
  89. const PaginationNoMargin = styled(Pagination)`
  90. margin: 0;
  91. `;