SaveDashboardErrorProxy.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import { css } from '@emotion/css';
  2. import React, { useEffect } from 'react';
  3. import { GrafanaTheme } from '@grafana/data';
  4. import { Button, ConfirmModal, Modal, stylesFactory, useTheme } from '@grafana/ui';
  5. import { DashboardModel } from 'app/features/dashboard/state';
  6. import { SaveDashboardAsButton } from './SaveDashboardButton';
  7. import { SaveDashboardModalProps } from './types';
  8. import { useDashboardSave } from './useDashboardSave';
  9. interface SaveDashboardErrorProxyProps {
  10. /** original dashboard */
  11. dashboard: DashboardModel;
  12. /** dashboard save model with applied modifications, i.e. title */
  13. dashboardSaveModel: any;
  14. error: any;
  15. onDismiss: () => void;
  16. }
  17. export const SaveDashboardErrorProxy: React.FC<SaveDashboardErrorProxyProps> = ({
  18. dashboard,
  19. dashboardSaveModel,
  20. error,
  21. onDismiss,
  22. }) => {
  23. const { onDashboardSave } = useDashboardSave(dashboard);
  24. useEffect(() => {
  25. if (error.data && isHandledError(error.data.status)) {
  26. error.isHandled = true;
  27. }
  28. }, [error]);
  29. return (
  30. <>
  31. {error.data && error.data.status === 'version-mismatch' && (
  32. <ConfirmModal
  33. isOpen={true}
  34. title="Conflict"
  35. body={
  36. <div>
  37. Someone else has updated this dashboard <br /> <small>Would you still like to save this dashboard?</small>
  38. </div>
  39. }
  40. confirmText="Save and overwrite"
  41. onConfirm={async () => {
  42. await onDashboardSave(dashboardSaveModel, { overwrite: true }, dashboard);
  43. onDismiss();
  44. }}
  45. onDismiss={onDismiss}
  46. />
  47. )}
  48. {error.data && error.data.status === 'name-exists' && (
  49. <ConfirmModal
  50. isOpen={true}
  51. title="Conflict"
  52. body={
  53. <div>
  54. A dashboard with the same name in selected folder already exists. <br />
  55. <small>Would you still like to save this dashboard?</small>
  56. </div>
  57. }
  58. confirmText="Save and overwrite"
  59. onConfirm={async () => {
  60. await onDashboardSave(dashboardSaveModel, { overwrite: true }, dashboard);
  61. onDismiss();
  62. }}
  63. onDismiss={onDismiss}
  64. />
  65. )}
  66. {error.data && error.data.status === 'plugin-dashboard' && (
  67. <ConfirmPluginDashboardSaveModal dashboard={dashboard} onDismiss={onDismiss} />
  68. )}
  69. </>
  70. );
  71. };
  72. const ConfirmPluginDashboardSaveModal: React.FC<SaveDashboardModalProps> = ({ onDismiss, dashboard }) => {
  73. const theme = useTheme();
  74. const { onDashboardSave } = useDashboardSave(dashboard);
  75. const styles = getConfirmPluginDashboardSaveModalStyles(theme);
  76. return (
  77. <Modal className={styles.modal} title="Plugin dashboard" icon="copy" isOpen={true} onDismiss={onDismiss}>
  78. <div className={styles.modalText}>
  79. Your changes will be lost when you update the plugin.
  80. <br />
  81. <small>
  82. Use <strong>Save As</strong> to create custom version.
  83. </small>
  84. </div>
  85. <Modal.ButtonRow>
  86. <Button variant="secondary" onClick={onDismiss} fill="outline">
  87. Cancel
  88. </Button>
  89. <SaveDashboardAsButton dashboard={dashboard} onSaveSuccess={onDismiss} />
  90. <Button
  91. variant="destructive"
  92. onClick={async () => {
  93. await onDashboardSave(dashboard.getSaveModelClone(), { overwrite: true }, dashboard);
  94. onDismiss();
  95. }}
  96. >
  97. Overwrite
  98. </Button>
  99. </Modal.ButtonRow>
  100. </Modal>
  101. );
  102. };
  103. const isHandledError = (errorStatus: string) => {
  104. switch (errorStatus) {
  105. case 'version-mismatch':
  106. case 'name-exists':
  107. case 'plugin-dashboard':
  108. return true;
  109. default:
  110. return false;
  111. }
  112. };
  113. const getConfirmPluginDashboardSaveModalStyles = stylesFactory((theme: GrafanaTheme) => ({
  114. modal: css`
  115. width: 500px;
  116. `,
  117. modalText: css`
  118. font-size: ${theme.typography.heading.h4};
  119. color: ${theme.colors.link};
  120. margin-bottom: calc(${theme.spacing.d} * 2);
  121. padding-top: ${theme.spacing.d};
  122. `,
  123. modalButtonRow: css`
  124. margin-bottom: 14px;
  125. a,
  126. button {
  127. margin-right: ${theme.spacing.d};
  128. }
  129. `,
  130. }));