DashboardChangedModal.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { css } from '@emotion/css';
  2. import React, { PureComponent } from 'react';
  3. import { GrafanaTheme } from '@grafana/data';
  4. import { config } from '@grafana/runtime';
  5. import { Modal, stylesFactory } from '@grafana/ui';
  6. import { dashboardWatcher } from './dashboardWatcher';
  7. import { DashboardEvent, DashboardEventAction } from './types';
  8. interface Props {
  9. event?: DashboardEvent;
  10. }
  11. interface State {
  12. dismiss?: boolean;
  13. }
  14. interface ActionInfo {
  15. label: string;
  16. description: string;
  17. action: () => void;
  18. }
  19. export class DashboardChangedModal extends PureComponent<Props, State> {
  20. state: State = {};
  21. discardAndReload: ActionInfo = {
  22. label: 'Discard local changes',
  23. description: 'Load the latest saved version for this dashboard',
  24. action: () => {
  25. dashboardWatcher.reloadPage();
  26. this.onDismiss();
  27. },
  28. };
  29. continueEditing: ActionInfo = {
  30. label: 'Continue editing',
  31. description:
  32. 'Keep your local changes and continue editing. Note: when you save, this will overwrite the most recent chages',
  33. action: () => {
  34. this.onDismiss();
  35. },
  36. };
  37. acceptDelete: ActionInfo = {
  38. label: 'Discard Local changes',
  39. description: 'view grafana homepage',
  40. action: () => {
  41. // Navigate to the root URL
  42. document.location.href = config.appUrl;
  43. },
  44. };
  45. onDismiss = () => {
  46. this.setState({ dismiss: true });
  47. };
  48. render() {
  49. const { event } = this.props;
  50. const { dismiss } = this.state;
  51. const styles = getStyles(config.theme);
  52. const isDelete = event?.action === DashboardEventAction.Deleted;
  53. const options = isDelete
  54. ? [this.continueEditing, this.acceptDelete]
  55. : [this.continueEditing, this.discardAndReload];
  56. return (
  57. <Modal
  58. isOpen={!dismiss}
  59. title="Dashboard Changed"
  60. icon="copy"
  61. onDismiss={this.onDismiss}
  62. onClickBackdrop={() => {}}
  63. className={styles.modal}
  64. >
  65. <div>
  66. {isDelete ? (
  67. <div>This dashboard has been deleted by another session</div>
  68. ) : (
  69. <div>This dashboard has been modifed by another session</div>
  70. )}
  71. <br />
  72. {options.map((opt) => {
  73. return (
  74. <div key={opt.label} onClick={opt.action} className={styles.radioItem}>
  75. <h3>{opt.label}</h3>
  76. {opt.description}
  77. </div>
  78. );
  79. })}
  80. <br />
  81. </div>
  82. </Modal>
  83. );
  84. }
  85. }
  86. const getStyles = stylesFactory((theme: GrafanaTheme) => {
  87. return {
  88. modal: css`
  89. width: 500px;
  90. `,
  91. radioItem: css`
  92. margin: 0;
  93. font-size: ${theme.typography.size.sm};
  94. color: ${theme.colors.textWeak};
  95. padding: 10px;
  96. cursor: pointer;
  97. width: 100%;
  98. &:hover {
  99. background: ${theme.colors.bgBlue1};
  100. color: ${theme.colors.text};
  101. }
  102. `,
  103. };
  104. });