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.

OrganizationKeyInput.tsx 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 * as classNames from 'classnames';
  22. import { debounce } from 'lodash';
  23. import ValidationInput from 'sonar-ui-common/components/controls/ValidationInput';
  24. import { translate } from 'sonar-ui-common/helpers/l10n';
  25. import { getHostUrl } from 'sonar-ui-common/helpers/urls';
  26. import { getOrganization } from '../../../api/organizations';
  27. interface Props {
  28. initialValue?: string;
  29. onChange: (value: string | undefined) => void;
  30. }
  31. interface State {
  32. error?: string;
  33. touched: boolean;
  34. validating: boolean;
  35. value: string;
  36. }
  37. export default class OrganizationKeyInput extends React.PureComponent<Props, State> {
  38. mounted = false;
  39. constructor(props: Props) {
  40. super(props);
  41. this.state = { error: undefined, touched: false, validating: false, value: '' };
  42. this.checkFreeKey = debounce(this.checkFreeKey, 250);
  43. }
  44. componentDidMount() {
  45. this.mounted = true;
  46. if (this.props.initialValue !== undefined) {
  47. this.setState({ value: this.props.initialValue });
  48. this.validateKey(this.props.initialValue);
  49. }
  50. }
  51. componentWillUnmount() {
  52. this.mounted = false;
  53. }
  54. checkFreeKey = (key: string) => {
  55. this.setState({ validating: true });
  56. return getOrganization(key)
  57. .then(organization => {
  58. if (this.mounted) {
  59. if (organization === undefined) {
  60. this.setState({ error: undefined, validating: false });
  61. this.props.onChange(key);
  62. } else {
  63. this.setState({
  64. error: translate('onboarding.create_organization.organization_name.taken'),
  65. touched: true,
  66. validating: false
  67. });
  68. this.props.onChange(undefined);
  69. }
  70. }
  71. })
  72. .catch(() => {
  73. if (this.mounted) {
  74. this.setState({ error: undefined, validating: false });
  75. this.props.onChange(key);
  76. }
  77. });
  78. };
  79. handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  80. const { value } = event.currentTarget;
  81. this.setState({ touched: true, value });
  82. this.validateKey(value);
  83. };
  84. validateKey(key: string) {
  85. if (key.length > 255 || !/^[a-z0-9][a-z0-9-]*[a-z0-9]?$/.test(key)) {
  86. this.setState({
  87. error: translate('onboarding.create_organization.organization_name.error'),
  88. touched: true
  89. });
  90. this.props.onChange(undefined);
  91. } else {
  92. this.checkFreeKey(key);
  93. }
  94. }
  95. render() {
  96. const isInvalid = this.state.touched && this.state.error !== undefined;
  97. const isValid = this.state.touched && !this.state.validating && this.state.error === undefined;
  98. return (
  99. <ValidationInput
  100. error={this.state.error}
  101. id="organization-key"
  102. isInvalid={isInvalid}
  103. isValid={isValid}
  104. label={translate('onboarding.create_organization.organization_name')}
  105. required={true}>
  106. <div className="display-inline-flex-baseline">
  107. <span className="little-spacer-right">
  108. {getHostUrl().replace(/https*:\/\//, '') + '/organizations/'}
  109. </span>
  110. <input
  111. autoFocus={true}
  112. className={classNames('input-super-large', {
  113. 'is-invalid': isInvalid,
  114. 'is-valid': isValid
  115. })}
  116. id="organization-key"
  117. maxLength={255}
  118. onChange={this.handleChange}
  119. type="text"
  120. value={this.state.value}
  121. />
  122. </div>
  123. </ValidationInput>
  124. );
  125. }
  126. }