DashboardRow.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import classNames from 'classnames';
  2. import React from 'react';
  3. import { Unsubscribable } from 'rxjs';
  4. import { selectors } from '@grafana/e2e-selectors';
  5. import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
  6. import { Icon } from '@grafana/ui';
  7. import appEvents from 'app/core/app_events';
  8. import { ShowConfirmModalEvent } from '../../../../types/events';
  9. import { DashboardModel } from '../../state/DashboardModel';
  10. import { PanelModel } from '../../state/PanelModel';
  11. import { RowOptionsButton } from '../RowOptions/RowOptionsButton';
  12. export interface DashboardRowProps {
  13. panel: PanelModel;
  14. dashboard: DashboardModel;
  15. }
  16. export class DashboardRow extends React.Component<DashboardRowProps, any> {
  17. sub?: Unsubscribable;
  18. componentDidMount() {
  19. this.sub = this.props.dashboard.events.subscribe(RefreshEvent, this.onVariableUpdated);
  20. }
  21. componentWillUnmount() {
  22. if (this.sub) {
  23. this.sub.unsubscribe();
  24. }
  25. }
  26. onVariableUpdated = () => {
  27. this.forceUpdate();
  28. };
  29. onToggle = () => {
  30. this.props.dashboard.toggleRow(this.props.panel);
  31. };
  32. onUpdate = (title: string, repeat?: string | null) => {
  33. this.props.panel.setProperty('title', title);
  34. this.props.panel.setProperty('repeat', repeat ?? undefined);
  35. this.props.panel.render();
  36. this.props.dashboard.processRepeats();
  37. this.forceUpdate();
  38. };
  39. onDelete = () => {
  40. appEvents.publish(
  41. new ShowConfirmModalEvent({
  42. title: 'Delete row',
  43. text: 'Are you sure you want to remove this row and all its panels?',
  44. altActionText: 'Delete row only',
  45. icon: 'trash-alt',
  46. onConfirm: () => {
  47. this.props.dashboard.removeRow(this.props.panel, true);
  48. },
  49. onAltAction: () => {
  50. this.props.dashboard.removeRow(this.props.panel, false);
  51. },
  52. })
  53. );
  54. };
  55. render() {
  56. const classes = classNames({
  57. 'dashboard-row': true,
  58. 'dashboard-row--collapsed': this.props.panel.collapsed,
  59. });
  60. const title = getTemplateSrv().replace(this.props.panel.title, this.props.panel.scopedVars, 'text');
  61. const count = this.props.panel.panels ? this.props.panel.panels.length : 0;
  62. const panels = count === 1 ? 'panel' : 'panels';
  63. const canEdit = this.props.dashboard.meta.canEdit === true;
  64. return (
  65. <div className={classes} data-testid="dashboard-row-container">
  66. <a
  67. className="dashboard-row__title pointer"
  68. data-testid={selectors.components.DashboardRow.title(title)}
  69. onClick={this.onToggle}
  70. >
  71. <Icon name={this.props.panel.collapsed ? 'angle-right' : 'angle-down'} />
  72. {title}
  73. <span className="dashboard-row__panel_count">
  74. ({count} {panels})
  75. </span>
  76. </a>
  77. {canEdit && (
  78. <div className="dashboard-row__actions">
  79. <RowOptionsButton
  80. title={this.props.panel.title}
  81. repeat={this.props.panel.repeat}
  82. onUpdate={this.onUpdate}
  83. />
  84. <a className="pointer" onClick={this.onDelete}>
  85. <Icon name="trash-alt" />
  86. </a>
  87. </div>
  88. )}
  89. {this.props.panel.collapsed === true && (
  90. <div className="dashboard-row__toggle-target" onClick={this.onToggle}>
  91. &nbsp;
  92. </div>
  93. )}
  94. {canEdit && <div className="dashboard-row__drag grid-drag-handle" />}
  95. </div>
  96. );
  97. }
  98. }