LibraryPanelCard.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { css } from '@emotion/css';
  2. import React, { ReactElement, useState } from 'react';
  3. import { GrafanaTheme2 } from '@grafana/data';
  4. import { config } from '@grafana/runtime';
  5. import { Icon, Link, useStyles2 } from '@grafana/ui';
  6. import { getPanelPluginNotFound } from 'app/features/panel/components/PanelPluginError';
  7. import { PanelTypeCard } from 'app/features/panel/components/VizTypePicker/PanelTypeCard';
  8. import { LibraryElementDTO } from '../../types';
  9. import { DeleteLibraryPanelModal } from '../DeleteLibraryPanelModal/DeleteLibraryPanelModal';
  10. export interface LibraryPanelCardProps {
  11. libraryPanel: LibraryElementDTO;
  12. onClick: (panel: LibraryElementDTO) => void;
  13. onDelete?: (panel: LibraryElementDTO) => void;
  14. showSecondaryActions?: boolean;
  15. }
  16. export const LibraryPanelCard: React.FC<LibraryPanelCardProps & { children?: JSX.Element | JSX.Element[] }> = ({
  17. libraryPanel,
  18. onClick,
  19. onDelete,
  20. showSecondaryActions,
  21. }) => {
  22. const [showDeletionModal, setShowDeletionModal] = useState(false);
  23. const onDeletePanel = () => {
  24. onDelete?.(libraryPanel);
  25. setShowDeletionModal(false);
  26. };
  27. const panelPlugin = config.panels[libraryPanel.model.type] ?? getPanelPluginNotFound(libraryPanel.model.type).meta;
  28. return (
  29. <>
  30. <PanelTypeCard
  31. isCurrent={false}
  32. title={libraryPanel.name}
  33. description={libraryPanel.description}
  34. plugin={panelPlugin}
  35. onClick={() => onClick?.(libraryPanel)}
  36. onDelete={showSecondaryActions ? () => setShowDeletionModal(true) : undefined}
  37. >
  38. <FolderLink libraryPanel={libraryPanel} />
  39. </PanelTypeCard>
  40. {showDeletionModal && (
  41. <DeleteLibraryPanelModal
  42. libraryPanel={libraryPanel}
  43. onConfirm={onDeletePanel}
  44. onDismiss={() => setShowDeletionModal(false)}
  45. />
  46. )}
  47. </>
  48. );
  49. };
  50. interface FolderLinkProps {
  51. libraryPanel: LibraryElementDTO;
  52. }
  53. function FolderLink({ libraryPanel }: FolderLinkProps): ReactElement | null {
  54. const styles = useStyles2(getStyles);
  55. if (!libraryPanel.meta.folderUid && !libraryPanel.meta.folderName) {
  56. return null;
  57. }
  58. if (!libraryPanel.meta.folderUid) {
  59. return (
  60. <span className={styles.metaContainer}>
  61. <Icon name={'folder'} size="sm" />
  62. <span>{libraryPanel.meta.folderName}</span>
  63. </span>
  64. );
  65. }
  66. return (
  67. <span className={styles.metaContainer}>
  68. <Link href={`/dashboards/f/${libraryPanel.meta.folderUid}`}>
  69. <Icon name={'folder-upload'} size="sm" />
  70. <span>{libraryPanel.meta.folderName}</span>
  71. </Link>
  72. </span>
  73. );
  74. }
  75. function getStyles(theme: GrafanaTheme2) {
  76. return {
  77. metaContainer: css`
  78. display: flex;
  79. align-items: center;
  80. color: ${theme.colors.text.secondary};
  81. font-size: ${theme.typography.bodySmall.fontSize};
  82. padding-top: ${theme.spacing(0.5)};
  83. svg {
  84. margin-right: ${theme.spacing(0.5)};
  85. margin-bottom: 3px;
  86. }
  87. `,
  88. };
  89. }