SearchItem.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { css } from '@emotion/css';
  2. import React, { FC, useCallback } from 'react';
  3. import { GrafanaTheme2 } from '@grafana/data';
  4. import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
  5. import { Card, Icon, IconName, TagList, useStyles2 } from '@grafana/ui';
  6. import { SEARCH_ITEM_HEIGHT } from '../constants';
  7. import { DashboardSectionItem, OnToggleChecked } from '../types';
  8. import { SearchCheckbox } from './SearchCheckbox';
  9. export interface Props {
  10. item: DashboardSectionItem;
  11. editable?: boolean;
  12. onTagSelected: (name: string) => any;
  13. onToggleChecked?: OnToggleChecked;
  14. }
  15. const selectors = e2eSelectors.components.Search;
  16. const getIconFromMeta = (meta = ''): IconName => {
  17. const metaIconMap = new Map<string, IconName>([
  18. ['errors', 'info-circle'],
  19. ['views', 'eye'],
  20. ]);
  21. return metaIconMap.has(meta) ? metaIconMap.get(meta)! : 'sort-amount-down';
  22. };
  23. export const SearchItem: FC<Props> = ({ item, editable, onToggleChecked, onTagSelected }) => {
  24. const styles = useStyles2(getStyles);
  25. const tagSelected = useCallback(
  26. (tag: string, event: React.MouseEvent<HTMLElement>) => {
  27. event.stopPropagation();
  28. event.preventDefault();
  29. onTagSelected(tag);
  30. },
  31. [onTagSelected]
  32. );
  33. const handleCheckboxClick = useCallback(
  34. (ev: React.MouseEvent) => {
  35. ev.stopPropagation();
  36. ev.preventDefault();
  37. if (onToggleChecked) {
  38. onToggleChecked(item);
  39. }
  40. },
  41. [item, onToggleChecked]
  42. );
  43. const folderTitle = item.folderTitle || 'General';
  44. return (
  45. <Card
  46. data-testid={selectors.dashboardItem(item.title)}
  47. href={item.url}
  48. style={{ minHeight: SEARCH_ITEM_HEIGHT }}
  49. className={styles.container}
  50. >
  51. <Card.Heading>{item.title}</Card.Heading>
  52. <Card.Figure align={'center'} className={styles.checkbox}>
  53. <SearchCheckbox
  54. aria-label="Select dashboard"
  55. editable={editable}
  56. checked={item.checked}
  57. onClick={handleCheckboxClick}
  58. />
  59. </Card.Figure>
  60. <Card.Meta separator={''}>
  61. <span className={styles.metaContainer}>
  62. <Icon name={'folder'} aria-hidden />
  63. {folderTitle}
  64. </span>
  65. {item.sortMetaName && (
  66. <span className={styles.metaContainer}>
  67. <Icon name={getIconFromMeta(item.sortMetaName)} />
  68. {item.sortMeta} {item.sortMetaName}
  69. </span>
  70. )}
  71. </Card.Meta>
  72. <Card.Tags>
  73. <TagList tags={item.tags} onClick={tagSelected} getAriaLabel={(tag) => `Filter by tag "${tag}"`} />
  74. </Card.Tags>
  75. </Card>
  76. );
  77. };
  78. const getStyles = (theme: GrafanaTheme2) => {
  79. return {
  80. container: css`
  81. margin-bottom: ${theme.spacing(0.75)};
  82. padding: ${theme.spacing(1)} ${theme.spacing(2)};
  83. `,
  84. metaContainer: css`
  85. display: flex;
  86. align-items: center;
  87. margin-right: ${theme.spacing(1)};
  88. svg {
  89. margin-right: ${theme.spacing(0.5)};
  90. }
  91. `,
  92. checkbox: css`
  93. margin-right: 0;
  94. `,
  95. };
  96. };