Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

PRDecorationBinding.tsx 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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 {
  22. deleteProjectAlmBinding,
  23. getAlmSettings,
  24. getProjectAlmBinding,
  25. setProjectAzureBinding,
  26. setProjectBitbucketBinding,
  27. setProjectGithubBinding,
  28. setProjectGitlabBinding
  29. } from '../../../../api/alm-settings';
  30. import throwGlobalError from '../../../../app/utils/throwGlobalError';
  31. import { AlmKeys, AlmSettingsInstance, ProjectAlmBinding } from '../../../../types/alm-settings';
  32. import PRDecorationBindingRenderer from './PRDecorationBindingRenderer';
  33. interface Props {
  34. component: T.Component;
  35. }
  36. interface State {
  37. formData: ProjectAlmBinding;
  38. instances: AlmSettingsInstance[];
  39. isValid: boolean;
  40. loading: boolean;
  41. originalData?: ProjectAlmBinding;
  42. saving: boolean;
  43. success: boolean;
  44. }
  45. const FIELDS_BY_ALM: { [almKey in AlmKeys]: Array<keyof T.Omit<ProjectAlmBinding, 'key'>> } = {
  46. [AlmKeys.Azure]: [],
  47. [AlmKeys.Bitbucket]: ['repository', 'slug'],
  48. [AlmKeys.GitHub]: ['repository'],
  49. [AlmKeys.GitLab]: []
  50. };
  51. export default class PRDecorationBinding extends React.PureComponent<Props, State> {
  52. mounted = false;
  53. state: State = {
  54. formData: { key: '' },
  55. instances: [],
  56. isValid: false,
  57. loading: true,
  58. saving: false,
  59. success: false
  60. };
  61. componentDidMount() {
  62. this.mounted = true;
  63. this.fetchDefinitions();
  64. }
  65. componentWillUnmount() {
  66. this.mounted = false;
  67. }
  68. fetchDefinitions = () => {
  69. const project = this.props.component.key;
  70. return Promise.all([getAlmSettings(project), this.getProjectBinding(project)])
  71. .then(([instances, originalData]) => {
  72. if (this.mounted) {
  73. this.setState(({ formData }) => {
  74. const newFormData = originalData || formData;
  75. return {
  76. formData: newFormData,
  77. instances: instances || [],
  78. isValid: this.validateForm(newFormData),
  79. loading: false,
  80. originalData
  81. };
  82. });
  83. }
  84. })
  85. .catch(() => {
  86. if (this.mounted) {
  87. this.setState({ loading: false });
  88. }
  89. });
  90. };
  91. getProjectBinding(project: string): Promise<ProjectAlmBinding | undefined> {
  92. return getProjectAlmBinding(project).catch((response: Response) => {
  93. if (response && response.status === 404) {
  94. return Promise.resolve(undefined);
  95. }
  96. return throwGlobalError(response);
  97. });
  98. }
  99. catchError = () => {
  100. if (this.mounted) {
  101. this.setState({ saving: false });
  102. }
  103. };
  104. handleReset = () => {
  105. const { component } = this.props;
  106. this.setState({ saving: true });
  107. deleteProjectAlmBinding(component.key)
  108. .then(() => {
  109. if (this.mounted) {
  110. this.setState({
  111. formData: {
  112. key: '',
  113. repository: '',
  114. slug: ''
  115. },
  116. originalData: undefined,
  117. saving: false,
  118. success: true
  119. });
  120. }
  121. })
  122. .catch(this.catchError);
  123. };
  124. submitProjectAlmBinding(
  125. alm: AlmKeys,
  126. key: string,
  127. almSpecificFields?: T.Omit<ProjectAlmBinding, 'key'>
  128. ): Promise<void> {
  129. const almSetting = key;
  130. const project = this.props.component.key;
  131. switch (alm) {
  132. case AlmKeys.Azure:
  133. return setProjectAzureBinding({
  134. almSetting,
  135. project
  136. });
  137. case AlmKeys.Bitbucket: {
  138. if (!almSpecificFields) {
  139. return Promise.reject();
  140. }
  141. const { repository = '', slug = '' } = almSpecificFields;
  142. return setProjectBitbucketBinding({
  143. almSetting,
  144. project,
  145. repository,
  146. slug
  147. });
  148. }
  149. case AlmKeys.GitHub: {
  150. const repository = almSpecificFields && almSpecificFields.repository;
  151. if (!repository) {
  152. return Promise.reject();
  153. }
  154. return setProjectGithubBinding({
  155. almSetting,
  156. project,
  157. repository
  158. });
  159. }
  160. case AlmKeys.GitLab:
  161. return setProjectGitlabBinding({
  162. almSetting,
  163. project
  164. });
  165. default:
  166. return Promise.reject();
  167. }
  168. }
  169. handleSubmit = () => {
  170. this.setState({ saving: true });
  171. const {
  172. formData: { key, ...additionalFields },
  173. instances
  174. } = this.state;
  175. const selected = instances.find(i => i.key === key);
  176. if (!key || !selected) {
  177. return;
  178. }
  179. if (key) {
  180. this.submitProjectAlmBinding(selected.alm, key, additionalFields)
  181. .then(() => {
  182. if (this.mounted) {
  183. this.setState({
  184. saving: false,
  185. success: true
  186. });
  187. }
  188. })
  189. .then(this.fetchDefinitions)
  190. .catch(this.catchError);
  191. }
  192. };
  193. handleFieldChange = (id: keyof ProjectAlmBinding, value: string) => {
  194. this.setState(({ formData }) => {
  195. const newFormData = {
  196. ...formData,
  197. [id]: value
  198. };
  199. return {
  200. formData: newFormData,
  201. isValid: this.validateForm(newFormData),
  202. success: false
  203. };
  204. });
  205. };
  206. validateForm = ({ key, ...additionalFields }: State['formData']) => {
  207. const { instances } = this.state;
  208. const selected = instances.find(i => i.key === key);
  209. if (!key || !selected) {
  210. return false;
  211. }
  212. return FIELDS_BY_ALM[selected.alm].reduce(
  213. (result: boolean, field) => result && Boolean(additionalFields[field]),
  214. true
  215. );
  216. };
  217. render() {
  218. return (
  219. <PRDecorationBindingRenderer
  220. onFieldChange={this.handleFieldChange}
  221. onReset={this.handleReset}
  222. onSubmit={this.handleSubmit}
  223. {...this.state}
  224. />
  225. );
  226. }
  227. }