bulkNotice.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import {t, tct, tn} from 'sentry/locale';
  4. import {defined} from 'sentry/utils';
  5. import Button from '../button';
  6. import {PanelAlert} from '../panels';
  7. function getSelectAllText(allRowsCount?: number, bulkLimit?: number) {
  8. if (!defined(allRowsCount)) {
  9. return {
  10. noticeText: t('Selected all items across all pages.'),
  11. actionText: t('Select all items across all pages.'),
  12. };
  13. }
  14. if (bulkLimit && allRowsCount > bulkLimit) {
  15. return {
  16. noticeText: tct('Selected up to the first [count] items.', {
  17. count: bulkLimit,
  18. }),
  19. actionText: tct('Select the first [count] items.', {
  20. count: bulkLimit,
  21. }),
  22. };
  23. }
  24. return {
  25. noticeText: tct('Selected all [count] items.', {
  26. count: allRowsCount,
  27. }),
  28. actionText: tct('Select all [count] items.', {
  29. count: allRowsCount,
  30. }),
  31. };
  32. }
  33. type Props = {
  34. /**
  35. * Number of columns to stretch the notice (used in grid-column)
  36. */
  37. columnsCount: number;
  38. /**
  39. * Are all rows across all pages selected?
  40. */
  41. isAllSelected: boolean;
  42. /**
  43. * Are all rows on current page selected?
  44. */
  45. isPageSelected: boolean;
  46. /**
  47. * Callback to select all rows across all pages
  48. */
  49. onSelectAllRows: () => void;
  50. /**
  51. * Callback to clear selection of all rows
  52. */
  53. onUnselectAllRows: () => void;
  54. /**
  55. * Number of selected rows
  56. */
  57. selectedRowsCount: number;
  58. /**
  59. * Number of all rows across all pages
  60. */
  61. allRowsCount?: number;
  62. /**
  63. * Number of max items we can perform bulk operations on
  64. */
  65. bulkLimit?: number;
  66. className?: string;
  67. };
  68. function BulkNotice({
  69. selectedRowsCount,
  70. columnsCount,
  71. isPageSelected,
  72. isAllSelected,
  73. onSelectAllRows,
  74. onUnselectAllRows,
  75. bulkLimit,
  76. allRowsCount,
  77. className,
  78. }: Props) {
  79. if ((allRowsCount && allRowsCount <= selectedRowsCount) || !isPageSelected) {
  80. return null;
  81. }
  82. const {noticeText, actionText} = getSelectAllText(allRowsCount, bulkLimit);
  83. return (
  84. <Wrapper columnsCount={columnsCount} className={className}>
  85. {isAllSelected ? (
  86. <Fragment>
  87. {noticeText}{' '}
  88. <AlertButton priority="link" onClick={onUnselectAllRows}>
  89. {t('Cancel selection.')}
  90. </AlertButton>
  91. </Fragment>
  92. ) : (
  93. <Fragment>
  94. {tn(
  95. '%s item on this page selected.',
  96. '%s items on this page selected.',
  97. selectedRowsCount
  98. )}{' '}
  99. <AlertButton priority="link" onClick={onSelectAllRows}>
  100. {actionText}
  101. </AlertButton>
  102. </Fragment>
  103. )}
  104. </Wrapper>
  105. );
  106. }
  107. type WrapperProps = {columnsCount: number} & React.ComponentProps<typeof PanelAlert>;
  108. const Wrapper = styled(({columnsCount: _columnsCount, ...props}: WrapperProps) => (
  109. <PanelAlert {...props} />
  110. ))`
  111. grid-column: span ${p => p.columnsCount};
  112. text-align: center;
  113. `;
  114. const AlertButton = styled(Button)`
  115. &,
  116. &:hover,
  117. &:active,
  118. &:focus {
  119. /* match the styles of an <a> tag inside Alert */
  120. color: ${p => p.theme.textColor};
  121. border: none;
  122. border-radius: 0;
  123. border-bottom: 1px dotted ${p => p.theme.textColor};
  124. padding-bottom: 1px;
  125. font-size: 15px;
  126. }
  127. `;
  128. export default BulkNotice;