You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ListFooter.tsx 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2022 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import classNames from 'classnames';
  21. import * as React from 'react';
  22. import { translate, translateWithParameters } from '../../helpers/l10n';
  23. import { formatMeasure } from '../../helpers/measures';
  24. import DeferredSpinner from '../ui/DeferredSpinner';
  25. import { Button } from './buttons';
  26. export interface ListFooterProps {
  27. accessibleLoadMoreLabel?: string;
  28. count: number;
  29. className?: string;
  30. loading?: boolean;
  31. loadMore?: () => void;
  32. needReload?: boolean;
  33. pageSize?: number;
  34. reload?: () => void;
  35. ready?: boolean;
  36. total?: number;
  37. }
  38. export default function ListFooter(props: ListFooterProps) {
  39. const {
  40. accessibleLoadMoreLabel,
  41. className,
  42. count,
  43. loadMore,
  44. loading,
  45. needReload,
  46. total,
  47. pageSize,
  48. ready = true
  49. } = props;
  50. const rootNode = React.useRef<HTMLDivElement>(null);
  51. const onLoadMore = React.useCallback(() => {
  52. if (loadMore) {
  53. loadMore();
  54. }
  55. if (rootNode.current) {
  56. rootNode.current.focus();
  57. }
  58. }, [loadMore, rootNode]);
  59. let hasMore = false;
  60. if (total !== undefined) {
  61. hasMore = total > count;
  62. } else if (pageSize !== undefined) {
  63. hasMore = count % pageSize === 0;
  64. }
  65. let button;
  66. if (needReload && props.reload) {
  67. button = (
  68. <Button className="spacer-left" data-test="reload" disabled={loading} onClick={props.reload}>
  69. {translate('reload')}
  70. </Button>
  71. );
  72. } else if (hasMore && props.loadMore) {
  73. button = (
  74. <Button
  75. aria-label={accessibleLoadMoreLabel}
  76. className="spacer-left"
  77. disabled={loading}
  78. data-test="show-more"
  79. onClick={onLoadMore}>
  80. {translate('show_more')}
  81. </Button>
  82. );
  83. }
  84. return (
  85. <div
  86. tabIndex={-1}
  87. ref={rootNode}
  88. className={classNames(
  89. 'list-footer spacer-top note text-center',
  90. { 'new-loading': !ready },
  91. className
  92. )}>
  93. {total !== undefined
  94. ? translateWithParameters(
  95. 'x_of_y_shown',
  96. formatMeasure(count, 'INT', null),
  97. formatMeasure(total, 'INT', null)
  98. )
  99. : translateWithParameters('x_show', formatMeasure(count, 'INT', null))}
  100. {button}
  101. {loading && <DeferredSpinner className="text-bottom spacer-left position-absolute" />}
  102. </div>
  103. );
  104. }