VariableOptions.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { css, cx } from '@emotion/css';
  2. import React, { PureComponent } from 'react';
  3. import { selectors } from '@grafana/e2e-selectors';
  4. import { Tooltip } from '@grafana/ui';
  5. import { VariableOption } from '../../types';
  6. export interface Props extends React.HTMLProps<HTMLUListElement> {
  7. multi: boolean;
  8. values: VariableOption[];
  9. selectedValues: VariableOption[];
  10. highlightIndex: number;
  11. onToggle: (option: VariableOption, clearOthers: boolean) => void;
  12. onToggleAll: () => void;
  13. /**
  14. * Used for aria-controls
  15. */
  16. id: string;
  17. }
  18. export class VariableOptions extends PureComponent<Props> {
  19. onToggle = (option: VariableOption) => (event: React.MouseEvent<HTMLAnchorElement>) => {
  20. const clearOthers = event.shiftKey || event.ctrlKey || event.metaKey;
  21. this.handleEvent(event);
  22. this.props.onToggle(option, clearOthers);
  23. };
  24. onToggleAll = (event: React.MouseEvent<HTMLAnchorElement>) => {
  25. this.handleEvent(event);
  26. this.props.onToggleAll();
  27. };
  28. handleEvent(event: React.MouseEvent<HTMLAnchorElement>) {
  29. event.preventDefault();
  30. event.stopPropagation();
  31. }
  32. render() {
  33. // Don't want to pass faulty rest props to the div
  34. const { multi, values, highlightIndex, selectedValues, onToggle, onToggleAll, ...restProps } = this.props;
  35. return (
  36. <div className={`${multi ? 'variable-value-dropdown multi' : 'variable-value-dropdown single'}`}>
  37. <div className="variable-options-wrapper">
  38. <ul
  39. className={listStyles}
  40. aria-label={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownDropDown}
  41. {...restProps}
  42. >
  43. {this.renderMultiToggle()}
  44. {values.map((option, index) => this.renderOption(option, index))}
  45. </ul>
  46. </div>
  47. </div>
  48. );
  49. }
  50. renderOption(option: VariableOption, index: number) {
  51. const { highlightIndex } = this.props;
  52. const selectClass = option.selected ? 'variable-option pointer selected' : 'variable-option pointer';
  53. const highlightClass = index === highlightIndex ? `${selectClass} highlighted` : selectClass;
  54. return (
  55. <li key={`${option.value}`}>
  56. <a role="checkbox" aria-checked={option.selected} className={highlightClass} onClick={this.onToggle(option)}>
  57. <span className="variable-option-icon"></span>
  58. <span data-testid={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(`${option.text}`)}>
  59. {option.text}
  60. </span>
  61. </a>
  62. </li>
  63. );
  64. }
  65. renderMultiToggle() {
  66. const { multi, selectedValues } = this.props;
  67. if (!multi) {
  68. return null;
  69. }
  70. return (
  71. <Tooltip content={'Clear selections'} placement={'top'}>
  72. <a
  73. className={`${
  74. selectedValues.length > 1
  75. ? 'variable-options-column-header many-selected'
  76. : 'variable-options-column-header'
  77. }`}
  78. role="checkbox"
  79. aria-checked={selectedValues.length > 1 ? 'mixed' : 'false'}
  80. onClick={this.onToggleAll}
  81. aria-label="Toggle all values"
  82. data-placement="top"
  83. >
  84. <span className="variable-option-icon"></span>
  85. Selected ({selectedValues.length})
  86. </a>
  87. </Tooltip>
  88. );
  89. }
  90. }
  91. const listStyles = cx(
  92. 'variable-options-column',
  93. css`
  94. list-style-type: none;
  95. `
  96. );