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.

Form.tsx 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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 { ResetButtonLink, SubmitButton } from 'sonar-ui-common/components/controls/buttons';
  22. import Select, { Creatable } from 'sonar-ui-common/components/controls/Select';
  23. import SimpleModal from 'sonar-ui-common/components/controls/SimpleModal';
  24. import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
  25. import MandatoryFieldMarker from 'sonar-ui-common/components/ui/MandatoryFieldMarker';
  26. import MandatoryFieldsExplanation from 'sonar-ui-common/components/ui/MandatoryFieldsExplanation';
  27. import { translate } from 'sonar-ui-common/helpers/l10n';
  28. export interface MetricProps {
  29. description: string;
  30. domain?: string;
  31. key: string;
  32. name: string;
  33. type: string;
  34. }
  35. interface Props {
  36. confirmButtonText: string;
  37. domains: string[];
  38. metric?: T.Metric;
  39. header: string;
  40. onClose: () => void;
  41. onSubmit: (data: MetricProps) => Promise<void>;
  42. types: string[];
  43. }
  44. interface State extends MetricProps {}
  45. export default class Form extends React.PureComponent<Props, State> {
  46. constructor(props: Props) {
  47. super(props);
  48. this.state = {
  49. description: (props.metric && props.metric.description) || '',
  50. domain: props.metric && props.metric.domain,
  51. key: (props.metric && props.metric.key) || '',
  52. name: (props.metric && props.metric.name) || '',
  53. type: (props.metric && props.metric.type) || 'INT'
  54. };
  55. }
  56. handleSubmit = () => {
  57. return this.props
  58. .onSubmit({
  59. description: this.state.description,
  60. domain: this.state.domain,
  61. key: this.state.key,
  62. name: this.state.name,
  63. type: this.state.type
  64. })
  65. .then(this.props.onClose);
  66. };
  67. handleKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  68. this.setState({ key: event.currentTarget.value });
  69. };
  70. handleDescriptionChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
  71. this.setState({ description: event.currentTarget.value });
  72. };
  73. handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  74. this.setState({ name: event.currentTarget.value });
  75. };
  76. handleDomainChange = (option: { value: string } | null) => {
  77. this.setState({ domain: option ? option.value : undefined });
  78. };
  79. handleTypeChange = ({ value }: { value: string }) => {
  80. this.setState({ type: value });
  81. };
  82. render() {
  83. const domains = [...this.props.domains];
  84. if (this.state.domain) {
  85. domains.push(this.state.domain);
  86. }
  87. return (
  88. <SimpleModal
  89. header={this.props.header}
  90. onClose={this.props.onClose}
  91. onSubmit={this.handleSubmit}
  92. size="small">
  93. {({ onCloseClick, onFormSubmit, submitting }) => (
  94. <form onSubmit={onFormSubmit}>
  95. <header className="modal-head">
  96. <h2>{this.props.header}</h2>
  97. </header>
  98. <div className="modal-body modal-container">
  99. <MandatoryFieldsExplanation className="modal-field" />
  100. <div className="modal-field">
  101. <label htmlFor="create-metric-key">
  102. {translate('key')}
  103. <MandatoryFieldMarker />
  104. </label>
  105. <input
  106. autoFocus={true}
  107. id="create-metric-key"
  108. maxLength={64}
  109. name="key"
  110. onChange={this.handleKeyChange}
  111. required={true}
  112. type="text"
  113. value={this.state.key}
  114. />
  115. </div>
  116. <div className="modal-field">
  117. <label htmlFor="create-metric-name">
  118. {translate('name')}
  119. <MandatoryFieldMarker />
  120. </label>
  121. <input
  122. id="create-metric-name"
  123. maxLength={64}
  124. name="name"
  125. onChange={this.handleNameChange}
  126. required={true}
  127. type="text"
  128. value={this.state.name}
  129. />
  130. </div>
  131. <div className="modal-field">
  132. <label htmlFor="create-metric-description">{translate('description')}</label>
  133. <textarea
  134. id="create-metric-description"
  135. name="description"
  136. onChange={this.handleDescriptionChange}
  137. value={this.state.description}
  138. />
  139. </div>
  140. <div className="modal-field">
  141. <label htmlFor="create-metric-domain">{translate('custom_metrics.domain')}</label>
  142. <Creatable
  143. id="create-metric-domain"
  144. onChange={this.handleDomainChange}
  145. options={domains.map(domain => ({ label: domain, value: domain }))}
  146. value={this.state.domain}
  147. />
  148. </div>
  149. <div className="modal-field">
  150. <label htmlFor="create-metric-type">
  151. {translate('type')}
  152. <MandatoryFieldMarker />
  153. </label>
  154. <Select
  155. clearable={false}
  156. id="create-metric-type"
  157. onChange={this.handleTypeChange}
  158. options={this.props.types.map(type => ({
  159. label: translate('metric.type', type),
  160. value: type
  161. }))}
  162. value={this.state.type}
  163. />
  164. </div>
  165. </div>
  166. <footer className="modal-foot">
  167. <DeferredSpinner className="spacer-right" loading={submitting} />
  168. <SubmitButton disabled={submitting} id="create-metric-submit">
  169. {this.props.confirmButtonText}
  170. </SubmitButton>
  171. <ResetButtonLink
  172. disabled={submitting}
  173. id="create-metric-cancel"
  174. onClick={onCloseClick}>
  175. {translate('cancel')}
  176. </ResetButtonLink>
  177. </footer>
  178. </form>
  179. )}
  180. </SimpleModal>
  181. );
  182. }
  183. }