deadClickList.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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. cursor: location.query.cursor,
  30. prefix: '',
  31. });
  32. if (!hasDeadClickFeature) {
  33. return (
  34. <Layout.Page withPadding>
  35. <Alert type="warning">{t("You don't have access to this feature")}</Alert>
  36. </Layout.Page>
  37. );
  38. }
  39. return (
  40. <SentryDocumentTitle
  41. title={t('Top Selectors with Dead Clicks')}
  42. orgSlug={organization.slug}
  43. >
  44. <Layout.Header>
  45. <Layout.HeaderContent>
  46. <Layout.Title>
  47. {t('Top Selectors with Dead Clicks')}
  48. <PageHeadingQuestionTooltip
  49. title={t('See the top selectors your users have dead clicked on.')}
  50. docsUrl="https://docs.sentry.io/product/session-replay/replay-page-and-filters/"
  51. />
  52. </Layout.Title>
  53. </Layout.HeaderContent>
  54. </Layout.Header>
  55. <PageFiltersContainer>
  56. <Layout.Body>
  57. <Layout.Main fullWidth>
  58. <LayoutGap>
  59. <PageFilterBar condensed>
  60. <ProjectPageFilter resetParamsOnChange={['cursor']} />
  61. <EnvironmentPageFilter resetParamsOnChange={['cursor']} />
  62. <DatePageFilter alignDropdown="left" resetParamsOnChange={['cursor']} />
  63. </PageFilterBar>
  64. <SelectorTable
  65. data={hydratedSelectorData(data, 'count_dead_clicks')}
  66. isError={isError}
  67. isLoading={isLoading}
  68. location={location}
  69. clickCountColumn={{key: 'count_dead_clicks', name: 'dead clicks'}}
  70. clickCountSortable
  71. />
  72. </LayoutGap>
  73. <PaginationNoMargin
  74. pageLinks={pageLinks}
  75. onCursor={(cursor, path, searchQuery) => {
  76. browserHistory.push({
  77. pathname: path,
  78. query: {...searchQuery, cursor},
  79. });
  80. }}
  81. />
  82. </Layout.Main>
  83. </Layout.Body>
  84. </PageFiltersContainer>
  85. </SentryDocumentTitle>
  86. );
  87. }
  88. const LayoutGap = styled('div')`
  89. display: grid;
  90. gap: ${space(2)};
  91. `;
  92. const PaginationNoMargin = styled(Pagination)`
  93. margin: 0;
  94. `;