]> source.dussan.org Git - sonarqube.git/commitdiff
Rewrite part of the settings page
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>
Wed, 14 Nov 2018 16:11:59 +0000 (17:11 +0100)
committerSonarTech <sonartech@sonarsource.com>
Thu, 15 Nov 2018 19:21:00 +0000 (20:21 +0100)
56 files changed:
server/sonar-web/src/main/js/api/settings.ts
server/sonar-web/src/main/js/app/types.ts
server/sonar-web/src/main/js/apps/projectBranches/components/LeakPeriodForm.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/LongBranchesPattern.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/LongBranchesPatternForm.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/SettingForm.tsx
server/sonar-web/src/main/js/apps/settings/__tests__/DefinitionActions-test.tsx
server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/Definition.js
server/sonar-web/src/main/js/apps/settings/components/DefinitionActions.tsx
server/sonar-web/src/main/js/apps/settings/components/inputs/Input.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/Input.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForNumber.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForNumber.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForPassword.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForPassword.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForString.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForString.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/PrimitiveInput.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/PrimitiveInput.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.js [deleted file]
server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/settings/constants.js [deleted file]
server/sonar-web/src/main/js/apps/settings/propTypes.js [deleted file]
server/sonar-web/src/main/js/apps/settings/types.js
server/sonar-web/src/main/js/apps/settings/utils.js [deleted file]
server/sonar-web/src/main/js/apps/settings/utils.ts [new file with mode: 0644]

index 2c0ad2d72104e7d1d2abe986c01d446e9469eac5..fbea55db86bddf2b0424260887e8eb20ee68ddaa 100644 (file)
  */
 import { omitBy } from 'lodash';
 import { getJSON, RequestData, post, postJSON } from '../helpers/request';
-import { TYPE_PROPERTY_SET } from '../apps/settings/constants';
-import { BranchParameters } from '../app/types';
+import {
+  BranchParameters,
+  SettingCategoryDefinition,
+  SettingValue,
+  SettingType
+} from '../app/types';
 import throwGlobalError from '../app/utils/throwGlobalError';
 
