return getJSON('/api/qualitygates/list').catch(throwGlobalError);
}
-export function fetchQualityGate(id: string): Promise<QualityGate> {
+export function fetchQualityGate(id: number): Promise<QualityGate> {
return getJSON('/api/qualitygates/show', { id }).catch(throwGlobalError);
}
-export function createQualityGate(name: string): Promise<any> {
- return postJSON('/api/qualitygates/create', { name });
+export function createQualityGate(data: {
+ name: string;
+ organization?: string;
+}): Promise<QualityGate> {
+ return postJSON('/api/qualitygates/create', data).catch(throwGlobalError);
}
-export function deleteQualityGate(id: string): Promise<void> {
+export function deleteQualityGate(id: number): Promise<void> {
return post('/api/qualitygates/destroy', { id });
}
-export function renameQualityGate(id: string, name: string): Promise<void> {
- return post('/api/qualitygates/rename', { id, name });
+export function renameQualityGate(data: {
+ id: number;
+ name: string;
+ organization?: string;
+}): Promise<void | Response> {
+ return post('/api/qualitygates/rename', data).catch(throwGlobalError);
}
-export function copyQualityGate(id: string, name: string): Promise<any> {
- return postJSON('/api/qualitygates/copy', { id, name });
+export function copyQualityGate(data: {
+ id: number;
+ name: string;
+ organization?: string;
+}): Promise<QualityGate> {
+ return postJSON('/api/qualitygates/copy', data).catch(throwGlobalError);
}
-export function setQualityGateAsDefault(id: string): Promise<void | Response> {
+export function setQualityGateAsDefault(id: number): Promise<void | Response> {
return post('/api/qualitygates/set_as_default', { id }).catch(throwGlobalError);
}
-export function createCondition(gateId: string, condition: RequestData): Promise<any> {
+export function createCondition(gateId: number, condition: RequestData): Promise<any> {
return postJSON('/api/qualitygates/create_condition', { ...condition, gateId });
}
return postJSON('/api/qualitygates/update_condition', condition);
}
-export function deleteCondition(id: string): Promise<void> {
+export function deleteCondition(id: number): Promise<void> {
return post('/api/qualitygates/delete_condition', { id });
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 PropTypes from 'prop-types';
+import Modal from '../../../components/controls/Modal';
+import { copyQualityGate, QualityGate } from '../../../api/quality-gates';
+import { getQualityGateUrl } from '../../../helpers/urls';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ qualityGate: QualityGate;
+ onCopy: (newQualityGate: QualityGate) => void;
+ onClose: () => void;
+ organization?: string;
+}
+
+interface State {
+ loading: boolean;
+ name: string;
+}
+
+export default class CopyQualityGateForm extends React.PureComponent<Props, State> {
+ mounted: boolean;
+
+ static contextTypes = {
+ router: PropTypes.object
+ };
+
+ constructor(props: Props) {
+ super(props);
+ this.state = { loading: false, name: props.qualityGate.name };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
+ this.setState({ name: event.currentTarget.value });
+ };
+
+ handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { qualityGate, organization } = this.props;
+ const { name } = this.state;
+ if (name) {
+ this.setState({ loading: true });
+ copyQualityGate({ id: qualityGate.id, name, organization }).then(
+ qualityGate => {
+ this.props.onCopy(qualityGate);
+ this.props.onClose();
+ this.context.router.push(
+ getQualityGateUrl(String(qualityGate.id), this.props.organization)
+ );
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ }
+ };
+
+ render() {
+ const { qualityGate } = this.props;
+ const { loading, name } = this.state;
+ const header = translate('quality_gates.copy');
+ const submitDisabled = loading || !name || (qualityGate && qualityGate.name === name);
+
+ return (
+ <Modal contentLabel={header} onRequestClose={this.props.onClose}>
+ <form id="quality-gate-form" onSubmit={this.handleFormSubmit}>
+ <div className="modal-head">
+ <h2>{header}</h2>
+ </div>
+ <div className="modal-body">
+ <div className="modal-field">
+ <label htmlFor="quality-gate-form-name">
+ {translate('name')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ autoFocus={true}
+ id="quality-gate-form-name"
+ maxLength={100}
+ onChange={this.handleNameChange}
+ required={true}
+ size={50}
+ type="text"
+ value={name}
+ />
+ </div>
+ </div>
+ <div className="modal-foot">
+ {loading && <i className="spinner spacer-right" />}
+ <button disabled={submitDisabled} className="js-confirm">
+ {translate('copy')}
+ </button>
+ <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 PropTypes from 'prop-types';
+import Modal from '../../../components/controls/Modal';
+import { createQualityGate, QualityGate } from '../../../api/quality-gates';
+import { translate } from '../../../helpers/l10n';
+import { getQualityGateUrl } from '../../../helpers/urls';
+
+interface Props {
+ onCreate: (qualityGate: QualityGate) => void;
+ onClose: () => void;
+ organization?: string;
+}
+
+interface State {
+ loading: boolean;
+ name: string;
+}
+
+export default class CreateQualityGateForm extends React.PureComponent<Props, State> {
+ mounted: boolean;
+
+ static contextTypes = {
+ router: PropTypes.object
+ };
+
+ state = { loading: false, name: '' };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
+ this.setState({ name: event.currentTarget.value });
+ };
+
+ handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { organization } = this.props;
+ const { name } = this.state;
+ if (name) {
+ this.setState({ loading: true });
+ createQualityGate({ name, organization }).then(
+ qualityGate => {
+ this.props.onCreate(qualityGate);
+ this.context.router.push(getQualityGateUrl(String(qualityGate.id), organization));
+ this.props.onClose();
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ }
+ };
+
+ render() {
+ const { loading, name } = this.state;
+ const header = translate('quality_gates.rename');
+ const submitDisabled = loading || !name;
+
+ return (
+ <Modal contentLabel={header} onRequestClose={this.props.onClose}>
+ <form id="quality-gate-form" onSubmit={this.handleFormSubmit}>
+ <div className="modal-head">
+ <h2>{header}</h2>
+ </div>
+ <div className="modal-body">
+ <div className="modal-field">
+ <label htmlFor="quality-gate-form-name">
+ {translate('name')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ autoFocus={true}
+ id="quality-gate-form-name"
+ maxLength={100}
+ onChange={this.handleNameChange}
+ required={true}
+ size={50}
+ type="text"
+ value={name}
+ />
+ </div>
+ </div>
+ <div className="modal-foot">
+ {loading && <i className="spinner spacer-right" />}
+ <button disabled={submitDisabled} className="js-confirm">
+ {translate('save')}
+ </button>
+ <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>
+ );
+ }
+}
--- /dev/null
+import {} from '../../overview/qualityGate/QualityGate';
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 PropTypes from 'prop-types';
+import Modal from '../../../components/controls/Modal';
+import { getQualityGatesUrl } from '../../../helpers/urls';
+import { deleteQualityGate, QualityGate } from '../../../api/quality-gates';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+
+interface Props {
+ onClose: () => void;
+ onDelete: (qualityGate: QualityGate) => void;
+ organization?: string;
+ qualityGate: QualityGate;
+}
+
+interface State {
+ loading: boolean;
+}
+
+export default class DeleteQualityGateForm extends React.PureComponent<Props, State> {
+ mounted: boolean;
+
+ static contextTypes = {
+ router: PropTypes.object
+ };
+
+ state: State = { loading: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { organization, qualityGate } = this.props;
+ this.setState({ loading: true });
+ deleteQualityGate(qualityGate.id).then(
+ () => {
+ this.props.onDelete(qualityGate);
+ this.context.router.replace(getQualityGatesUrl(organization));
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ render() {
+ const { qualityGate } = this.props;
+ const header = translate('quality_gates.delete');
+
+ return (
+ <Modal contentLabel={header} onRequestClose={this.props.onClose}>
+ <form id="delete-profile-form" onSubmit={this.handleFormSubmit}>
+ <div className="modal-head">
+ <h2>{header}</h2>
+ </div>
+ <div className="modal-body">
+ <p>
+ {translateWithParameters('quality_gates.delete.confirm.message', qualityGate.name)}
+ </p>
+ </div>
+ <div className="modal-foot">
+ {this.state.loading && <i className="spinner spacer-right" />}
+ <button className="js-delete button-red" disabled={this.state.loading}>
+ {translate('delete')}
+ </button>
+ <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>
+ );
+ }
+}
import { fetchQualityGate, setQualityGateAsDefault } from '../../../api/quality-gates';
import DetailsHeader from './DetailsHeader';
import DetailsContent from './DetailsContent';
-import RenameView from '../views/rename-view';
-import CopyView from '../views/copy-view';
-import DeleteView from '../views/delete-view';
-import { getQualityGatesUrl, getQualityGateUrl } from '../../../helpers/urls';
export default class Details extends React.PureComponent {
static contextTypes = {
() => {}
);
- handleRenameClick = () => {
- const { qualityGate, onRename } = this.props;
- new RenameView({
- qualityGate,
- onRename: (qualityGate, newName) => {
- onRename(qualityGate, newName);
- }
- }).render();
- };
-
- handleCopyClick = () => {
- const { qualityGate, onCopy, organization } = this.props;
- const { router } = this.context;
- new CopyView({
- qualityGate,
- onCopy: newQualityGate => {
- onCopy(newQualityGate);
- router.push(getQualityGateUrl(newQualityGate.id, organization && organization.key));
- }
- }).render();
- };
-
- handleSetAsDefaultClick = () => {
- const { qualityGate, onSetAsDefault } = this.props;
- if (!qualityGate.isDefault) {
- setQualityGateAsDefault(qualityGate.id).then(() => onSetAsDefault(qualityGate), () => {});
- }
- };
-
- handleDeleteClick = () => {
- const { qualityGate, onDelete, organization } = this.props;
- const { router } = this.context;
- new DeleteView({
- qualityGate,
- onDelete: qualityGate => {
- onDelete(qualityGate);
- router.replace(getQualityGatesUrl(organization && organization.key));
- }
- }).render();
- };
-
render() {
- const { qualityGate, metrics } = this.props;
+ const { organization, metrics, qualityGate } = this.props;
const { onAddCondition, onDeleteCondition, onSaveCondition } = this.props;
if (!qualityGate) {
<Helmet title={qualityGate.name} />
<DetailsHeader
qualityGate={qualityGate}
- onRename={this.handleRenameClick}
- onCopy={this.handleCopyClick}
- onSetAsDefault={this.handleSetAsDefaultClick}
- onDelete={this.handleDeleteClick}
- organization={this.props.organization}
+ onRename={this.props.onRename}
+ onCopy={this.props.onCopy}
+ onSetAsDefault={this.props.onSetAsDefault}
+ onDelete={this.props.onDelete}
+ organization={organization && organization.key}
/>
<DetailsContent
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 BuiltInQualityGateBadge from './BuiltInQualityGateBadge';
-import { translate } from '../../../helpers/l10n';
-
-export default class DetailsHeader extends React.PureComponent {
- handleRenameClick = e => {
- e.preventDefault();
- this.props.onRename();
- };
-
- handleCopyClick = e => {
- e.preventDefault();
- this.props.onCopy();
- };
-
- handleSetAsDefaultClick = e => {
- e.preventDefault();
- this.props.onSetAsDefault();
- };
-
- handleDeleteClick = e => {
- e.preventDefault();
- this.props.onDelete();
- };
-
- render() {
- const { qualityGate } = this.props;
- const actions = qualityGate.actions || {};
- return (
- <div className="layout-page-header-panel layout-page-main-header issues-main-header">
- <div className="layout-page-header-panel-inner layout-page-main-header-inner">
- <div className="layout-page-main-inner">
- <h2 className="pull-left">
- {qualityGate.name}
- {qualityGate.isBuiltIn && <BuiltInQualityGateBadge className="spacer-left" />}
- </h2>
-
- <div className="pull-right">
- {actions.rename && (
- <button id="quality-gate-rename" onClick={this.handleRenameClick}>
- {translate('rename')}
- </button>
- )}
- {actions.copy && (
- <button
- className="little-spacer-left"
- id="quality-gate-copy"
- onClick={this.handleCopyClick}>
- {translate('copy')}
- </button>
- )}
- {actions.setAsDefault && (
- <button
- className="little-spacer-left"
- id="quality-gate-toggle-default"
- onClick={this.handleSetAsDefaultClick}>
- {translate('set_as_default')}
- </button>
- )}
- {actions.delete && (
- <button
- id="quality-gate-delete"
- className="little-spacer-left button-red"
- onClick={this.handleDeleteClick}>
- {translate('delete')}
- </button>
- )}
- </div>
- </div>
- </div>
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 BuiltInQualityGateBadge from './BuiltInQualityGateBadge';
+import RenameQualityGateForm from './RenameQualityGateForm';
+import CopyQualityGateForm from './CopyQualityGateForm';
+import DeleteQualityGateForm from './DeleteQualityGateForm';
+import { QualityGate, setQualityGateAsDefault } from '../../../api/quality-gates';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ qualityGate: QualityGate;
+ onRename: (qualityGate: QualityGate, newName: string) => void;
+ onCopy: (newQualityGate: QualityGate) => void;
+ onSetAsDefault: (qualityGate: QualityGate) => void;
+ onDelete: (qualityGate: QualityGate) => void;
+ organization?: string;
+}
+
+interface State {
+ openPopup?: string;
+}
+
+export default class DetailsHeader extends React.PureComponent<Props, State> {
+ state = { openPopup: undefined };
+
+ handleRenameClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ this.setState({ openPopup: 'rename' });
+ };
+
+ handleCopyClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ this.setState({ openPopup: 'copy' });
+ };
+
+ handleSetAsDefaultClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ const { qualityGate, onSetAsDefault } = this.props;
+ if (!qualityGate.isDefault) {
+ setQualityGateAsDefault(qualityGate.id).then(() => onSetAsDefault(qualityGate), () => {});
+ }
+ };
+
+ handleDeleteClick = (e: React.SyntheticEvent<HTMLButtonElement>) => {
+ e.preventDefault();
+ this.setState({ openPopup: 'delete' });
+ };
+
+ handleClosePopup = () => this.setState({ openPopup: undefined });
+
+ render() {
+ const { organization, qualityGate } = this.props;
+ const { openPopup } = this.state;
+ const actions = qualityGate.actions || ({} as any);
+ return (
+ <div className="layout-page-header-panel layout-page-main-header issues-main-header">
+ <div className="layout-page-header-panel-inner layout-page-main-header-inner">
+ <div className="layout-page-main-inner">
+ <h2 className="pull-left">
+ {qualityGate.name}
+ {qualityGate.isBuiltIn && <BuiltInQualityGateBadge className="spacer-left" />}
+ </h2>
+
+ <div className="pull-right">
+ {actions.rename && (
+ <button id="quality-gate-rename" onClick={this.handleRenameClick}>
+ {translate('rename')}
+ </button>
+ )}
+ {actions.copy && (
+ <button
+ className="little-spacer-left"
+ id="quality-gate-copy"
+ onClick={this.handleCopyClick}>
+ {translate('copy')}
+ </button>
+ )}
+ {actions.setAsDefault && (
+ <button
+ className="little-spacer-left"
+ id="quality-gate-toggle-default"
+ onClick={this.handleSetAsDefaultClick}>
+ {translate('set_as_default')}
+ </button>
+ )}
+ {actions.delete && (
+ <button
+ id="quality-gate-delete"
+ className="little-spacer-left button-red"
+ onClick={this.handleDeleteClick}>
+ {translate('delete')}
+ </button>
+ )}
+ {openPopup === 'rename' && (
+ <RenameQualityGateForm
+ onRename={this.props.onRename}
+ organization={organization}
+ onClose={this.handleClosePopup}
+ qualityGate={qualityGate}
+ />
+ )}
+
+ {openPopup === 'copy' && (
+ <CopyQualityGateForm
+ onCopy={this.props.onCopy}
+ organization={organization}
+ onClose={this.handleClosePopup}
+ qualityGate={qualityGate}
+ />
+ )}
+
+ {openPopup === 'delete' && (
+ <DeleteQualityGateForm
+ onDelete={this.props.onDelete}
+ organization={organization}
+ onClose={this.handleClosePopup}
+ qualityGate={qualityGate}
+ />
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
{qualityGates.map(qualityGate => (
<Link
key={qualityGate.id}
- to={getQualityGateUrl(qualityGate.id, organization && organization.key)}
+ to={getQualityGateUrl(String(qualityGate.id), organization && organization.key)}
activeClassName="active"
className="list-group-item"
data-id={qualityGate.id}>
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 CreateView from '../views/create-view';
-import { translate } from '../../../helpers/l10n';
-
-export default function ListHeader({ canCreate, onAdd }) {
- function handleAddClick(e) {
- e.preventDefault();
- new CreateView({ onAdd }).render();
- }
-
- return (
- <header className="page-header">
- <h1 className="page-title">{translate('quality_gates.page')}</h1>
- {canCreate && (
- <div className="page-actions">
- <button id="quality-gate-add" onClick={handleAddClick}>
- {translate('create')}
- </button>
- </div>
- )}
- </header>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 CreateQualityGateForm from '../components/CreateQualityGateForm';
+import { QualityGate } from '../../../api/quality-gates';
+import { translate } from '../../../helpers/l10n';
+import { Organization } from '../../../app/types';
+
+interface Props {
+ canCreate: boolean;
+ onAdd: (qualityGate: QualityGate) => void;
+ organization?: Organization;
+}
+
+interface State {
+ createQualityGateOpen: boolean;
+}
+
+export default class ListHeader extends React.PureComponent<Props, State> {
+ state = { createQualityGateOpen: false };
+
+ openCreateQualityGateForm = () => this.setState({ createQualityGateOpen: true });
+ closeCreateQualityGateForm = () => this.setState({ createQualityGateOpen: false });
+
+ render() {
+ const { organization } = this.props;
+
+ return (
+ <header className="page-header">
+ <h1 className="page-title">{translate('quality_gates.page')}</h1>
+ {this.props.canCreate && (
+ <div className="page-actions">
+ <button id="quality-gate-add" onClick={this.openCreateQualityGateForm}>
+ {translate('create')}
+ </button>
+ </div>
+ )}
+ {this.state.createQualityGateOpen && (
+ <CreateQualityGateForm
+ onClose={this.closeCreateQualityGateForm}
+ onCreate={this.props.onAdd}
+ organization={organization && organization.key}
+ />
+ )}
+ </header>
+ );
+ }
+}
updateStore({ actions, qualityGates });
if (qualityGates && qualityGates.length === 1 && !actions.create) {
this.context.router.replace(
- getQualityGateUrl(qualityGates[0].id, organization && organization.key)
+ getQualityGateUrl(String(qualityGates[0].id), organization && organization.key)
);
}
});
- handleAdd = qualityGate => {
- const { addQualityGate, organization } = this.props;
- const { router } = this.context;
-
- addQualityGate(qualityGate);
- router.push(getQualityGateUrl(qualityGate.id, organization && organization.key));
- };
-
render() {
const { children, qualityGates, actions, organization } = this.props;
const defaultTitle = translate('quality_gates.page');
<div className="layout-page-side" style={{ top }}>
<div className="layout-page-side-inner">
<div className="layout-page-filters">
- <ListHeader canCreate={actions && actions.create} onAdd={this.handleAdd} />
+ <ListHeader
+ canCreate={actions && actions.create}
+ onAdd={this.props.addQualityGate}
+ organization={organization}
+ />
{qualityGates && <List organization={organization} qualityGates={qualityGates} />}
</div>
</div>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 Modal from '../../../components/controls/Modal';
+import { QualityGate, renameQualityGate } from '../../../api/quality-gates';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ qualityGate: QualityGate;
+ onRename: (qualityGate: QualityGate, newName: string) => void;
+ onClose: () => void;
+ organization?: string;
+}
+
+interface State {
+ loading: boolean;
+ name: string;
+}
+
+export default class RenameQualityGateForm extends React.PureComponent<Props, State> {
+ mounted: boolean;
+
+ constructor(props: Props) {
+ super(props);
+ this.state = { loading: false, name: props.qualityGate.name };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
+ this.setState({ name: event.currentTarget.value });
+ };
+
+ handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { qualityGate, organization } = this.props;
+ const { name } = this.state;
+ if (name) {
+ this.setState({ loading: true });
+ renameQualityGate({ id: qualityGate.id, name, organization }).then(
+ () => {
+ this.props.onRename(qualityGate, name);
+ this.props.onClose();
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ }
+ };
+
+ render() {
+ const { qualityGate } = this.props;
+ const { loading, name } = this.state;
+ const header = translate('quality_gates.rename');
+ const submitDisabled = loading || !name || (qualityGate && qualityGate.name === name);
+
+ return (
+ <Modal contentLabel={header} onRequestClose={this.props.onClose}>
+ <form id="quality-gate-form" onSubmit={this.handleFormSubmit}>
+ <div className="modal-head">
+ <h2>{header}</h2>
+ </div>
+ <div className="modal-body">
+ <div className="modal-field">
+ <label htmlFor="quality-gate-form-name">
+ {translate('name')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ autoFocus={true}
+ id="quality-gate-form-name"
+ maxLength={100}
+ onChange={this.handleNameChange}
+ required={true}
+ size={50}
+ type="text"
+ value={name}
+ />
+ </div>
+ </div>
+ <div className="modal-foot">
+ {loading && <i className="spinner spacer-right" />}
+ <button disabled={submitDisabled} className="js-confirm">
+ {translate('rename')}
+ </button>
+ <a href="#" className="js-modal-close" onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>
+ );
+ }
+}
+++ /dev/null
-<form id="quality-gate-form">
- <div class="modal-head">
- <h2>{{t 'quality_gates' method }}</h2>
- </div>
- <div class="modal-body">
- <div class="js-modal-messages"></div>
- <div class="modal-field">
- <label for="quality-gate-form-name">{{t 'name'}} <em class="mandatory">*</em></label>
- <input id="quality-gate-form-name" type="text" size="50" maxlength="100" value="{{name}}" required>
- </div>
- </div>
- <div class="modal-foot">
- <button id="quality-gate-form-submit">
- {{#eq method 'rename'}}{{t 'save'}}{{/eq}}
- {{#eq method 'copy'}}{{t 'copy'}}{{/eq}}
- {{#eq method 'create'}}{{t 'create'}}{{/eq}}
- </button>
- <a id="quality-gate-form-cancel" href="#" class="js-modal-close">{{t 'cancel'}}</a>
- </div>
-</form>
+++ /dev/null
-<form id="delete-gate-form">
- <div class="modal-head">
- <h2>{{t 'quality_gates.delete'}}</h2>
- </div>
- <div class="modal-body">
- <div class="js-modal-messages"></div>
- {{#if isDefault}}
- {{tp 'quality_gates.delete.confirm.default' name}}
- {{else}}
- {{tp 'quality_gates.delete.confirm.message' name}}
- {{/if}}
- </div>
- <div class="modal-foot">
- <button id="delete-gate-submit">{{t 'delete'}}</button>
- <a href="#" class="js-modal-close" id="delete-gate-cancel">{{t 'cancel'}}</a>
- </div>
-</form>
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 ModalForm from '../../../components/common/modal-form';
-import Template from '../templates/quality-gate-form.hbs';
-import { copyQualityGate } from '../../../api/quality-gates';
-import { parseError } from '../../../helpers/request';
-
-export default ModalForm.extend({
- template: Template,
-
- onFormSubmit() {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
- this.disableForm();
- this.sendRequest();
- },
-
- sendRequest() {
- const { id } = this.options.qualityGate;
- const name = this.$('#quality-gate-form-name').val();
-
- copyQualityGate(id, name).then(
- qualityGate => {
- this.destroy();
- this.options.onCopy(qualityGate);
- },
- error => {
- this.enableForm();
- parseError(error).then(msg => this.showErrors([{ msg }]));
- }
- );
- },
-
- serializeData() {
- return { method: 'copy', ...this.options.qualityGate };
- }
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 ModalForm from '../../../components/common/modal-form';
-import Template from '../templates/quality-gate-form.hbs';
-import { createQualityGate } from '../../../api/quality-gates';
-import { parseError } from '../../../helpers/request';
-
-export default ModalForm.extend({
- template: Template,
-
- onFormSubmit() {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
- this.disableForm();
- this.sendRequest();
- },
-
- sendRequest() {
- const name = this.$('#quality-gate-form-name').val();
-
- createQualityGate(name).then(
- qualityGate => {
- this.destroy();
- this.options.onAdd(qualityGate);
- },
- error => {
- this.enableForm();
- parseError(error).then(msg => this.showErrors([{ msg }]));
- }
- );
- },
-
- serializeData() {
- return { method: 'create' };
- }
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 ModalForm from '../../../components/common/modal-form';
-import Template from '../templates/quality-gates-delete.hbs';
-import { deleteQualityGate } from '../../../api/quality-gates';
-import { parseError } from '../../../helpers/request';
-
-export default ModalForm.extend({
- template: Template,
-
- onFormSubmit() {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
- this.disableForm();
- this.sendRequest();
- },
-
- sendRequest() {
- const { id } = this.options.qualityGate;
-
- deleteQualityGate(id).then(
- () => {
- this.destroy();
- this.options.onDelete(this.options.qualityGate);
- },
- error => {
- this.enableForm();
- parseError(error).then(msg => this.showErrors([{ msg }]));
- }
- );
- },
-
- serializeData() {
- return this.options.qualityGate;
- }
-});
export default Marionette.ItemView.extend({
template: () => {},
+ initialize(options) {
+ this.organization = options.organization;
+ },
+
onRender() {
const { qualityGate } = this.options;
+ const extra = {
+ gateId: qualityGate.id
+ };
+ if (this.organization) {
+ extra.organization = this.organization.key;
+ }
+
new SelectList({
el: this.options.container,
width: '100%',
searchUrl: window.baseUrl + '/api/qualitygates/search?gateId=' + qualityGate.id,
selectUrl: window.baseUrl + '/api/qualitygates/select',
deselectUrl: window.baseUrl + '/api/qualitygates/deselect',
- extra: {
- gateId: qualityGate.id
- },
+ extra,
selectParameter: 'projectId',
selectParameterValue: 'id',
labels: {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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 ModalForm from '../../../components/common/modal-form';
-import Template from '../templates/quality-gate-form.hbs';
-import { renameQualityGate } from '../../../api/quality-gates';
-import { parseError } from '../../../helpers/request';
-
-export default ModalForm.extend({
- template: Template,
-
- onFormSubmit() {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
- this.disableForm();
- this.sendRequest();
- },
-
- sendRequest() {
- const { id } = this.options.qualityGate;
- const name = this.$('#quality-gate-form-name').val();
-
- renameQualityGate(id, name).then(
- () => {
- this.destroy();
- this.options.onRename(this.options.qualityGate, name);
- },
- error => {
- this.enableForm();
- parseError(error).then(msg => this.showErrors([{ msg }]));
- }
- );
- },
-
- serializeData() {
- return { method: 'rename', ...this.options.qualityGate };
- }
-});