You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ApplicationDetails.tsx 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2020 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import * as React from 'react';
  21. import { Link } from 'react-router';
  22. import { Button } from 'sonar-ui-common/components/controls/buttons';
  23. import ConfirmButton from 'sonar-ui-common/components/controls/ConfirmButton';
  24. import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
  25. import { deleteApplication, editApplication, refreshApplication } from '../../api/application';
  26. import addGlobalSuccessMessage from '../../app/utils/addGlobalSuccessMessage';
  27. import { Application, ApplicationProject } from '../../types/application';
  28. import { Branch } from '../../types/branch-like';
  29. import ApplicationBranches from './ApplicationBranches';
  30. import ApplicationDetailsProjects from './ApplicationDetailsProjects';
  31. import EditForm from './EditForm';
  32. interface Props {
  33. application: Application;
  34. canRecompute: boolean | undefined;
  35. onAddProject: (project: ApplicationProject) => void;
  36. onDelete: (key: string) => void;
  37. onEdit: (key: string, name: string, description: string) => void;
  38. onRemoveProject: (projectKey: string) => void;
  39. onUpdateBranches: (branches: Branch[]) => void;
  40. pathname: string;
  41. single: boolean | undefined;
  42. }
  43. interface State {
  44. editing: boolean;
  45. loading: boolean;
  46. }
  47. export default class ApplicationDetails extends React.PureComponent<Props, State> {
  48. mounted = false;
  49. state: State = {
  50. editing: false,
  51. loading: false
  52. };
  53. componentDidMount() {
  54. this.mounted = true;
  55. }
  56. componenWillUnmount() {
  57. this.mounted = false;
  58. }
  59. handleRefreshClick = () => {
  60. this.setState({ loading: true });
  61. refreshApplication(this.props.application.key).then(() => {
  62. addGlobalSuccessMessage(translate('application_console.refresh_started'));
  63. this.stopLoading();
  64. }, this.stopLoading);
  65. };
  66. handleDelete = async () => {
  67. await deleteApplication(this.props.application.key);
  68. this.props.onDelete(this.props.application.key);
  69. };
  70. handleEditClick = () => {
  71. this.setState({ editing: true });
  72. };
  73. handleEditFormClose = () => {
  74. this.setState({ editing: false });
  75. };
  76. stopLoading = () => {
  77. if (this.mounted) {
  78. this.setState({ loading: false });
  79. }
  80. };
  81. render() {
  82. const { loading } = this.state;
  83. const { application } = this.props;
  84. const canDelete = !this.props.single;
  85. return (
  86. <div className="boxed-group portfolios-console-details" id="view-details">
  87. <div className="boxed-group-actions">
  88. <Button
  89. className="little-spacer-right"
  90. id="view-details-edit"
  91. onClick={this.handleEditClick}>
  92. {translate('edit')}
  93. </Button>
  94. {this.props.canRecompute && (
  95. <Button
  96. className="little-spacer-right"
  97. disabled={loading}
  98. onClick={this.handleRefreshClick}>
  99. {loading && <i className="little-spacer-right spinner" />}
  100. {translate('application_console.recompute')}
  101. </Button>
  102. )}
  103. {canDelete && (
  104. <ConfirmButton
  105. confirmButtonText={translate('delete')}
  106. isDestructive={true}
  107. modalBody={translateWithParameters(
  108. 'application_console.do_you_want_to_delete',
  109. application.name
  110. )}
  111. modalHeader={translate('application_console.delete_application')}
  112. onConfirm={this.handleDelete}>
  113. {({ onClick }) => (
  114. <Button className="button-red" id="view-details-delete" onClick={onClick}>
  115. {translate('delete')}
  116. </Button>
  117. )}
  118. </ConfirmButton>
  119. )}
  120. </div>
  121. <header className="boxed-group-header" id="view-details-header">
  122. <h2 className="text-limited" title={application.name}>
  123. {application.name}
  124. </h2>
  125. </header>
  126. <div className="boxed-group-inner" id="view-details-content">
  127. <div className="big-spacer-bottom">
  128. {application.description && (
  129. <div className="little-spacer-bottom">{application.description}</div>
  130. )}
  131. <div className="subtitle">
  132. {translate('key')}: {application.key}
  133. <Link
  134. className="spacer-left"
  135. to={{ pathname: '/dashboard', query: { id: application.key } }}>
  136. {translate('application_console.open_dashbard')}
  137. </Link>
  138. </div>
  139. </div>
  140. <ApplicationDetailsProjects
  141. onAddProject={this.props.onAddProject}
  142. onRemoveProject={this.props.onRemoveProject}
  143. application={this.props.application}
  144. />
  145. <ApplicationBranches
  146. application={this.props.application}
  147. onUpdateBranches={this.props.onUpdateBranches}
  148. />
  149. </div>
  150. {this.state.editing && (
  151. <EditForm
  152. header={translate('portfolios.edit_application')}
  153. onChange={editApplication}
  154. onClose={this.handleEditFormClose}
  155. onEdit={this.props.onEdit}
  156. application={application}
  157. />
  158. )}
  159. </div>
  160. );
  161. }
  162. }