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.

RuleDetailsTagsPopup.tsx 2.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 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 { MultiSelector } from 'design-system';
  21. import { difference, uniq, without } from 'lodash';
  22. import * as React from 'react';
  23. import { getRuleTags } from '../../../api/rules';
  24. import { translate } from '../../../helpers/l10n';
  25. export interface Props {
  26. setTags: (tags: string[]) => void;
  27. sysTags: string[];
  28. tags: string[];
  29. }
  30. interface State {
  31. searchResult: string[];
  32. }
  33. const LIST_SIZE = 10;
  34. export default class RuleDetailsTagsPopup extends React.PureComponent<Props, State> {
  35. mounted = false;
  36. state: State = { searchResult: [] };
  37. componentDidMount() {
  38. this.mounted = true;
  39. }
  40. componentWillUnmount() {
  41. this.mounted = false;
  42. }
  43. onSearch = (query: string) => {
  44. return getRuleTags({
  45. q: query,
  46. ps: Math.min(this.props.tags.length + LIST_SIZE, 100),
  47. }).then(
  48. (searchResult) => {
  49. if (this.mounted) {
  50. this.setState({ searchResult });
  51. }
  52. },
  53. () => {},
  54. );
  55. };
  56. onSelect = (tag: string) => {
  57. this.props.setTags(uniq([...this.props.tags, tag]));
  58. };
  59. onUnselect = (tag: string) => {
  60. this.props.setTags(without(this.props.tags, tag));
  61. };
  62. render() {
  63. const { sysTags, tags } = this.props;
  64. const { searchResult } = this.state;
  65. const availableTags = difference(searchResult, tags);
  66. const selectedTags = [...sysTags, ...tags];
  67. return (
  68. <MultiSelector
  69. createElementLabel={translate('coding_rules.create_tag')}
  70. headerLabel={translate('tags')}
  71. searchInputAriaLabel={translate('search.search_for_tags')}
  72. noResultsLabel={translate('no_results')}
  73. onSearch={this.onSearch}
  74. onSelect={this.onSelect}
  75. onUnselect={this.onUnselect}
  76. selectedElements={selectedTags}
  77. selectedElementsDisabled={sysTags}
  78. elements={availableTags}
  79. renderTooltip={(element: string, disabled: boolean) => {
  80. if (sysTags.includes(element) && disabled) {
  81. return translate('coding_rules.system_tags_tooltip');
  82. }
  83. return null;
  84. }}
  85. />
  86. );
  87. }
  88. }