controls.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import * as React from 'react';
  2. import styled from '@emotion/styled';
  3. import Feature from 'app/components/acl/feature';
  4. import FeatureDisabled from 'app/components/acl/featureDisabled';
  5. import Button from 'app/components/button';
  6. import ButtonBar from 'app/components/buttonBar';
  7. import Confirm from 'app/components/confirm';
  8. import Hovercard from 'app/components/hovercard';
  9. import {IconEdit} from 'app/icons';
  10. import {t} from 'app/locale';
  11. import space from 'app/styles/space';
  12. import {Organization} from 'app/types';
  13. import {DashboardListItem, DashboardState} from './types';
  14. type Props = {
  15. organization: Organization;
  16. dashboards: DashboardListItem[];
  17. onEdit: () => void;
  18. onCancel: () => void;
  19. onCommit: () => void;
  20. onDelete: () => void;
  21. dashboardState: DashboardState;
  22. };
  23. class Controls extends React.Component<Props> {
  24. render() {
  25. const {dashboardState, dashboards, onEdit, onCancel, onCommit, onDelete} = this.props;
  26. const cancelButton = (
  27. <Button
  28. data-test-id="dashboard-cancel"
  29. onClick={e => {
  30. e.preventDefault();
  31. onCancel();
  32. }}
  33. >
  34. {t('Cancel')}
  35. </Button>
  36. );
  37. if ([DashboardState.EDIT, DashboardState.PENDING_DELETE].includes(dashboardState)) {
  38. return (
  39. <StyledButtonBar gap={1} key="edit-controls">
  40. {cancelButton}
  41. <Confirm
  42. priority="danger"
  43. message={t('Are you sure you want to delete this dashboard?')}
  44. onConfirm={onDelete}
  45. disabled={dashboards.length <= 1}
  46. >
  47. <Button data-test-id="dashboard-delete" priority="danger">
  48. {t('Delete')}
  49. </Button>
  50. </Confirm>
  51. <Button
  52. data-test-id="dashboard-commit"
  53. onClick={e => {
  54. e.preventDefault();
  55. onCommit();
  56. }}
  57. priority="primary"
  58. >
  59. {t('Save and Finish')}
  60. </Button>
  61. </StyledButtonBar>
  62. );
  63. }
  64. if (dashboardState === 'create') {
  65. return (
  66. <StyledButtonBar gap={1} key="create-controls">
  67. {cancelButton}
  68. <Button
  69. data-test-id="dashboard-commit"
  70. onClick={e => {
  71. e.preventDefault();
  72. onCommit();
  73. }}
  74. priority="primary"
  75. >
  76. {t('Save and Finish')}
  77. </Button>
  78. </StyledButtonBar>
  79. );
  80. }
  81. return (
  82. <StyledButtonBar gap={1} key="controls">
  83. <DashboardEditFeature>
  84. {hasFeature => (
  85. <Button
  86. data-test-id="dashboard-edit"
  87. onClick={e => {
  88. e.preventDefault();
  89. onEdit();
  90. }}
  91. priority="primary"
  92. icon={<IconEdit size="xs" />}
  93. disabled={!hasFeature}
  94. >
  95. {t('Edit Dashboard')}
  96. </Button>
  97. )}
  98. </DashboardEditFeature>
  99. </StyledButtonBar>
  100. );
  101. }
  102. }
  103. const DashboardEditFeature = ({
  104. children,
  105. }: {
  106. children: (hasFeature: boolean) => React.ReactNode;
  107. }) => {
  108. const noFeatureMessage = t('Requires dashboard editing.');
  109. const renderDisabled = p => (
  110. <Hovercard
  111. body={
  112. <FeatureDisabled
  113. features={p.features}
  114. hideHelpToggle
  115. message={noFeatureMessage}
  116. featureName={noFeatureMessage}
  117. />
  118. }
  119. >
  120. {p.children(p)}
  121. </Hovercard>
  122. );
  123. return (
  124. <Feature
  125. hookName="feature-disabled:dashboards-edit"
  126. features={['organizations:dashboards-edit']}
  127. renderDisabled={renderDisabled}
  128. >
  129. {({hasFeature}) => children(hasFeature)}
  130. </Feature>
  131. );
  132. };
  133. const StyledButtonBar = styled(ButtonBar)`
  134. @media (max-width: ${p => p.theme.breakpoints[0]}) {
  135. grid-auto-flow: row;
  136. grid-row-gap: ${space(1)};
  137. width: 100%;
  138. }
  139. `;
  140. export default Controls;