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(
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
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'));
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();
}
}
}
}
-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,
}
}
-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));
}
}
-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);
);
}
-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);
organizationsEnabled?: boolean;
productionDatabase: boolean;
qualifiers: string[];
+ settings: { [key: string]: string };
standalone?: boolean;
version: string;
}
Boolean = 'BOOLEAN',
Float = 'FLOAT',
Integer = 'INTEGER',
+ License = 'LICENSE',
Long = 'LONG',
SingleSelectList = 'SINGLE_SELECT_LIST',
PropertySet = 'PROPERTY_SET'
*/
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));
});
interface Props {
appState: Pick<AppState, 'defaultOrganization' | 'organizationsEnabled'>;
currentUser: CurrentUser;
- customText?: { value: string };
+ customText?: string;
fetchAboutPageSettings: () => Promise<void>;
location: Location;
}
</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 />
}
}
-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;
import { Organization } from '../../../app/types';
interface StateProps {
- anyoneCanCreate?: { value: string };
+ anyoneCanCreate: boolean;
canAdmin?: boolean;
organizations: Organization[];
}
};
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 (
}
}
-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
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 }) => {
export const fetchIfAnyoneCanCreateOrganizations = () => (dispatch: Dispatch) => {
return getValues({ keys: 'sonar.organizations.anyoneCanCreate' }).then(values => {
- dispatch(receiveValues(values, undefined));
+ dispatch(receiveValues(values));
});
};
}
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')
};
};
+++ /dev/null
-/*
- * 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.
- */
-/* eslint-disable import/order */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import DefinitionActions from '../components/DefinitionActions';
-import { SettingType } from '../../../app/types';
-
-const definition = {
- category: 'baz',
- description: 'lorem',
- fields: [],
- key: 'key',
- name: 'foobar',
- options: [],
- subCategory: 'bar',
- type: SettingType.String
-};
-
-const settings = {
- key: 'key',
- definition,
- value: 'baz'
-};
-
-it('displays default message when value is default', () => {
- const wrapper = shallowRender('', false, true);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('displays save button when it can be saved', () => {
- const wrapper = shallowRender('foo', false, true);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('displays cancel button when value changed and no error', () => {
- const wrapper = shallowRender('foo', false, true);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('displays cancel button when value changed and has error', () => {
- const wrapper = shallowRender('foo', true, true);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('disables save button on error', () => {
- const wrapper = shallowRender('foo', true, true);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('displays reset button when empty and not default', () => {
- const wrapper = shallowRender('', true, false);
- expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(changedValue: string, hasError: boolean, isDefault: boolean) {
- return shallow(
- <DefinitionActions
- changedValue={changedValue}
- hasError={hasError}
- hasValueChanged={changedValue !== ''}
- isDefault={isDefault}
- onCancel={() => {}}
- onReset={() => {}}
- onSave={() => {}}
- setting={settings}
- />
- );
-}
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`disables save button on error 1`] = `
-<Fragment>
- <div
- className="settings-definition-changes nowrap"
- >
- <Button
- className="spacer-right button-success"
- disabled={true}
- onClick={[Function]}
- >
- save
- </Button>
- <Button
- className="spacer-right button-link"
- onClick={[Function]}
- >
- cancel
- </Button>
- </div>
-</Fragment>
-`;
-
-exports[`displays cancel button when value changed and has error 1`] = `
-<Fragment>
- <div
- className="settings-definition-changes nowrap"
- >
- <Button
- className="spacer-right button-success"
- disabled={true}
- onClick={[Function]}
- >
- save
- </Button>
- <Button
- className="spacer-right button-link"
- onClick={[Function]}
- >
- cancel
- </Button>
- </div>
-</Fragment>
-`;
-
-exports[`displays cancel button when value changed and no error 1`] = `
-<Fragment>
- <div
- className="settings-definition-changes nowrap"
- >
- <Button
- className="spacer-right button-success"
- disabled={false}
- onClick={[Function]}
- >
- save
- </Button>
- <Button
- className="spacer-right button-link"
- onClick={[Function]}
- >
- cancel
- </Button>
- </div>
-</Fragment>
-`;
-
-exports[`displays default message when value is default 1`] = `
-<Fragment>
- <div
- className="spacer-top note"
- style={
- Object {
- "lineHeight": "24px",
- }
- }
- >
- settings._default
- </div>
- <div
- className="settings-definition-changes nowrap"
- >
- <Button
- className="spacer-right"
- onClick={[Function]}
- >
- reset_verb
- </Button>
- <span
- className="note"
- >
- default
- :
- settings.default.no_value
- </span>
- </div>
-</Fragment>
-`;
-
-exports[`displays reset button when empty and not default 1`] = `
-<Fragment>
- <div
- className="settings-definition-changes nowrap"
- >
- <Button
- className="spacer-right"
- onClick={[Function]}
- >
- reset_verb
- </Button>
- <span
- className="note"
- >
- default
- :
- settings.default.no_value
- </span>
- </div>
-</Fragment>
-`;
-
-exports[`displays save button when it can be saved 1`] = `
-<Fragment>
- <div
- className="settings-definition-changes nowrap"
- >
- <Button
- className="spacer-right button-success"
- disabled={false}
- onClick={[Function]}
- >
- save
- </Button>
- <Button
- className="spacer-right button-link"
- onClick={[Function]}
- >
- cancel
- </Button>
- </div>
-</Fragment>
-`;
+++ /dev/null
-/*
- * 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);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { 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';
+
+interface Category {
+ key: string;
+ name: string;
+}
+
+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={classNames({
+ active: category.key.toLowerCase() === selectedCategory.toLowerCase()
+ })}
+ title={category.name}
+ to={{ pathname, query }}>
+ {category.name}
+ </IndexLink>
+ );
+ }
+
+ render() {
+ const categoriesWithName = this.props.categories.map(key => ({
+ key,
+ name: getCategoryName(key)
+ }));
+ const sortedCategories = sortBy(categoriesWithName, category => category.name.toLowerCase());
+ return (
+ <ul className="side-tabs-menu">
+ {sortedCategories.map(category => (
+ <li key={category.key}>{this.renderLink(category)}</li>
+ ))}
+ </ul>
+ );
+ }
+}
+
+const mapStateToProps = (state: Store) => ({
+ categories: getSettingsAppAllCategories(state)
+});
+
+export default connect(mapStateToProps)(CategoriesList);
+++ /dev/null
-/*
- * 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 Helmet from 'react-helmet';
-import PageHeader from './PageHeader';
-import CategoryDefinitionsList from './CategoryDefinitionsList';
-import AllCategoriesList from './AllCategoriesList';
-import WildcardsHelp from './WildcardsHelp';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
-import { translate } from '../../../helpers/l10n';
-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 };
-
- componentDidMount() {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true }));
- }
-
- componentDidUpdate(prevProps /*: Props*/) {
- if (prevProps.component !== this.props.component) {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.fetchSettings(componentKey);
- }
- }
-
- render() {
- if (!this.state.loaded) {
- return null;
- }
-
- const { query } = this.props.location;
- const selectedCategory = query.category || this.props.defaultCategory;
-
- return (
- <div className="page page-limited" id="settings-page">
- <Suggestions suggestions="settings" />
- <Helmet title={translate('settings.page')} />
-
- <PageHeader component={this.props.component} />
-
- <div className="side-tabs-layout settings-layout">
- <div className="side-tabs-side">
- <AllCategoriesList
- component={this.props.component}
- defaultCategory={this.props.defaultCategory}
- selectedCategory={selectedCategory}
- />
- </div>
- <div className="side-tabs-main">
- <CategoryDefinitionsList category={selectedCategory} component={this.props.component} />
- {selectedCategory === 'exclusions' && <WildcardsHelp />}
- </div>
- </div>
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * 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);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Helmet from 'react-helmet';
+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';
+
+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() {
+ this.mounted = true;
+ this.fetchSettings();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.component !== this.props.component) {
+ 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.loading) {
+ return null;
+ }
+
+ const { query } = this.props.location;
+ const selectedCategory = query.category || this.props.defaultCategory;
+
+ return (
+ <div className="page page-limited" id="settings-page">
+ <Suggestions suggestions="settings" />
+ <Helmet title={translate('settings.page')} />
+
+ <PageHeader component={this.props.component} />
+
+ <div className="side-tabs-layout settings-layout">
+ <div className="side-tabs-side">
+ <AllCategoriesList
+ component={this.props.component}
+ defaultCategory={this.props.defaultCategory}
+ selectedCategory={selectedCategory}
+ />
+ </div>
+ <div className="side-tabs-main">
+ <CategoryDefinitionsList category={selectedCategory} component={this.props.component} />
+ {selectedCategory === 'exclusions' && <WildcardsHelp />}
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
+const mapStateToProps = (state: Store) => ({
+ defaultCategory: getSettingsAppDefaultCategory(state)
+});
+
+const mapDispatchToProps = { fetchSettings: fetchSettings as any };
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(App);
+++ /dev/null
-/*
- * 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 { sortBy } from 'lodash';
-import { IndexLink } from 'react-router';
-import { getCategoryName } from '../utils';
-
-/*::
-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;
- }
-
- const className =
- category.key.toLowerCase() === this.props.selectedCategory.toLowerCase() ? 'active' : '';
-
- const pathname = this.props.component ? '/project/settings' : '/settings';
-
- return (
- <IndexLink className={className} title={category.name} to={{ pathname, query }}>
- {category.name}
- </IndexLink>
- );
- }
-
- render() {
- const categoriesWithName = this.props.categories.map(key => ({
- key,
- name: getCategoryName(key)
- }));
- const sortedCategories = sortBy(categoriesWithName, category => category.name.toLowerCase());
-
- return (
- <ul className="side-tabs-menu">
- {sortedCategories.map(category => (
- <li key={category.key}>{this.renderLink(category)}</li>
- ))}
- </ul>
- );
- }
-}
+++ /dev/null
-/*
- * 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 { connect } from 'react-redux';
-import SubCategoryDefinitionsList from './SubCategoryDefinitionsList';
-import { fetchValues } from '../store/actions';
-import { getSettingsAppSettingsForCategory } from '../../../store/rootReducer';
-
-const mapStateToProps = (state, ownProps) => ({
- settings: getSettingsAppSettingsForCategory(
- state,
- ownProps.category,
- ownProps.component ? ownProps.component.key : null
- )
-});
-
-const mapDispatchToProps = { fetchValues };
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(SubCategoryDefinitionsList);
--- /dev/null
+/*
+ * 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 SubCategoryDefinitionsList from './SubCategoryDefinitionsList';
+import { fetchValues } from '../store/actions';
+import { getSettingsAppSettingsForCategory, Store } from '../../../store/rootReducer';
+import { Component } from '../../../app/types';
+
+interface Props {
+ category: string;
+ component?: Component;
+}
+
+const mapStateToProps = (state: Store, ownProps: Props) => ({
+ settings: getSettingsAppSettingsForCategory(
+ state,
+ ownProps.category,
+ ownProps.component && ownProps.component.key
+ )
+});
+
+const mapDispatchToProps = { fetchValues };
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(SubCategoryDefinitionsList);
+++ /dev/null
-/*
- * 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 { connect } from 'react-redux';
-import classNames from 'classnames';
-import Input from './inputs/Input';
-import DefinitionActions from './DefinitionActions';
-import {
- getPropertyName,
- getPropertyDescription,
- getSettingValue,
- isDefaultOrInherited
-} from '../utils';
-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 {
- getSettingsAppChangedValue,
- isSettingsAppLoading,
- getSettingsAppValidationMessage
-} from '../../../store/rootReducer';
-
-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
- };
-
- state = {
- success: false
- };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- safeSetState(changes) {
- if (this.mounted) {
- this.setState(changes);
- }
- }
-
- handleChange = value => {
- 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 */
- });
- };
-
- 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);
- };
-
- handleCheck = () => {
- const componentKey = this.props.component ? this.props.component.key : null;
- this.props.checkValue(this.props.setting.definition.key, componentKey);
- };
-
- 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(() => {
- this.safeSetState({ success: true });
- this.timeout = setTimeout(() => this.safeSetState({ success: false }), 3000);
- })
- .catch(() => {
- /* do nothing */
- });
- }
- };
-
- render() {
- const { setting, changedValue, loading } = this.props;
- const { definition } = setting;
- const propertyName = getPropertyName(definition);
- const hasError = this.props.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);
-
- return (
- <div className={className} 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) }}
- />
-
- <div className="settings-definition-key note little-spacer-top">
- {translateWithParameters('settings.key_x', definition.key)}
- </div>
- </div>
-
- <div className="settings-definition-right">
- <div className="settings-definition-state">
- {loading && (
- <span className="text-info">
- <i className="spinner spacer-right" />
- {translate('settings.state.saving')}
- </span>
- )}
-
- {!loading &&
- hasError && (
- <span className="text-danger">
- <AlertErrorIcon className="spacer-right" />
- <span>
- {translateWithParameters(
- 'settings.state.validation_failed',
- this.props.validationMessage
- )}
- </span>
- </span>
- )}
-
- {!loading &&
- !hasError &&
- this.state.success && (
- <span className="text-success">
- <AlertSuccessIcon className="spacer-right" />
- {translate('settings.state.saved')}
- </span>
- )}
- </div>
-
- <Input
- hasValueChanged={hasValueChanged}
- onCancel={this.handleCancel}
- onChange={this.handleChange}
- onSave={this.handleSave}
- setting={setting}
- value={effectiveValue}
- />
-
- <DefinitionActions
- changedValue={changedValue}
- hasError={hasError}
- hasValueChanged={hasValueChanged}
- isDefault={isDefault}
- onCancel={this.handleCancel}
- onReset={this.handleReset}
- onSave={this.handleSave}
- setting={setting}
- />
- </div>
- </div>
- );
- }
-}
-
-const mapStateToProps = (state, ownProps) => ({
- changedValue: getSettingsAppChangedValue(state, ownProps.setting.definition.key),
- loading: isSettingsAppLoading(state, ownProps.setting.definition.key),
- validationMessage: getSettingsAppValidationMessage(state, ownProps.setting.definition.key)
-});
-
-export default connect(
- mapStateToProps,
- {
- changeValue,
- saveValue,
- resetValue,
- passValidation,
- cancelChange,
- checkValue
- }
-)(Definition);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { connect } from 'react-redux';
+import classNames from 'classnames';
+import Input from './inputs/Input';
+import DefinitionActions from './DefinitionActions';
+import {
+ getPropertyName,
+ getPropertyDescription,
+ getSettingValue,
+ isDefaultOrInherited
+} from '../utils';
+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 { cancelChange, changeValue, passValidation } from '../store/settingsPage';
+import {
+ getSettingsAppChangedValue,
+ getSettingsAppValidationMessage,
+ isSettingsAppLoading,
+ 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;
+}
+
+interface State {
+ success: boolean;
+}
+
+export class Definition extends React.PureComponent<Props, State> {
+ timeout?: number;
+ mounted = false;
+ state = { success: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ safeSetState(changes: State) {
+ if (this.mounted) {
+ this.setState(changes);
+ }
+ }
+
+ handleChange = (value: any) => {
+ clearTimeout(this.timeout);
+ this.props.changeValue(this.props.setting.definition.key, value);
+ this.handleCheck();
+ };
+
+ handleReset = () => {
+ 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 { setting } = this.props;
+ this.props.cancelChange(setting.definition.key);
+ this.props.passValidation(setting.definition.key);
+ };
+
+ handleCheck = () => {
+ const { setting } = this.props;
+ this.props.checkValue(setting.definition.key);
+ };
+
+ handleSave = () => {
+ if (this.props.changedValue != null) {
+ this.safeSetState({ success: false });
+ const { component, setting } = this.props;
+ this.props.saveValue(setting.definition.key, component && component.key).then(
+ () => {
+ this.safeSetState({ success: true });
+ this.timeout = window.setTimeout(() => this.safeSetState({ success: false }), 3000);
+ },
+ () => {}
+ );
+ }
+ };
+
+ render() {
+ const { changedValue, loading, setting, validationMessage } = this.props;
+ const { definition } = setting;
+ const propertyName = getPropertyName(definition);
+ const hasError = validationMessage != null;
+ const hasValueChanged = changedValue != null;
+ const effectiveValue = hasValueChanged ? changedValue : getSettingValue(setting);
+ const isDefault = isDefaultOrInherited(setting);
+ const description = getPropertyDescription(definition);
+ return (
+ <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>
+
+ {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)}
+ </div>
+ </div>
+
+ <div className="settings-definition-right">
+ <div className="settings-definition-state">
+ {loading && (
+ <span className="text-info">
+ <i className="spinner spacer-right" />
+ {translate('settings.state.saving')}
+ </span>
+ )}
+
+ {!loading &&
+ validationMessage && (
+ <span className="text-danger">
+ <AlertErrorIcon className="spacer-right" />
+ <span>
+ {translateWithParameters('settings.state.validation_failed', validationMessage)}
+ </span>
+ </span>
+ )}
+
+ {!loading &&
+ !hasError &&
+ this.state.success && (
+ <span className="text-success">
+ <AlertSuccessIcon className="spacer-right" />
+ {translate('settings.state.saved')}
+ </span>
+ )}
+ </div>
+
+ <Input
+ hasValueChanged={hasValueChanged}
+ onCancel={this.handleCancel}
+ onChange={this.handleChange}
+ onSave={this.handleSave}
+ setting={setting}
+ value={effectiveValue}
+ />
+
+ <DefinitionActions
+ changedValue={changedValue}
+ hasError={hasError}
+ hasValueChanged={hasValueChanged}
+ isDefault={isDefault}
+ onCancel={this.handleCancel}
+ onReset={this.handleReset}
+ onSave={this.handleSave}
+ setting={setting}
+ />
+ </div>
+ </div>
+ );
+ }
+}
+
+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,
+ mapDispatchToProps
+)(Definition);
+++ /dev/null
-/*
- * 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>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Definition from './Definition';
+import { Component, Setting } from '../../../app/types';
+
+interface Props {
+ component?: Component;
+ settings: Setting[];
+}
+
+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>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { connect } from 'react-redux';
-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';
-
-class EmailForm extends React.PureComponent {
- constructor(props) {
- super(props);
- this.state = {
- recipient: this.props.currentUser.email,
- subject: translate('email_configuration.test.subject'),
- message: translate('email_configuration.test.message_text'),
- loading: false,
- success: false,
- error: null
- };
- }
-
- handleFormSubmit = event => {
- event.preventDefault();
- this.setState({ success: false, error: null, 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 }))
- );
- };
-
- render() {
- return (
- <div className="huge-spacer-top">
- <h3 className="spacer-bottom">{translate('email_configuration.test.title')}</h3>
-
- <form onSubmit={this.handleFormSubmit} style={{ marginLeft: 201 }}>
- {this.state.success && (
- <div className="modal-field">
- <Alert variant="success">
- {translateWithParameters(
- 'email_configuration.test.email_was_sent_to_x',
- this.state.recipient
- )}
- </Alert>
- </div>
- )}
-
- {this.state.error != null && (
- <div className="modal-field">
- <Alert variant="error">{this.state.error}</Alert>
- </div>
- )}
-
- <div className="modal-field">
- <label htmlFor="test-email-to">
- {translate('email_configuration.test.to_address')}
- <em className="mandatory">*</em>
- </label>
- <input
- className="settings-large-input"
- disabled={this.state.loading}
- id="test-email-to"
- onChange={e => this.setState({ recipient: e.target.value })}
- required={true}
- type="email"
- value={this.state.recipient}
- />
- </div>
- <div className="modal-field">
- <label htmlFor="test-email-subject">
- {translate('email_configuration.test.subject')}
- </label>
- <input
- className="settings-large-input"
- disabled={this.state.loading}
- id="test-email-subject"
- onChange={e => this.setState({ subject: e.target.value })}
- type="text"
- value={this.state.subject}
- />
- </div>
- <div className="modal-field">
- <label htmlFor="test-email-message">
- {translate('email_configuration.test.message')}
- <em className="mandatory">*</em>
- </label>
- <textarea
- className="settings-large-input"
- disabled={this.state.loading}
- id="test-email-title"
- onChange={e => this.setState({ message: e.target.value })}
- required={true}
- rows="5"
- value={this.state.message}
- />
- </div>
-
- <div className="modal-field">
- {this.state.loading && <i className="spacer-right spinner" />}
- <SubmitButton disabled={this.state.loading}>
- {translate('email_configuration.test.send')}
- </SubmitButton>
- </div>
- </form>
- </div>
- );
- }
-}
-
-const mapStateToProps = state => ({
- currentUser: getCurrentUser(state)
-});
-
-export default connect(mapStateToProps)(EmailForm);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { sendTestEmail } from '../../../api/settings';
+import { parseError } from '../../../helpers/request';
+import { SubmitButton } from '../../../components/ui/buttons';
+import { Alert } from '../../../components/ui/Alert';
+import { LoggedInUser } from '../../../app/types';
+import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
+
+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 || '',
+ subject: translate('email_configuration.test.subject'),
+ message: translate('email_configuration.test.message_text'),
+ loading: false,
+ success: false
+ };
+ }
+
+ 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: undefined, loading: true });
+ const { recipient, subject, message } = this.state;
+ 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() {
+ return (
+ <div className="huge-spacer-top">
+ <h3 className="spacer-bottom">{translate('email_configuration.test.title')}</h3>
+
+ <form onSubmit={this.handleFormSubmit} style={{ marginLeft: 201 }}>
+ {this.state.success && (
+ <div className="modal-field">
+ <Alert variant="success">
+ {translateWithParameters(
+ 'email_configuration.test.email_was_sent_to_x',
+ this.state.recipient
+ )}
+ </Alert>
+ </div>
+ )}
+
+ {this.state.error != null && (
+ <div className="modal-field">
+ <Alert variant="error">{this.state.error}</Alert>
+ </div>
+ )}
+
+ <div className="modal-field">
+ <label htmlFor="test-email-to">
+ {translate('email_configuration.test.to_address')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={this.state.loading}
+ id="test-email-to"
+ onChange={this.onRecipientChange}
+ required={true}
+ type="email"
+ value={this.state.recipient}
+ />
+ </div>
+ <div className="modal-field">
+ <label htmlFor="test-email-subject">
+ {translate('email_configuration.test.subject')}
+ </label>
+ <input
+ className="settings-large-input"
+ disabled={this.state.loading}
+ id="test-email-subject"
+ onChange={this.onSubjectChange}
+ type="text"
+ value={this.state.subject}
+ />
+ </div>
+ <div className="modal-field">
+ <label htmlFor="test-email-message">
+ {translate('email_configuration.test.message')}
+ <em className="mandatory">*</em>
+ </label>
+ <textarea
+ className="settings-large-input"
+ disabled={this.state.loading}
+ id="test-email-title"
+ onChange={this.onMessageChange}
+ required={true}
+ rows={5}
+ value={this.state.message}
+ />
+ </div>
+
+ <div className="modal-field">
+ {this.state.loading && <i className="spacer-right spinner" />}
+ <SubmitButton disabled={this.state.loading}>
+ {translate('email_configuration.test.send')}
+ </SubmitButton>
+ </div>
+ </form>
+ </div>
+ );
+ }
+}
+
+export default withCurrentUser(EmailForm);
+++ /dev/null
-/*
- * 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 InstanceMessage from '../../../components/common/InstanceMessage';
-import { translate } from '../../../helpers/l10n';
-
-export default class PageHeader extends React.PureComponent {
- static propTypes = {
- component: PropTypes.object
- };
-
- render() {
- const title =
- this.props.component != null
- ? translate('project_settings.page')
- : translate('settings.page');
-
- const description =
- this.props.component != null ? (
- 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>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import InstanceMessage from '../../../components/common/InstanceMessage';
+import { translate } from '../../../helpers/l10n';
+import { Component } from '../../../app/types';
+
+interface Props {
+ component?: Component;
+}
+
+export default function PageHeader({ component }: Props) {
+ const title = component ? translate('project_settings.page') : translate('settings.page');
+
+ 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>
+ );
+}
+++ /dev/null
-/*
- * 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 { groupBy, isEqual, sortBy } from 'lodash';
-import DefinitionsList from './DefinitionsList';
-import EmailForm from './EmailForm';
-import { getSubCategoryName, getSubCategoryDescription } from '../utils';
-
-export default class SubCategoryDefinitionsList extends React.PureComponent {
- static propTypes = {
- component: PropTypes.object,
- fetchValues: PropTypes.func,
- settings: PropTypes.array.isRequired
- };
-
- componentDidMount() {
- this.fetchValues();
- }
-
- componentDidUpdate(prevProps /*: Object */) {
- 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)) {
- this.fetchValues();
- }
- }
-
- fetchValues() {
- const keys = this.props.settings.map(setting => setting.definition.key).join();
- this.props.fetchValues(keys, this.props.component && this.props.component.key);
- }
-
- 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);
- const subCategories = Object.keys(bySubCategory).map(key => ({
- key,
- name: getSubCategoryName(bySubCategory[key][0].definition.category, key),
- description: getSubCategoryDescription(bySubCategory[key][0].definition.category, key)
- }));
- const sortedSubCategories = sortBy(subCategories, subCategory =>
- subCategory.name.toLowerCase()
- );
-
- return (
- <ul className="settings-sub-categories-list">
- {sortedSubCategories.map(subCategory => (
- <li key={subCategory.key}>
- <h2 className="settings-sub-category-name">{subCategory.name}</h2>
- {subCategory.description != null && (
- <div
- className="settings-sub-category-description markdown"
- dangerouslySetInnerHTML={{ __html: subCategory.description }}
- />
- )}
- <DefinitionsList
- component={this.props.component}
- settings={bySubCategory[subCategory.key]}
- />
- {this.renderEmailForm(subCategory.key)}
- </li>
- ))}
- </ul>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { 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';
+
+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: 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)) {
+ this.fetchValues();
+ }
+ }
+
+ fetchValues() {
+ const keys = this.props.settings.map(setting => setting.definition.key).join();
+ this.props.fetchValues(keys, this.props.component && this.props.component.key);
+ }
+
+ 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);
+ const subCategories = Object.keys(bySubCategory).map(key => ({
+ key,
+ name: getSubCategoryName(bySubCategory[key][0].definition.category, key),
+ description: getSubCategoryDescription(bySubCategory[key][0].definition.category, key)
+ }));
+ const sortedSubCategories = sortBy(subCategories, subCategory =>
+ subCategory.name.toLowerCase()
+ );
+ return (
+ <ul className="settings-sub-categories-list">
+ {sortedSubCategories.map(subCategory => (
+ <li key={subCategory.key}>
+ <h2 className="settings-sub-category-name">{subCategory.name}</h2>
+ {subCategory.description != null && (
+ <div
+ className="settings-sub-category-description markdown"
+ dangerouslySetInnerHTML={{ __html: subCategory.description }}
+ />
+ )}
+ <DefinitionsList
+ component={this.props.component}
+ settings={bySubCategory[subCategory.key]}
+ />
+ {this.renderEmailForm(subCategory.key)}
+ </li>
+ ))}
+ </ul>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-
-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>
-
- <table className="data spacer-bottom">
- <tbody>
- <tr>
- <td>*</td>
- <td>Match zero or more characters</td>
- </tr>
- <tr>
- <td>**</td>
- <td>Match zero or more directories</td>
- </tr>
- <tr>
- <td>?</td>
- <td>Match a single character</td>
- </tr>
- </tbody>
- </table>
-
- <table className="data zebra">
- <thead>
- <tr>
- <th>Example</th>
- <th>Matches</th>
- <th>Does not match</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>**/foo/*.js</td>
- <td>
- <ul>
- <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>
- </ul>
- </td>
- </tr>
- <tr>
- <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>
- </ul>
- </td>
- <td>
- <ul>
- <li>src/foo/ui/bar.js</li>
- <li>src/bar.js</li>
- </ul>
- </td>
- </tr>
- <tr>
- <td>src/foo/**</td>
- <td>
- <ul>
- <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>
- </ul>
- </td>
- </tr>
- <tr>
- <td>**/foo?.js</td>
- <td>
- <ul>
- <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>
- </ul>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { translate } from '../../../helpers/l10n';
+
+export default function WildcardsHelp() {
+ return (
+ <div className="huge-spacer-top">
+ <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>{translate('settings.wildcards.zero_more_char')}</td>
+ </tr>
+ <tr>
+ <td>**</td>
+ <td>{translate('settings.wildcards.zero_more_dir')}</td>
+ </tr>
+ <tr>
+ <td>?</td>
+ <td>{translate('settings.wildcards.single_char')}</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table className="data zebra">
+ <thead>
+ <tr>
+ <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>
+ <ul>
+ <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>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <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>
+ </ul>
+ </td>
+ <td>
+ <ul>
+ <li>{'src/foo/ui/bar.js'}</li>
+ <li>{'src/bar.js'}</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{'src/foo/**'}</td>
+ <td>
+ <ul>
+ <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>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{'**/foo?.js'}</td>
+ <td>
+ <ul>
+ <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>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+/* eslint-disable import/order */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import DefinitionActions from '../DefinitionActions';
+import { SettingType } from '../../../../app/types';
+
+const definition = {
+ category: 'baz',
+ description: 'lorem',
+ fields: [],
+ key: 'key',
+ name: 'foobar',
+ options: [],
+ subCategory: 'bar',
+ type: SettingType.String
+};
+
+const settings = {
+ key: 'key',
+ definition,
+ value: 'baz'
+};
+
+it('displays default message when value is default', () => {
+ const wrapper = shallowRender('', false, true);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('displays save button when it can be saved', () => {
+ const wrapper = shallowRender('foo', false, true);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('displays cancel button when value changed and no error', () => {
+ const wrapper = shallowRender('foo', false, true);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('displays cancel button when value changed and has error', () => {
+ const wrapper = shallowRender('foo', true, true);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('disables save button on error', () => {
+ const wrapper = shallowRender('foo', true, true);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('displays reset button when empty and not default', () => {
+ const wrapper = shallowRender('', true, false);
+ expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(changedValue: string, hasError: boolean, isDefault: boolean) {
+ return shallow(
+ <DefinitionActions
+ changedValue={changedValue}
+ hasError={hasError}
+ hasValueChanged={changedValue !== ''}
+ isDefault={isDefault}
+ onCancel={() => {}}
+ onReset={() => {}}
+ onSave={() => {}}
+ setting={settings}
+ />
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`disables save button on error 1`] = `
+<Fragment>
+ <div
+ className="settings-definition-changes nowrap"
+ >
+ <Button
+ className="spacer-right button-success"
+ disabled={true}
+ onClick={[Function]}
+ >
+ save
+ </Button>
+ <Button
+ className="spacer-right button-link"
+ onClick={[Function]}
+ >
+ cancel
+ </Button>
+ </div>
+</Fragment>
+`;
+
+exports[`displays cancel button when value changed and has error 1`] = `
+<Fragment>
+ <div
+ className="settings-definition-changes nowrap"
+ >
+ <Button
+ className="spacer-right button-success"
+ disabled={true}
+ onClick={[Function]}
+ >
+ save
+ </Button>
+ <Button
+ className="spacer-right button-link"
+ onClick={[Function]}
+ >
+ cancel
+ </Button>
+ </div>
+</Fragment>
+`;
+
+exports[`displays cancel button when value changed and no error 1`] = `
+<Fragment>
+ <div
+ className="settings-definition-changes nowrap"
+ >
+ <Button
+ className="spacer-right button-success"
+ disabled={false}
+ onClick={[Function]}
+ >
+ save
+ </Button>
+ <Button
+ className="spacer-right button-link"
+ onClick={[Function]}
+ >
+ cancel
+ </Button>
+ </div>
+</Fragment>
+`;
+
+exports[`displays default message when value is default 1`] = `
+<Fragment>
+ <div
+ className="spacer-top note"
+ style={
+ Object {
+ "lineHeight": "24px",
+ }
+ }
+ >
+ settings._default
+ </div>
+ <div
+ className="settings-definition-changes nowrap"
+ >
+ <Button
+ className="spacer-right"
+ onClick={[Function]}
+ >
+ reset_verb
+ </Button>
+ <span
+ className="note"
+ >
+ default
+ :
+ settings.default.no_value
+ </span>
+ </div>
+</Fragment>
+`;
+
+exports[`displays reset button when empty and not default 1`] = `
+<Fragment>
+ <div
+ className="settings-definition-changes nowrap"
+ >
+ <Button
+ className="spacer-right"
+ onClick={[Function]}
+ >
+ reset_verb
+ </Button>
+ <span
+ className="note"
+ >
+ default
+ :
+ settings.default.no_value
+ </span>
+ </div>
+</Fragment>
+`;
+
+exports[`displays save button when it can be saved 1`] = `
+<Fragment>
+ <div
+ className="settings-definition-changes nowrap"
+ >
+ <Button
+ className="spacer-right button-success"
+ disabled={false}
+ onClick={[Function]}
+ >
+ save
+ </Button>
+ <Button
+ className="spacer-right button-link"
+ onClick={[Function]}
+ >
+ cancel
+ </Button>
+ </div>
+</Fragment>
+`;
+++ /dev/null
-/*
- * 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();
- });
-};
--- /dev/null
+/*
+ * 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();
+ });
+ };
+}
--- /dev/null
+/*
+ * 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 { keyBy, sortBy, uniqBy } from 'lodash';
+import { ActionType } from '../../../store/utils/actions';
+import { SettingCategoryDefinition } from '../../../app/types';
+import { DEFAULT_CATEGORY, getCategoryName } from '../utils';
+
+const enum Actions {
+ ReceiveDefinitions = 'RECEIVE_DEFINITIONS'
+}
+
+type Action = ActionType<typeof receiveDefinitions, Actions.ReceiveDefinitions>;
+
+export interface State {
+ [key: string]: SettingCategoryDefinition;
+}
+
+export function receiveDefinitions(definitions: SettingCategoryDefinition[]) {
+ return { type: Actions.ReceiveDefinitions, definitions };
+}
+
+export default function components(state: State = {}, action: Action) {
+ if (action.type === Actions.ReceiveDefinitions) {
+ return keyBy(action.definitions, 'key');
+ }
+ return state;
+}
+
+export function getDefinition(state: State, key: string) {
+ return state[key];
+}
+
+export function getAllDefinitions(state: State) {
+ return Object.keys(state).map(key => state[key]);
+}
+
+export function getDefinitionsForCategory(state: State, category: string) {
+ return getAllDefinitions(state).filter(
+ definition => definition.category.toLowerCase() === category.toLowerCase()
+ );
+}
+
+export function getAllCategories(state: State) {
+ return uniqBy(getAllDefinitions(state).map(definition => definition.category), category =>
+ category.toLowerCase()
+ );
+}
+
+export function getDefaultCategory(state: State) {
+ const categories = getAllCategories(state);
+ if (categories.includes(DEFAULT_CATEGORY)) {
+ return DEFAULT_CATEGORY;
+ } else {
+ const sortedCategories = sortBy(categories, category =>
+ getCategoryName(category).toLowerCase()
+ );
+ return sortedCategories[0];
+ }
+}
+++ /dev/null
-/*
- * 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
-});
+++ /dev/null
-/*
- * 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 { keyBy, sortBy, uniqBy } from 'lodash';
-import { RECEIVE_DEFINITIONS } from './actions';
-import { DEFAULT_CATEGORY, getCategoryName } from '../../utils';
-/*:: import type { Definition } from '../../types'; */
-
-/*::
-type State = { [key: string]: Definition };
-*/
-
-/*::
-type Action = { type: string, definitions: Definition[] };
-*/
-
-const reducer = (state /*: State */ = {}, action /*: Action */) => {
- if (action.type === RECEIVE_DEFINITIONS) {
- return keyBy(action.definitions, 'key');
- }
-
- return state;
-};
-
-export default reducer;
-
-export function getDefinition(state /*: State */, key /*: string */) /*: Definition */ {
- return state[key];
-}
-
-export function getAllDefinitions(state /*: State */) /*: Definition[] */ {
- return Object.keys(state).map(key => state[key]);
-}
-
-export const getDefinitionsForCategory = (state /*: State */, category /*: string */) =>
- getAllDefinitions(state).filter(
- definition => definition.category.toLowerCase() === category.toLowerCase()
- );
-
-export const getAllCategories = (state /*: State */) =>
- uniqBy(getAllDefinitions(state).map(definition => definition.category), category =>
- category.toLowerCase()
- );
-
-export const getDefaultCategory = (state /*: State */) => {
- const categories = getAllCategories(state);
- if (categories.includes(DEFAULT_CATEGORY)) {
- return DEFAULT_CATEGORY;
- } else {
- const sortedCategories = sortBy(categories, category =>
- getCategoryName(category).toLowerCase()
- );
- return sortedCategories[0];
- }
-};
+++ /dev/null
-/*
- * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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]);
+}
+++ /dev/null
-/*
- * 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
-});
+++ /dev/null
-/*
- * 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];
+++ /dev/null
-/*
- * 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
-});
+++ /dev/null
-/*
- * 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];
+++ /dev/null
-/*
- * 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);
+++ /dev/null
-/*
- * 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
-});
+++ /dev/null
-/*
- * 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];
--- /dev/null
+/*
+ * 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];
+}
+++ /dev/null
-/*
- * 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.
- */
-interface SettingValue {
- key: string;
- value?: string;
-}
-
-export const RECEIVE_VALUES = 'RECEIVE_VALUES';
-
-export function receiveValues(settings: SettingValue[], componentKey?: string) {
- return { type: RECEIVE_VALUES, settings, componentKey };
-}
+++ /dev/null
-/*
- * 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];
-};
+++ /dev/null
-/*
- * 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
-};
-*/
);
}
-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);
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 = {
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;
}
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 =
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) {
end_date=End Date
edit=Edit
events=Events
+example=Example
explore=Explore
false=False
favorite=Favorite
settings.default.complex_value=<complex value>
settings.default.password=<password>
settings.reset_confirm.title=Reset Setting
-settings.reset_confirm.description=Are you sure that you want to reset this setting ?
+settings.reset_confirm.description=Are you sure that you want to reset this setting?
+settings.wildcards=Wildcards
+settings.wildcards.following_rules_are_applied=Following rules are applied:
+settings.wildcards.zero_more_char=Match zero or more characters
+settings.wildcards.zero_more_dir=Match zero or more directories
+settings.wildcards.single_char=Match a single character
+settings.wildcards.matches=Matches
+settings.wildcards.does_no_match=Does not match
property.category.general=General
property.category.general.email=Email