-interface DefinitionField {
-  description: string;
-  key: string;
-  name: string;
-  options: string[];
-}
-
-export interface Definition {
-  category: string;
-  description: string;
-  fields: DefinitionField[];
-  key: string;
-  name: string;
-  options: string[];
-  subCategory: string;
-  type: string;
-}
-
-export function getDefinitions(component?: string): Promise<{ definitions: Definition[] }> {
+export function getDefinitions(component?: string): Promise<SettingCategoryDefinition[]> {
   return getJSON('/api/settings/list_definitions', { component }).then(r => r.definitions);
 }
 
-export interface SettingValue {
-  inherited?: boolean;
-  key: string;
-  parentValue?: string;
-  parentValues?: string[];
-  value?: any;
-  values?: string[];
-}
-
 export function getValues(
   data: { keys: string; component?: string } & BranchParameters
 ): Promise<SettingValue[]> {
@@ -66,7 +43,7 @@ export function setSettingValue(definition: any, value: any, component?: string)
 
   if (definition.multiValues) {
     data.values = value;
-  } else if (definition.type === TYPE_PROPERTY_SET) {
+  } else if (definition.type === SettingType.PropertySet) {
     data.fieldValues = value
       .map((fields: any) => omitBy(fields, value => value == null))
       .map(JSON.stringify);
index ce8d5e9009538429e8f2448d5f4a9c7d59d986ed..8e36aa9859117fc063433c64f7a65fcfe24bfa93 100644 (file)
@@ -698,6 +698,53 @@ export enum RuleType {
   Unknown = 'UNKNOWN'
 }
 
+export type Setting = SettingValue & { definition: SettingDefinition };
+
+export enum SettingType {
+  String = 'STRING',
+  Text = 'TEXT',
+  Password = 'PASSWORD',
+  Boolean = 'BOOLEAN',
+  Float = 'FLOAT',
+  Integer = 'INTEGER',
+  Long = 'LONG',
+  SingleSelectList = 'SINGLE_SELECT_LIST',
+  PropertySet = 'PROPERTY_SET'
+}
+
+export interface SettingDefinition {
+  description?: string;
+  key: string;
+  name?: string;
+  options: string[];
+  type?: SettingType;
+}
+
+export interface SettingFieldDefinition extends SettingDefinition {
+  description: string;
+  name: string;
+}
+
+export interface SettingCategoryDefinition extends SettingDefinition {
+  category: string;
+  defaultValue?: string;
+  deprecatedKey?: string;
+  fields: SettingFieldDefinition[];
+  multiValues?: boolean;
+  subCategory: string;
+}
+
+export interface SettingValue {
+  fieldValues?: Array<{ [key: string]: string }>;
+  inherited?: boolean;
+  key: string;
+  parentFieldValues?: Array<{ [key: string]: string }>;
+  parentValue?: string;
+  parentValues?: string[];
+  value?: string;
+  values?: string[];
+}
+
 export interface ShortLivingBranch extends Branch {
   isMain: false;
   isOrphan?: true;
index 5812a3d3c608ded56df7c567909c7e411fdb33ee..ebfc5e35072ecc7dd9128af46875c6d874fdd48d 100644 (file)
@@ -20,8 +20,9 @@
 import * as React from 'react';
 import SettingForm from './SettingForm';
 import { translate } from '../../../helpers/l10n';
-import { getValues, SettingValue } from '../../../api/settings';
+import { getValues } from '../../../api/settings';
 import Modal from '../../../components/controls/Modal';
+import { SettingValue } from '../../../app/types';
 
 interface Props {
   branch: string;
index 487ec48c432294caf54143e9b0b4ee1245877f4f..e0b17e46f8ed47ced2219cc9132d1b83cb9a6fa2 100644 (file)
  */
 import * as React from 'react';
 import LongBranchesPatternForm from './LongBranchesPatternForm';
-import { getValues, SettingValue } from '../../../api/settings';
+import { getValues } from '../../../api/settings';
 import { EditButton } from '../../../components/ui/buttons';
 import { translate } from '../../../helpers/l10n';
+import { SettingValue } from '../../../app/types';
 
 interface Props {
   project: string;
index ddc08a23d517461b63a77992149745b6953b4c4a..d323cf22a81f03b62789b73af68fdc4854804468 100644 (file)
@@ -20,8 +20,8 @@
 import * as React from 'react';
 import SettingForm from './SettingForm';
 import { translate } from '../../../helpers/l10n';
-import { SettingValue } from '../../../api/settings';
 import Modal from '../../../components/controls/Modal';
+import { SettingValue } from '../../../app/types';
 
 interface Props {
   onChange: () => void;
index 45533ab1da6368b9a557d5a1adaf4a38db01bbcb..08f1bb0e802a21cb6c36f1004bdf21ab21dbeafa 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { SettingValue, setSimpleSettingValue, resetSettingValue } from '../../../api/settings';
+import { setSimpleSettingValue, resetSettingValue } from '../../../api/settings';
 import { Button, SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { SettingValue } from '../../../app/types';
 
 interface Props {
   branch?: string;
index f13959d9abf52e89c2d6ff4a38e4c22916ec32b0..76b1d29491c956b23e05270fc07d59b3830a5efc 100644 (file)
@@ -21,6 +21,7 @@
 import * as React from 'react';
 import { shallow } from 'enzyme';
 import DefinitionActions from '../components/DefinitionActions';
+import { SettingType } from '../../../app/types';
 
 const definition = {
   category: 'baz',
@@ -30,7 +31,7 @@ const definition = {
   name: 'foobar',
   options: [],
   subCategory: 'bar',
-  type: 'foo'
+  type: SettingType.String
 };
 
 const settings = {
diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.js b/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.js
deleted file mode 100644 (file)
index 9136399..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { getEmptyValue, getDefaultValue } from '../utils';
-import {
-  TYPE_PROPERTY_SET,
-  TYPE_STRING,
-  TYPE_SINGLE_SELECT_LIST,
-  TYPE_BOOLEAN
-} from '../constants';
-
-const fields = [{ key: 'foo', type: TYPE_STRING }, { key: 'bar', type: TYPE_SINGLE_SELECT_LIST }];
-
-describe('#getEmptyValue()', () => {
-  it('should work for property sets', () => {
-    const setting = { type: TYPE_PROPERTY_SET, fields };
-    expect(getEmptyValue(setting)).toEqual([{ foo: '', bar: null }]);
-  });
-
-  it('should work for multi values string', () => {
-    const setting = { type: TYPE_STRING, multiValues: true };
-    expect(getEmptyValue(setting)).toEqual(['']);
-  });
-
-  it('should work for multi values boolean', () => {
-    const setting = { type: TYPE_BOOLEAN, multiValues: true };
-    expect(getEmptyValue(setting)).toEqual([null]);
-  });
-});
-
-describe('#getDefaultValue()', () => {
-  const check = (parentValue, expected) => {
-    const setting = { definition: { type: TYPE_BOOLEAN }, parentValue };
-    expect(getDefaultValue(setting)).toEqual(expected);
-  };
-
-  it('should work for boolean field when passing true', () => check(true, 'settings.boolean.true'));
-  it('should work for boolean field when passing "true"', () =>
-    check('true', 'settings.boolean.true'));
-  it('should work for boolean field when passing false', () =>
-    check(false, 'settings.boolean.false'));
-  it('should work for boolean field when passing "false"', () =>
-    check('false', 'settings.boolean.false'));
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/settings/__tests__/utils-test.ts
new file mode 100644 (file)
index 0000000..53605d9
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { getEmptyValue, getDefaultValue } from '../utils';
+import { SettingFieldDefinition, SettingCategoryDefinition, SettingType } from '../../../app/types';
+
+const fields = [
+  { key: 'foo', type: SettingType.String } as SettingFieldDefinition,
+  { key: 'bar', type: SettingType.SingleSelectList } as SettingFieldDefinition
+];
+
+const settingDefinition: SettingCategoryDefinition = {
+  category: 'test',
+  fields: [],
+  key: 'test',
+  options: [],
+  subCategory: 'subtest'
+};
+
+describe('#getEmptyValue()', () => {
+  it('should work for property sets', () => {
+    const setting = { ...settingDefinition, type: SettingType.PropertySet, fields };
+    expect(getEmptyValue(setting)).toEqual([{ foo: '', bar: null }]);
+  });
+
+  it('should work for multi values string', () => {
+    const setting = { ...settingDefinition, type: SettingType.String, multiValues: true };
+    expect(getEmptyValue(setting)).toEqual(['']);
+  });
+
+  it('should work for multi values boolean', () => {
+    const setting = { ...settingDefinition, type: SettingType.Boolean, multiValues: true };
+    expect(getEmptyValue(setting)).toEqual([null]);
+  });
+});
+
+describe('#getDefaultValue()', () => {
+  const check = (parentValue?: string, expected?: string) => {
+    const setting = {
+      definition: { key: 'test', options: [], type: SettingType.Boolean },
+      parentValue,
+      key: 'test'
+    };
+    expect(getDefaultValue(setting)).toEqual(expected);
+  };
+
+  it('should work for boolean field when passing "true"', () =>
+    check('true', 'settings.boolean.true'));
+  it('should work for boolean field when passing "false"', () =>
+    check('false', 'settings.boolean.false'));
+});
index 668c22c63770153dab5eee16112872b79c63fd5f..1ce6ac3ba105eb810ced24054a058d8e2ccec0cb 100644 (file)
@@ -36,7 +36,6 @@ import { translateWithParameters, translate } from '../../../helpers/l10n';
 import { resetValue, saveValue, checkValue } from '../store/actions';
 import { passValidation } from '../store/settingsPage/validationMessages/actions';
 import { cancelChange, changeValue } from '../store/settingsPage/changedValues/actions';
-import { TYPE_PASSWORD } from '../constants';
 import {
   getSettingsAppChangedValue,
   isSettingsAppLoading,
@@ -196,6 +195,7 @@ class Definition extends React.PureComponent {
             hasValueChanged={hasValueChanged}
             onCancel={this.handleCancel}
             onChange={this.handleChange}
+            onSave={this.handleSave}
             setting={setting}
             value={effectiveValue}
           />
index 2f2df1482962c6bf9a44c2ac242def9dc90edf65..b7fab85c9adf6e1cf17786e8beeefac7efeb597a 100644 (file)
  */
 import * as React from 'react';
 import Modal from '../../../components/controls/Modal';
+import { Button, ResetButtonLink, SubmitButton } from '../../../components/ui/buttons';
 import { isEmptyValue, getDefaultValue, getSettingValue } from '../utils';
 import { translate } from '../../../helpers/l10n';
-import { Button, ResetButtonLink, SubmitButton } from '../../../components/ui/buttons';
-import { SettingValue, Definition } from '../../../api/settings';
+import { Setting } from '../../../app/types';
 
 type Props = {
   changedValue: string;
@@ -32,7 +32,7 @@ type Props = {
   onCancel: () => void;
   onReset: () => void;
   onSave: () => void;
-  setting: SettingValue & { definition: Definition };
+  setting: Setting;
 };
 
 type State = { reseting: boolean };
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/Input.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/Input.js
deleted file mode 100644 (file)
index 852fcc4..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import PropertySetInput from './PropertySetInput';
-import MultiValueInput from './MultiValueInput';
-import PrimitiveInput from './PrimitiveInput';
-import { TYPE_PROPERTY_SET } from '../../constants';
-
-export default class Input extends React.PureComponent {
-  static propTypes = {
-    setting: PropTypes.object.isRequired,
-    value: PropTypes.any,
-    onChange: PropTypes.func.isRequired
-  };
-
-  render() {
-    const { definition } = this.props.setting;
-
-    if (definition.multiValues) {
-      return <MultiValueInput {...this.props} />;
-    }
-
-    if (definition.type === TYPE_PROPERTY_SET) {
-      return <PropertySetInput {...this.props} />;
-    }
-
-    return <PrimitiveInput {...this.props} />;
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/Input.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/Input.tsx
new file mode 100644 (file)
index 0000000..cbe09c0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import PropertySetInput from './PropertySetInput';
+import MultiValueInput from './MultiValueInput';
+import PrimitiveInput from './PrimitiveInput';
+import { DefaultInputProps, isCategoryDefinition } from '../../utils';
+import { SettingType } from '../../../../app/types';
+
+export default function Input(props: DefaultInputProps) {
+  const { definition } = props.setting;
+
+  if (isCategoryDefinition(definition) && definition.multiValues) {
+    return <MultiValueInput {...props} />;
+  }
+
+  if (definition.type === SettingType.PropertySet) {
+    return <PropertySetInput {...props} />;
+  }
+
+  return <PrimitiveInput {...props} />;
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.js
deleted file mode 100644 (file)
index 1a7cb68..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import Toggle from '../../../../components/controls/Toggle';
-import { defaultInputPropTypes } from '../../propTypes';
-import { translate } from '../../../../helpers/l10n';
-
-export default class InputForBoolean extends React.PureComponent {
-  static propTypes = {
-    ...defaultInputPropTypes,
-    value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string])
-  };
-
-  render() {
-    const hasValue = this.props.value != null;
-    const displayedValue = hasValue ? this.props.value : false;
-
-    return (
-      <div className="display-inline-block text-top">
-        <Toggle name={this.props.name} onChange={this.props.onChange} value={displayedValue} />
-
-        {!hasValue && <span className="spacer-left note">{translate('settings.not_set')}</span>}
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForBoolean.tsx
new file mode 100644 (file)
index 0000000..0be7302
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import Toggle from '../../../../components/controls/Toggle';
+import { translate } from '../../../../helpers/l10n';
+import { DefaultSpecializedInputProps } from '../../utils';
+
+interface Props extends DefaultSpecializedInputProps {
+  value: string | boolean | undefined;
+}
+
+export default function InputForBoolean({ onChange, name, value }: Props) {
+  const displayedValue = value != null ? value : false;
+  return (
+    <div className="display-inline-block text-top">
+      <Toggle name={name} onChange={onChange} value={displayedValue} />
+      {value == null && <span className="spacer-left note">{translate('settings.not_set')}</span>}
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForNumber.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForNumber.js
deleted file mode 100644 (file)
index b756f60..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import SimpleInput from './SimpleInput';
-
-export default function InputForNumber(props) {
-  return <SimpleInput {...props} className="input-small" type="text" />;
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForNumber.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForNumber.tsx
new file mode 100644 (file)
index 0000000..21d7570
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import SimpleInput from './SimpleInput';
+import { DefaultSpecializedInputProps } from '../../utils';
+
+export default function InputForNumber(props: DefaultSpecializedInputProps) {
+  return <SimpleInput {...props} className="input-small" type="text" />;
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForPassword.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForPassword.js
deleted file mode 100644 (file)
index 9a91a26..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import * as theme from '../../../../app/theme';
-import { translate } from '../../../../helpers/l10n';
-import { defaultInputPropTypes } from '../../propTypes';
-import LockIcon from '../../../../components/icons-components/LockIcon';
-import { Button } from '../../../../components/ui/buttons';
-
-export default class InputForPassword extends React.PureComponent {
-  static propTypes = defaultInputPropTypes;
-
-  state = {
-    value: '',
-    changing: false
-  };
-
-  componentWillReceiveProps(nextProps /*: Props*/) {
-    if (!nextProps.hasValueChanged && this.props.hasValueChanged) {
-      this.setState({ changing: false, value: '' });
-    }
-  }
-
-  handleInputChange(e) {
-    this.props.onChange(e.target.value);
-    this.setState({ changing: true, value: e.target.value });
-  }
-
-  handleChangeClick = () => {
-    this.setState({ changing: true });
-  };
-
-  renderInput() {
-    return (
-      <form>
-        <input className="hidden" type="password" />
-        <input
-          autoComplete="off"
-          autoFocus={this.state.changing}
-          className="js-password-input settings-large-input text-top"
-          name={this.props.name}
-          onChange={e => this.handleInputChange(e)}
-          type="password"
-          value={this.state.value}
-        />
-      </form>
-    );
-  }
-
-  render() {
-    const hasValue = !!this.props.value;
-
-    if (this.state.changing || !hasValue) {
-      return this.renderInput();
-    }
-
-    return (
-      <div>
-        <LockIcon className="text-middle big-spacer-right" fill={theme.gray60} />
-        <Button className="text-middle" onClick={this.handleChangeClick}>
-          {translate('change_verb')}
-        </Button>
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForPassword.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForPassword.tsx
new file mode 100644 (file)
index 0000000..412bff6
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import * as theme from '../../../../app/theme';
+import LockIcon from '../../../../components/icons-components/LockIcon';
+import { Button } from '../../../../components/ui/buttons';
+import { translate } from '../../../../helpers/l10n';
+import { DefaultSpecializedInputProps } from '../../utils';
+
+interface State {
+  changing: boolean;
+  value: string;
+}
+
+export default class InputForPassword extends React.PureComponent<
+  DefaultSpecializedInputProps,
+  State
+> {
+  state: State = {
+    value: '',
+    changing: false
+  };
+
+  componentDidUpdate(prevProps: DefaultSpecializedInputProps) {
+    if (!prevProps.hasValueChanged && this.props.hasValueChanged) {
+      this.setState({ changing: false, value: '' });
+    }
+  }
+
+  handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+    this.props.onChange(event.target.value);
+    this.setState({ changing: true, value: event.target.value });
+  };
+
+  handleChangeClick = () => {
+    this.setState({ changing: true });
+  };
+
+  renderInput() {
+    return (
+      <form>
+        <input className="hidden" type="password" />
+        <input
+          autoComplete="off"
+          autoFocus={this.state.changing}
+          className="js-password-input settings-large-input text-top"
+          name={this.props.name}
+          onChange={this.handleInputChange}
+          type="password"
+          value={this.state.value}
+        />
+      </form>
+    );
+  }
+
+  render() {
+    const hasValue = !!this.props.value;
+
+    if (this.state.changing || !hasValue) {
+      return this.renderInput();
+    }
+
+    return (
+      <>
+        <LockIcon className="text-middle big-spacer-right" fill={theme.gray60} />
+        <Button className="text-middle" onClick={this.handleChangeClick}>
+          {translate('change_verb')}
+        </Button>
+      </>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.js
deleted file mode 100644 (file)
index 1517396..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import Select from '../../../../components/controls/Select';
-import { defaultInputPropTypes } from '../../propTypes';
-
-export default class InputForSingleSelectList extends React.PureComponent {
-  static propTypes = {
-    ...defaultInputPropTypes,
-    options: PropTypes.arrayOf(PropTypes.string).isRequired
-  };
-
-  handleInputChange(option) {
-    this.props.onChange(option.value);
-  }
-
-  render() {
-    const options = this.props.options.map(option => ({
-      label: option,
-      value: option
-    }));
-
-    return (
-      <Select
-        className="settings-large-input"
-        clearable={false}
-        name={this.props.name}
-        onChange={option => this.handleInputChange(option)}
-        options={options}
-        value={this.props.value}
-      />
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForSingleSelectList.tsx
new file mode 100644 (file)
index 0000000..71466a8
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import Select from '../../../../components/controls/Select';
+import { DefaultSpecializedInputProps } from '../../utils';
+import { SettingCategoryDefinition } from '../../../../app/types';
+
+type Props = DefaultSpecializedInputProps & Pick<SettingCategoryDefinition, 'options'>;
+
+export default class InputForSingleSelectList extends React.PureComponent<Props> {
+  handleInputChange = ({ value }: { value: string }) => {
+    this.props.onChange(value);
+  };
+
+  render() {
+    const options = this.props.options.map(option => ({
+      label: option,
+      value: option
+    }));
+
+    return (
+      <Select
+        className="settings-large-input"
+        clearable={false}
+        name={this.props.name}
+        onChange={this.handleInputChange}
+        options={options}
+        value={this.props.value}
+      />
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForString.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForString.js
deleted file mode 100644 (file)
index a837569..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import SimpleInput from './SimpleInput';
-
-export default function InputForString(props) {
-  return <SimpleInput {...props} className="settings-large-input" type="text" />;
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForString.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForString.tsx
new file mode 100644 (file)
index 0000000..da681e1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import SimpleInput from './SimpleInput';
+import { DefaultSpecializedInputProps } from '../../utils';
+
+export default function InputForString(props: DefaultSpecializedInputProps) {
+  return <SimpleInput {...props} className="settings-large-input" type="text" />;
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.js
deleted file mode 100644 (file)
index 7193e8a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { defaultInputPropTypes } from '../../propTypes';
-
-export default class InputForText extends React.PureComponent {
-  static propTypes = defaultInputPropTypes;
-
-  handleInputChange(e) {
-    this.props.onChange(e.target.value);
-  }
-
-  render() {
-    return (
-      <textarea
-        className="settings-large-input text-top"
-        name={this.props.name}
-        onChange={e => this.handleInputChange(e)}
-        rows="5"
-        value={this.props.value || ''}
-      />
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/InputForText.tsx
new file mode 100644 (file)
index 0000000..7e40841
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { DefaultSpecializedInputProps } from '../../utils';
+
+export default class InputForText extends React.PureComponent<DefaultSpecializedInputProps> {
+  handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
+    this.props.onChange(event.target.value);
+  };
+
+  render() {
+    return (
+      <textarea
+        className="settings-large-input text-top"
+        name={this.props.name}
+        onChange={this.handleInputChange}
+        rows={5}
+        value={this.props.value || ''}
+      />
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.js
deleted file mode 100644 (file)
index 47ddb19..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import PrimitiveInput from './PrimitiveInput';
-import { getEmptyValue } from '../../utils';
-import { DeleteButton } from '../../../../components/ui/buttons';
-
-export default class MultiValueInput extends React.PureComponent {
-  static propTypes = {
-    setting: PropTypes.object.isRequired,
-    value: PropTypes.array,
-    onChange: PropTypes.func.isRequired
-  };
-
-  ensureValue() {
-    return this.props.value || [];
-  }
-
-  handleSingleInputChange(index, value) {
-    const newValue = [...this.ensureValue()];
-    newValue.splice(index, 1, value);
-    this.props.onChange(newValue);
-  }
-
-  handleDeleteValue(index) {
-    const newValue = [...this.ensureValue()];
-    newValue.splice(index, 1);
-    this.props.onChange(newValue);
-  }
-
-  prepareSetting() {
-    const { setting } = this.props;
-    const newDefinition = { ...setting.definition, multiValues: false };
-    return {
-      ...setting,
-      definition: newDefinition,
-      values: undefined
-    };
-  }
-
-  renderInput(value, index, isLast) {
-    return (
-      <li className="spacer-bottom" key={index}>
-        <PrimitiveInput
-          onChange={this.handleSingleInputChange.bind(this, index)}
-          setting={this.prepareSetting()}
-          value={value}
-        />
-
-        {!isLast && (
-          <div className="display-inline-block spacer-left">
-            <DeleteButton
-              className="js-remove-value"
-              onClick={this.handleDeleteValue.bind(this, index)}
-            />
-          </div>
-        )}
-      </li>
-    );
-  }
-
-  render() {
-    const displayedValue = [...this.ensureValue(), ...getEmptyValue(this.props.setting.definition)];
-
-    return (
-      <div>
-        <ul>
-          {displayedValue.map((value, index) =>
-            this.renderInput(value, index, index === displayedValue.length - 1)
-          )}
-        </ul>
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/MultiValueInput.tsx
new file mode 100644 (file)
index 0000000..aed3333
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import PrimitiveInput from './PrimitiveInput';
+import { getEmptyValue, DefaultInputProps } from '../../utils';
+import { DeleteButton } from '../../../../components/ui/buttons';
+
+export default class MultiValueInput extends React.PureComponent<DefaultInputProps> {
+  ensureValue = () => {
+    return this.props.value || [];
+  };
+
+  handleSingleInputChange = (index: number, value: any) => {
+    const newValue = [...this.ensureValue()];
+    newValue.splice(index, 1, value);
+    this.props.onChange(newValue);
+  };
+
+  handleDeleteValue = (index: number) => {
+    const newValue = [...this.ensureValue()];
+    newValue.splice(index, 1);
+    this.props.onChange(newValue);
+  };
+
+  renderInput(value: any, index: number, isLast: boolean) {
+    const { setting } = this.props;
+    return (
+      <li className="spacer-bottom" key={index}>
+        <PrimitiveInput
+          hasValueChanged={this.props.hasValueChanged}
+          onChange={value => this.handleSingleInputChange(index, value)}
+          setting={{
+            ...setting,
+            definition: { ...setting.definition, multiValues: false },
+            values: undefined
+          }}
+          value={value}
+        />
+
+        {!isLast && (
+          <div className="display-inline-block spacer-left">
+            <DeleteButton
+              className="js-remove-value"
+              onClick={() => this.handleDeleteValue(index)}
+            />
+          </div>
+        )}
+      </li>
+    );
+  }
+
+  render() {
+    const displayedValue = [...this.ensureValue(), ...getEmptyValue(this.props.setting.definition)];
+    return (
+      <div>
+        <ul>
+          {displayedValue.map((value, index) =>
+            this.renderInput(value, index, index === displayedValue.length - 1)
+          )}
+        </ul>
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/PrimitiveInput.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/PrimitiveInput.js
deleted file mode 100644 (file)
index 327031a..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import InputForString from './InputForString';
-import InputForText from './InputForText';
-import InputForPassword from './InputForPassword';
-import InputForBoolean from './InputForBoolean';
-import InputForNumber from './InputForNumber';
-import InputForSingleSelectList from './InputForSingleSelectList';
-import { getUniqueName, isDefaultOrInherited } from '../../utils';
-import * as types from '../../constants';
-
-const typeMapping = {
-  [types.TYPE_STRING]: InputForString,
-  [types.TYPE_TEXT]: InputForText,
-  [types.TYPE_PASSWORD]: InputForPassword,
-  [types.TYPE_BOOLEAN]: InputForBoolean,
-  [types.TYPE_INTEGER]: InputForNumber,
-  [types.TYPE_LONG]: InputForNumber,
-  [types.TYPE_FLOAT]: InputForNumber
-};
-
-export default class PrimitiveInput extends React.PureComponent {
-  static propTypes = {
-    setting: PropTypes.object.isRequired,
-    value: PropTypes.any,
-    onChange: PropTypes.func.isRequired
-  };
-
-  render() {
-    const { setting, value, onChange, ...other } = this.props;
-    const { definition } = setting;
-
-    const name = getUniqueName(definition);
-
-    if (definition.type === types.TYPE_SINGLE_SELECT_LIST) {
-      return (
-        <InputForSingleSelectList
-          isDefault={isDefaultOrInherited(setting)}
-          name={name}
-          onChange={onChange}
-          options={definition.options}
-          value={value}
-          {...other}
-        />
-      );
-    }
-
-    const InputComponent = typeMapping[definition.type] || InputForString;
-    return (
-      <InputComponent
-        isDefault={isDefaultOrInherited(setting)}
-        name={name}
-        onChange={onChange}
-        value={value}
-        {...other}
-      />
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/PrimitiveInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/PrimitiveInput.tsx
new file mode 100644 (file)
index 0000000..7f611e1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import InputForString from './InputForString';
+import InputForText from './InputForText';
+import InputForPassword from './InputForPassword';
+import InputForBoolean from './InputForBoolean';
+import InputForNumber from './InputForNumber';
+import InputForSingleSelectList from './InputForSingleSelectList';
+import {
+  getUniqueName,
+  isDefaultOrInherited,
+  DefaultInputProps,
+  DefaultSpecializedInputProps
+} from '../../utils';
+import { SettingType } from '../../../../app/types';
+
+const typeMapping: {
+  [type in SettingType]?:
+    | React.ComponentClass<DefaultSpecializedInputProps>
+    | React.StatelessComponent<DefaultSpecializedInputProps>
+} = {
+  [SettingType.String]: InputForString,
+  [SettingType.Text]: InputForText,
+  [SettingType.Password]: InputForPassword,
+  [SettingType.Boolean]: InputForBoolean,
+  [SettingType.Integer]: InputForNumber,
+  [SettingType.Long]: InputForNumber,
+  [SettingType.Float]: InputForNumber
+};
+
+interface Props extends DefaultInputProps {
+  name?: string;
+}
+
+export default class PrimitiveInput extends React.PureComponent<Props> {
+  render() {
+    const { setting, ...other } = this.props;
+    const { definition } = setting;
+
+    const name = this.props.name || getUniqueName(definition);
+
+    if (definition.type === SettingType.SingleSelectList) {
+      return (
+        <InputForSingleSelectList
+          isDefault={isDefaultOrInherited(setting)}
+          name={name}
+          options={definition.options}
+          {...other}
+        />
+      );
+    }
+
+    const InputComponent = (definition.type && typeMapping[definition.type]) || InputForString;
+    return <InputComponent isDefault={isDefaultOrInherited(setting)} name={name} {...other} />;
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.js
deleted file mode 100644 (file)
index 62f86ad..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import PrimitiveInput from './PrimitiveInput';
-import { getEmptyValue, getUniqueName } from '../../utils';
-import { DeleteButton } from '../../../../components/ui/buttons';
-
-export default class PropertySetInput extends React.PureComponent {
-  static propTypes = {
-    setting: PropTypes.object.isRequired,
-    value: PropTypes.array,
-    onChange: PropTypes.func.isRequired
-  };
-
-  ensureValue() {
-    return this.props.value || [];
-  }
-
-  getFieldName(field) {
-    return getUniqueName(this.props.setting.definition, field.key);
-  }
-
-  handleDeleteValue(index) {
-    const newValue = [...this.ensureValue()];
-    newValue.splice(index, 1);
-    this.props.onChange(newValue);
-  }
-
-  handleInputChange(index, fieldKey, value) {
-    const emptyValue = getEmptyValue(this.props.setting.definition)[0];
-    const newValue = [...this.ensureValue()];
-    const newFields = { ...emptyValue, ...newValue[index], [fieldKey]: value };
-    newValue.splice(index, 1, newFields);
-    return this.props.onChange(newValue);
-  }
-
-  renderFields(fieldValues, index, isLast) {
-    const { setting } = this.props;
-
-    return (
-      <tr key={index}>
-        {setting.definition.fields.map(field => (
-          <td key={field.key}>
-            <PrimitiveInput
-              name={this.getFieldName(field)}
-              onChange={this.handleInputChange.bind(this, index, field.key)}
-              setting={{ definition: field, value: fieldValues[field.key] }}
-              value={fieldValues[field.key]}
-            />
-          </td>
-        ))}
-        <td className="thin nowrap text-middle">
-          {!isLast && (
-            <DeleteButton
-              className="js-remove-value"
-              onClick={this.handleDeleteValue.bind(this, index)}
-            />
-          )}
-        </td>
-      </tr>
-    );
-  }
-
-  render() {
-    const { setting } = this.props;
-
-    const displayedValue = [...this.ensureValue(), ...getEmptyValue(this.props.setting.definition)];
-
-    return (
-      <div>
-        <table
-          className="data zebra-hover no-outer-padding"
-          style={{ width: 'auto', minWidth: 480, marginTop: -12 }}>
-          <thead>
-            <tr>
-              {setting.definition.fields.map(field => (
-                <th key={field.key}>
-                  {field.name}
-                  {field.description != null && (
-                    <span className="spacer-top small">{field.description}</span>
-                  )}
-                </th>
-              ))}
-              <th>&nbsp;</th>
-            </tr>
-          </thead>
-          <tbody>
-            {displayedValue.map((fieldValues, index) =>
-              this.renderFields(fieldValues, index, index === displayedValue.length - 1)
-            )}
-          </tbody>
-        </table>
-      </div>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/PropertySetInput.tsx
new file mode 100644 (file)
index 0000000..5130710
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import PrimitiveInput from './PrimitiveInput';
+import { getEmptyValue, getUniqueName, DefaultInputProps, isCategoryDefinition } from '../../utils';
+import { DeleteButton } from '../../../../components/ui/buttons';
+
+export default class PropertySetInput extends React.PureComponent<DefaultInputProps> {
+  ensureValue() {
+    return this.props.value || [];
+  }
+
+  handleDeleteValue = (index: number) => {
+    const newValue = [...this.ensureValue()];
+    newValue.splice(index, 1);
+    this.props.onChange(newValue);
+  };
+
+  handleInputChange = (index: number, fieldKey: string, value: any) => {
+    const emptyValue = getEmptyValue(this.props.setting.definition)[0];
+    const newValue = [...this.ensureValue()];
+    const newFields = { ...emptyValue, ...newValue[index], [fieldKey]: value };
+    newValue.splice(index, 1, newFields);
+    return this.props.onChange(newValue);
+  };
+
+  renderFields(fieldValues: any, index: number, isLast: boolean) {
+    const { setting } = this.props;
+    const { definition } = setting;
+
+    return (
+      <tr key={index}>
+        {isCategoryDefinition(definition) &&
+          definition.fields.map(field => (
+            <td key={field.key}>
+              <PrimitiveInput
+                hasValueChanged={this.props.hasValueChanged}
+                name={getUniqueName(definition, field.key)}
+                onChange={value => this.handleInputChange(index, field.key, value)}
+                setting={{ ...setting, definition: field, value: fieldValues[field.key] }}
+                value={fieldValues[field.key]}
+              />
+            </td>
+          ))}
+        <td className="thin nowrap text-middle">
+          {!isLast && (
+            <DeleteButton
+              className="js-remove-value"
+              onClick={() => this.handleDeleteValue(index)}
+            />
+          )}
+        </td>
+      </tr>
+    );
+  }
+
+  render() {
+    const { definition } = this.props.setting;
+    const displayedValue = [...this.ensureValue(), ...getEmptyValue(definition)];
+
+    return (
+      <div>
+        <table
+          className="data zebra-hover no-outer-padding"
+          style={{ width: 'auto', minWidth: 480, marginTop: -12 }}>
+          <thead>
+            <tr>
+              {isCategoryDefinition(definition) &&
+                definition.fields.map(field => (
+                  <th key={field.key}>
+                    {field.name}
+                    {field.description != null && (
+                      <span className="spacer-top small">{field.description}</span>
+                    )}
+                  </th>
+                ))}
+              <th>&nbsp;</th>
+            </tr>
+          </thead>
+          <tbody>
+            {displayedValue.map((fieldValues, index) =>
+              this.renderFields(fieldValues, index, index === displayedValue.length - 1)
+            )}
+          </tbody>
+        </table>
+      </div>
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.js
deleted file mode 100644 (file)
index c2a38bc..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import PropTypes from 'prop-types';
-import { defaultInputPropTypes } from '../../propTypes';
-
-export default class SimpleInput extends React.PureComponent {
-  static propTypes = {
-    ...defaultInputPropTypes,
-    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
-    type: PropTypes.string.isRequired,
-    className: PropTypes.string.isRequired,
-    onCancel: PropTypes.func,
-    onSave: PropTypes.func
-  };
-
-  handleInputChange = event => {
-    this.props.onChange(event.currentTarget.value);
-  };
-
-  handleKeyDown = event => {
-    if (event.keyCode === 13) {
-      if (this.props.onSave) {
-        this.props.onSave();
-      }
-    } else if (event.keyCode === 27) {
-      if (this.props.onCancel) {
-        this.props.onCancel();
-      }
-    }
-  };
-
-  render() {
-    return (
-      <input
-        className={this.props.className + ' text-top'}
-        name={this.props.name}
-        onChange={this.handleInputChange}
-        onKeyDown={this.handleKeyDown}
-        type={this.props.type}
-        value={this.props.value || ''}
-      />
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/SimpleInput.tsx
new file mode 100644 (file)
index 0000000..451eaeb
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { DefaultSpecializedInputProps } from '../../utils';
+
+interface Props extends DefaultSpecializedInputProps {
+  className?: string;
+  type: string;
+  value: string | number;
+}
+
+export default class SimpleInput extends React.PureComponent<Props> {
+  handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+    this.props.onChange(event.currentTarget.value);
+  };
+
+  handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
+    if (event.keyCode === 13 && this.props.onSave) {
+      this.props.onSave();
+    } else if (event.keyCode === 27 && this.props.onCancel) {
+      this.props.onCancel();
+    }
+  };
+
+  render() {
+    return (
+      <input
+        className={classNames('text-top', this.props.className)}
+        name={this.props.name}
+        onChange={this.handleInputChange}
+        onKeyDown={this.handleKeyDown}
+        type={this.props.type}
+        value={this.props.value || ''}
+      />
+    );
+  }
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.js
deleted file mode 100644 (file)
index 5877a37..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import Input from '../Input';
-import PrimitiveInput from '../PrimitiveInput';
-import MultiValueInput from '../MultiValueInput';
-import PropertySetInput from '../PropertySetInput';
-import { TYPE_STRING, TYPE_PROPERTY_SET } from '../../../constants';
-
-it('should render PrimitiveInput', () => {
-  const setting = { definition: { key: 'example', type: TYPE_STRING } };
-  const onChange = jest.fn();
-  const input = shallow(<Input onChange={onChange} setting={setting} value="foo" />).find(
-    PrimitiveInput
-  );
-  expect(input.length).toBe(1);
-  expect(input.prop('setting')).toBe(setting);
-  expect(input.prop('value')).toBe('foo');
-  expect(input.prop('onChange')).toBe(onChange);
-});
-
-it('should render MultiValueInput', () => {
-  const setting = { definition: { key: 'example', type: TYPE_STRING, multiValues: true } };
-  const value = ['foo', 'bar'];
-  const onChange = jest.fn();
-  const input = shallow(<Input onChange={onChange} setting={setting} value={value} />).find(
-    MultiValueInput
-  );
-  expect(input.length).toBe(1);
-  expect(input.prop('setting')).toBe(setting);
-  expect(input.prop('value')).toBe(value);
-  expect(input.prop('onChange')).toBe(onChange);
-});
-
-it('should render PropertySetInput', () => {
-  const setting = { definition: { key: 'example', type: TYPE_PROPERTY_SET, fields: [] } };
-  const value = [{ foo: 'bar' }];
-  const onChange = jest.fn();
-  const input = shallow(<Input onChange={onChange} setting={setting} value={value} />).find(
-    PropertySetInput
-  );
-  expect(input.length).toBe(1);
-  expect(input.prop('setting')).toBe(setting);
-  expect(input.prop('value')).toBe(value);
-  expect(input.prop('onChange')).toBe(onChange);
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/Input-test.tsx
new file mode 100644 (file)
index 0000000..15399a4
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Input from '../Input';
+import { SettingType } from '../../../../../app/types';
+import { DefaultInputProps } from '../../../utils';
+
+const settingValue = {
+  key: 'example'
+};
+
+const settingDefinition = {
+  category: 'general',
+  fields: [],
+  key: 'example',
+  options: [],
+  subCategory: 'Branches',
+  type: SettingType.String
+};
+
+it('should render PrimitiveInput', () => {
+  const setting = { ...settingValue, definition: settingDefinition };
+  const onChange = jest.fn();
+  const input = shallowRender({ onChange, setting }).find('PrimitiveInput');
+  expect(input.length).toBe(1);
+  expect(input.prop('setting')).toBe(setting);
+  expect(input.prop('value')).toBe('foo');
+  expect(input.prop('onChange')).toBe(onChange);
+});
+
+it('should render MultiValueInput', () => {
+  const setting = { ...settingValue, definition: { ...settingDefinition, multiValues: true } };
+  const onChange = jest.fn();
+  const value = ['foo', 'bar'];
+  const input = shallowRender({ onChange, setting, value }).find('MultiValueInput');
+  expect(input.length).toBe(1);
+  expect(input.prop('setting')).toBe(setting);
+  expect(input.prop('value')).toBe(value);
+  expect(input.prop('onChange')).toBe(onChange);
+});
+
+it('should render PropertySetInput', () => {
+  const setting = {
+    ...settingValue,
+    definition: { ...settingDefinition, type: SettingType.PropertySet, fields: [] }
+  };
+
+  const onChange = jest.fn();
+  const value = [{ foo: 'bar' }];
+  const input = shallowRender({ onChange, setting, value }).find('PropertySetInput');
+  expect(input.length).toBe(1);
+  expect(input.prop('setting')).toBe(setting);
+  expect(input.prop('value')).toBe(value);
+  expect(input.prop('onChange')).toBe(onChange);
+});
+
+function shallowRender(props: Partial<DefaultInputProps> = {}) {
+  return shallow(
+    <Input
+      onChange={jest.fn()}
+      setting={{ ...settingValue, definition: settingDefinition }}
+      value="foo"
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.js
deleted file mode 100644 (file)
index 95b3809..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import InputForBoolean from '../InputForBoolean';
-import Toggle from '../../../../../components/controls/Toggle';
-
-it('should render Toggle', () => {
-  const onChange = jest.fn();
-  const toggle = shallow(
-    <InputForBoolean isDefault={false} name="foo" onChange={onChange} value={true} />
-  ).find(Toggle);
-  expect(toggle.length).toBe(1);
-  expect(toggle.prop('name')).toBe('foo');
-  expect(toggle.prop('value')).toBe(true);
-  expect(toggle.prop('onChange')).toBeTruthy();
-});
-
-it('should render Toggle without value', () => {
-  const onChange = jest.fn();
-  const input = shallow(<InputForBoolean isDefault={false} name="foo" onChange={onChange} />);
-  const toggle = input.find(Toggle);
-  expect(toggle.length).toBe(1);
-  expect(toggle.prop('name')).toBe('foo');
-  expect(toggle.prop('value')).toBe(false);
-  expect(toggle.prop('onChange')).toBeTruthy();
-  expect(input.find('.note').length).toBe(1);
-});
-
-it('should call onChange', () => {
-  const onChange = jest.fn();
-  const input = shallow(
-    <InputForBoolean isDefault={false} name="foo" onChange={onChange} value={true} />
-  );
-  const toggle = input.find(Toggle);
-  expect(toggle.length).toBe(1);
-  expect(toggle.prop('onChange')).toBeTruthy();
-
-  toggle.prop('onChange')(false);
-
-  expect(onChange).toBeCalledWith(false);
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForBoolean-test.tsx
new file mode 100644 (file)
index 0000000..94bd44b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import InputForBoolean from '../InputForBoolean';
+import { DefaultSpecializedInputProps } from '../../../utils';
+
+it('should render Toggle', () => {
+  const onChange = jest.fn();
+  const toggle = shallowRender({ onChange }).find('Toggle');
+  expect(toggle.length).toBe(1);
+  expect(toggle.prop('name')).toBe('foo');
+  expect(toggle.prop('value')).toBe(true);
+  expect(toggle.prop('onChange')).toBeTruthy();
+});
+
+it('should render Toggle without value', () => {
+  const onChange = jest.fn();
+  const input = shallowRender({ onChange, value: undefined });
+  const toggle = input.find('Toggle');
+  expect(toggle.length).toBe(1);
+  expect(toggle.prop('name')).toBe('foo');
+  expect(toggle.prop('value')).toBe(false);
+  expect(toggle.prop('onChange')).toBeTruthy();
+  expect(input.find('.note').length).toBe(1);
+});
+
+it('should call onChange', () => {
+  const onChange = jest.fn();
+
+  const input = shallowRender({ onChange, value: true });
+  const toggle = input.find('Toggle');
+  expect(toggle.length).toBe(1);
+  expect(toggle.prop('onChange')).toBeTruthy();
+
+  toggle.prop<Function>('onChange')(false);
+
+  expect(onChange).toBeCalledWith(false);
+});
+
+function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
+  return shallow(
+    <InputForBoolean isDefault={false} name="foo" onChange={jest.fn()} value={true} {...props} />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.js
deleted file mode 100644 (file)
index 4745ce3..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import InputForNumber from '../InputForNumber';
-import SimpleInput from '../SimpleInput';
-
-it('should render SimpleInput', () => {
-  const onChange = jest.fn();
-  const simpleInput = shallow(
-    <InputForNumber isDefault={false} name="foo" onChange={onChange} value={17} />
-  ).find(SimpleInput);
-  expect(simpleInput.length).toBe(1);
-  expect(simpleInput.prop('name')).toBe('foo');
-  expect(simpleInput.prop('value')).toBe(17);
-  expect(simpleInput.prop('type')).toBe('text');
-  expect(simpleInput.prop('onChange')).toBeTruthy();
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForNumber-test.tsx
new file mode 100644 (file)
index 0000000..73bb6c2
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import InputForNumber from '../InputForNumber';
+import SimpleInput from '../SimpleInput';
+
+it('should render SimpleInput', () => {
+  const onChange = jest.fn();
+  const simpleInput = shallow(
+    <InputForNumber isDefault={false} name="foo" onChange={onChange} value={17} />
+  ).find(SimpleInput);
+  expect(simpleInput.length).toBe(1);
+  expect(simpleInput.prop('name')).toBe('foo');
+  expect(simpleInput.prop('value')).toBe(17);
+  expect(simpleInput.prop('type')).toBe('text');
+  expect(simpleInput.prop('onChange')).toBeTruthy();
+});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.js
deleted file mode 100644 (file)
index f16f908..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import InputForPassword from '../InputForPassword';
-import { click, change, submit } from '../../../../../helpers/testUtils';
-
-it('should render lock icon, but no form', () => {
-  const onChange = jest.fn();
-  const input = shallow(
-    <InputForPassword isDefault={false} name="foo" onChange={onChange} value="bar" />
-  );
-  expect(input.find('LockIcon').length).toBe(1);
-  expect(input.find('form').length).toBe(0);
-});
-
-it('should open form', () => {
-  const onChange = jest.fn();
-  const input = shallow(
-    <InputForPassword isDefault={false} name="foo" onChange={onChange} value="bar" />
-  );
-  const button = input.find('Button');
-  expect(button.length).toBe(1);
-
-  click(button);
-  expect(input.find('form').length).toBe(1);
-});
-
-it('should set value', () => {
-  const onChange = jest.fn(() => Promise.resolve());
-  const input = shallow(
-    <InputForPassword isDefault={false} name="foo" onChange={onChange} value="bar" />
-  );
-  click(input.find('Button'));
-  change(input.find('.js-password-input'), 'secret');
-  submit(input.find('form'));
-  expect(onChange).toBeCalledWith('secret');
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForPassword-test.tsx
new file mode 100644 (file)
index 0000000..01e0dff
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import InputForPassword from '../InputForPassword';
+import { click, change, submit } from '../../../../../helpers/testUtils';
+import { DefaultSpecializedInputProps } from '../../../utils';
+
+it('should render lock icon, but no form', () => {
+  const onChange = jest.fn();
+  const input = shallowRender({ onChange });
+
+  expect(input.find('LockIcon').length).toBe(1);
+  expect(input.find('form').length).toBe(0);
+});
+
+it('should open form', () => {
+  const onChange = jest.fn();
+  const input = shallowRender({ onChange });
+  const button = input.find('Button');
+  expect(button.length).toBe(1);
+
+  click(button);
+  expect(input.find('form').length).toBe(1);
+});
+
+it('should set value', () => {
+  const onChange = jest.fn(() => Promise.resolve());
+  const input = shallowRender({ onChange });
+
+  click(input.find('Button'));
+  change(input.find('.js-password-input'), 'secret');
+  submit(input.find('form'));
+  expect(onChange).toBeCalledWith('secret');
+});
+
+function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
+  return shallow(
+    <InputForPassword
+      hasValueChanged={false}
+      isDefault={false}
+      name="foo"
+      onChange={jest.fn()}
+      value="bar"
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.js
deleted file mode 100644 (file)
index e3c17c0..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import InputForSingleSelectList from '../InputForSingleSelectList';
-
-it('should render Select', () => {
-  const onChange = jest.fn();
-  const select = shallow(
-    <InputForSingleSelectList
-      isDefault={false}
-      name="foo"
-      onChange={onChange}
-      options={['foo', 'bar', 'baz']}
-      value="bar"
-    />
-  ).find('Select');
-  expect(select.length).toBe(1);
-  expect(select.prop('name')).toBe('foo');
-  expect(select.prop('value')).toBe('bar');
-  expect(select.prop('options')).toEqual([
-    { value: 'foo', label: 'foo' },
-    { value: 'bar', label: 'bar' },
-    { value: 'baz', label: 'baz' }
-  ]);
-  expect(select.prop('onChange')).toBeTruthy();
-});
-
-it('should call onChange', () => {
-  const onChange = jest.fn();
-  const select = shallow(
-    <InputForSingleSelectList
-      isDefault={false}
-      name="foo"
-      onChange={onChange}
-      options={['foo', 'bar', 'baz']}
-      value="bar"
-    />
-  ).find('Select');
-  expect(select.length).toBe(1);
-  expect(select.prop('onChange')).toBeTruthy();
-
-  select.prop('onChange')({ value: 'baz', label: 'baz' });
-  expect(onChange).toBeCalledWith('baz');
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForSingleSelectList-test.tsx
new file mode 100644 (file)
index 0000000..3b45104
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import InputForSingleSelectList from '../InputForSingleSelectList';
+import { DefaultSpecializedInputProps } from '../../../utils';
+
+it('should render Select', () => {
+  const onChange = jest.fn();
+  const select = shallowRender({ onChange }).find('Select');
+  expect(select.length).toBe(1);
+  expect(select.prop('name')).toBe('foo');
+  expect(select.prop('value')).toBe('bar');
+  expect(select.prop('options')).toEqual([
+    { value: 'foo', label: 'foo' },
+    { value: 'bar', label: 'bar' },
+    { value: 'baz', label: 'baz' }
+  ]);
+  expect(select.prop('onChange')).toBeTruthy();
+});
+
+it('should call onChange', () => {
+  const onChange = jest.fn();
+  const select = shallowRender({ onChange }).find('Select');
+  expect(select.length).toBe(1);
+  expect(select.prop('onChange')).toBeTruthy();
+
+  select.prop<Function>('onChange')({ value: 'baz', label: 'baz' });
+  expect(onChange).toBeCalledWith('baz');
+});
+
+function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
+  return shallow(
+    <InputForSingleSelectList
+      isDefault={false}
+      name="foo"
+      onChange={jest.fn()}
+      options={['foo', 'bar', 'baz']}
+      value="bar"
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.js
deleted file mode 100644 (file)
index 01f312c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import InputForString from '../InputForString';
-import SimpleInput from '../SimpleInput';
-
-it('should render SimpleInput', () => {
-  const onChange = jest.fn();
-  const simpleInput = shallow(
-    <InputForString isDefault={false} name="foo" onChange={onChange} value="bar" />
-  ).find(SimpleInput);
-  expect(simpleInput.length).toBe(1);
-  expect(simpleInput.prop('name')).toBe('foo');
-  expect(simpleInput.prop('value')).toBe('bar');
-  expect(simpleInput.prop('type')).toBe('text');
-  expect(simpleInput.prop('onChange')).toBeTruthy();
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForString-test.tsx
new file mode 100644 (file)
index 0000000..172dbd4
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import InputForString from '../InputForString';
+import SimpleInput from '../SimpleInput';
+
+it('should render SimpleInput', () => {
+  const onChange = jest.fn();
+  const simpleInput = shallow(
+    <InputForString isDefault={false} name="foo" onChange={onChange} value="bar" />
+  ).find(SimpleInput);
+  expect(simpleInput.length).toBe(1);
+  expect(simpleInput.prop('name')).toBe('foo');
+  expect(simpleInput.prop('value')).toBe('bar');
+  expect(simpleInput.prop('type')).toBe('text');
+  expect(simpleInput.prop('onChange')).toBeTruthy();
+});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.js
deleted file mode 100644 (file)
index 387873b..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import InputForText from '../InputForText';
-import { change } from '../../../../../helpers/testUtils';
-
-it('should render textarea', () => {
-  const onChange = jest.fn();
-  const textarea = shallow(
-    <InputForText isDefault={false} name="foo" onChange={onChange} value="bar" />
-  ).find('textarea');
-  expect(textarea.length).toBe(1);
-  expect(textarea.prop('name')).toBe('foo');
-  expect(textarea.prop('value')).toBe('bar');
-  expect(textarea.prop('onChange')).toBeTruthy();
-});
-
-it('should call onChange', () => {
-  const onChange = jest.fn();
-  const textarea = shallow(
-    <InputForText isDefault={false} name="foo" onChange={onChange} value="bar" />
-  ).find('textarea');
-  expect(textarea.length).toBe(1);
-  expect(textarea.prop('onChange')).toBeTruthy();
-
-  change(textarea, 'qux');
-
-  expect(onChange).toBeCalledWith('qux');
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/InputForText-test.tsx
new file mode 100644 (file)
index 0000000..5298ff1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import InputForText from '../InputForText';
+import { change } from '../../../../../helpers/testUtils';
+import { DefaultSpecializedInputProps } from '../../../utils';
+
+it('should render textarea', () => {
+  const onChange = jest.fn();
+  const textarea = shallowRender({ onChange }).find('textarea');
+  expect(textarea.length).toBe(1);
+  expect(textarea.prop('name')).toBe('foo');
+  expect(textarea.prop('value')).toBe('bar');
+  expect(textarea.prop('onChange')).toBeTruthy();
+});
+
+it('should call onChange', () => {
+  const onChange = jest.fn();
+  const textarea = shallowRender({ onChange }).find('textarea');
+  expect(textarea.length).toBe(1);
+  expect(textarea.prop('onChange')).toBeTruthy();
+
+  change(textarea, 'qux');
+  expect(onChange).toBeCalledWith('qux');
+});
+
+function shallowRender(props: Partial<DefaultSpecializedInputProps> = {}) {
+  return shallow(
+    <InputForText isDefault={false} name="foo" onChange={jest.fn()} value="bar" {...props} />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.js
deleted file mode 100644 (file)
index b8a777d..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import MultiValueInput from '../MultiValueInput';
-import PrimitiveInput from '../PrimitiveInput';
-import { click } from '../../../../../helpers/testUtils';
-
-const definition = { multiValues: true };
-
-const assertValues = (inputs, values) => {
-  values.forEach((value, index) => {
-    const input = inputs.at(index);
-    expect(input.prop('value')).toBe(value);
-  });
-};
-
-it('should render one value', () => {
-  const multiValueInput = shallow(
-    <MultiValueInput onChange={jest.fn()} setting={{ definition }} value={['foo']} />
-  );
-  const stringInputs = multiValueInput.find(PrimitiveInput);
-  expect(stringInputs.length).toBe(1 + 1);
-  assertValues(stringInputs, ['foo', '']);
-});
-
-it('should render several values', () => {
-  const multiValueInput = shallow(
-    <MultiValueInput onChange={jest.fn()} setting={{ definition }} value={['foo', 'bar', 'baz']} />
-  );
-  const stringInputs = multiValueInput.find(PrimitiveInput);
-  expect(stringInputs.length).toBe(3 + 1);
-  assertValues(stringInputs, ['foo', 'bar', 'baz', '']);
-});
-
-it('should remove value', () => {
-  const onChange = jest.fn();
-  const multiValueInput = shallow(
-    <MultiValueInput onChange={onChange} setting={{ definition }} value={['foo', 'bar', 'baz']} />
-  );
-  click(multiValueInput.find('.js-remove-value').at(1));
-  expect(onChange).toBeCalledWith(['foo', 'baz']);
-});
-
-it('should change existing value', () => {
-  const onChange = jest.fn();
-  const multiValueInput = shallow(
-    <MultiValueInput onChange={onChange} setting={{ definition }} value={['foo', 'bar', 'baz']} />
-  );
-  multiValueInput
-    .find(PrimitiveInput)
-    .at(1)
-    .prop('onChange')('qux');
-  expect(onChange).toBeCalledWith(['foo', 'qux', 'baz']);
-});
-
-it('should add new value', () => {
-  const onChange = jest.fn();
-  const multiValueInput = shallow(
-    <MultiValueInput onChange={onChange} setting={{ definition }} value={['foo']} />
-  );
-  multiValueInput
-    .find(PrimitiveInput)
-    .at(1)
-    .prop('onChange')('bar');
-  expect(onChange).toBeCalledWith(['foo', 'bar']);
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/MultiValueInput-test.tsx
new file mode 100644 (file)
index 0000000..2fab1a3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow, ShallowWrapper } from 'enzyme';
+import MultiValueInput from '../MultiValueInput';
+import PrimitiveInput from '../PrimitiveInput';
+import { click } from '../../../../../helpers/testUtils';
+import { DefaultInputProps } from '../../../utils';
+import { SettingType } from '../../../../../app/types';
+
+const settingValue = {
+  key: 'example'
+};
+
+const settingDefinition = {
+  category: 'general',
+  fields: [],
+  key: 'example',
+  multiValues: true,
+  options: [],
+  subCategory: 'Branches',
+  type: SettingType.String
+};
+
+const assertValues = (inputs: ShallowWrapper<any>, values: string[]) => {
+  values.forEach((value, index) => {
+    const input = inputs.at(index);
+    expect(input.prop('value')).toBe(value);
+  });
+};
+
+it('should render one value', () => {
+  const multiValueInput = shallowRender();
+  const stringInputs = multiValueInput.find(PrimitiveInput);
+  expect(stringInputs.length).toBe(1 + 1);
+  assertValues(stringInputs, ['foo', '']);
+});
+
+it('should render several values', () => {
+  const multiValueInput = shallowRender({ value: ['foo', 'bar', 'baz'] });
+  const stringInputs = multiValueInput.find(PrimitiveInput);
+  expect(stringInputs.length).toBe(3 + 1);
+  assertValues(stringInputs, ['foo', 'bar', 'baz', '']);
+});
+
+it('should remove value', () => {
+  const onChange = jest.fn();
+  const multiValueInput = shallowRender({ onChange, value: ['foo', 'bar', 'baz'] });
+  click(multiValueInput.find('.js-remove-value').at(1));
+  expect(onChange).toBeCalledWith(['foo', 'baz']);
+});
+
+it('should change existing value', () => {
+  const onChange = jest.fn();
+  const multiValueInput = shallowRender({ onChange, value: ['foo', 'bar', 'baz'] });
+  multiValueInput
+    .find(PrimitiveInput)
+    .at(1)
+    .prop('onChange')('qux');
+  expect(onChange).toBeCalledWith(['foo', 'qux', 'baz']);
+});
+
+it('should add new value', () => {
+  const onChange = jest.fn();
+  const multiValueInput = shallowRender({ onChange });
+  multiValueInput
+    .find(PrimitiveInput)
+    .at(1)
+    .prop('onChange')('bar');
+  expect(onChange).toBeCalledWith(['foo', 'bar']);
+});
+
+function shallowRender(props: Partial<DefaultInputProps> = {}) {
+  return shallow(
+    <MultiValueInput
+      onChange={jest.fn()}
+      setting={{ ...settingValue, definition: settingDefinition }}
+      value={['foo']}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.js b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.js
deleted file mode 100644 (file)
index 35f2c96..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import SimpleInput from '../SimpleInput';
-import { change } from '../../../../../helpers/testUtils';
-
-it('should render input', () => {
-  const onChange = jest.fn();
-  const input = shallow(
-    <SimpleInput
-      className="input-large"
-      isDefault={false}
-      name="foo"
-      onChange={onChange}
-      type="text"
-      value="bar"
-    />
-  ).find('input');
-  expect(input.length).toBe(1);
-  expect(input.prop('type')).toBe('text');
-  expect(input.prop('className')).toContain('input-large');
-  expect(input.prop('name')).toBe('foo');
-  expect(input.prop('value')).toBe('bar');
-  expect(input.prop('onChange')).toBeTruthy();
-});
-
-it('should call onChange', () => {
-  const onChange = jest.fn();
-  const input = shallow(
-    <SimpleInput
-      className="input-large"
-      isDefault={false}
-      name="foo"
-      onChange={onChange}
-      type="text"
-      value="bar"
-    />
-  ).find('input');
-  expect(input.length).toBe(1);
-  expect(input.prop('onChange')).toBeTruthy();
-
-  change(input, 'qux');
-
-  expect(onChange).toBeCalledWith('qux');
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/inputs/__tests__/SimpleInput-test.tsx
new file mode 100644 (file)
index 0000000..5777763
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import SimpleInput from '../SimpleInput';
+import { change } from '../../../../../helpers/testUtils';
+
+it('should render input', () => {
+  const onChange = jest.fn();
+  const input = shallow(
+    <SimpleInput
+      className="input-large"
+      isDefault={false}
+      name="foo"
+      onChange={onChange}
+      type="text"
+      value="bar"
+    />
+  ).find('input');
+  expect(input.length).toBe(1);
+  expect(input.prop('type')).toBe('text');
+  expect(input.prop('className')).toContain('input-large');
+  expect(input.prop('name')).toBe('foo');
+  expect(input.prop('value')).toBe('bar');
+  expect(input.prop('onChange')).toBeTruthy();
+});
+
+it('should call onChange', () => {
+  const onChange = jest.fn();
+  const input = shallow(
+    <SimpleInput
+      className="input-large"
+      isDefault={false}
+      name="foo"
+      onChange={onChange}
+      type="text"
+      value="bar"
+    />
+  ).find('input');
+  expect(input.length).toBe(1);
+  expect(input.prop('onChange')).toBeTruthy();
+
+  change(input, 'qux');
+  expect(onChange).toBeCalledWith('qux');
+});
diff --git a/server/sonar-web/src/main/js/apps/settings/constants.js b/server/sonar-web/src/main/js/apps/settings/constants.js
deleted file mode 100644 (file)
index ae627eb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-export const TYPE_STRING = 'STRING';
-export const TYPE_TEXT = 'TEXT';
-export const TYPE_PASSWORD = 'PASSWORD';
-export const TYPE_BOOLEAN = 'BOOLEAN';
-export const TYPE_FLOAT = 'FLOAT';
-export const TYPE_INTEGER = 'INTEGER';
-export const TYPE_LONG = 'LONG';
-export const TYPE_SINGLE_SELECT_LIST = 'SINGLE_SELECT_LIST';
-export const TYPE_PROPERTY_SET = 'PROPERTY_SET';
diff --git a/server/sonar-web/src/main/js/apps/settings/propTypes.js b/server/sonar-web/src/main/js/apps/settings/propTypes.js
deleted file mode 100644 (file)
index 66f7c47..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import PropTypes from 'prop-types';
-
-export const defaultInputPropTypes = {
-  name: PropTypes.string.isRequired,
-  value: PropTypes.any,
-  isDefault: PropTypes.bool.isRequired,
-  onChange: PropTypes.func.isRequired
-};
index b37796a6ca7f03f35b9d08d7a26192ae1258b45c..c0f10cb73ea1a5ad39c0089f7476c8f8947361ae 100644 (file)
@@ -24,10 +24,3 @@ export type Definition = {
   category: string
 };
 */
-
-/*::
-export type SettingValue = {
-  key: string,
-  value?: string
-};
-*/
diff --git a/server/sonar-web/src/main/js/apps/settings/utils.js b/server/sonar-web/src/main/js/apps/settings/utils.js
deleted file mode 100644 (file)
index b7aa3a8..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import {
-  TYPE_PROPERTY_SET,
-  TYPE_BOOLEAN,
-  TYPE_SINGLE_SELECT_LIST,
-  TYPE_PASSWORD
-} from './constants';
-import { translate, hasMessage } from '../../helpers/l10n';
-
-export const DEFAULT_CATEGORY = 'general';
-
-export function getPropertyName(definition) {
-  const key = `property.${definition.key}.name`;
-  return hasMessage(key) ? translate(key) : definition.name;
-}
-
-export function getPropertyDescription(definition) {
-  const key = `property.${definition.key}.description`;
-  return hasMessage(key) ? translate(key) : definition.description;
-}
-
-export function getCategoryName(category) {
-  const key = `property.category.${category}`;
-  return hasMessage(key) ? translate(key) : category;
-}
-
-export function getSubCategoryName(category, subCategory) {
-  const key = `property.category.${category}.${subCategory}`;
-  return hasMessage(key) ? translate(key) : getCategoryName(subCategory);
-}
-
-export function getSubCategoryDescription(category, subCategory) {
-  const key = `property.category.${category}.${subCategory}.description`;
-  return hasMessage(key) ? translate(key) : null;
-}
-
-export function getUniqueName(definition, index = null) {
-  const indexSuffix = index != null ? `[${index}]` : '';
-  return `settings[${definition.key}]${indexSuffix}`;
-}
-
-export function getSettingValue(setting) {
-  if (setting.definition.multiValues) {
-    return setting.values;
-  } else if (setting.definition.type === TYPE_PROPERTY_SET) {
-    return setting.fieldValues;
-  } else {
-    return setting.value;
-  }
-}
-
-export function isEmptyValue(definition, value) {
-  if (value == null) {
-    return true;
-  } else if (definition.type === TYPE_BOOLEAN) {
-    return false;
-  } else {
-    return value.length === 0;
-  }
-}
-
-export function getEmptyValue(definition) {
-  if (definition.multiValues) {
-    return [getEmptyValue({ ...definition, multiValues: false })];
-  }
-
-  if (definition.type === TYPE_PROPERTY_SET) {
-    const value = {};
-    definition.fields.forEach(field => (value[field.key] = getEmptyValue(field)));
-    return [value];
-  }
-
-  if (definition.type === TYPE_BOOLEAN || definition.type === TYPE_SINGLE_SELECT_LIST) {
-    return null;
-  }
-
-  return '';
-}
-
-export function isDefaultOrInherited(setting) {
-  return !!setting.default || !!setting.inherited;
-}
-
-function getParentValue(setting) {
-  if (setting.definition.multiValues) {
-    return setting.parentValues;
-  } else if (setting.definition.type === TYPE_PROPERTY_SET) {
-    return setting.parentFieldValues;
-  } else {
-    return setting.parentValue;
-  }
-}
-
-/**
- * Get and format the default value
- * @param setting
- * @returns {string}
- */
-export function getDefaultValue(setting) {
-  const parentValue = getParentValue(setting);
-
-  if (parentValue == null) {
-    return setting.definition.defaultValue
-      ? setting.definition.defaultValue
-      : translate('settings.default.no_value');
-  }
-
-  if (setting.definition.multiValues) {
-    return parentValue.length > 0 ? parentValue.join(', ') : translate('settings.default.no_value');
-  }
-
-  if (setting.definition.type === TYPE_PROPERTY_SET) {
-    return parentValue.length > 0
-      ? translate('settings.default.complex_value')
-      : translate('settings.default.no_value');
-  }
-
-  if (setting.definition.type === TYPE_PASSWORD) {
-    return translate('settings.default.password');
-  }
-
-  if (setting.definition.type === TYPE_BOOLEAN) {
-    const isTrue = parentValue === true || parentValue === 'true';
-    return isTrue ? translate('settings.boolean.true') : translate('settings.boolean.false');
-  }
-
-  return parentValue;
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/utils.ts b/server/sonar-web/src/main/js/apps/settings/utils.ts
new file mode 100644 (file)
index 0000000..40abef3
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+import { translate, hasMessage } from '../../helpers/l10n';
+import {
+  Omit,
+  Setting,
+  SettingCategoryDefinition,
+  SettingType,
+  SettingDefinition
+} from '../../app/types';
+
+export const DEFAULT_CATEGORY = 'general';
+
+export type DefaultSpecializedInputProps = Omit<DefaultInputProps, 'setting'> & {
+  isDefault: boolean;
+  name: string;
+};
+
+export interface DefaultInputProps {
+  hasValueChanged?: boolean;
+  onCancel?: () => void;
+  onChange: (value: any) => void;
+  onSave?: () => void;
+  setting: Setting;
+  value: any;
+}
+
+export function getPropertyName(definition: SettingDefinition) {
+  const key = `property.${definition.key}.name`;
+  return hasMessage(key) ? translate(key) : definition.name;
+}
+
+export function getPropertyDescription(definition: SettingDefinition) {
+  const key = `property.${definition.key}.description`;
+  return hasMessage(key) ? translate(key) : definition.description;
+}
+
+export function getCategoryName(category: string) {
+  const key = `property.category.${category}`;
+  return hasMessage(key) ? translate(key) : category;
+}
+
+export function getSubCategoryName(category: string, subCategory: string) {
+  const key = `property.category.${category}.${subCategory}`;
+  return hasMessage(key) ? translate(key) : getCategoryName(subCategory);
+}
+
+export function getSubCategoryDescription(category: string, subCategory: string) {
+  const key = `property.category.${category}.${subCategory}.description`;
+  return hasMessage(key) ? translate(key) : null;
+}
+
+export function getUniqueName(definition: SettingDefinition, index?: string) {
+  const indexSuffix = index ? `[${index}]` : '';
+  return `settings[${definition.key}]${indexSuffix}`;
+}
+
+export function getSettingValue({ definition, fieldValues, value, values }: Setting) {
+  if (isCategoryDefinition(definition) && definition.multiValues) {
+    return values;
+  } else if (definition.type === SettingType.PropertySet) {
+    return fieldValues;
+  } else {
+    return value;
+  }
+}
+
+export function isEmptyValue(definition: SettingDefinition, value: any) {
+  if (value == null) {
+    return true;
+  } else if (definition.type === SettingType.Boolean) {
+    return false;
+  } else {
+    return value.length === 0;
+  }
+}
+
+export function isCategoryDefinition(item: SettingDefinition): item is SettingCategoryDefinition {
+  return Boolean((item as any).fields);
+}
+
+export function getEmptyValue(item: SettingDefinition | SettingCategoryDefinition): any {
+  if (isCategoryDefinition(item)) {
+    if (item.multiValues) {
+      return [getEmptyValue({ ...item, multiValues: false })];
+    }
+
+    if (item.type === SettingType.PropertySet) {
+      const value: { [key: string]: string } = {};
+      item.fields.forEach(field => (value[field.key] = getEmptyValue(field)));
+      return [value];
+    }
+  }
+
+  if (item.type === SettingType.Boolean || item.type === SettingType.SingleSelectList) {
+    return null;
+  }
+  return '';
+}
+
+export function isDefaultOrInherited(setting: Setting) {
+  return Boolean(setting.inherited);
+}
+
+export function getDefaultValue(setting: Setting) {
+  const { definition, parentFieldValues, parentValue, parentValues } = setting;
+
+  if (definition.type === SettingType.Password) {
+    return translate('settings.default.password');
+  }
+
+  if (definition.type === SettingType.Boolean && parentValue) {
+    const isTrue = parentValue === 'true';
+    return isTrue ? translate('settings.boolean.true') : translate('settings.boolean.false');
+  }
+
+  if (
+    isCategoryDefinition(definition) &&
+    definition.multiValues &&
+    parentValues &&
+    parentValues.length > 0
+  ) {
+    return parentValues.join(', ');
+  }
+
+  if (
+    definition.type === SettingType.PropertySet &&
+    parentFieldValues &&
+    parentFieldValues.length > 0
+  ) {
+    return translate('settings.default.complex_value');
+  }
+
+  if (parentValue == null) {
+    return isCategoryDefinition(definition) && definition.defaultValue
+      ? definition.defaultValue
+      : translate('settings.default.no_value');
+  }
+
+  return parentValue;
+}