aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2018-05-02 12:00:07 +0200
committerSonarTech <sonartech@sonarsource.com>2018-05-03 20:20:49 +0200
commit8b16ffe330aecd26680dc46a0ba229af058132d4 (patch)
treef156ee63c8f7ad8c30b060dddf5125cf6802ce86 /server
parent51e5ed846a7db98e5fe3493aebad4a27b1d36459 (diff)
downloadsonarqube-8b16ffe330aecd26680dc46a0ba229af058132d4.tar.gz
sonarqube-8b16ffe330aecd26680dc46a0ba229af058132d4.zip
SQBILLING-93 SonarCloud notifies Muppet when an organization is deleted
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java11
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java18
-rw-r--r--server/sonar-web/src/main/js/api/organizations.ts17
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.js122
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx135
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.js34
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx67
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.js.snap174
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap84
11 files changed, 340 insertions, 335 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
index baba8d3af8c..797211a328b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
@@ -48,6 +48,11 @@ public interface BillingValidations {
*/
boolean canUpdateProjectVisibilityToPrivate(Organization organization);
+ /**
+ * Actions to do on an organization deletion
+ */
+ void onDelete(Organization organization);
+
class Organization {
private final String key;
private final String uuid;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
index f2494087d3a..717c323dd97 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
@@ -55,4 +55,12 @@ public class BillingValidationsProxyImpl implements BillingValidationsProxy {
public boolean canUpdateProjectVisibilityToPrivate(Organization organization) {
return billingValidationsExtension == null || billingValidationsExtension.canUpdateProjectVisibilityToPrivate(organization);
}
+
+ @Override
+ public void onDelete(Organization organization) {
+ if (billingValidationsExtension == null) {
+ return;
+ }
+ billingValidationsExtension.onDelete(organization);
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
index 3a486a15bd2..f7c8158dfcc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java
@@ -35,6 +35,8 @@ import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.component.ComponentCleanerService;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.DefaultOrganization;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.OrganizationFlags;
@@ -62,10 +64,11 @@ public class DeleteAction implements OrganizationsWsAction {
private final UserIndexer userIndexer;
private final QProfileFactory qProfileFactory;
private final ProjectLifeCycleListeners projectLifeCycleListeners;
+ private final BillingValidationsProxy billingValidations;
- public DeleteAction(UserSession userSession, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider,
- ComponentCleanerService componentCleanerService, OrganizationFlags organizationFlags, UserIndexer userIndexer,
- QProfileFactory qProfileFactory, ProjectLifeCycleListeners projectLifeCycleListeners) {
+ public DeleteAction(UserSession userSession, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider, ComponentCleanerService componentCleanerService,
+ OrganizationFlags organizationFlags, UserIndexer userIndexer, QProfileFactory qProfileFactory, ProjectLifeCycleListeners projectLifeCycleListeners,
+ BillingValidationsProxy billingValidations) {
this.userSession = userSession;
this.dbClient = dbClient;
this.defaultOrganizationProvider = defaultOrganizationProvider;
@@ -74,6 +77,7 @@ public class DeleteAction implements OrganizationsWsAction {
this.userIndexer = userIndexer;
this.qProfileFactory = qProfileFactory;
this.projectLifeCycleListeners = projectLifeCycleListeners;
+ this.billingValidations = billingValidations;
}
@Override
@@ -116,6 +120,7 @@ public class DeleteAction implements OrganizationsWsAction {
deleteQualityProfiles(dbSession, organization);
deleteQualityGates(dbSession, organization);
deleteOrganization(dbSession, organization);
+ billingValidations.onDelete(new BillingValidations.Organization(organization.getKey(), organization.getUuid()));
response.noContent();
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
index 78f7909f20d..5790c4e44f9 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/DeleteActionTest.java
@@ -59,6 +59,8 @@ import org.sonar.server.es.SearchOptions;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.organization.TestOrganizationFlags;
import org.sonar.server.project.Project;
@@ -119,11 +121,13 @@ public class DeleteActionTest {
private final WebhookDeliveryDao deliveryDao = dbClient.webhookDeliveryDao();
private final WebhookDeliveryDbTester webhookDeliveryDbTester = db.webhookDelivery();
private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class);
+ private BillingValidationsProxy billingValidationsProxy = mock(BillingValidationsProxy.class);
private WsActionTester wsTester = new WsActionTester(
- new DeleteAction(userSession, dbClient, defaultOrganizationProvider, spiedComponentCleanerService, organizationFlags, userIndexer, qProfileFactory, projectLifeCycleListeners));
+ new DeleteAction(userSession, dbClient, defaultOrganizationProvider, spiedComponentCleanerService, organizationFlags, userIndexer, qProfileFactory, projectLifeCycleListeners,
+ billingValidationsProxy));
@Test
- public void test_definition() {
+ public void definition() {
WebService.Action action = wsTester.getDef();
assertThat(action.key()).isEqualTo("delete");
assertThat(action.isPost()).isTrue();
@@ -542,6 +546,16 @@ public class DeleteActionTest {
}
}
+ @Test
+ public void call_billing_validation_on_delete() {
+ OrganizationDto organization = db.organizations().insert();
+ logInAsAdministrator(organization);
+
+ sendRequest(organization);
+
+ verify(billingValidationsProxy).onDelete(any(BillingValidations.Organization.class));
+ }
+
@DataProvider
public static Object[][] indexOfFailingProjectDeletion() {
return new Object[][]{
diff --git a/server/sonar-web/src/main/js/api/organizations.ts b/server/sonar-web/src/main/js/api/organizations.ts
index 943249011cd..cc321f31678 100644
--- a/server/sonar-web/src/main/js/api/organizations.ts
+++ b/server/sonar-web/src/main/js/api/organizations.ts
@@ -104,3 +104,20 @@ export function changeProjectVisibility(
): Promise<void> {
return post('/api/organizations/update_project_visibility', { organization, projectVisibility });
}
+
+export interface OrganizationBilling {
+ nclocCount: number;
+ subscription: {
+ plan?: {
+ maxNcloc: number;
+ price: number;
+ };
+ nextBillingDate?: string;
+ status: 'active' | 'inactive' | 'suspended';
+ trial: boolean;
+ };
+}
+
+export function getOrganizationBilling(organization: string): Promise<OrganizationBilling> {
+ return getJSON('/api/billing/show', { organization, p: 1, ps: 1 });
+}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.js
deleted file mode 100644
index df8a8333091..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import React from 'react';
-import Helmet from 'react-helmet';
-import { connect } from 'react-redux';
-import { withRouter } from 'react-router';
-import Modal from '../../../components/controls/Modal';
-import { translate } from '../../../helpers/l10n';
-import { getOrganizationByKey } from '../../../store/rootReducer';
-import { deleteOrganization } from '../actions';
-
-class OrganizationDelete extends React.PureComponent {
- /*:: props: {
- organization: {
- key: string,
- name: string
- },
- router: {
- replace: string => void
- },
- deleteOrganization: string => Promise<*>
- };
-*/
-
- state = {
- deleting: false,
- loading: false
- };
-
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
- this.setState({ loading: true });
- this.props.deleteOrganization(this.props.organization.key).then(() => {
- this.props.router.replace('/');
- });
- };
-
- handleOpenModal = () => {
- this.setState({ deleting: true });
- };
-
- handleCloseModal = () => {
- this.setState({ deleting: false });
- };
-
- renderModal() {
- return (
- <Modal contentLabel="modal form" onRequestClose={this.handleCloseModal}>
- <header className="modal-head">
- <h2>{translate('organization.delete')}</h2>
- </header>
-
- <form onSubmit={this.handleSubmit}>
- <div className="modal-body">{translate('organization.delete.question')}</div>
-
- <footer className="modal-foot">
- {this.state.loading ? (
- <i className="spinner" />
- ) : (
- <div>
- <button type="submit" className="button-red">
- {translate('delete')}
- </button>
- <button type="reset" className="button-link" onClick={this.handleCloseModal}>
- {translate('cancel')}
- </button>
- </div>
- )}
- </footer>
- </form>
- </Modal>
- );
- }
-
- render() {
- const title = translate('organization.delete');
- return (
- <div className="page page-limited">
- <Helmet title={title} />
-
- <header className="page-header">
- <h1 className="page-title">{title}</h1>
- <div className="page-description">{translate('organization.delete.description')}</div>
- </header>
-
- <div>
- <button
- className="button-red"
- disabled={this.state.loading || this.state.deleting}
- onClick={this.handleOpenModal}>
- {translate('delete')}
- </button>
- {this.state.deleting && this.renderModal()}
- </div>
- </div>
- );
- }
-}
-
-const mapDispatchToProps = { deleteOrganization };
-
-export default connect(null, mapDispatchToProps)(withRouter(OrganizationDelete));
-
-export const UnconnectedOrganizationDelete = OrganizationDelete;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx
new file mode 100644
index 00000000000..e68bb78f79c
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx
@@ -0,0 +1,135 @@
+/*
+ * 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 PropTypes from 'prop-types';
+import Helmet from 'react-helmet';
+import { connect } from 'react-redux';
+import ConfirmButton from '../../../components/controls/ConfirmButton';
+import { translate } from '../../../helpers/l10n';
+import { deleteOrganization } from '../actions';
+import { Organization } from '../../../app/types';
+import { Button } from '../../../components/ui/buttons';
+import { getOrganizationBilling } from '../../../api/organizations';
+
+interface DispatchToProps {
+ deleteOrganization: (key: string) => Promise<void>;
+}
+
+interface OwnProps {
+ organization: Pick<Organization, 'key' | 'name'>;
+}
+
+type Props = OwnProps & DispatchToProps;
+
+interface State {
+ hasPaidPlan?: boolean;
+}
+
+export class OrganizationDelete extends React.PureComponent<Props, State> {
+ mounted = false;
+ static contextTypes = {
+ router: PropTypes.object,
+ onSonarCloud: PropTypes.bool
+ };
+
+ state: State = {};
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchOrganizationPlanInfo();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchOrganizationPlanInfo = () => {
+ if (this.context.onSonarCloud) {
+ getOrganizationBilling(this.props.organization.key).then(
+ billingInfo => {
+ if (this.mounted) {
+ this.setState({
+ hasPaidPlan: billingInfo.subscription.status !== 'inactive'
+ });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ hasPaidPlan: false });
+ }
+ }
+ );
+ }
+ };
+
+ onDelete = () => {
+ return this.props.deleteOrganization(this.props.organization.key).then(() => {
+ this.context.router.replace('/');
+ });
+ };
+
+ render() {
+ const { hasPaidPlan } = this.state;
+ const { onSonarCloud } = this.context;
+ const title = translate('organization.delete');
+ return (
+ <>
+ <Helmet title={title} />
+ <div className="page page-limited">
+ <header className="page-header">
+ <h1 className="page-title">{title}</h1>
+ <div className="page-description">
+ {onSonarCloud
+ ? translate('organization.delete.description.sonarcloud')
+ : translate('organization.delete.description')}
+ </div>
+ </header>
+ <ConfirmButton
+ confirmButtonText={translate('delete')}
+ isDestructive={true}
+ modalBody={
+ <div>
+ {translate('organization.delete.question')}
+ {hasPaidPlan && (
+ <p className="alert alert-warn big-spacer-top">
+ {translate('organization.delete.sonarcloud.paid_plan_info')}
+ </p>
+ )}
+ </div>
+ }
+ modalHeader={translate('organization.delete')}
+ onConfirm={this.onDelete}>
+ {({ onClick }) => (
+ <Button className="js-custom-measure-delete button-red" onClick={onClick}>
+ {translate('delete')}
+ </Button>
+ )}
+ </ConfirmButton>
+ </div>
+ </>
+ );
+ }
+}
+
+const mapDispatchToProps: DispatchToProps = { deleteOrganization: deleteOrganization as any };
+
+export default connect<null, DispatchToProps, OwnProps>(null, mapDispatchToProps)(
+ OrganizationDelete
+);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.js
deleted file mode 100644
index 1be39fb949f..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { UnconnectedOrganizationDelete } from '../OrganizationDelete';
-
-it('smoke test', () => {
- const organization = { key: 'foo', name: 'Foo' };
- const wrapper = shallow(<UnconnectedOrganizationDelete organization={organization} />);
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({ deleting: true });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({ loading: true });
- expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx
new file mode 100644
index 00000000000..fff071d494a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx
@@ -0,0 +1,67 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { OrganizationDelete } from '../OrganizationDelete';
+import { getOrganizationBilling } from '../../../../api/organizations';
+import { waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/organizations', () => ({
+ getOrganizationBilling: jest.fn(() =>
+ Promise.resolve({ nclocCount: 1000, subscription: { status: 'active', trial: true } })
+ )
+}));
+
+beforeEach(() => {
+ (getOrganizationBilling as jest.Mock<any>).mockClear();
+});
+
+it('smoke test', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should redirect the page', async () => {
+ const deleteOrganization = jest.fn(() => Promise.resolve());
+ const replace = jest.fn();
+ const wrapper = getWrapper({ deleteOrganization }, { router: { replace } });
+ (wrapper.instance() as OrganizationDelete).onDelete();
+ await waitAndUpdate(wrapper);
+ expect(deleteOrganization).toHaveBeenCalledWith('foo');
+ expect(replace).toHaveBeenCalledWith('/');
+});
+
+it('should show a info message for paying organization', async () => {
+ const wrapper = getWrapper({}, { onSonarCloud: true });
+ await waitAndUpdate(wrapper);
+ expect(getOrganizationBilling).toHaveBeenCalledWith('foo');
+ expect(wrapper).toMatchSnapshot();
+});
+
+function getWrapper(props = {}, context = {}) {
+ return shallow(
+ <OrganizationDelete
+ deleteOrganization={jest.fn(() => Promise.resolve())}
+ organization={{ key: 'foo', name: 'Foo' }}
+ {...props}
+ />,
+
+ { context: { router: { replace: jest.fn() }, ...context } }
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.js.snap
deleted file mode 100644
index d8593ee9ffc..00000000000
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.js.snap
+++ /dev/null
@@ -1,174 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`smoke test 1`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.delete"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.delete
- </h1>
- <div
- className="page-description"
- >
- organization.delete.description
- </div>
- </header>
- <div>
- <button
- className="button-red"
- disabled={false}
- onClick={[Function]}
- >
- delete
- </button>
- </div>
-</div>
-`;
-
-exports[`smoke test 2`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.delete"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.delete
- </h1>
- <div
- className="page-description"
- >
- organization.delete.description
- </div>
- </header>
- <div>
- <button
- className="button-red"
- disabled={true}
- onClick={[Function]}
- >
- delete
- </button>
- <Modal
- contentLabel="modal form"
- onRequestClose={[Function]}
- >
- <header
- className="modal-head"
- >
- <h2>
- organization.delete
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- organization.delete.question
- </div>
- <footer
- className="modal-foot"
- >
- <div>
- <button
- className="button-red"
- type="submit"
- >
- delete
- </button>
- <button
- className="button-link"
- onClick={[Function]}
- type="reset"
- >
- cancel
- </button>
- </div>
- </footer>
- </form>
- </Modal>
- </div>
-</div>
-`;
-
-exports[`smoke test 3`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.delete"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.delete
- </h1>
- <div
- className="page-description"
- >
- organization.delete.description
- </div>
- </header>
- <div>
- <button
- className="button-red"
- disabled={true}
- onClick={[Function]}
- >
- delete
- </button>
- <Modal
- contentLabel="modal form"
- onRequestClose={[Function]}
- >
- <header
- className="modal-head"
- >
- <h2>
- organization.delete
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- organization.delete.question
- </div>
- <footer
- className="modal-foot"
- >
- <i
- className="spinner"
- />
- </footer>
- </form>
- </Modal>
- </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap
new file mode 100644
index 00000000000..0f7e0df211a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationDelete-test.tsx.snap
@@ -0,0 +1,84 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should show a info message for paying organization 1`] = `
+<React.Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.delete"
+ />
+ <div
+ className="page page-limited"
+ >
+ <header
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ organization.delete
+ </h1>
+ <div
+ className="page-description"
+ >
+ organization.delete.description.sonarcloud
+ </div>
+ </header>
+ <ConfirmButton
+ confirmButtonText="delete"
+ isDestructive={true}
+ modalBody={
+ <div>
+ organization.delete.question
+ <p
+ className="alert alert-warn big-spacer-top"
+ >
+ organization.delete.sonarcloud.paid_plan_info
+ </p>
+ </div>
+ }
+ modalHeader="organization.delete"
+ onConfirm={[Function]}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`smoke test 1`] = `
+<React.Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.delete"
+ />
+ <div
+ className="page page-limited"
+ >
+ <header
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ organization.delete
+ </h1>
+ <div
+ className="page-description"
+ >
+ organization.delete.description
+ </div>
+ </header>
+ <ConfirmButton
+ confirmButtonText="delete"
+ isDestructive={true}
+ modalBody={
+ <div>
+ organization.delete.question
+ </div>
+ }
+ modalHeader="organization.delete"
+ onConfirm={[Function]}
+ />
+ </div>
+</React.Fragment>
+`;