}
export function fetchQualityGate(data: {
- id: number;
+ id: number | string;
organization?: string;
}): Promise<T.QualityGate> {
return getJSON('/api/qualitygates/show', data).catch(throwGlobalError);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 { WithRouterProps } from 'react-router';
+import Helmet from 'react-helmet';
+import Details from './Details';
+import Intro from './Intro';
+import List from './List';
+import ListHeader from './ListHeader';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
+import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
+import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
+import { fetchQualityGates } from '../../../api/quality-gates';
+import { translate } from '../../../helpers/l10n';
+import {
+ addSideBarClass,
+ addWhitePageClass,
+ removeSideBarClass,
+ removeWhitePageClass
+} from '../../../helpers/pages';
+import { getQualityGateUrl } from '../../../helpers/urls';
+import '../../../components/search-navigator.css';
+import '../styles.css';
+
+interface Props extends WithRouterProps {
+ organization?: Pick<T.Organization, 'key'>;
+}
+
+interface State {
+ canCreate: boolean;
+ loading: boolean;
+ qualityGates: T.QualityGate[];
+}
+
+class App extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { canCreate: false, loading: true, qualityGates: [] };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchQualityGates();
+ addWhitePageClass();
+ addSideBarClass();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ removeWhitePageClass();
+ removeSideBarClass();
+ }
+
+ fetchQualityGates = () => {
+ const { organization } = this.props;
+ return fetchQualityGates({ organization: organization && organization.key }).then(
+ ({ actions, qualitygates: qualityGates }) => {
+ if (this.mounted) {
+ this.setState({ canCreate: actions.create, loading: false, qualityGates });
+
+ if (qualityGates && qualityGates.length === 1 && !actions.create) {
+ this.props.router.replace(
+ getQualityGateUrl(String(qualityGates[0].id), organization && organization.key)
+ );
+ }
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ handleSetDefault = (qualityGate: T.QualityGate) => {
+ this.setState(({ qualityGates }) => {
+ return {
+ qualityGates: qualityGates.map(candidate => {
+ if (candidate.isDefault || candidate.id === qualityGate.id) {
+ return { ...candidate, isDefault: candidate.id === qualityGate.id };
+ }
+ return candidate;
+ })
+ };
+ });
+ };
+
+ renderContent() {
+ const { id } = this.props.params;
+ const organizationKey = this.props.organization && this.props.organization.key;
+ if (id !== undefined) {
+ return (
+ <Details
+ id={id}
+ onSetDefault={this.handleSetDefault}
+ organization={organizationKey}
+ qualityGates={this.state.qualityGates}
+ refreshQualityGates={this.fetchQualityGates}
+ />
+ );
+ } else {
+ return (
+ <Intro
+ organization={organizationKey}
+ qualityGates={this.state.qualityGates}
+ router={this.props.router}
+ />
+ );
+ }
+ }
+
+ render() {
+ const { canCreate, qualityGates } = this.state;
+ const defaultTitle = translate('quality_gates.page');
+ const organization = this.props.organization && this.props.organization.key;
+
+ return (
+ <>
+ <Helmet defaultTitle={defaultTitle} titleTemplate={'%s - ' + defaultTitle} />
+ <div className="layout-page" id="quality-gates-page">
+ <Suggestions suggestions="quality_gates" />
+
+ <ScreenPositionHelper className="layout-page-side-outer">
+ {({ top }) => (
+ <div className="layout-page-side" style={{ top }}>
+ <div className="layout-page-side-inner">
+ <div className="layout-page-filters">
+ <ListHeader
+ canCreate={canCreate}
+ organization={organization}
+ refreshQualityGates={this.fetchQualityGates}
+ />
+ {qualityGates.length > 0 && (
+ <List organization={organization} qualityGates={qualityGates} />
+ )}
+ </div>
+ </div>
+ </div>
+ )}
+ </ScreenPositionHelper>
+
+ <DeferredSpinner loading={this.state.loading}>{this.renderContent()}</DeferredSpinner>
+ </div>
+ </>
+ );
+ }
+}
+
+export default App;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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 DetailsHeader from './DetailsHeader';
+import DetailsContent from './DetailsContent';
+import { getMetrics, Store } from '../../../store/rootReducer';
+import { fetchMetrics } from '../../../store/rootActions';
+import { fetchQualityGate } from '../../../api/quality-gates';
+import { checkIfDefault, addCondition, replaceCondition, deleteCondition } from '../utils';
+
+interface OwnProps {
+ id: string;
+ onSetDefault: (qualityGate: T.QualityGate) => void;
+ organization?: string;
+ qualityGates: T.QualityGate[];
+ refreshQualityGates: () => Promise<void>;
+}
+
+interface StateToProps {
+ metrics: { [key: string]: T.Metric };
+}
+
+interface DispatchToProps {
+ fetchMetrics: () => void;
+}
+
+type Props = StateToProps & DispatchToProps & OwnProps;
+
+interface State {
+ loading: boolean;
+ qualityGate?: T.QualityGate;
+}
+
+export class Details extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { loading: true };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.props.fetchMetrics();
+ this.fetchDetails();
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ if (prevProps.id !== this.props.id) {
+ this.fetchDetails();
+ }
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchDetails = () => {
+ const { id, organization } = this.props;
+ this.setState({ loading: true });
+ return fetchQualityGate({ id, organization }).then(
+ qualityGate => {
+ if (this.mounted) {
+ this.setState({ loading: false, qualityGate });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ handleAddCondition = (condition: T.Condition) => {
+ this.setState(({ qualityGate }) => {
+ if (!qualityGate) {
+ return null;
+ }
+ return { qualityGate: addCondition(qualityGate, condition) };
+ });
+ };
+
+ handleSaveCondition = (newCondition: T.Condition, oldCondition: T.Condition) => {
+ this.setState(({ qualityGate }) => {
+ if (!qualityGate) {
+ return null;
+ }
+ return { qualityGate: replaceCondition(qualityGate, newCondition, oldCondition) };
+ });
+ };
+
+ handleRemoveCondition = (condition: T.Condition) => {
+ this.setState(({ qualityGate }) => {
+ if (!qualityGate) {
+ return null;
+ }
+ return { qualityGate: deleteCondition(qualityGate, condition) };
+ });
+ };
+
+ handleSetDefault = () => {
+ this.setState(({ qualityGate }) => {
+ if (!qualityGate) {
+ return null;
+ }
+ this.props.onSetDefault(qualityGate);
+ const newQualityGate: T.QualityGate = {
+ ...qualityGate,
+ actions: { ...qualityGate.actions, delete: false, setAsDefault: false }
+ };
+ return { qualityGate: newQualityGate };
+ });
+ };
+
+ render() {
+ const { organization, metrics, refreshQualityGates } = this.props;
+ const { qualityGate } = this.state;
+
+ if (!qualityGate) {
+ return null;
+ }
+
+ return (
+ <>
+ <Helmet title={qualityGate.name} />
+ <div className="layout-page-main">
+ <DetailsHeader
+ onSetDefault={this.handleSetDefault}
+ organization={organization}
+ qualityGate={qualityGate}
+ refreshItem={this.fetchDetails}
+ refreshList={refreshQualityGates}
+ />
+ <DetailsContent
+ isDefault={checkIfDefault(qualityGate, this.props.qualityGates)}
+ metrics={metrics}
+ onAddCondition={this.handleAddCondition}
+ onRemoveCondition={this.handleRemoveCondition}
+ onSaveCondition={this.handleSaveCondition}
+ organization={organization}
+ qualityGate={qualityGate}
+ />
+ </div>
+ </>
+ );
+ }
+}
+
+const mapDispatchToProps: DispatchToProps = { fetchMetrics };
+
+const mapStateToProps = (state: Store): StateToProps => ({
+ metrics: getMetrics(state)
+});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Details);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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 { withRouter, WithRouterProps } from 'react-router';
-import Helmet from 'react-helmet';
-import { connect } from 'react-redux';
-import DetailsHeader from './DetailsHeader';
-import DetailsContent from './DetailsContent';
-import { getMetrics, Store } from '../../../store/rootReducer';
-import { fetchMetrics } from '../../../store/rootActions';
-import { fetchQualityGate } from '../../../api/quality-gates';
-import { checkIfDefault, addCondition, replaceCondition, deleteCondition } from '../utils';
-
-interface OwnProps {
- onSetDefault: (qualityGate: T.QualityGate) => void;
- organization?: string;
- params: { id: number };
- qualityGates: T.QualityGate[];
- refreshQualityGates: () => Promise<void>;
-}
-
-interface StateToProps {
- metrics: { [key: string]: T.Metric };
-}
-
-interface DispatchToProps {
- fetchMetrics: () => void;
-}
-
-type Props = StateToProps & DispatchToProps & OwnProps & WithRouterProps;
-
-interface State {
- loading: boolean;
- qualityGate?: T.QualityGate;
-}
-
-export class DetailsApp extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { loading: true };
-
- componentDidMount() {
- this.mounted = true;
- this.props.fetchMetrics();
- this.fetchDetails();
- }
-
- componentWillReceiveProps(nextProps: Props) {
- if (nextProps.params.id !== this.props.params.id) {
- this.setState({ loading: true });
- this.fetchDetails(nextProps);
- }
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchDetails = ({ organization, params } = this.props) => {
- return fetchQualityGate({ id: params.id, organization }).then(
- qualityGate => {
- if (this.mounted) {
- this.setState({ loading: false, qualityGate });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- handleAddCondition = (condition: T.Condition) => {
- this.setState(({ qualityGate }) => {
- if (!qualityGate) {
- return null;
- }
- return { qualityGate: addCondition(qualityGate, condition) };
- });
- };
-
- handleSaveCondition = (newCondition: T.Condition, oldCondition: T.Condition) => {
- this.setState(({ qualityGate }) => {
- if (!qualityGate) {
- return null;
- }
- return { qualityGate: replaceCondition(qualityGate, newCondition, oldCondition) };
- });
- };
-
- handleRemoveCondition = (condition: T.Condition) => {
- this.setState(({ qualityGate }) => {
- if (!qualityGate) {
- return null;
- }
- return { qualityGate: deleteCondition(qualityGate, condition) };
- });
- };
-
- handleSetDefault = () => {
- this.setState(({ qualityGate }) => {
- if (!qualityGate) {
- return null;
- }
- this.props.onSetDefault(qualityGate);
- const newQualityGate: T.QualityGate = {
- ...qualityGate,
- actions: { ...qualityGate.actions, delete: false, setAsDefault: false }
- };
- return { qualityGate: newQualityGate };
- });
- };
-
- render() {
- const { organization, metrics, refreshQualityGates } = this.props;
- const { qualityGate } = this.state;
-
- if (!qualityGate) {
- return null;
- }
-
- return (
- <>
- <Helmet title={qualityGate.name} />
- <div className="layout-page-main">
- <DetailsHeader
- onSetDefault={this.handleSetDefault}
- organization={organization}
- qualityGate={qualityGate}
- refreshItem={this.fetchDetails}
- refreshList={refreshQualityGates}
- />
- <DetailsContent
- isDefault={checkIfDefault(qualityGate, this.props.qualityGates)}
- metrics={metrics}
- onAddCondition={this.handleAddCondition}
- onRemoveCondition={this.handleRemoveCondition}
- onSaveCondition={this.handleSaveCondition}
- organization={organization}
- qualityGate={qualityGate}
- />
- </div>
- </>
- );
- }
-}
-
-const mapDispatchToProps: DispatchToProps = { fetchMetrics };
-
-const mapStateToProps = (state: Store): StateToProps => ({
- metrics: getMetrics(state)
-});
-
-export default withRouter(
- connect(
- mapStateToProps,
- mapDispatchToProps
- )(DetailsApp)
-);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 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 { withRouter, WithRouterProps } from 'react-router';
-import Helmet from 'react-helmet';
-import ListHeader from './ListHeader';
-import List from './List';
-import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
-import { fetchQualityGates } from '../../../api/quality-gates';
-import { translate } from '../../../helpers/l10n';
-import {
- addSideBarClass,
- addWhitePageClass,
- removeSideBarClass,
- removeWhitePageClass
-} from '../../../helpers/pages';
-import { getQualityGateUrl } from '../../../helpers/urls';
-import '../../../components/search-navigator.css';
-import '../styles.css';
-
-interface Props extends WithRouterProps {
- children: React.ReactElement<{
- organization?: string;
- refreshQualityGates: () => Promise<void>;
- }>;
- organization: Pick<T.Organization, 'key'>;
-}
-
-interface State {
- canCreate: boolean;
- loading: boolean;
- qualityGates: T.QualityGate[];
-}
-
-class QualityGatesApp extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = { canCreate: false, loading: true, qualityGates: [] };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchQualityGates();
- addWhitePageClass();
- addSideBarClass();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- removeWhitePageClass();
- removeSideBarClass();
- }
-
- fetchQualityGates = () => {
- const { organization } = this.props;
- return fetchQualityGates({ organization: organization && organization.key }).then(
- ({ actions, qualitygates: qualityGates }) => {
- if (this.mounted) {
- this.setState({ canCreate: actions.create, loading: false, qualityGates });
-
- if (qualityGates && qualityGates.length === 1 && !actions.create) {
- this.props.router.replace(
- getQualityGateUrl(String(qualityGates[0].id), organization && organization.key)
- );
- }
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- handleSetDefault = (qualityGate: T.QualityGate) => {
- this.setState(({ qualityGates }) => {
- return {
- qualityGates: qualityGates.map(candidate => {
- if (candidate.isDefault || candidate.id === qualityGate.id) {
- return { ...candidate, isDefault: candidate.id === qualityGate.id };
- }
- return candidate;
- })
- };
- });
- };
-
- render() {
- const { children } = this.props;
- const { canCreate, loading, qualityGates } = this.state;
- const defaultTitle = translate('quality_gates.page');
- const organization = this.props.organization && this.props.organization.key;
-
- return (
- <>
- <Helmet defaultTitle={defaultTitle} titleTemplate={'%s - ' + defaultTitle} />
- <div className="layout-page" id="quality-gates-page">
- <Suggestions suggestions="quality_gates" />
-
- <ScreenPositionHelper className="layout-page-side-outer">
- {({ top }) => (
- <div className="layout-page-side" style={{ top }}>
- <div className="layout-page-side-inner">
- <div className="layout-page-filters">
- <ListHeader
- canCreate={canCreate}
- organization={organization}
- refreshQualityGates={this.fetchQualityGates}
- />
- {qualityGates.length > 0 && (
- <List organization={organization} qualityGates={qualityGates} />
- )}
- </div>
- </div>
- </div>
- )}
- </ScreenPositionHelper>
- {!loading &&
- React.cloneElement(children, {
- onSetDefault: this.handleSetDefault,
- organization,
- qualityGates,
- refreshQualityGates: this.fetchQualityGates
- })}
- </div>
- </>
- );
- }
-}
-
-export default withRouter(QualityGatesApp);
*/
import { lazyLoad } from '../../components/lazyLoad';
-const routes = [
- {
- component: lazyLoad(() => import('./components/QualityGatesApp')),
- childRoutes: [
- {
- indexRoute: { component: lazyLoad(() => import('./components/Intro')) }
- },
- {
- path: 'show/:id',
- component: lazyLoad(() => import('./components/DetailsApp'))
- }
- ]
- }
-];
+const App = lazyLoad(() => import('./components/App'));
+
+const routes = [{ indexRoute: { component: App } }, { path: 'show/:id', component: App }];
export default routes;