import { getComponentData } from '../../api/components';
import { getMeasures } from '../../api/measures';
import { getComponentNavigation } from '../../api/nav';
-import { fetchOrganizations } from '../../store/rootActions';
+import { fetchOrganization } from '../../store/rootActions';
import { STATUSES } from '../../apps/background-tasks/constants';
import {
isPullRequest,
interface Props {
appState: Pick<T.AppState, 'organizationsEnabled'>;
children: any;
- fetchOrganizations: (organizations: string[]) => void;
+ fetchOrganization: (organization: string) => void;
location: {
query: { branch?: string; id: string; pullRequest?: string };
};
const component = this.addQualifier({ ...nav, ...data });
if (this.props.appState.organizationsEnabled) {
- this.props.fetchOrganizations([component.organization]);
+ this.props.fetchOrganization(component.organization);
}
return component;
})
appState: getAppState(state)
});
-const mapDispatchToProps = { fetchOrganizations };
+const mapDispatchToProps = { fetchOrganization };
export default connect(
mapStateToProps,
const wrapper = shallow<ComponentContainer>(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'foo' } }}>
<Inner />
</ComponentContainer>
mount(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'moduleKey' } }}>
<Inner />
</ComponentContainer>
const wrapper = mount(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'portfolioKey' } }}>
<Inner />
</ComponentContainer>
const wrapper = shallow(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'portfolioKey' } }}>
<Inner />
</ComponentContainer>
const wrapper = shallow(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'foo', branch: 'feature' } }}>
<Inner />
</ComponentContainer>
it('loads organization', async () => {
(getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
- const fetchOrganizations = jest.fn();
+ const fetchOrganization = jest.fn();
mount(
<ComponentContainer
appState={{ organizationsEnabled: true }}
- fetchOrganizations={fetchOrganizations}
+ fetchOrganization={fetchOrganization}
location={{ query: { id: 'foo' } }}>
<Inner />
</ComponentContainer>
);
await new Promise(setImmediate);
- expect(fetchOrganizations).toBeCalledWith(['org']);
+ expect(fetchOrganization).toBeCalledWith('org');
});
it('fetches status', async () => {
mount(
<ComponentContainer
appState={{ organizationsEnabled: true }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'foo' } }}>
<Inner />
</ComponentContainer>
const wrapper = shallow(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'foo' } }}>
<Inner />
</ComponentContainer>
const wrapper = shallow(
<ComponentContainer
appState={{ organizationsEnabled: false }}
- fetchOrganizations={jest.fn()}
+ fetchOrganization={jest.fn()}
location={{ query: { id: 'foo' } }}>
<Inner />
</ComponentContainer>
import Extension from './Extension';
import NotFound from '../NotFound';
import { getOrganizationByKey, Store } from '../../../store/rootReducer';
-import { fetchOrganization } from '../../../apps/organizations/actions';
+import { fetchOrganization } from '../../../store/rootActions';
interface StateToProps {
organization?: T.Organization;
import { addGlobalSuccessMessage } from '../../store/globalMessages';
import { translate, translateWithParameters } from '../../helpers/l10n';
-export const fetchOrganization = (key: string) => (dispatch: Dispatch) => {
- return Promise.all([api.getOrganization(key), api.getOrganizationNavigation(key)]).then(
- ([organization, navigation]) => {
- if (organization) {
- const organizationWithPermissions = { ...organization, ...navigation };
- dispatch(actions.receiveOrganizations([organizationWithPermissions]));
- }
- }
- );
-};
-
export const createOrganization = (organization: T.OrganizationBase) => (
dispatch: Dispatch<any>
) => {
import { connect } from 'react-redux';
import { Location } from 'history';
import OrganizationNavigation from '../navigation/OrganizationNavigation';
-import { fetchOrganization } from '../actions';
import NotFound from '../../../app/components/NotFound';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import {
getMyOrganizations,
Store
} from '../../../store/rootReducer';
+import { fetchOrganization } from '../../../store/rootActions';
interface OwnProps {
children?: React.ReactNode;
}
}
-const mapDispatchToProps: DispatchToProps = { fetchMetrics };
+const mapDispatchToProps: DispatchToProps = {
+ fetchMetrics
+};
const mapStateToProps = (state: Store): StateToProps => ({
metrics: getMetrics(state)
--- /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 { shallow } from 'enzyme';
+import { Meta } from '../MetaContainer';
+import {
+ mockAppState,
+ mockCurrentUser,
+ mockOrganization,
+ mockComponent
+} from '../../../../helpers/testUtils';
+
+it('should render correctly', () => {
+ const wrapper = shallowRender();
+ expect(wrapper).toMatchSnapshot();
+ expect(metaQualityGateRendered(wrapper)).toBe(true);
+});
+
+it('should hide QG and QP links if the organization has a paid plan, and the user is not a member', () => {
+ const wrapper = shallowRender({
+ organization: mockOrganization({ key: 'other_key', subscription: 'PAID' })
+ });
+ expect(wrapper).toMatchSnapshot();
+ expect(metaQualityGateRendered(wrapper)).toBe(false);
+});
+
+it('should show QG and QP links if the organization has a paid plan, and the user is a member', () => {
+ const wrapper = shallowRender({
+ organization: mockOrganization({ subscription: 'PAID' })
+ });
+ expect(wrapper).toMatchSnapshot();
+ expect(metaQualityGateRendered(wrapper)).toBe(true);
+});
+
+function metaQualityGateRendered(wrapper: any) {
+ return wrapper.find('#overview-meta-quality-gate').exists();
+}
+
+function shallowRender(props: Partial<Meta['props']> = {}) {
+ return shallow(
+ <Meta
+ appState={mockAppState({ organizationsEnabled: true })}
+ component={mockComponent()}
+ currentUser={mockCurrentUser()}
+ onComponentChange={jest.fn()}
+ organization={mockOrganization()}
+ userOrganizations={[mockOrganization()]}
+ {...props}
+ />
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should hide QG and QP links if the organization has a paid plan, and the user is not a member 1`] = `
+<div
+ className="overview-meta"
+>
+ <div
+ className="overview-meta-card"
+ >
+ <h4
+ className="overview-meta-header"
+ >
+ overview.about_this_project.TRK
+ </h4>
+ <MetaTags
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ <MetaLinks
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ <div
+ className="overview-meta-card"
+ >
+ <MetaKey
+ componentKey="my-project"
+ qualifier="TRK"
+ />
+ <MetaOrganizationKey
+ organization="foo"
+ />
+ </div>
+</div>
+`;
+
+exports[`should render correctly 1`] = `
+<div
+ className="overview-meta"
+>
+ <div
+ className="overview-meta-card"
+ >
+ <h4
+ className="overview-meta-header"
+ >
+ overview.about_this_project.TRK
+ </h4>
+ <MetaTags
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ <div
+ className="overview-meta-card"
+ id="overview-meta-quality-gate"
+ >
+ <MetaQualityGate
+ organization="foo"
+ qualityGate={
+ Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ }
+ }
+ />
+ <Connect(MetaQualityProfiles)
+ headerClassName="big-spacer-top"
+ organization="foo"
+ profiles={
+ Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ]
+ }
+ />
+ </div>
+ <MetaLinks
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ <div
+ className="overview-meta-card"
+ >
+ <MetaKey
+ componentKey="my-project"
+ qualifier="TRK"
+ />
+ <MetaOrganizationKey
+ organization="foo"
+ />
+ </div>
+</div>
+`;
+
+exports[`should show QG and QP links if the organization has a paid plan, and the user is a member 1`] = `
+<div
+ className="overview-meta"
+>
+ <div
+ className="overview-meta-card"
+ >
+ <h4
+ className="overview-meta-header"
+ >
+ overview.about_this_project.TRK
+ </h4>
+ <MetaTags
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ <div
+ className="overview-meta-card"
+ id="overview-meta-quality-gate"
+ >
+ <MetaQualityGate
+ organization="foo"
+ qualityGate={
+ Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ }
+ }
+ />
+ <Connect(MetaQualityProfiles)
+ headerClassName="big-spacer-top"
+ organization="foo"
+ profiles={
+ Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ]
+ }
+ />
+ </div>
+ <MetaLinks
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "organization": "foo",
+ "qualifier": "TRK",
+ "qualityGate": Object {
+ "isDefault": true,
+ "key": "30",
+ "name": "Sonar way",
+ },
+ "qualityProfiles": Array [
+ Object {
+ "deleted": false,
+ "key": "my-qp",
+ "language": "ts",
+ "name": "Sonar way",
+ },
+ ],
+ "tags": Array [],
+ }
+ }
+ />
+ <div
+ className="overview-meta-card"
+ >
+ <MetaKey
+ componentKey="my-project"
+ qualifier="TRK"
+ />
+ <MetaOrganizationKey
+ organization="foo"
+ />
+ </div>
+</div>
+`;
import { connect } from 'react-redux';
import App from './App';
import { getCurrentUser, getOrganizationByKey, Store } from '../../../../store/rootReducer';
-import { fetchOrganization } from '../../../organizations/actions';
+import { fetchOrganization } from '../../../../store/rootActions';
interface OwnProps {
component: T.Component;
import { getAppState, getOrganizationByKey, getCurrentUser, Store } from '../../store/rootReducer';
import { receiveOrganizations } from '../../store/organizations';
import { changeProjectDefaultVisibility } from '../../api/permissions';
-import { fetchOrganization } from '../organizations/actions';
+import { fetchOrganization } from '../../store/rootActions';
interface StateProps {
appState: { defaultOrganization: string; qualifiers: string[] };
import * as auth from '../api/auth';
import { getLanguages } from '../api/languages';
import { getAllMetrics } from '../api/metrics';
-import { getOrganizations } from '../api/organizations';
+import { getOrganizations, getOrganization, getOrganizationNavigation } from '../api/organizations';
export function fetchLanguages() {
return (dispatch: Dispatch) => {
};
}
+export const fetchOrganization = (key: string) => (dispatch: Dispatch) => {
+ return Promise.all([getOrganization(key), getOrganizationNavigation(key)]).then(
+ ([organization, navigation]) => {
+ if (organization) {
+ const organizationWithPermissions = { ...organization, ...navigation };
+ dispatch(receiveOrganizations([organizationWithPermissions]));
+ }
+ }
+ );
+};
+
export function doLogin(login: string, password: string) {
return (dispatch: Dispatch<any>) =>
auth.login(login, password).then(