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.6KB

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