aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-11-19 11:41:06 +0100
committersonartech <sonartech@sonarsource.com>2018-11-30 11:20:35 +0100
commit50c708c1b62796cba971ed6579cb72373261e857 (patch)
tree0462dcd0c342845ac4a7a1923c0da0c1097a9588 /server/sonar-web
parent0a52c5067d46ce684231b8f61ea9f72d4d89fc22 (diff)
downloadsonarqube-50c708c1b62796cba971ed6579cb72373261e857.tar.gz
sonarqube-50c708c1b62796cba971ed6579cb72373261e857.zip
Rewrite remaining of the settings page to TS
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/api/settings.ts17
-rw-r--r--server/sonar-web/src/main/js/app/components/App.tsx23
-rw-r--r--server/sonar-web/src/main/js/app/components/PageTracker.tsx9
-rw-r--r--server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx9
-rw-r--r--server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx12
-rw-r--r--server/sonar-web/src/main/js/app/types.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/about/actions.ts3
-rw-r--r--server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx19
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/actions.ts4
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js34
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js)70
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AppContainer.js34
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/AppContainer.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/App.js)80
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js)13
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/Definition.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/Definition.js)158
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js42
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.tsx (renamed from server/sonar-web/src/main/js/apps/settings/store/values/actions.ts)24
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/EmailForm.js)85
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/PageHeader.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/PageHeader.js)43
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js)25
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.tsx (renamed from server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.js)65
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx (renamed from server/sonar-web/src/main/js/apps/settings/__tests__/DefinitionActions-test.tsx)4
-rw-r--r--server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/settings/__tests__/__snapshots__/DefinitionActions-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/actions.js127
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/actions.ts141
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/definitions.ts (renamed from server/sonar-web/src/main/js/apps/settings/store/definitions/reducer.js)52
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/definitions/actions.js33
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/rootReducer.js79
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/rootReducer.ts73
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage.ts113
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/actions.js33
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/reducer.js37
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/actions.js31
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/reducer.js36
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/reducer.js37
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/actions.js33
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/reducer.js36
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/values.ts85
-rw-r--r--server/sonar-web/src/main/js/apps/settings/store/values/reducer.js74
-rw-r--r--server/sonar-web/src/main/js/apps/settings/types.js26
-rw-r--r--server/sonar-web/src/main/js/components/ui/Avatar.tsx12
-rw-r--r--server/sonar-web/src/main/js/store/appState.ts30
-rw-r--r--server/sonar-web/src/main/js/store/globalMessages.ts4
-rw-r--r--server/sonar-web/src/main/js/store/rootReducer.ts4
46 files changed, 858 insertions, 1042 deletions
diff --git a/server/sonar-web/src/main/js/api/settings.ts b/server/sonar-web/src/main/js/api/settings.ts
index fbea55db86b..11b37f1d02f 100644
--- a/server/sonar-web/src/main/js/api/settings.ts
+++ b/server/sonar-web/src/main/js/api/settings.ts
@@ -23,12 +23,17 @@ import {
BranchParameters,
SettingCategoryDefinition,
SettingValue,
- SettingType
+ SettingType,
+ SettingDefinition
} from '../app/types';
import throwGlobalError from '../app/utils/throwGlobalError';
+import { isCategoryDefinition } from '../apps/settings/utils';
export function getDefinitions(component?: string): Promise<SettingCategoryDefinition[]> {
- return getJSON('/api/settings/list_definitions', { component }).then(r => r.definitions);
+ return getJSON('/api/settings/list_definitions', { component }).then(
+ r => r.definitions,
+ throwGlobalError
+ );
}
export function getValues(
@@ -37,11 +42,15 @@ export function getValues(
return getJSON('/api/settings/values', data).then(r => r.settings);
}
-export function setSettingValue(definition: any, value: any, component?: string): Promise<void> {
+export function setSettingValue(
+ definition: SettingDefinition,
+ value: any,
+ component?: string
+): Promise<void> {
const { key } = definition;
const data: RequestData = { key, component };
- if (definition.multiValues) {
+ if (isCategoryDefinition(definition) && definition.multiValues) {
data.values = value;
} else if (definition.type === SettingType.PropertySet) {
data.fieldValues = value
diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx
index e5257a4a171..df1277c2222 100644
--- a/server/sonar-web/src/main/js/app/components/App.tsx
+++ b/server/sonar-web/src/main/js/app/components/App.tsx
@@ -27,6 +27,7 @@ import { fetchMyOrganizations } from '../../apps/account/organizations/actions';
import { getInstance, isSonarCloud } from '../../helpers/system';
import { lazyLoad } from '../../components/lazyLoad';
import { getCurrentUser, getAppState, getGlobalSettingValue, Store } from '../../store/rootReducer';
+import { isLoggedIn } from '../../helpers/users';
const PageTracker = lazyLoad(() => import('./PageTracker'));
@@ -70,10 +71,8 @@ class App extends React.PureComponent<Props> {
this.mounted = true;
this.props.fetchLanguages();
const { appState, currentUser } = this.props;
- if (appState && currentUser) {
- if (appState.organizationsEnabled && currentUser.isLoggedIn) {
- this.props.fetchMyOrganizations();
- }
+ if (appState && isSonarCloud() && currentUser && isLoggedIn(currentUser)) {
+ this.props.fetchMyOrganizations();
}
}
@@ -104,12 +103,16 @@ class App extends React.PureComponent<Props> {
}
}
-const mapStateToProps = (state: Store): StateProps => ({
- appState: getAppState(state),
- currentUser: getCurrentUser(state),
- enableGravatar: (getGlobalSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true',
- gravatarServerUrl: (getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl') || {}).value || ''
-});
+const mapStateToProps = (state: Store): StateProps => {
+ const enableGravatar = getGlobalSettingValue(state, 'sonar.lf.enableGravatar');
+ const gravatarServerUrl = getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl');
+ return {
+ appState: getAppState(state),
+ currentUser: getCurrentUser(state),
+ enableGravatar: Boolean(enableGravatar && enableGravatar.value === 'true'),
+ gravatarServerUrl: (gravatarServerUrl && gravatarServerUrl.value) || ''
+ };
+};
const mapDispatchToProps = ({
fetchLanguages,
diff --git a/server/sonar-web/src/main/js/app/components/PageTracker.tsx b/server/sonar-web/src/main/js/app/components/PageTracker.tsx
index 2ae8c85026b..e1620791c9d 100644
--- a/server/sonar-web/src/main/js/app/components/PageTracker.tsx
+++ b/server/sonar-web/src/main/js/app/components/PageTracker.tsx
@@ -59,8 +59,11 @@ export class PageTracker extends React.PureComponent<Props> {
}
}
-const mapStateToProps = (state: Store): StateProps => ({
- trackingId: (getGlobalSettingValue(state, 'sonar.analytics.trackingId') || {}).value
-});
+const mapStateToProps = (state: Store): StateProps => {
+ const trackingId = getGlobalSettingValue(state, 'sonar.analytics.trackingId');
+ return {
+ trackingId: trackingId && trackingId.value
+ };
+};
export default withRouter(connect(mapStateToProps)(PageTracker));
diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx
index 3037367c20e..a2565b563f7 100644
--- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx
+++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx
@@ -124,8 +124,11 @@ export class ProductNewsMenuItem extends React.PureComponent<Props, State> {
}
}
-const mapStateToProps = (state: Store): StateProps => ({
- accessToken: (getGlobalSettingValue(state, 'sonar.prismic.accessToken') || {}).value
-});
+const mapStateToProps = (state: Store): StateProps => {
+ const accessToken = getGlobalSettingValue(state, 'sonar.prismic.accessToken');
+ return {
+ accessToken: accessToken && accessToken.value
+ };
+};
export default connect(mapStateToProps)(ProductNewsMenuItem);
diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx
index 876a1ccc62f..7cc8a5e14a4 100644
--- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx
+++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavBranding.tsx
@@ -50,9 +50,13 @@ export function SonarCloudNavBranding() {
);
}
-const mapStateToProps = (state: Store): StateProps => ({
- customLogoUrl: (getGlobalSettingValue(state, 'sonar.lf.logoUrl') || {}).value,
- customLogoWidth: (getGlobalSettingValue(state, 'sonar.lf.logoWidthPx') || {}).value
-});
+const mapStateToProps = (state: Store): StateProps => {
+ const customLogoUrl = getGlobalSettingValue(state, 'sonar.lf.logoUrl');
+ const customLogoWidth = getGlobalSettingValue(state, 'sonar.lf.logoWidthPx');
+ return {
+ customLogoUrl: customLogoUrl && customLogoUrl.value,
+ customLogoWidth: customLogoWidth && customLogoWidth.value
+ };
+};
export default connect(mapStateToProps)(GlobalNavBranding);
diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts
index 542324c1cd6..427cfe2a463 100644
--- a/server/sonar-web/src/main/js/app/types.ts
+++ b/server/sonar-web/src/main/js/app/types.ts
@@ -86,6 +86,7 @@ export interface AppState {
organizationsEnabled?: boolean;
productionDatabase: boolean;
qualifiers: string[];
+ settings: { [key: string]: string };
standalone?: boolean;
version: string;
}
@@ -739,6 +740,7 @@ export enum SettingType {
Boolean = 'BOOLEAN',
Float = 'FLOAT',
Integer = 'INTEGER',
+ License = 'LICENSE',
Long = 'LONG',
SingleSelectList = 'SINGLE_SELECT_LIST',
PropertySet = 'PROPERTY_SET'
diff --git a/server/sonar-web/src/main/js/apps/about/actions.ts b/server/sonar-web/src/main/js/apps/about/actions.ts
index c9f54bb37e1..e99ab66bfb1 100644
--- a/server/sonar-web/src/main/js/apps/about/actions.ts
+++ b/server/sonar-web/src/main/js/apps/about/actions.ts
@@ -19,12 +19,11 @@
*/
import { Dispatch } from 'redux';
import { getValues } from '../../api/settings';
-import { receiveValues } from '../settings/store/values/actions';
+import { receiveValues } from '../settings/store/values';
export function fetchAboutPageSettings() {
return (dispatch: Dispatch) => {
const keys = ['sonar.lf.aboutText'];
-
return getValues({ keys: keys.join() }).then(values => {
dispatch(receiveValues(values));
});
diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx b/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
index 6771f875ffe..752000d6e13 100644
--- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
+++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.tsx
@@ -48,7 +48,7 @@ import '../styles.css';
interface Props {
appState: Pick<AppState, 'defaultOrganization' | 'organizationsEnabled'>;
currentUser: CurrentUser;
- customText?: { value: string };
+ customText?: string;
fetchAboutPageSettings: () => Promise<void>;
location: Location;
}
@@ -158,13 +158,9 @@ class AboutApp extends React.PureComponent<Props, State> {
</div>
</div>
- {customText != null &&
- customText.value && (
- <div
- className="about-page-section"
- dangerouslySetInnerHTML={{ __html: customText.value }}
- />
- )}
+ {customText && (
+ <div className="about-page-section" dangerouslySetInnerHTML={{ __html: customText }} />
+ )}
<AboutLanguages />
@@ -195,11 +191,14 @@ class AboutApp extends React.PureComponent<Props, State> {
}
}
-const mapStateToProps = (state: Store) => ({
- appState: getAppState(state),
- currentUser: getCurrentUser(state),
- customText: getGlobalSettingValue(state, 'sonar.lf.aboutText')
-});
+const mapStateToProps = (state: Store) => {
+ const customText = getGlobalSettingValue(state, 'sonar.lf.aboutText');
+ return {
+ appState: getAppState(state),
+ currentUser: getCurrentUser(state),
+ customText: customText && customText.value
+ };
+};
const mapDispatchToProps = { fetchAboutPageSettings } as any;
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
index 94d4f9a7952..3ec744841b8 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/UserOrganizations.tsx
@@ -33,7 +33,7 @@ import {
import { Organization } from '../../../app/types';
interface StateProps {
- anyoneCanCreate?: { value: string };
+ anyoneCanCreate: boolean;
canAdmin?: boolean;
organizations: Organization[];
}
@@ -68,9 +68,7 @@ class UserOrganizations extends React.PureComponent<Props, State> {
};
render() {
- const anyoneCanCreate =
- this.props.anyoneCanCreate != null && this.props.anyoneCanCreate.value === 'true';
-
+ const { anyoneCanCreate } = this.props;
const canCreateOrganizations = !this.state.loading && (anyoneCanCreate || this.props.canAdmin);
return (
@@ -100,11 +98,14 @@ class UserOrganizations extends React.PureComponent<Props, State> {
}
}
-const mapStateToProps = (state: Store): StateProps => ({
- anyoneCanCreate: getGlobalSettingValue(state, 'sonar.organizations.anyoneCanCreate'),
- canAdmin: getAppState(state).canAdmin,
- organizations: getMyOrganizations(state)
-});
+const mapStateToProps = (state: Store): StateProps => {
+ const anyoneCanCreate = getGlobalSettingValue(state, 'sonar.organizations.anyoneCanCreate');
+ return {
+ anyoneCanCreate: Boolean(anyoneCanCreate && anyoneCanCreate.value === 'true'),
+ canAdmin: getAppState(state).canAdmin,
+ organizations: getMyOrganizations(state)
+ };
+};
const mapDispatchToProps = {
fetchIfAnyoneCanCreateOrganizations: fetchIfAnyoneCanCreateOrganizations as any
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/actions.ts b/server/sonar-web/src/main/js/apps/account/organizations/actions.ts
index 73fa8566dcd..329d831e107 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/actions.ts
+++ b/server/sonar-web/src/main/js/apps/account/organizations/actions.ts
@@ -21,7 +21,7 @@ import { Dispatch } from 'redux';
import { getOrganizations } from '../../../api/organizations';
import { receiveMyOrganizations } from '../../../store/organizations';
import { getValues } from '../../../api/settings';
-import { receiveValues } from '../../settings/store/values/actions';
+import { receiveValues } from '../../settings/store/values';
export const fetchMyOrganizations = () => (dispatch: Dispatch) => {
return getOrganizations({ member: true }).then(({ organizations }) => {
@@ -31,6 +31,6 @@ export const fetchMyOrganizations = () => (dispatch: Dispatch) => {
export const fetchIfAnyoneCanCreateOrganizations = () => (dispatch: Dispatch) => {
return getValues({ keys: 'sonar.organizations.anyoneCanCreate' }).then(values => {
- dispatch(receiveValues(values, undefined));
+ dispatch(receiveValues(values));
});
};
diff --git a/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx b/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx
index 76627ae77bd..463d28dacbe 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/AppContainer.tsx
@@ -36,11 +36,11 @@ interface StateToProps {
}
const mapStateToProps = (state: Store) => {
+ const updateCenterActive = getGlobalSettingValue(state, 'sonar.updatecenter.activate');
return {
currentEdition: getAppState(state).edition,
standaloneMode: getAppState(state).standalone,
- updateCenterActive:
- (getGlobalSettingValue(state, 'sonar.updatecenter.activate') || {}).value === 'true'
+ updateCenterActive: Boolean(updateCenterActive && updateCenterActive.value === 'true')
};
};
diff --git a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js
deleted file mode 100644
index e59bff69f20..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.js
+++ /dev/null
@@ -1,34 +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.
- */
-// @flow
-import React from 'react';
-import { connect } from 'react-redux';
-import CategoriesList from './CategoriesList';
-import { getSettingsAppAllCategories } from '../../../store/rootReducer';
-
-function AllCategoriesList(props) {
- return <CategoriesList {...props} />;
-}
-
-const mapStateToProps = state => ({
- categories: getSettingsAppAllCategories(state)
-});
-
-export default connect(mapStateToProps)(AllCategoriesList);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx
index 8b61e566c2e..f01a2ed2b25 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/AllCategoriesList.tsx
@@ -17,49 +17,42 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { connect } from 'react-redux';
import { sortBy } from 'lodash';
import { IndexLink } from 'react-router';
import { getCategoryName } from '../utils';
+import { Component } from '../../../app/types';
+import { getSettingsAppAllCategories, Store } from '../../../store/rootReducer';
-/*::
-type Category = {
- key: string,
- name: string
-};
-*/
-
-/*::
-type Props = {
- categories: Category[],
- component?: { key: string },
- defaultCategory: string,
- selectedCategory: string
-};
-*/
-
-export default class CategoriesList extends React.PureComponent {
- /*:: rops: Props; */
-
- renderLink(category /*: Category */) {
- const query /*: Object */ = {};
-
- if (category.key !== this.props.defaultCategory) {
- query.category = category.key.toLowerCase();
- }
-
- if (this.props.component) {
- query.id = this.props.component.key;
- }
+interface Category {
+ key: string;
+ name: string;
+}
- const className =
- category.key.toLowerCase() === this.props.selectedCategory.toLowerCase() ? 'active' : '';
+interface Props {
+ categories: string[];
+ component?: Component;
+ defaultCategory: string;
+ selectedCategory: string;
+}
+export class CategoriesList extends React.PureComponent<Props> {
+ renderLink(category: Category) {
+ const { component, defaultCategory, selectedCategory } = this.props;
const pathname = this.props.component ? '/project/settings' : '/settings';
-
+ const query = {
+ category: category.key !== defaultCategory ? category.key.toLowerCase() : undefined,
+ id: component && component.key
+ };
return (
- <IndexLink className={className} title={category.name} to={{ pathname, query }}>
+ <IndexLink
+ className={classNames({
+ active: category.key.toLowerCase() === selectedCategory.toLowerCase()
+ })}
+ title={category.name}
+ to={{ pathname, query }}>
{category.name}
</IndexLink>
);
@@ -71,7 +64,6 @@ export default class CategoriesList extends React.PureComponent {
name: getCategoryName(key)
}));
const sortedCategories = sortBy(categoriesWithName, category => category.name.toLowerCase());
-
return (
<ul className="side-tabs-menu">
{sortedCategories.map(category => (
@@ -81,3 +73,9 @@ export default class CategoriesList extends React.PureComponent {
);
}
}
+
+const mapStateToProps = (state: Store) => ({
+ categories: getSettingsAppAllCategories(state)
+});
+
+export default connect(mapStateToProps)(CategoriesList);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js
deleted file mode 100644
index d2d4f003e7a..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/AppContainer.js
+++ /dev/null
@@ -1,34 +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 { connect } from 'react-redux';
-import App from './App';
-import { fetchSettings } from '../store/actions';
-import { getSettingsAppDefaultCategory } from '../../../store/rootReducer';
-
-const mapStateToProps = state => ({
- defaultCategory: getSettingsAppDefaultCategory(state)
-});
-
-const mapdispatchToProps = { fetchSettings };
-
-export default connect(
- mapStateToProps,
- mapdispatchToProps
-)(App);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.tsx
index 378494100f6..7a65fab906e 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/App.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/AppContainer.tsx
@@ -17,51 +17,64 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
+import * as React from 'react';
import Helmet from 'react-helmet';
-import PageHeader from './PageHeader';
-import CategoryDefinitionsList from './CategoryDefinitionsList';
+import { connect } from 'react-redux';
+import { WithRouterProps } from 'react-router';
import AllCategoriesList from './AllCategoriesList';
+import CategoryDefinitionsList from './CategoryDefinitionsList';
+import PageHeader from './PageHeader';
import WildcardsHelp from './WildcardsHelp';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
+import { fetchSettings } from '../store/actions';
+import { getSettingsAppDefaultCategory, Store } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
+import { Component } from '../../../app/types';
import '../styles.css';
import '../side-tabs.css';
-/*::
-type Props = {
- component?: { key: string },
- defaultCategory: ?string,
- fetchSettings(componentKey: ?string): Promise<*>,
- location: { query: {} }
-};
-*/
-
-/*::
-type State = {
- loaded: boolean
-};
-*/
-
-export default class App extends React.PureComponent {
- /*:: props: Props; */
- state /*: State */ = { loaded: false };
+interface Props {
+ component?: Component;
+ defaultCategory: string;
+ fetchSettings(component?: string): Promise<void>;
+}
+
+interface State {
+ loading: boolean;
+}
+
+export class App extends React.PureComponent<Props & WithRouterProps, State> {
+ mounted = false;
+ state: State = { loading: true };
componentDidMount() {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true }));
+ this.mounted = true;
+ this.fetchSettings();
}
- componentDidUpdate(prevProps /*: Props*/) {
+ componentDidUpdate(prevProps: Props) {
if (prevProps.component !== this.props.component) {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.fetchSettings(componentKey);
+ this.fetchSettings();
}
}
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchSettings = () => {
+ const { component } = this.props;
+ this.props.fetchSettings(component && component.key).then(this.stopLoading, this.stopLoading);
+ };
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
render() {
- if (!this.state.loaded) {
+ if (this.state.loading) {
return null;
}
@@ -92,3 +105,14 @@ export default class App extends React.PureComponent {
);
}
}
+
+const mapStateToProps = (state: Store) => ({
+ defaultCategory: getSettingsAppDefaultCategory(state)
+});
+
+const mapDispatchToProps = { fetchSettings: fetchSettings as any };
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(App);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.tsx
index 630ce8bbc98..87f503f9ee8 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/CategoryDefinitionsList.tsx
@@ -17,17 +17,22 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
import { connect } from 'react-redux';
import SubCategoryDefinitionsList from './SubCategoryDefinitionsList';
import { fetchValues } from '../store/actions';
-import { getSettingsAppSettingsForCategory } from '../../../store/rootReducer';
+import { getSettingsAppSettingsForCategory, Store } from '../../../store/rootReducer';
+import { Component } from '../../../app/types';
-const mapStateToProps = (state, ownProps) => ({
+interface Props {
+ category: string;
+ component?: Component;
+}
+
+const mapStateToProps = (state: Store, ownProps: Props) => ({
settings: getSettingsAppSettingsForCategory(
state,
ownProps.category,
- ownProps.component ? ownProps.component.key : null
+ ownProps.component && ownProps.component.key
)
});
diff --git a/server/sonar-web/src/main/js/apps/settings/components/Definition.js b/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
index 1ce6ac3ba10..d9b9b34d837 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/Definition.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/Definition.tsx
@@ -17,9 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
-import PropTypes from 'prop-types';
+import * as React from 'react';
import { connect } from 'react-redux';
import classNames from 'classnames';
import Input from './inputs/Input';
@@ -34,35 +32,37 @@ import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon'
import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon';
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 { cancelChange, changeValue, passValidation } from '../store/settingsPage';
import {
getSettingsAppChangedValue,
+ getSettingsAppValidationMessage,
isSettingsAppLoading,
- getSettingsAppValidationMessage
+ Store
} from '../../../store/rootReducer';
+import { Component, Setting } from '../../../app/types';
+
+interface Props {
+ cancelChange: (key: string) => void;
+ changedValue: any;
+ changeValue: (key: string, value: any) => void;
+ checkValue: (key: string) => boolean;
+ component?: Component;
+ loading: boolean;
+ passValidation: (key: string) => void;
+ resetValue: (key: string, component?: string) => Promise<void>;
+ saveValue: (key: string, component?: string) => Promise<void>;
+ setting: Setting;
+ validationMessage?: string;
+}
-class Definition extends React.PureComponent {
- /*:: mounted: boolean; */
- /*:: timeout: number; */
-
- static propTypes = {
- component: PropTypes.object,
- setting: PropTypes.object.isRequired,
- changedValue: PropTypes.any,
- loading: PropTypes.bool.isRequired,
- validationMessage: PropTypes.string,
-
- changeValue: PropTypes.func.isRequired,
- cancelChange: PropTypes.func.isRequired,
- saveValue: PropTypes.func.isRequired,
- resetValue: PropTypes.func.isRequired,
- passValidation: PropTypes.func.isRequired
- };
+interface State {
+ success: boolean;
+}
- state = {
- success: false
- };
+export class Definition extends React.PureComponent<Props, State> {
+ timeout?: number;
+ mounted = false;
+ state = { success: false };
componentDidMount() {
this.mounted = true;
@@ -72,87 +72,80 @@ class Definition extends React.PureComponent {
this.mounted = false;
}
- safeSetState(changes) {
+ safeSetState(changes: State) {
if (this.mounted) {
this.setState(changes);
}
}
- handleChange = value => {
+ handleChange = (value: any) => {
clearTimeout(this.timeout);
this.props.changeValue(this.props.setting.definition.key, value);
this.handleCheck();
};
handleReset = () => {
- const componentKey = this.props.component ? this.props.component.key : null;
- const { definition } = this.props.setting;
- return this.props
- .resetValue(definition.key, componentKey)
- .then(() => {
- this.props.cancelChange(definition.key, componentKey);
- this.safeSetState({ success: true });
- this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000);
- })
- .catch(() => {
- /* do nothing */
- });
+ const { component, setting } = this.props;
+ const { definition } = setting;
+ const componentKey = component && component.key;
+ return this.props.resetValue(definition.key, componentKey).then(() => {
+ this.props.cancelChange(definition.key);
+ this.safeSetState({ success: true });
+ this.timeout = window.setTimeout(() => this.safeSetState({ success: false }), 3000);
+ });
};
handleCancel = () => {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.cancelChange(this.props.setting.definition.key, componentKey);
- this.props.passValidation(this.props.setting.definition.key);
+ const { setting } = this.props;
+ this.props.cancelChange(setting.definition.key);
+ this.props.passValidation(setting.definition.key);
};
handleCheck = () => {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.checkValue(this.props.setting.definition.key, componentKey);
+ const { setting } = this.props;
+ this.props.checkValue(setting.definition.key);
};
handleSave = () => {
if (this.props.changedValue != null) {
this.safeSetState({ success: false });
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props
- .saveValue(this.props.setting.definition.key, componentKey)
- .then(() => {
+ const { component, setting } = this.props;
+ this.props.saveValue(setting.definition.key, component && component.key).then(
+ () => {
this.safeSetState({ success: true });
- this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000);
- })
- .catch(() => {
- /* do nothing */
- });
+ this.timeout = window.setTimeout(() => this.safeSetState({ success: false }), 3000);
+ },
+ () => {}
+ );
}
};
render() {
- const { setting, changedValue, loading } = this.props;
+ const { changedValue, loading, setting, validationMessage } = this.props;
const { definition } = setting;
const propertyName = getPropertyName(definition);
- const hasError = this.props.validationMessage != null;
-
+ const hasError = validationMessage != null;
const hasValueChanged = changedValue != null;
-
- const className = classNames('settings-definition', {
- 'settings-definition-changed': hasValueChanged
- });
-
const effectiveValue = hasValueChanged ? changedValue : getSettingValue(setting);
-
const isDefault = isDefaultOrInherited(setting);
-
+ const description = getPropertyDescription(definition);
return (
- <div className={className} data-key={definition.key}>
+ <div
+ className={classNames('settings-definition', {
+ 'settings-definition-changed': hasValueChanged
+ })}
+ data-key={definition.key}>
<div className="settings-definition-left">
<h3 className="settings-definition-name" title={propertyName}>
{propertyName}
</h3>
- <div
- className="markdown small spacer-top"
- dangerouslySetInnerHTML={{ __html: getPropertyDescription(definition) }}
- />
+ {description && (
+ <div
+ className="markdown small spacer-top"
+ dangerouslySetInnerHTML={{ __html: description }}
+ />
+ )}
<div className="settings-definition-key note little-spacer-top">
{translateWithParameters('settings.key_x', definition.key)}
@@ -169,14 +162,11 @@ class Definition extends React.PureComponent {
)}
{!loading &&
- hasError && (
+ validationMessage && (
<span className="text-danger">
<AlertErrorIcon className="spacer-right" />
<span>
- {translateWithParameters(
- 'settings.state.validation_failed',
- this.props.validationMessage
- )}
+ {translateWithParameters('settings.state.validation_failed', validationMessage)}
</span>
</span>
)}
@@ -216,20 +206,22 @@ class Definition extends React.PureComponent {
}
}
-const mapStateToProps = (state, ownProps) => ({
+const mapStateToProps = (state: Store, ownProps: Pick<Props, 'setting'>) => ({
changedValue: getSettingsAppChangedValue(state, ownProps.setting.definition.key),
loading: isSettingsAppLoading(state, ownProps.setting.definition.key),
validationMessage: getSettingsAppValidationMessage(state, ownProps.setting.definition.key)
});
+const mapDispatchToProps = {
+ cancelChange: cancelChange as any,
+ changeValue: changeValue as any,
+ checkValue: checkValue as any,
+ passValidation: passValidation as any,
+ resetValue: resetValue as any,
+ saveValue: saveValue as any
+};
+
export default connect(
mapStateToProps,
- {
- changeValue,
- saveValue,
- resetValue,
- passValidation,
- cancelChange,
- checkValue
- }
+ mapDispatchToProps
)(Definition);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js
deleted file mode 100644
index d62e687ce8b..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.js
+++ /dev/null
@@ -1,42 +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.
- */
-// @flow
-import React from 'react';
-import PropTypes from 'prop-types';
-import Definition from './Definition';
-
-export default class DefinitionsList extends React.PureComponent {
- static propTypes = {
- component: PropTypes.object,
- settings: PropTypes.array.isRequired
- };
-
- render() {
- return (
- <ul className="settings-definitions-list">
- {this.props.settings.map(setting => (
- <li key={setting.definition.key}>
- <Definition component={this.props.component} setting={setting} />
- </li>
- ))}
- </ul>
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/settings/store/values/actions.ts b/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.tsx
index a7d6f8f30a8..2f597afc239 100644
--- a/server/sonar-web/src/main/js/apps/settings/store/values/actions.ts
+++ b/server/sonar-web/src/main/js/apps/settings/components/DefinitionsList.tsx
@@ -17,13 +17,23 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-interface SettingValue {
- key: string;
- value?: string;
-}
+import * as React from 'react';
+import Definition from './Definition';
+import { Component, Setting } from '../../../app/types';
-export const RECEIVE_VALUES = 'RECEIVE_VALUES';
+interface Props {
+ component?: Component;
+ settings: Setting[];
+}
-export function receiveValues(settings: SettingValue[], componentKey?: string) {
- return { type: RECEIVE_VALUES, settings, componentKey };
+export default function DefinitionsList({ component, settings }: Props) {
+ return (
+ <ul className="settings-definitions-list">
+ {settings.map(setting => (
+ <li key={setting.definition.key}>
+ <Definition component={component} setting={setting} />
+ </li>
+ ))}
+ </ul>
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.js b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx
index e3777e25633..f1516115bba 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/EmailForm.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/EmailForm.tsx
@@ -17,36 +17,79 @@
* 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 { connect } from 'react-redux';
+import * as React from 'react';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { sendTestEmail } from '../../../api/settings';
import { parseError } from '../../../helpers/request';
-import { getCurrentUser } from '../../../store/rootReducer';
import { SubmitButton } from '../../../components/ui/buttons';
import { Alert } from '../../../components/ui/Alert';
+import { LoggedInUser } from '../../../app/types';
+import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
-class EmailForm extends React.PureComponent {
- constructor(props) {
+interface Props {
+ currentUser: LoggedInUser;
+}
+
+interface State {
+ recipient: string;
+ subject: string;
+ message: string;
+ loading: boolean;
+ success: boolean;
+ error?: string;
+}
+
+class EmailForm extends React.PureComponent<Props, State> {
+ mounted = false;
+
+ constructor(props: Props) {
super(props);
this.state = {
- recipient: this.props.currentUser.email,
+ recipient: this.props.currentUser.email || '',
subject: translate('email_configuration.test.subject'),
message: translate('email_configuration.test.message_text'),
loading: false,
- success: false,
- error: null
+ success: false
};
}
- handleFormSubmit = event => {
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleError = (error: { response: Response }) => {
+ return parseError(error).then(message => {
+ if (this.mounted) {
+ this.setState({ error: message, loading: false });
+ }
+ });
+ };
+
+ handleFormSubmit = (event: React.FormEvent) => {
event.preventDefault();
- this.setState({ success: false, error: null, loading: true });
+ this.setState({ success: false, error: undefined, loading: true });
const { recipient, subject, message } = this.state;
- sendTestEmail(recipient, subject, message).then(
- () => this.setState({ success: true, loading: false }),
- error => parseError(error).then(message => this.setState({ error: message, loading: false }))
- );
+ sendTestEmail(recipient, subject, message).then(() => {
+ if (this.mounted) {
+ this.setState({ success: true, loading: false });
+ }
+ }, this.handleError);
+ };
+
+ onRecipientChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ recipient: event.target.value });
+ };
+
+ onSubjectChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ subject: event.target.value });
+ };
+
+ onMessageChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
+ this.setState({ message: event.target.value });
};
render() {
@@ -81,7 +124,7 @@ class EmailForm extends React.PureComponent {
className="settings-large-input"
disabled={this.state.loading}
id="test-email-to"
- onChange={e => this.setState({ recipient: e.target.value })}
+ onChange={this.onRecipientChange}
required={true}
type="email"
value={this.state.recipient}
@@ -95,7 +138,7 @@ class EmailForm extends React.PureComponent {
className="settings-large-input"
disabled={this.state.loading}
id="test-email-subject"
- onChange={e => this.setState({ subject: e.target.value })}
+ onChange={this.onSubjectChange}
type="text"
value={this.state.subject}
/>
@@ -109,9 +152,9 @@ class EmailForm extends React.PureComponent {
className="settings-large-input"
disabled={this.state.loading}
id="test-email-title"
- onChange={e => this.setState({ message: e.target.value })}
+ onChange={this.onMessageChange}
required={true}
- rows="5"
+ rows={5}
value={this.state.message}
/>
</div>
@@ -128,8 +171,4 @@ class EmailForm extends React.PureComponent {
}
}
-const mapStateToProps = state => ({
- currentUser: getCurrentUser(state)
-});
-
-export default connect(mapStateToProps)(EmailForm);
+export default withCurrentUser(EmailForm);
diff --git a/server/sonar-web/src/main/js/apps/settings/components/PageHeader.js b/server/sonar-web/src/main/js/apps/settings/components/PageHeader.tsx
index 77e21d06141..18b2f644585 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/PageHeader.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/PageHeader.tsx
@@ -17,35 +17,28 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
-import PropTypes from 'prop-types';
+import * as React from 'react';
import InstanceMessage from '../../../components/common/InstanceMessage';
import { translate } from '../../../helpers/l10n';
+import { Component } from '../../../app/types';
-export default class PageHeader extends React.PureComponent {
- static propTypes = {
- component: PropTypes.object
- };
+interface Props {
+ component?: Component;
+}
- render() {
- const title =
- this.props.component != null
- ? translate('project_settings.page')
- : translate('settings.page');
+export default function PageHeader({ component }: Props) {
+ const title = component ? translate('project_settings.page') : translate('settings.page');
- const description =
- this.props.component != null ? (
- translate('project_settings.page.description')
- ) : (
- <InstanceMessage message={translate('settings.page.description')} />
- );
+ const description = component ? (
+ translate('project_settings.page.description')
+ ) : (
+ <InstanceMessage message={translate('settings.page.description')} />
+ );
- return (
- <header className="page-header">
- <h1 className="page-title">{title}</h1>
- <div className="page-description">{description}</div>
- </header>
- );
- }
+ return (
+ <header className="page-header">
+ <h1 className="page-title">{title}</h1>
+ <div className="page-description">{description}</div>
+ </header>
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx
index 075d96c4734..34fa14caaa0 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx
@@ -17,26 +17,26 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
-import React from 'react';
-import PropTypes from 'prop-types';
+import * as React from 'react';
import { groupBy, isEqual, sortBy } from 'lodash';
import DefinitionsList from './DefinitionsList';
import EmailForm from './EmailForm';
import { getSubCategoryName, getSubCategoryDescription } from '../utils';
+import { Component, SettingCategoryDefinition, Setting } from '../../../app/types';
-export default class SubCategoryDefinitionsList extends React.PureComponent {
- static propTypes = {
- component: PropTypes.object,
- fetchValues: PropTypes.func,
- settings: PropTypes.array.isRequired
- };
+interface Props {
+ category: string;
+ component?: Component;
+ fetchValues: Function;
+ settings: Array<Setting & { definition: SettingCategoryDefinition }>;
+}
+export default class SubCategoryDefinitionsList extends React.PureComponent<Props> {
componentDidMount() {
this.fetchValues();
}
- componentDidUpdate(prevProps /*: Object */) {
+ componentDidUpdate(prevProps: Props) {
const prevKeys = prevProps.settings.map(setting => setting.definition.key);
const keys = this.props.settings.map(setting => setting.definition.key);
if (prevProps.component !== this.props.component || !isEqual(prevKeys, keys)) {
@@ -49,13 +49,13 @@ export default class SubCategoryDefinitionsList extends React.PureComponent {
this.props.fetchValues(keys, this.props.component && this.props.component.key);
}
- renderEmailForm(subCategoryKey /*: string */) {
+ renderEmailForm = (subCategoryKey: string) => {
const isEmailSettings = this.props.category === 'general' && subCategoryKey === 'email';
if (!isEmailSettings) {
return null;
}
return <EmailForm />;
- }
+ };
render() {
const bySubCategory = groupBy(this.props.settings, setting => setting.definition.subCategory);
@@ -67,7 +67,6 @@ export default class SubCategoryDefinitionsList extends React.PureComponent {
const sortedSubCategories = sortBy(subCategories, subCategory =>
subCategory.name.toLowerCase()
);
-
return (
<ul className="settings-sub-categories-list">
{sortedSubCategories.map(subCategory => (
diff --git a/server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.js b/server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.tsx
index 42c2047aecf..bcebe583031 100644
--- a/server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.js
+++ b/server/sonar-web/src/main/js/apps/settings/components/WildcardsHelp.tsx
@@ -17,27 +17,28 @@
* 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 React from 'react';
+import { translate } from '../../../helpers/l10n';
export default function WildcardsHelp() {
return (
<div className="huge-spacer-top">
- <h2 className="spacer-bottom">Wildcards</h2>
- <p className="spacer-bottom">Following rules are applied:</p>
+ <h2 className="spacer-bottom">{translate('settings.wildcards')}</h2>
+ <p className="spacer-bottom">{translate('settings.wildcards.following_rules_are_applied')}</p>
<table className="data spacer-bottom">
<tbody>
<tr>
<td>*</td>
- <td>Match zero or more characters</td>
+ <td>{translate('settings.wildcards.zero_more_char')}</td>
</tr>
<tr>
<td>**</td>
- <td>Match zero or more directories</td>
+ <td>{translate('settings.wildcards.zero_more_dir')}</td>
</tr>
<tr>
<td>?</td>
- <td>Match a single character</td>
+ <td>{translate('settings.wildcards.single_char')}</td>
</tr>
</tbody>
</table>
@@ -45,72 +46,72 @@ export default function WildcardsHelp() {
<table className="data zebra">
<thead>
<tr>
- <th>Example</th>
- <th>Matches</th>
- <th>Does not match</th>
+ <th>{translate('example')}</th>
+ <th>{translate('settings.wildcards.matches')}</th>
+ <th>{translate('settings.wildcards.does_no_match')}</th>
</tr>
</thead>
<tbody>
<tr>
- <td>**/foo/*.js</td>
+ <td>{'**/foo/*.js'}</td>
<td>
<ul>
- <li>src/foo/bar.js</li>
- <li>lib/ui/foo/bar.js</li>
+ <li>{'src/foo/bar.js'}</li>
+ <li>{'lib/ui/foo/bar.js'}</li>
</ul>
</td>
<td>
<ul>
- <li>src/bar.js</li>
- <li>src/foo2/bar.js</li>
+ <li>{'src/bar.js'}</li>
+ <li>{'src/foo2/bar.js'}</li>
</ul>
</td>
</tr>
<tr>
- <td>src/foo/*bar*.js</td>
+ <td>{'src/foo/*bar*.js'}</td>
<td>
<ul>
- <li>src/foo/bar.js</li>
- <li>src/foo/bar1.js</li>
- <li>src/foo/bar123.js</li>
- <li>src/foo/123bar123.js</li>
+ <li>{'src/foo/bar.js'}</li>
+ <li>{'src/foo/bar1.js'}</li>
+ <li>{'src/foo/bar123.js'}</li>
+ <li>{'src/foo/123bar123.js'}</li>
</ul>
</td>
<td>
<ul>
- <li>src/foo/ui/bar.js</li>
- <li>src/bar.js</li>
+ <li>{'src/foo/ui/bar.js'}</li>
+ <li>{'src/bar.js'}</li>
</ul>
</td>
</tr>
<tr>
- <td>src/foo/**</td>
+ <td>{'src/foo/**'}</td>
<td>
<ul>
- <li>src/foo/bar.js</li>
- <li>src/foo/ui/bar.js</li>
+ <li>{'src/foo/bar.js'}</li>
+ <li>{'src/foo/ui/bar.js'}</li>
</ul>
</td>
<td>
<ul>
- <li>src/bar/foo/bar.js</li>
- <li>src/bar.js</li>
+ <li>{'src/bar/foo/bar.js'}</li>
+ <li>{'src/bar.js'}</li>
</ul>
</td>
</tr>
<tr>
- <td>**/foo?.js</td>
+ <td>{'**/foo?.js'}</td>
<td>
<ul>
- <li>src/foo1.js</li>
- <li>src/bar/foo1.js</li>
+ <li>{'src/foo1.js'}</li>
+ <li>{'src/bar/foo1.js'}</li>
</ul>
</td>
<td>
<ul>
- <li>src/foo.js</li>
- <li>src/foo12.js</li>
- <li>src/12foo3.js</li>
+ <li>{'src/foo.js'}</li>
+ <li>{'src/foo12.js'}</li>
+ <li>{'src/12foo3.js'}</li>
</ul>
</td>
</tr>
diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/DefinitionActions-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx
index 76b1d29491c..432be0e9f3b 100644
--- a/server/sonar-web/src/main/js/apps/settings/__tests__/DefinitionActions-test.tsx
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/DefinitionActions-test.tsx
@@ -20,8 +20,8 @@
/* eslint-disable import/order */
import * as React from 'react';
import { shallow } from 'enzyme';
-import DefinitionActions from '../components/DefinitionActions';
-import { SettingType } from '../../../app/types';
+import DefinitionActions from '../DefinitionActions';
+import { SettingType } from '../../../../app/types';
const definition = {
category: 'baz',
diff --git a/server/sonar-web/src/main/js/apps/settings/__tests__/__snapshots__/DefinitionActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap
index 046e36dbc27..046e36dbc27 100644
--- a/server/sonar-web/src/main/js/apps/settings/__tests__/__snapshots__/DefinitionActions-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/__snapshots__/DefinitionActions-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/settings/store/actions.js b/server/sonar-web/src/main/js/apps/settings/store/actions.js
deleted file mode 100644
index 34bdf549004..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/actions.js
+++ /dev/null
@@ -1,127 +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 { receiveValues } from './values/actions';
-import { receiveDefinitions } from './definitions/actions';
-import { startLoading, stopLoading } from './settingsPage/loading/actions';
-import { passValidation, failValidation } from './settingsPage/validationMessages/actions';
-import { cancelChange } from './settingsPage/changedValues/actions';
-import {
- getDefinitions,
- getValues,
- setSettingValue,
- resetSettingValue
-} from '../../../api/settings';
-import { parseError } from '../../../helpers/request';
-import { addGlobalErrorMessage, closeAllGlobalMessages } from '../../../store/globalMessages';
-import { isEmptyValue } from '../utils';
-import { translate } from '../../../helpers/l10n';
-import { getSettingsAppDefinition, getSettingsAppChangedValue } from '../../../store/rootReducer';
-
-export const fetchSettings = componentKey => dispatch => {
- return getDefinitions(componentKey).then(
- definitions => {
- const filtered = definitions
- .filter(definition => definition.type !== 'LICENSE')
- // do not display this setting on project level
- .filter(
- definition =>
- componentKey == null || definition.key !== 'sonar.branch.longLivedBranches.regex'
- );
- dispatch(receiveDefinitions(filtered));
- },
- e => parseError(e).then(message => dispatch(addGlobalErrorMessage(message)))
- );
-};
-
-export const fetchValues = (keys, component) => dispatch =>
- getValues({ keys, component }).then(
- settings => {
- dispatch(receiveValues(settings, component));
- dispatch(closeAllGlobalMessages());
- },
- () => {}
- );
-
-export const checkValue = (key, componentKey) => (dispatch, getState) => {
- const state = getState();
- const definition = getSettingsAppDefinition(state, key);
- const value = getSettingsAppChangedValue(state, key);
-
- if (isEmptyValue(definition, value)) {
- if (definition.defaultValue === undefined) {
- dispatch(failValidation(key, translate('settings.state.value_cant_be_empty_no_default')));
- } else {
- dispatch(failValidation(key, translate('settings.state.value_cant_be_empty')));
- }
- return false;
- }
-
- dispatch(passValidation(key));
- return true;
-};
-
-export const saveValue = (key, componentKey) => (dispatch, getState) => {
- dispatch(startLoading(key));
-
- const state = getState();
- const definition = getSettingsAppDefinition(state, key);
- const value = getSettingsAppChangedValue(state, key);
-
- if (isEmptyValue(definition, value)) {
- dispatch(failValidation(key, translate('settings.state.value_cant_be_empty')));
- dispatch(stopLoading(key));
- return Promise.reject();
- }
-
- return setSettingValue(definition, value, componentKey)
- .then(() => getValues({ keys: key, component: componentKey }))
- .then(values => {
- dispatch(receiveValues(values, componentKey));
- dispatch(cancelChange(key));
- dispatch(passValidation(key));
- dispatch(stopLoading(key));
- })
- .catch(e => {
- dispatch(stopLoading(key));
- parseError(e).then(message => dispatch(failValidation(key, message)));
- return Promise.reject();
- });
-};
-
-export const resetValue = (key, componentKey) => dispatch => {
- dispatch(startLoading(key));
-
- return resetSettingValue({ keys: key, component: componentKey })
- .then(() => getValues({ keys: key, component: componentKey }))
- .then(values => {
- if (values.length > 0) {
- dispatch(receiveValues(values, componentKey));
- } else {
- dispatch(receiveValues([{ key }], componentKey));
- }
- dispatch(passValidation(key));
- dispatch(stopLoading(key));
- })
- .catch(e => {
- dispatch(stopLoading(key));
- parseError(e).then(message => dispatch(failValidation(key, message)));
- return Promise.reject();
- });
-};
diff --git a/server/sonar-web/src/main/js/apps/settings/store/actions.ts b/server/sonar-web/src/main/js/apps/settings/store/actions.ts
new file mode 100644
index 00000000000..d3b3526c06f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/store/actions.ts
@@ -0,0 +1,141 @@
+/*
+ * 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 { Dispatch } from 'redux';
+import { receiveValues } from './values';
+import { receiveDefinitions } from './definitions';
+import {
+ cancelChange,
+ failValidation,
+ passValidation,
+ startLoading,
+ stopLoading
+} from './settingsPage';
+import {
+ getDefinitions,
+ getValues,
+ setSettingValue,
+ resetSettingValue
+} from '../../../api/settings';
+import { parseError } from '../../../helpers/request';
+import { closeAllGlobalMessages } from '../../../store/globalMessages';
+import { isEmptyValue } from '../utils';
+import { translate } from '../../../helpers/l10n';
+import {
+ getSettingsAppDefinition,
+ getSettingsAppChangedValue,
+ Store
+} from '../../../store/rootReducer';
+import { SettingType } from '../../../app/types';
+
+export function fetchSettings(component?: string) {
+ return (dispatch: Dispatch) => {
+ return getDefinitions(component).then(definitions => {
+ const filtered = definitions
+ .filter(definition => definition.type !== SettingType.License)
+ // do not display this setting on project level
+ .filter(
+ definition => !component || definition.key !== 'sonar.branch.longLivedBranches.regex'
+ );
+ dispatch(receiveDefinitions(filtered));
+ });
+ };
+}
+
+export function fetchValues(keys: string, component?: string) {
+ return (dispatch: Dispatch) =>
+ getValues({ keys, component }).then(settings => {
+ dispatch(receiveValues(settings, component));
+ dispatch(closeAllGlobalMessages());
+ });
+}
+
+export function checkValue(key: string) {
+ return (dispatch: Dispatch, getState: () => Store) => {
+ const state = getState();
+ const definition = getSettingsAppDefinition(state, key);
+ const value = getSettingsAppChangedValue(state, key);
+
+ if (isEmptyValue(definition, value)) {
+ if (definition.defaultValue === undefined) {
+ dispatch(failValidation(key, translate('settings.state.value_cant_be_empty_no_default')));
+ } else {
+ dispatch(failValidation(key, translate('settings.state.value_cant_be_empty')));
+ }
+ return false;
+ }
+
+ dispatch(passValidation(key));
+ return true;
+ };
+}
+
+export function saveValue(key: string, component?: string) {
+ return (dispatch: Dispatch, getState: () => Store) => {
+ dispatch(startLoading(key));
+ const state = getState();
+ const definition = getSettingsAppDefinition(state, key);
+ const value = getSettingsAppChangedValue(state, key);
+
+ if (isEmptyValue(definition, value)) {
+ dispatch(failValidation(key, translate('settings.state.value_cant_be_empty')));
+ dispatch(stopLoading(key));
+ return Promise.reject();
+ }
+
+ return setSettingValue(definition, value, component)
+ .then(() => getValues({ keys: key, component }))
+ .then(values => {
+ dispatch(receiveValues(values, component));
+ dispatch(cancelChange(key));
+ dispatch(passValidation(key));
+ dispatch(stopLoading(key));
+ })
+ .catch(handleError(key, dispatch));
+ };
+}
+
+export function resetValue(key: string, component?: string) {
+ return (dispatch: Dispatch) => {
+ dispatch(startLoading(key));
+
+ return resetSettingValue({ keys: key, component })
+ .then(() => getValues({ keys: key, component }))
+ .then(values => {
+ if (values.length > 0) {
+ dispatch(receiveValues(values, component));
+ } else {
+ dispatch(receiveValues([{ key }], component));
+ }
+ dispatch(passValidation(key));
+ dispatch(stopLoading(key));
+ })
+ .catch(handleError(key, dispatch));
+ };
+}
+
+function handleError(key: string, dispatch: Dispatch) {
+ return (error: { response: Response }) => {
+ dispatch(stopLoading(key));
+ return parseError(error).then(message => {
+ dispatch(failValidation(key, message));
+ return Promise.reject();
+ });
+ };
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/store/definitions/reducer.js b/server/sonar-web/src/main/js/apps/settings/store/definitions.ts
index 8d5e17530ae..fef242043bf 100644
--- a/server/sonar-web/src/main/js/apps/settings/store/definitions/reducer.js
+++ b/server/sonar-web/src/main/js/apps/settings/store/definitions.ts
@@ -17,49 +17,53 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// @flow
import { keyBy, sortBy, uniqBy } from 'lodash';
-import { RECEIVE_DEFINITIONS } from './actions';
-import { DEFAULT_CATEGORY, getCategoryName } from '../../utils';
-/*:: import type { Definition } from '../../types'; */
+import { ActionType } from '../../../store/utils/actions';
+import { SettingCategoryDefinition } from '../../../app/types';
+import { DEFAULT_CATEGORY, getCategoryName } from '../utils';
-/*::
-type State = { [key: string]: Definition };
-*/
+const enum Actions {
+ ReceiveDefinitions = 'RECEIVE_DEFINITIONS'
+}
+
+type Action = ActionType<typeof receiveDefinitions, Actions.ReceiveDefinitions>;
+
+export interface State {
+ [key: string]: SettingCategoryDefinition;
+}
-/*::
-type Action = { type: string, definitions: Definition[] };
-*/
+export function receiveDefinitions(definitions: SettingCategoryDefinition[]) {
+ return { type: Actions.ReceiveDefinitions, definitions };
+}
-const reducer = (state /*: State */ = {}, action /*: Action */) => {
- if (action.type === RECEIVE_DEFINITIONS) {
+export default function components(state: State = {}, action: Action) {
+ if (action.type === Actions.ReceiveDefinitions) {
return keyBy(action.definitions, 'key');
}
-
return state;
-};
-
-export default reducer;
+}
-export function getDefinition(state /*: State */, key /*: string */) /*: Definition */ {
+export function getDefinition(state: State, key: string) {
return state[key];
}
-export function getAllDefinitions(state /*: State */) /*: Definition[] */ {
+export function getAllDefinitions(state: State) {
return Object.keys(state).map(key => state[key]);
}
-export const getDefinitionsForCategory = (state /*: State */, category /*: string */) =>
- getAllDefinitions(state).filter(
+export function getDefinitionsForCategory(state: State, category: string) {
+ return getAllDefinitions(state).filter(
definition => definition.category.toLowerCase() === category.toLowerCase()
);
+}
-export const getAllCategories = (state /*: State */) =>
- uniqBy(getAllDefinitions(state).map(definition => definition.category), category =>
+export function getAllCategories(state: State) {
+ return uniqBy(getAllDefinitions(state).map(definition => definition.category), category =>
category.toLowerCase()
);
+}
-export const getDefaultCategory = (state /*: State */) => {
+export function getDefaultCategory(state: State) {
const categories = getAllCategories(state);
if (categories.includes(DEFAULT_CATEGORY)) {
return DEFAULT_CATEGORY;
@@ -69,4 +73,4 @@ export const getDefaultCategory = (state /*: State */) => {
);
return sortedCategories[0];
}
-};
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/store/definitions/actions.js b/server/sonar-web/src/main/js/apps/settings/store/definitions/actions.js
deleted file mode 100644
index e80a3ea20f7..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/definitions/actions.js
+++ /dev/null
@@ -1,33 +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.
- */
-// @flow
-/*:: import type { Definition } from '../../types'; */
-
-export const RECEIVE_DEFINITIONS /*: string */ = 'RECEIVE_DEFINITIONS';
-
-/**
- * Receive definitions action creator
- * @param {Array} definitions
- * @returns {Object}
- */
-export const receiveDefinitions = (definitions /*: Definition[] */) => ({
- type: RECEIVE_DEFINITIONS,
- definitions
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js b/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js
deleted file mode 100644
index 24b85559003..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/rootReducer.js
+++ /dev/null
@@ -1,79 +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.
- */
-// @flow
-import { combineReducers } from 'redux';
-import definitions, * as fromDefinitions from './definitions/reducer';
-import values, * as fromValues from './values/reducer';
-import settingsPage, * as fromSettingsPage from './settingsPage/reducer';
-import globalMessages, * as fromGlobalMessages from '../../../store/globalMessages';
-/*:: import type { State as GlobalMessagesState } from '../../../store/globalMessages'; */
-/*:: import type { State as ValuesState } from './values/reducer'; */
-
-/*::
-type State = {
- definitions: {},
- globalMessages: GlobalMessagesState,
- settingsPage: {},
- values: ValuesState
-};
-*/
-
-const rootReducer = combineReducers({
- definitions,
- values,
- settingsPage,
- globalMessages
-});
-
-export default rootReducer;
-
-export const getDefinition = (state /*: State */, key /*: string */) =>
- fromDefinitions.getDefinition(state.definitions, key);
-
-export const getAllCategories = (state /*: State */) =>
- fromDefinitions.getAllCategories(state.definitions);
-
-export const getDefaultCategory = (state /*: State */) =>
- fromDefinitions.getDefaultCategory(state.definitions);
-
-export const getValue = (state /*: State */, key /*: string */, componentKey /*: ?string */) =>
- fromValues.getValue(state.values, key, componentKey);
-
-export const getSettingsForCategory = (
- state /*: State */,
- category /*: string */,
- componentKey /*: ?string */
-) =>
- fromDefinitions.getDefinitionsForCategory(state.definitions, category).map(definition => ({
- ...getValue(state, definition.key, componentKey),
- definition
- }));
-
-export const getChangedValue = (state /*: State */, key /*: string */) =>
- fromSettingsPage.getChangedValue(state.settingsPage, key);
-
-export const isLoading = (state /*: State */, key /*: string */) =>
- fromSettingsPage.isLoading(state.settingsPage, key);
-
-export const getValidationMessage = (state /*: State */, key /*: string */) =>
- fromSettingsPage.getValidationMessage(state.settingsPage, key);
-
-export const getGlobalMessages = (state /*: State */) =>
- fromGlobalMessages.getGlobalMessages(state.globalMessages);
diff --git a/server/sonar-web/src/main/js/apps/settings/store/rootReducer.ts b/server/sonar-web/src/main/js/apps/settings/store/rootReducer.ts
new file mode 100644
index 00000000000..625d6490155
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/store/rootReducer.ts
@@ -0,0 +1,73 @@
+/*
+ * 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 { combineReducers } from 'redux';
+import definitions, * as fromDefinitions from './definitions';
+import values, * as fromValues from './values';
+import settingsPage, * as fromSettingsPage from './settingsPage';
+import globalMessages, * as fromGlobalMessages from '../../../store/globalMessages';
+
+interface State {
+ definitions: fromDefinitions.State;
+ globalMessages: fromGlobalMessages.State;
+ settingsPage: fromSettingsPage.State;
+ values: fromValues.State;
+}
+
+export default combineReducers({ definitions, values, settingsPage, globalMessages });
+
+export function getDefinition(state: State, key: string) {
+ return fromDefinitions.getDefinition(state.definitions, key);
+}
+
+export function getAllCategories(state: State) {
+ return fromDefinitions.getAllCategories(state.definitions);
+}
+
+export function getDefaultCategory(state: State) {
+ return fromDefinitions.getDefaultCategory(state.definitions);
+}
+
+export function getValue(state: State, key: string, component?: string) {
+ return fromValues.getValue(state.values, key, component);
+}
+
+export function getSettingsForCategory(state: State, category: string, component?: string) {
+ return fromDefinitions.getDefinitionsForCategory(state.definitions, category).map(definition => ({
+ key: definition.key,
+ ...getValue(state, definition.key, component),
+ definition
+ }));
+}
+
+export function getChangedValue(state: State, key: string) {
+ return fromSettingsPage.getChangedValue(state.settingsPage, key);
+}
+
+export function isLoading(state: State, key: string) {
+ return fromSettingsPage.isLoading(state.settingsPage, key);
+}
+
+export function getValidationMessage(state: State, key: string) {
+ return fromSettingsPage.getValidationMessage(state.settingsPage, key);
+}
+
+export function getGlobalMessages(state: State) {
+ return fromGlobalMessages.getGlobalMessages(state.globalMessages);
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage.ts b/server/sonar-web/src/main/js/apps/settings/store/settingsPage.ts
new file mode 100644
index 00000000000..25365a8d232
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/store/settingsPage.ts
@@ -0,0 +1,113 @@
+/*
+ * 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 { omit } from 'lodash';
+import { combineReducers } from 'redux';
+import { ActionType } from '../../../store/utils/actions';
+
+const enum Actions {
+ CancelChange = 'settingsPage/CANCEL_CHANGE',
+ ChangeValue = 'settingsPage/CHANGE_VALUE',
+ FailValidation = 'settingsPage/FAIL_VALIDATION',
+ PassValidation = 'settingsPage/PASS_VALIDATION',
+ StartLoading = 'settingsPage/START_LOADING',
+ StopLoading = 'settingsPage/STOP_LOADING'
+}
+
+type Action =
+ | ActionType<typeof cancelChange, Actions.CancelChange>
+ | ActionType<typeof changeValue, Actions.ChangeValue>
+ | ActionType<typeof failValidation, Actions.FailValidation>
+ | ActionType<typeof passValidation, Actions.PassValidation>
+ | ActionType<typeof startLoading, Actions.StartLoading>
+ | ActionType<typeof stopLoading, Actions.StopLoading>;
+
+export interface State {
+ changedValues: { [key: string]: any };
+ loading: { [key: string]: boolean };
+ validationMessages: { [key: string]: string };
+}
+
+export function cancelChange(key: string) {
+ return { type: Actions.CancelChange, key };
+}
+
+export function changeValue(key: string, value: any) {
+ return { type: Actions.ChangeValue, key, value };
+}
+
+function changedValues(state: State['changedValues'] = {}, action: Action) {
+ if (action.type === Actions.ChangeValue) {
+ return { ...state, [action.key]: action.value };
+ }
+ if (action.type === Actions.CancelChange) {
+ return omit(state, action.key);
+ }
+ return state;
+}
+
+export function failValidation(key: string, message: string) {
+ return { type: Actions.FailValidation, key, message };
+}
+
+export function passValidation(key: string) {
+ return { type: Actions.PassValidation, key };
+}
+
+function validationMessages(state: State['validationMessages'] = {}, action: Action) {
+ if (action.type === Actions.FailValidation) {
+ return { ...state, [action.key]: action.message };
+ }
+ if (action.type === Actions.PassValidation) {
+ return omit(state, action.key);
+ }
+ return state;
+}
+
+export function startLoading(key: string) {
+ return { type: Actions.StartLoading, key };
+}
+
+export function stopLoading(key: string) {
+ return { type: Actions.StopLoading, key };
+}
+
+function loading(state: State['loading'] = {}, action: Action) {
+ if (action.type === Actions.StartLoading) {
+ return { ...state, [action.key]: true };
+ }
+ if (action.type === Actions.StopLoading) {
+ return { ...state, [action.key]: false };
+ }
+ return state;
+}
+
+export default combineReducers({ changedValues, loading, validationMessages });
+
+export function getChangedValue(state: State, key: string) {
+ return state.changedValues[key];
+}
+
+export function getValidationMessage(state: State, key: string): string | undefined {
+ return state.validationMessages[key];
+}
+
+export function isLoading(state: State, key: string) {
+ return Boolean(state.loading[key]);
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/actions.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/actions.js
deleted file mode 100644
index 0364e252770..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/actions.js
+++ /dev/null
@@ -1,33 +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 CHANGE_VALUE = 'settingsPage/CHANGE_VALUE';
-
-export const changeValue = (key, value) => ({
- type: CHANGE_VALUE,
- key,
- value
-});
-
-export const CANCEL_CHANGE = 'settingsPage/CANCEL_CHANGE';
-
-export const cancelChange = key => ({
- type: CANCEL_CHANGE,
- key
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/reducer.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/reducer.js
deleted file mode 100644
index 1c6978d7558..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/changedValues/reducer.js
+++ /dev/null
@@ -1,37 +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 { omit } from 'lodash';
-import { CHANGE_VALUE, CANCEL_CHANGE } from './actions';
-
-const reducer = (state = {}, action = {}) => {
- if (action.type === CHANGE_VALUE) {
- return { ...state, [action.key]: action.value };
- }
-
- if (action.type === CANCEL_CHANGE) {
- return omit(state, action.key);
- }
-
- return state;
-};
-
-export default reducer;
-
-export const getChangedValue = (state, key) => state[key];
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/actions.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/actions.js
deleted file mode 100644
index 291c0feb459..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/actions.js
+++ /dev/null
@@ -1,31 +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 START_LOADING = 'settingsPage/START_LOADING';
-
-export const startLoading = key => ({
- type: START_LOADING,
- key
-});
-export const STOP_LOADING = 'settingsPage/STOP_LOADING';
-
-export const stopLoading = key => ({
- type: STOP_LOADING,
- key
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/reducer.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/reducer.js
deleted file mode 100644
index e220fab09a4..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/loading/reducer.js
+++ /dev/null
@@ -1,36 +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 { START_LOADING, STOP_LOADING } from './actions';
-
-const reducer = (state = {}, action = {}) => {
- if (action.type === START_LOADING) {
- return { ...state, [action.key]: true };
- }
-
- if (action.type === STOP_LOADING) {
- return { ...state, [action.key]: false };
- }
-
- return state;
-};
-
-export default reducer;
-
-export const isLoading = (state, key) => !!state[key];
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/reducer.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/reducer.js
deleted file mode 100644
index f19e0584984..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/reducer.js
+++ /dev/null
@@ -1,37 +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 { combineReducers } from 'redux';
-import changedValues, * as fromChangedValues from './changedValues/reducer';
-import validationMessages, * as fromValidationMessages from './validationMessages/reducer';
-import loading, * as fromLoading from './loading/reducer';
-
-export default combineReducers({
- changedValues,
- validationMessages,
- loading
-});
-
-export const getChangedValue = (state, key) =>
- fromChangedValues.getChangedValue(state.changedValues, key);
-
-export const getValidationMessage = (state, key) =>
- fromValidationMessages.getValidationMessage(state.validationMessages, key);
-
-export const isLoading = (state, key) => fromLoading.isLoading(state.loading, key);
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/actions.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/actions.js
deleted file mode 100644
index d073581f67d..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/actions.js
+++ /dev/null
@@ -1,33 +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 FAIL_VALIDATION = 'settingsPage/FAIL_VALIDATION';
-
-export const failValidation = (key, message) => ({
- type: FAIL_VALIDATION,
- key,
- message
-});
-
-export const PASS_VALIDATION = 'settingsPage/PASS_VALIDATION';
-
-export const passValidation = key => ({
- type: PASS_VALIDATION,
- key
-});
diff --git a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/reducer.js b/server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/reducer.js
deleted file mode 100644
index 9b8da6ffd32..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/settingsPage/validationMessages/reducer.js
+++ /dev/null
@@ -1,36 +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 { FAIL_VALIDATION, PASS_VALIDATION } from './actions';
-
-const reducer = (state = {}, action = {}) => {
- if (action.type === FAIL_VALIDATION) {
- return { ...state, [action.key]: action.message };
- }
-
- if (action.type === PASS_VALIDATION) {
- return { ...state, [action.key]: null };
- }
-
- return state;
-};
-
-export default reducer;
-
-export const getValidationMessage = (state, key) => state[key];
diff --git a/server/sonar-web/src/main/js/apps/settings/store/values.ts b/server/sonar-web/src/main/js/apps/settings/store/values.ts
new file mode 100644
index 00000000000..e00727a86a5
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/settings/store/values.ts
@@ -0,0 +1,85 @@
+/*
+ * 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 { combineReducers } from 'redux';
+import { keyBy } from 'lodash';
+import { ActionType } from '../../../store/utils/actions';
+import { Action as AppStateAction, Actions as AppStateActions } from '../../../store/appState';
+import { SettingValue } from '../../../app/types';
+
+enum Actions {
+ receiveValues = 'RECEIVE_VALUES'
+}
+
+type Action = ActionType<typeof receiveValues, Actions.receiveValues>;
+
+interface SettingsState {
+ [key: string]: SettingValue;
+}
+
+export interface State {
+ components: { [component: string]: SettingsState };
+ global: SettingsState;
+}
+
+export function receiveValues(
+ settings: Array<{ key: string; value?: string }>,
+ component?: string
+) {
+ return { type: Actions.receiveValues, settings, component };
+}
+
+function components(state: State['components'] = {}, action: Action) {
+ const { component: key } = action;
+ if (!key) {
+ return state;
+ }
+ if (action.type === Actions.receiveValues) {
+ const settingsByKey = keyBy(action.settings, 'key');
+ return { ...state, [key]: { ...(state[key] || {}), ...settingsByKey } };
+ }
+ return state;
+}
+
+function global(state: State['components'] = {}, action: Action | AppStateAction) {
+ if (action.type === Actions.receiveValues) {
+ if (action.component) {
+ return state;
+ }
+ const settingsByKey = keyBy(action.settings, 'key');
+ return { ...state, ...settingsByKey };
+ }
+ if (action.type === AppStateActions.SetAppState) {
+ const settingsByKey: SettingsState = {};
+ Object.keys(action.appState.settings).forEach(
+ key => (settingsByKey[key] = { key, value: action.appState.settings[key] })
+ );
+ return { ...state, ...settingsByKey };
+ }
+ return state;
+}
+
+export default combineReducers({ components, global });
+
+export function getValue(state: State, key: string, component?: string): SettingValue | undefined {
+ if (component) {
+ return state.components[component] && state.components[component][key];
+ }
+ return state.global[key];
+}
diff --git a/server/sonar-web/src/main/js/apps/settings/store/values/reducer.js b/server/sonar-web/src/main/js/apps/settings/store/values/reducer.js
deleted file mode 100644
index 5da0fdc6da8..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/store/values/reducer.js
+++ /dev/null
@@ -1,74 +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.
- */
-// @flow
-import { combineReducers } from 'redux';
-import { keyBy } from 'lodash';
-import { RECEIVE_VALUES } from './actions';
-
-/*::
-type SettingsState = { [key: string]: {} };
-type ComponentsState = { [key: string]: SettingsState };
-export type State = { components: ComponentsState, global: SettingsState };
-*/
-
-const componentsSettings = (state /*: ComponentsState */ = {}, action /*: Object */) => {
- if (!action.componentKey) {
- return state;
- }
-
- const key = action.componentKey;
- if (action.type === RECEIVE_VALUES) {
- const settingsByKey = keyBy(action.settings, 'key');
- return { ...state, [key]: { ...(state[key] || {}), ...settingsByKey } };
- }
-
- return state;
-};
-
-const globalSettings = (state /*: SettingsState */ = {}, action /*: Object */) => {
- if (action.componentKey) {
- return state;
- }
-
- if (action.type === RECEIVE_VALUES) {
- const settingsByKey = keyBy(action.settings, 'key');
- return { ...state, ...settingsByKey };
- }
-
- if (action.type === 'SET_APP_STATE') {
- const settingsByKey = {};
- Object.keys(action.appState.settings).forEach(
- key => (settingsByKey[key] = { value: action.appState.settings[key] })
- );
- return { ...state, ...settingsByKey };
- }
-
- return state;
-};
-
-export default combineReducers({ components: componentsSettings, global: globalSettings });
-
-export const getValue = (state /*: State */, key /*: string */, componentKey /*: ?string */) => {
- let settings = state.global;
- if (componentKey) {
- settings = state.components[componentKey];
- }
- return settings && settings[key];
-};
diff --git a/server/sonar-web/src/main/js/apps/settings/types.js b/server/sonar-web/src/main/js/apps/settings/types.js
deleted file mode 100644
index c0f10cb73ea..00000000000
--- a/server/sonar-web/src/main/js/apps/settings/types.js
+++ /dev/null
@@ -1,26 +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.
- */
-// @flow
-/*::
-export type Definition = {
- key: string,
- category: string
-};
-*/
diff --git a/server/sonar-web/src/main/js/components/ui/Avatar.tsx b/server/sonar-web/src/main/js/components/ui/Avatar.tsx
index ad31cabb65d..6f32f8930cb 100644
--- a/server/sonar-web/src/main/js/components/ui/Avatar.tsx
+++ b/server/sonar-web/src/main/js/components/ui/Avatar.tsx
@@ -55,10 +55,14 @@ function Avatar(props: Props) {
);
}
-const mapStateToProps = (state: Store) => ({
- enableGravatar: (getGlobalSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true',
- gravatarServerUrl: (getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl') || {}).value
-});
+const mapStateToProps = (state: Store) => {
+ const enableGravatar = getGlobalSettingValue(state, 'sonar.lf.enableGravatar');
+ const gravatarServerUrl = getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl');
+ return {
+ enableGravatar: Boolean(enableGravatar && enableGravatar.value === 'true'),
+ gravatarServerUrl: (gravatarServerUrl && gravatarServerUrl.value) || ''
+ };
+};
export default connect(mapStateToProps)(Avatar);
diff --git a/server/sonar-web/src/main/js/store/appState.ts b/server/sonar-web/src/main/js/store/appState.ts
index 19a5e546944..89f31e98e12 100644
--- a/server/sonar-web/src/main/js/store/appState.ts
+++ b/server/sonar-web/src/main/js/store/appState.ts
@@ -21,21 +21,27 @@ import { ActionType } from './utils/actions';
import { Extension, AppState } from '../app/types';
import { EditionKey } from '../apps/marketplace/utils';
-type Action =
- | ActionType<typeof setAppState, 'SET_APP_STATE'>
- | ActionType<typeof setAdminPages, 'SET_ADMIN_PAGES'>
- | ActionType<typeof requireAuthorization, 'REQUIRE_AUTHORIZATION'>;
+export const enum Actions {
+ SetAppState = 'SET_APP_STATE',
+ SetAdminPages = 'SET_ADMIN_PAGES',
+ RequireAuthorization = 'REQUIRE_AUTHORIZATION'
+}
+
+export type Action =
+ | ActionType<typeof setAppState, Actions.SetAppState>
+ | ActionType<typeof setAdminPages, Actions.SetAdminPages>
+ | ActionType<typeof requireAuthorization, Actions.RequireAuthorization>;
export function setAppState(appState: AppState) {
- return { type: 'SET_APP_STATE', appState };
+ return { type: Actions.SetAppState, appState };
}
export function setAdminPages(adminPages: Extension[]) {
- return { type: 'SET_ADMIN_PAGES', adminPages };
+ return { type: Actions.SetAdminPages, adminPages };
}
export function requireAuthorization() {
- return { type: 'REQUIRE_AUTHORIZATION' };
+ return { type: Actions.RequireAuthorization };
}
const defaultValue: AppState = {
@@ -46,21 +52,19 @@ const defaultValue: AppState = {
organizationsEnabled: false,
productionDatabase: true,
qualifiers: [],
+ settings: {},
version: ''
};
export default function(state: AppState = defaultValue, action: Action): AppState {
- if (action.type === 'SET_APP_STATE') {
+ if (action.type === Actions.SetAppState) {
return { ...state, ...action.appState };
}
-
- if (action.type === 'SET_ADMIN_PAGES') {
+ if (action.type === Actions.SetAdminPages) {
return { ...state, adminPages: action.adminPages };
}
-
- if (action.type === 'REQUIRE_AUTHORIZATION') {
+ if (action.type === Actions.RequireAuthorization) {
return { ...state, authorizationError: true };
}
-
return state;
}
diff --git a/server/sonar-web/src/main/js/store/globalMessages.ts b/server/sonar-web/src/main/js/store/globalMessages.ts
index eabb58635a8..b1059021a6d 100644
--- a/server/sonar-web/src/main/js/store/globalMessages.ts
+++ b/server/sonar-web/src/main/js/store/globalMessages.ts
@@ -41,8 +41,8 @@ export function closeGlobalMessage(id: string) {
return { type: 'CLOSE_GLOBAL_MESSAGE', id };
}
-export function closeAllGlobalMessages(id: string) {
- return { type: 'CLOSE_ALL_GLOBAL_MESSAGES', id };
+export function closeAllGlobalMessages() {
+ return { type: 'CLOSE_ALL_GLOBAL_MESSAGES' };
}
type Action =
diff --git a/server/sonar-web/src/main/js/store/rootReducer.ts b/server/sonar-web/src/main/js/store/rootReducer.ts
index 3d3bcfacec7..336fe056b6b 100644
--- a/server/sonar-web/src/main/js/store/rootReducer.ts
+++ b/server/sonar-web/src/main/js/store/rootReducer.ts
@@ -109,9 +109,9 @@ export function getSettingsAppDefaultCategory(state: Store) {
export function getSettingsAppSettingsForCategory(
state: Store,
category: string,
- componentKey: string
+ component?: string
) {
- return fromSettingsApp.getSettingsForCategory(state.settingsApp, category, componentKey);
+ return fromSettingsApp.getSettingsForCategory(state.settingsApp, category, component);
}
export function getSettingsAppChangedValue(state: Store, key: string) {