aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-07-06 11:40:29 +0200
committerSonarTech <sonartech@sonarsource.com>2018-07-11 20:21:22 +0200
commit29b0f28f9e4fc05ce662212a55aef45ad0278201 (patch)
treee167021989b32129e7f7695ff1fc5d43b797a05f /server
parentd34f9f46391d73cb89e9b7ead8e828dc65362829 (diff)
downloadsonarqube-29b0f28f9e4fc05ce662212a55aef45ad0278201.tar.gz
sonarqube-29b0f28f9e4fc05ce662212a55aef45ad0278201.zip
Migrate remaining of organization app to TS
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/api/organizations.ts19
-rw-r--r--server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx (renamed from server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.js)48
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/lists.css4
-rw-r--r--server/sonar-web/src/main/js/app/types.ts36
-rw-r--r--server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx9
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/actions.ts (renamed from server/sonar-web/src/main/js/apps/organizations/actions.js)155
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/MembersList.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/MembersList.js)32
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/MembersListHeader.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/MembersListHeader.js)15
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js)37
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js)92
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.js)31
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembers.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembers.js)58
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembersContainer.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembersContainer.js)41
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersList-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersList-test.js)12
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListHeader-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListHeader-test.js)2
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListItem-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListItem-test.js)28
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.js)8
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.js)18
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationMembers-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationMembers-test.js)28
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.js)17
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap)6
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListHeader-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListHeader-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap)30
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.js.snap)14
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationMembers-test.js.snap)7
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.js.snap)5
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js)42
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js)49
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js)25
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/AddMemberForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/AddMemberForm-test.js)20
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js)31
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js)15
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap)5
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap)5
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenu.tsx)31
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx (renamed from server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenu-test.tsx)20
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenu-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectCard.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsList-test.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/utils.ts1
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx13
-rw-r--r--server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.ts.snap (renamed from server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.js.snap)0
-rw-r--r--server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.ts (renamed from server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.js)14
-rw-r--r--server/sonar-web/src/main/js/store/organizations/duck.ts9
-rw-r--r--server/sonar-web/src/main/js/store/organizations/utils.ts (renamed from server/sonar-web/src/main/js/store/organizations/utils.js)3
58 files changed, 621 insertions, 478 deletions
diff --git a/server/sonar-web/src/main/js/api/organizations.ts b/server/sonar-web/src/main/js/api/organizations.ts
index 95918a609b3..ffa4cb24fb2 100644
--- a/server/sonar-web/src/main/js/api/organizations.ts
+++ b/server/sonar-web/src/main/js/api/organizations.ts
@@ -17,24 +17,25 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { getJSON, post, postJSON, RequestData } from '../helpers/request';
+import { getJSON, post, postJSON } from '../helpers/request';
import throwGlobalError from '../app/utils/throwGlobalError';
-import { LightOrganization, Paging } from '../app/types';
+import { Organization, OrganizationBase, Paging } from '../app/types';
export function getOrganizations(data: {
organizations?: string;
member?: boolean;
}): Promise<{
- organizations: LightOrganization[];
+ organizations: Organization[];
paging: Paging;
}> {
return getJSON('/api/organizations/search', data);
}
-export function getOrganization(key: string): Promise<any> {
- return getOrganizations({ organizations: key })
- .then(r => r.organizations.find((o: any) => o.key === key))
- .catch(throwGlobalError);
+export function getOrganization(key: string): Promise<Organization | undefined> {
+ return getJSON('/api/organizations/search', { organizations: key }).then(
+ r => r.organizations.find((o: Organization) => o.key === key),
+ throwGlobalError
+ );
}
interface GetOrganizationNavigation {
@@ -50,11 +51,11 @@ export function getOrganizationNavigation(key: string): Promise<GetOrganizationN
return getJSON('/api/navigation/organization', { organization: key }).then(r => r.organization);
}
-export function createOrganization(data: RequestData): Promise<any> {
+export function createOrganization(data: OrganizationBase): Promise<Organization> {
return postJSON('/api/organizations/create', data).then(r => r.organization, throwGlobalError);
}
-export function updateOrganization(key: string, changes: RequestData): Promise<void> {
+export function updateOrganization(key: string, changes: OrganizationBase): Promise<void> {
return post('/api/organizations/update', { key, ...changes });
}
diff --git a/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.js b/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx
index f93fc31fba3..30699762fc9 100644
--- a/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.js
+++ b/server/sonar-web/src/main/js/app/components/extensions/OrganizationPageExtension.tsx
@@ -17,37 +17,45 @@
* 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 * as React from 'react';
import { connect } from 'react-redux';
import ExtensionContainer from './ExtensionContainer';
import ExtensionNotFound from './ExtensionNotFound';
import { getOrganizationByKey } from '../../../store/rootReducer';
import { fetchOrganization } from '../../../apps/organizations/actions';
-/*:: import type { Organization } from '../../../app/types'; */
+import { Organization } from '../../../app/types';
-/*::
-type Props = {
- fetchOrganization: string => void,
- location: {},
- organization: Organization,
+interface StateToProps {
+ organization?: Organization;
+}
+
+interface DispatchProps {
+ fetchOrganization: (organizationKey: string) => void;
+}
+
+interface OwnProps {
+ location: {};
params: {
- extensionKey: string,
- organizationKey: string,
- pluginKey: string
- }
-};
-*/
+ extensionKey: string;
+ organizationKey: string;
+ pluginKey: string;
+ };
+}
-class OrganizationPageExtension extends React.PureComponent {
- /*:: props: Props; */
+type Props = OwnProps & StateToProps & DispatchProps;
- refreshOrganization = () => this.props.fetchOrganization(this.props.organization.key);
+class OrganizationPageExtension extends React.PureComponent<Props> {
+ refreshOrganization = () =>
+ this.props.organization && this.props.fetchOrganization(this.props.organization.key);
render() {
const { extensionKey, pluginKey } = this.props.params;
const { organization } = this.props;
+ if (!organization) {
+ return null;
+ }
+
let pages = organization.pages || [];
if (organization.canAdmin && organization.adminPages) {
pages = pages.concat(organization.adminPages);
@@ -66,10 +74,12 @@ class OrganizationPageExtension extends React.PureComponent {
}
}
-const mapStateToProps = (state, ownProps /*: Props */) => ({
+const mapStateToProps = (state: any, ownProps: OwnProps) => ({
organization: getOrganizationByKey(state, ownProps.params.organizationKey)
});
const mapDispatchToProps = { fetchOrganization };
-export default connect(mapStateToProps, mapDispatchToProps)(OrganizationPageExtension);
+export default connect<StateToProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
+ OrganizationPageExtension
+);
diff --git a/server/sonar-web/src/main/js/app/styles/init/lists.css b/server/sonar-web/src/main/js/app/styles/init/lists.css
index 3ebd22f84e8..f8cc8a5489e 100644
--- a/server/sonar-web/src/main/js/app/styles/init/lists.css
+++ b/server/sonar-web/src/main/js/app/styles/init/lists.css
@@ -66,11 +66,11 @@ ol.list-styled {
outline: none;
}
-.list-item-checkable-link[disabled] {
+.list-item-checkable-link.disabled {
opacity: 0.7;
}
-.list-item-checkable-link[disabled] a::before {
+.list-item-checkable-link.disabled a::before {
background-color: var(--gray80);
border-color: var(--gray80);
}
diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts
index 6d359757c55..bddfe372c4a 100644
--- a/server/sonar-web/src/main/js/app/types.ts
+++ b/server/sonar-web/src/main/js/app/types.ts
@@ -337,26 +337,36 @@ export interface Notification {
projectName?: string;
type: string;
}
-export interface LightOrganization {
- avatar?: string;
- description?: string;
- guarded?: boolean;
- isAdmin?: boolean;
- key: string;
- name: string;
- subscription?: OrganizationSubscription;
- url?: string;
-}
-export interface Organization extends LightOrganization {
- adminPages?: { key: string; name: string }[];
+export interface Organization extends OrganizationBase {
+ adminPages?: Extension[];
canAdmin?: boolean;
canDelete?: boolean;
canProvisionProjects?: boolean;
canUpdateProjectsVisibilityToPrivate?: boolean;
+ guarded?: boolean;
+ isAdmin?: boolean;
isDefault?: boolean;
- pages?: { key: string; name: string }[];
+ key: string;
+ pages?: Extension[];
projectVisibility?: Visibility;
+ subscription?: OrganizationSubscription;
+}
+
+export interface OrganizationBase {
+ avatar?: string;
+ description?: string;
+ key?: string;
+ name: string;
+ url?: string;
+}
+
+export interface OrganizationMember {
+ login: string;
+ name: string;
+ avatar?: string;
+ email?: string;
+ groupCount?: number;
}
export enum OrganizationSubscription {
diff --git a/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx b/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx
index acc43e6de4c..9416f11a790 100644
--- a/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx
+++ b/server/sonar-web/src/main/js/apps/account/organizations/CreateOrganizationForm.tsx
@@ -22,14 +22,14 @@ import { debounce } from 'lodash';
import { connect } from 'react-redux';
import * as PropTypes from 'prop-types';
import { createOrganization } from '../../organizations/actions';
-import { Organization } from '../../../app/types';
+import { Organization, OrganizationBase } from '../../../app/types';
import Modal from '../../../components/controls/Modal';
import DocTooltip from '../../../components/docs/DocTooltip';
import { translate } from '../../../helpers/l10n';
import { SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
interface DispatchProps {
- createOrganization: (fields: Partial<Organization>) => Promise<{ key: string }>;
+ createOrganization: (fields: OrganizationBase) => Promise<Organization>;
}
interface Props extends DispatchProps {
diff --git a/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx b/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx
index ff1789ee68c..ec8376ede5f 100644
--- a/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/explore/ExploreProjects.tsx
@@ -26,5 +26,12 @@ interface Props {
}
export default function ExploreProjects(props: Props) {
- return <AllProjectsContainer isFavorite={false} storageOptionsSuffix="explore" {...props} />;
+ return (
+ <AllProjectsContainer
+ isFavorite={false}
+ organization={undefined}
+ storageOptionsSuffix="explore"
+ {...props}
+ />
+ );
}
diff --git a/server/sonar-web/src/main/js/apps/organizations/actions.js b/server/sonar-web/src/main/js/apps/organizations/actions.ts
index 2de045b6e89..7f5d8897a97 100644
--- a/server/sonar-web/src/main/js/apps/organizations/actions.js
+++ b/server/sonar-web/src/main/js/apps/organizations/actions.ts
@@ -17,7 +17,7 @@
* 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 { Dispatch } from 'redux';
import * as api from '../../api/organizations';
import * as actions from '../../store/organizations/duck';
import * as membersActions from '../../store/organizationsMembers/actions';
@@ -27,149 +27,132 @@ import { onFail } from '../../store/rootActions';
import { getOrganizationMembersState } from '../../store/rootReducer';
import { addGlobalSuccessMessage } from '../../store/globalMessages/duck';
import { translate, translateWithParameters } from '../../helpers/l10n';
-/*:: import type { Organization } from '../../app/types'; */
-/*:: import type { Member } from '../../store/organizationsMembers/actions'; */
+import { Organization, OrganizationMember, OrganizationBase } from '../../app/types';
const PAGE_SIZE = 50;
-const onRejected = (dispatch /*: Function */) => (error /*: Object */) => {
+const onRejected = (dispatch: Dispatch<any>) => (error: any) => {
onFail(dispatch)(error);
- return Promise.reject();
+ return Promise.reject(error);
};
-const onMembersFail = (organization /*: string */, dispatch /*: Function */) => (
- error /*: Object */
-) => {
- onFail(dispatch)(error);
- dispatch(membersActions.updateState(organization, { loading: false }));
-};
-
-export const fetchOrganization = (key /*: string */) => (dispatch /*: Function */) => {
- const onFulfilled = ([organization, navigation]) => {
- if (organization) {
- const organizationWithPermissions = { ...organization, ...navigation };
- dispatch(actions.receiveOrganizations([organizationWithPermissions]));
- }
- };
-
+export const fetchOrganization = (key: string) => (dispatch: Dispatch<any>) => {
return Promise.all([api.getOrganization(key), api.getOrganizationNavigation(key)]).then(
- onFulfilled,
+ ([organization, navigation]) => {
+ if (organization) {
+ const organizationWithPermissions = { ...organization, ...navigation };
+ dispatch(actions.receiveOrganizations([organizationWithPermissions]));
+ }
+ },
onFail(dispatch)
);
};
-export const fetchOrganizationGroups = (organization /*: string */) => (
- dispatch /*: Function */
-) => {
+export const fetchOrganizationGroups = (organization: string) => (dispatch: Dispatch<any>) => {
return searchUsersGroups({ organization }).then(response => {
dispatch(actions.receiveOrganizationGroups(organization, response.groups));
}, onFail(dispatch));
};
-export const createOrganization = (fields /*: Object */) => (dispatch /*: Function */) => {
- const onFulfilled = (organization /*: Organization */) => {
+export const createOrganization = (organization: OrganizationBase) => (dispatch: Dispatch<any>) => {
+ return api.createOrganization(organization).then((organization: Organization) => {
dispatch(actions.createOrganization(organization));
dispatch(
addGlobalSuccessMessage(translateWithParameters('organization.created', organization.name))
);
return organization;
- };
-
- return api.createOrganization(fields).then(onFulfilled, onRejected(dispatch));
+ }, onRejected(dispatch));
};
-export const updateOrganization = (key /*: string */, changes /*: {} */) => (
- dispatch /*: Function */
+export const updateOrganization = (key: string, changes: OrganizationBase) => (
+ dispatch: Dispatch<any>
) => {
- const onFulfilled = () => {
+ return api.updateOrganization(key, changes).then(() => {
dispatch(actions.updateOrganization(key, changes));
dispatch(addGlobalSuccessMessage(translate('organization.updated')));
- };
-
- return api.updateOrganization(key, changes).then(onFulfilled, onFail(dispatch));
+ }, onFail(dispatch));
};
-export const deleteOrganization = (key /*: string */) => (dispatch /*: Function */) => {
- const onFulfilled = () => {
+export const deleteOrganization = (key: string) => (dispatch: Dispatch<any>) => {
+ return api.deleteOrganization(key).then(() => {
dispatch(actions.deleteOrganization(key));
dispatch(addGlobalSuccessMessage(translate('organization.deleted')));
- };
-
- return api.deleteOrganization(key).then(onFulfilled, onFail(dispatch));
+ }, onFail(dispatch));
};
const fetchMembers = (
- dispatch /*: Function */,
- receiveAction /*: Function */,
- key /*: string */,
- query /*: ?string */,
- page /*: ?number */
+ data: {
+ organization: string;
+ p?: number;
+ ps?: number;
+ q?: string;
+ },
+ dispatch: Dispatch<any>,
+ receiveAction: Function
) => {
- dispatch(membersActions.updateState(key, { loading: true }));
- const data /*: Object */ = {
- organization: key,
- ps: PAGE_SIZE
- };
- if (page != null) {
- data.p = page;
+ dispatch(membersActions.updateState(data.organization, { loading: true }));
+ if (data.ps === undefined) {
+ data.ps = PAGE_SIZE;
}
- if (query) {
- data.q = query;
+ if (!data.q) {
+ data.q = undefined;
}
- return api.searchMembers(data).then(response => {
- dispatch(
- receiveAction(key, response.users, {
- loading: false,
- total: response.paging.total,
- pageIndex: response.paging.pageIndex,
- query: query || null
- })
- );
- }, onMembersFail(key, dispatch));
+ return api.searchMembers(data).then(
+ response => {
+ dispatch(
+ receiveAction(data.organization, response.users, {
+ loading: false,
+ total: response.paging.total,
+ pageIndex: response.paging.pageIndex,
+ query: data.q || null
+ })
+ );
+ },
+ (error: any) => {
+ onFail(dispatch)(error);
+ dispatch(membersActions.updateState(data.organization, { loading: false }));
+ }
+ );
};
-export const fetchOrganizationMembers = (key /*: string */, query /*: ?string */) => (
- dispatch /*: Function */
-) => fetchMembers(dispatch, membersActions.receiveMembers, key, query);
+export const fetchOrganizationMembers = (key: string, query?: string) => (
+ dispatch: Dispatch<any>
+) => fetchMembers({ organization: key, q: query }, dispatch, membersActions.receiveMembers);
-export const fetchMoreOrganizationMembers = (key /*: string */, query /*: ?string */) => (
- dispatch /*: Function */,
- getState /*: Function */
+export const fetchMoreOrganizationMembers = (key: string, query?: string) => (
+ dispatch: Dispatch<any>,
+ getState: () => any
) =>
fetchMembers(
+ { organization: key, p: getOrganizationMembersState(getState(), key).pageIndex + 1, q: query },
dispatch,
- membersActions.receiveMoreMembers,
- key,
- query,
- getOrganizationMembersState(getState(), key).pageIndex + 1
+ membersActions.receiveMoreMembers
);
-export const addOrganizationMember = (key /*: string */, member /*: Member */) => (
- dispatch /*: Function */
+export const addOrganizationMember = (key: string, member: OrganizationMember) => (
+ dispatch: Dispatch<any>
) => {
return api
.addMember({ login: member.login, organization: key })
.then(user => dispatch(membersActions.addMember(key, user)), onFail(dispatch));
};
-export const removeOrganizationMember = (key /*: string */, member /*: Member */) => (
- dispatch /*: Function */
+export const removeOrganizationMember = (key: string, member: OrganizationMember) => (
+ dispatch: Dispatch<any>
) => {
dispatch(membersActions.removeMember(key, member));
- return api.removeMember({ login: member.login, organization: key }).catch((
- error /*: Object */
- ) => {
+ return api.removeMember({ login: member.login, organization: key }).catch((error: any) => {
onFail(dispatch)(error);
dispatch(membersActions.addMember(key, member));
});
};
export const updateOrganizationMemberGroups = (
- organization /*: Organization */,
- member /*: Member */,
- add /*: Array<string> */,
- remove /*: Array<string> */
-) => (dispatch /*: Function */) => {
+ organization: Organization,
+ member: OrganizationMember,
+ add: string[],
+ remove: string[]
+) => (dispatch: Dispatch<any>) => {
dispatch(
receiveUser({
...member,
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/MembersList.js b/server/sonar-web/src/main/js/apps/organizations/components/MembersList.tsx
index 4ed74e4169e..641486606b5 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/MembersList.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/MembersList.tsx
@@ -17,25 +17,23 @@
* 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 * as React from 'react';
import MembersListItem from './MembersListItem';
-/*:: import type { Member } from '../../../store/organizationsMembers/actions'; */
-/*:: import type { Organization, Group } from '../../../app/types'; */
+import { Group, Organization, OrganizationMember } from '../../../app/types';
-/*::
-type Props = {
- members: Array<Member>,
- organizationGroups: Array<Group>,
- organization: Organization,
- removeMember: Member => void,
- updateMemberGroups: (member: Member, add: Array<string>, remove: Array<string>) => void
-};
-*/
-
-export default class MembersList extends React.PureComponent {
- /*:: props: Props; */
+interface Props {
+ members: OrganizationMember[];
+ organizationGroups: Group[];
+ organization: Organization;
+ removeMember: (member: OrganizationMember) => void;
+ updateMemberGroups: (
+ member: OrganizationMember,
+ add: Array<string>,
+ remove: Array<string>
+ ) => void;
+}
+export default class MembersList extends React.PureComponent<Props> {
render() {
return (
<div className="boxed-group boxed-group-inner">
@@ -45,8 +43,8 @@ export default class MembersList extends React.PureComponent {
<MembersListItem
key={member.login}
member={member}
- organizationGroups={this.props.organizationGroups}
organization={this.props.organization}
+ organizationGroups={this.props.organizationGroups}
removeMember={this.props.removeMember}
updateMemberGroups={this.props.updateMemberGroups}
/>
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/MembersListHeader.js b/server/sonar-web/src/main/js/apps/organizations/components/MembersListHeader.tsx
index ed3106ad23a..b703131b34a 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/MembersListHeader.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/MembersListHeader.tsx
@@ -17,20 +17,17 @@
* 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 * as React from 'react';
import SearchBox from '../../../components/controls/SearchBox';
import { formatMeasure } from '../../../helpers/measures';
import { translate } from '../../../helpers/l10n';
-/*::
-type Props = {
- handleSearch: (query?: string) => void,
- total?: number
-};
-*/
+interface Props {
+ handleSearch: (query?: string) => void;
+ total?: number;
+}
-export default function MembersListHeader({ handleSearch, total } /*: Props */) {
+export default function MembersListHeader({ handleSearch, total }: Props) {
return (
<div className="panel panel-vertical bordered-bottom spacer-bottom">
<SearchBox
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js b/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.tsx
index b17f5ee3991..99d71d9a4fa 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.tsx
@@ -17,8 +17,7 @@
* 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 * as React from 'react';
import RemoveMemberForm from './forms/RemoveMemberForm';
import ManageMemberGroupsForm from './forms/ManageMemberGroupsForm';
import Avatar from '../../../components/ui/Avatar';
@@ -28,30 +27,26 @@ import ActionsDropdown, {
ActionsDropdownDivider,
ActionsDropdownItem
} from '../../../components/controls/ActionsDropdown';
-/*:: import type { Member } from '../../../store/organizationsMembers/actions'; */
-/*:: import type { Organization, Group } from '../../../app/types'; */
+import { Group, Organization, OrganizationMember } from '../../../app/types';
-/*::
-type Props = {
- member: Member,
- organization: Organization,
- organizationGroups: Array<Group>,
- removeMember: Member => void,
- updateMemberGroups: (member: Member, add: Array<string>, remove: Array<string>) => void
-};
+interface Props {
+ member: OrganizationMember;
+ organization: Organization;
+ organizationGroups: Group[];
+ removeMember: (member: OrganizationMember) => void;
+ updateMemberGroups: (member: OrganizationMember, add: string[], remove: string[]) => void;
+}
-type State = {
- removeMemberForm: bool,
- manageGroupsForm: bool
+interface State {
+ removeMemberForm: boolean;
+ manageGroupsForm: boolean;
}
-*/
-const AVATAR_SIZE /*: number */ = 36;
+const AVATAR_SIZE = 36;
-export default class MembersListItem extends React.PureComponent {
- mounted /*: bool */ = false;
- /*:: props: Props; */
- state /*: State */ = { removeMemberForm: false, manageGroupsForm: false };
+export default class MembersListItem extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { removeMemberForm: false, manageGroupsForm: false };
componentDidMount() {
this.mounted = true;
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx
index aab0246bd05..2b5e9f301d4 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationAccessContainer.tsx
@@ -24,10 +24,12 @@ import { getOrganizationByKey, getCurrentUser } from '../../../store/rootReducer
import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
import { Organization, CurrentUser, isLoggedIn } from '../../../app/types';
import { isCurrentUserMemberOf, hasPrivateAccess } from '../../../helpers/organizations';
+import { getMyOrganizations } from '../../../store/organizations/duck';
interface StateToProps {
currentUser: CurrentUser;
organization?: Organization;
+ userOrganizations: Organization[];
}
interface OwnProps extends RouterState {
@@ -66,7 +68,8 @@ export class OrganizationAccess extends React.PureComponent<Props> {
const mapStateToProps = (state: any, ownProps: OwnProps) => ({
currentUser: getCurrentUser(state),
- organization: getOrganizationByKey(state, ownProps.params.organizationKey)
+ organization: getOrganizationByKey(state, ownProps.params.organizationKey),
+ userOrganizations: getMyOrganizations(state)
});
const OrganizationAccessContainer = connect<StateToProps, {}, OwnProps>(mapStateToProps)(
@@ -76,7 +79,9 @@ const OrganizationAccessContainer = connect<StateToProps, {}, OwnProps>(mapState
export function OrganizationPrivateAccess(props: OwnProps) {
return (
<OrganizationAccessContainer
- hasAccess={({ organization }: StateToProps) => hasPrivateAccess(organization)}
+ hasAccess={({ currentUser, organization, userOrganizations }: StateToProps) =>
+ hasPrivateAccess(currentUser, organization, userOrganizations)
+ }
{...props}
/>
);
@@ -85,7 +90,9 @@ export function OrganizationPrivateAccess(props: OwnProps) {
export function OrganizationMembersAccess(props: OwnProps) {
return (
<OrganizationAccessContainer
- hasAccess={({ organization }: StateToProps) => isCurrentUserMemberOf(organization)}
+ hasAccess={({ currentUser, organization, userOrganizations }: StateToProps) =>
+ isCurrentUserMemberOf(currentUser, organization, userOrganizations)
+ }
{...props}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx
index b78290609b8..af96e5ec02f 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationEdit.tsx
@@ -17,43 +17,41 @@
* 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 * as React from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import { debounce } from 'lodash';
import { translate } from '../../../helpers/l10n';
import { updateOrganization } from '../actions';
import { SubmitButton } from '../../../components/ui/buttons';
-/*:: import type { Organization } from '../../../app/types'; */
-
-/*::
-type Props = {
- organization: Organization,
- updateOrganization: (string, Object) => Promise<*>
-};
-*/
-
-class OrganizationEdit extends React.PureComponent {
- /*:: mounted: boolean; */
-
- /*:: props: Props; */
-
- /*:: state: {
- loading: boolean,
- avatar: string,
- avatarImage: string,
- description: string,
- name: string,
- url: string
- };
-*/
+import { Organization, OrganizationBase } from '../../../app/types';
+
+interface DispatchProps {
+ updateOrganization: (organization: string, changes: OrganizationBase) => Promise<any>;
+}
- constructor(props /*: Props */) {
+interface OwnProps {
+ organization: Organization;
+}
+
+type Props = OwnProps & DispatchProps;
+
+interface State {
+ loading: boolean;
+ avatar: string;
+ avatarImage: string;
+ description: string;
+ name: string;
+ url: string;
+}
+
+export class OrganizationEdit extends React.PureComponent<Props, State> {
+ mounted = false;
+
+ constructor(props: Props) {
super(props);
this.state = {
loading: false,
-
avatar: props.organization.avatar || '',
avatarImage: props.organization.avatar || '',
description: props.organization.description || '',
@@ -71,18 +69,18 @@ class OrganizationEdit extends React.PureComponent {
this.mounted = false;
}
- handleAvatarInputChange = (e /*: Object */) => {
- const { value } = e.target;
+ handleAvatarInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ const { value } = event.target;
this.setState({ avatar: value });
this.changeAvatarImage(value);
};
- changeAvatarImage = (value /*: string */) => {
+ changeAvatarImage = (value: string) => {
this.setState({ avatarImage: value });
};
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
const changes = {
avatar: this.state.avatar,
description: this.state.description,
@@ -90,11 +88,15 @@ class OrganizationEdit extends React.PureComponent {
url: this.state.url
};
this.setState({ loading: true });
- this.props.updateOrganization(this.props.organization.key, changes).then(() => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- });
+ this.props
+ .updateOrganization(this.props.organization.key, changes)
+ .then(this.stopLoading, this.stopLoading);
+ };
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
};
render() {
@@ -117,7 +119,7 @@ class OrganizationEdit extends React.PureComponent {
<input
disabled={this.state.loading}
id="organization-name"
- maxLength="64"
+ maxLength={64}
name="name"
onChange={e => this.setState({ name: e.target.value })}
required={true}
@@ -133,7 +135,7 @@ class OrganizationEdit extends React.PureComponent {
<input
disabled={this.state.loading}
id="organization-avatar"
- maxLength="256"
+ maxLength={256}
name="avatar"
onChange={this.handleAvatarInputChange}
type="text"
@@ -157,10 +159,10 @@ class OrganizationEdit extends React.PureComponent {
<textarea
disabled={this.state.loading}
id="organization-description"
- maxLength="256"
+ maxLength={256}
name="description"
onChange={e => this.setState({ description: e.target.value })}
- rows="3"
+ rows={3}
value={this.state.description}
/>
<div className="modal-field-description">
@@ -172,7 +174,7 @@ class OrganizationEdit extends React.PureComponent {
<input
disabled={this.state.loading}
id="organization-url"
- maxLength="256"
+ maxLength={256}
name="url"
onChange={e => this.setState({ url: e.target.value })}
type="text"
@@ -193,8 +195,6 @@ class OrganizationEdit extends React.PureComponent {
}
}
-const mapDispatchToProps = { updateOrganization };
-
-export default connect(null, mapDispatchToProps)(OrganizationEdit);
+const mapDispatchToProps = { updateOrganization: updateOrganization as any };
-export const UnconnectedOrganizationEdit = OrganizationEdit;
+export default connect<{}, DispatchProps, OwnProps>(null, mapDispatchToProps)(OrganizationEdit);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx
index 95fd1e085e9..a1209ecbb9c 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationGroupCheckbox.tsx
@@ -17,23 +17,19 @@
* 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 * as React from 'react';
+import * as classNames from 'classnames';
import Checkbox from '../../../components/controls/Checkbox';
-/*:: import type { Group } from '../../../app/types'; */
+import { Group } from '../../../app/types';
-/*::
-type Props = {
- group: Group,
- checked: boolean,
- onCheck: (string, boolean) => void
-};
-*/
-
-export default class OrganizationGroupCheckbox extends React.PureComponent {
- /*:: props: Props; */
+interface Props {
+ group: Group;
+ checked: boolean;
+ onCheck: (name: string, checked: boolean) => void;
+}
- onCheck = (checked /*: boolean */) => {
+export default class OrganizationGroupCheckbox extends React.PureComponent<Props> {
+ onCheck = (checked: boolean) => {
const { group } = this.props;
if (!group.default) {
this.props.onCheck(group.name, checked);
@@ -48,11 +44,8 @@ export default class OrganizationGroupCheckbox extends React.PureComponent {
const { group } = this.props;
return (
<li
- className="capitalize list-item-checkable-link"
- onClick={this.toggleCheck}
- tabIndex={0}
- role="listitem"
- disabled={group.default}>
+ className={classNames('capitalize list-item-checkable-link', { disabled: group.default })}
+ onClick={this.toggleCheck}>
<Checkbox checked={this.props.checked} onCheck={this.onCheck} /> {group.name}
</li>
);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembers.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembers.tsx
index fdafac5ca40..68096c99764 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembers.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembers.tsx
@@ -17,8 +17,7 @@
* 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 * as React from 'react';
import Helmet from 'react-helmet';
import MembersPageHeader from './MembersPageHeader';
import MembersListHeader from './MembersListHeader';
@@ -28,33 +27,28 @@ import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import ListFooter from '../../../components/controls/ListFooter';
import DocTooltip from '../../../components/docs/DocTooltip';
import { translate } from '../../../helpers/l10n';
-/*:: import type { Organization, Group } from '../../../app/types'; */
-/*:: import type { Member } from '../../../store/organizationsMembers/actions'; */
+import { Group, Organization, OrganizationMember } from '../../../app/types';
-/*::
-type Props = {
- members: Array<Member>,
- memberLogins: Array<string>,
- organizationGroups: Array<Group>,
- status: { loading?: boolean, total?: number, pageIndex?: number, query?: string },
- organization: Organization,
- fetchOrganizationMembers: (organizationKey: string, query?: string) => void,
- fetchMoreOrganizationMembers: (organizationKey: string, query?: string) => void,
- fetchOrganizationGroups: (organizationKey: string) => void,
- addOrganizationMember: (organizationKey: string, member: Member) => void,
- removeOrganizationMember: (organizationKey: string, member: Member) => void,
+interface Props {
+ addOrganizationMember: (organizationKey: string, member: OrganizationMember) => void;
+ fetchMoreOrganizationMembers: (organizationKey: string, query?: string) => void;
+ fetchOrganizationGroups: (organizationKey: string) => void;
+ fetchOrganizationMembers: (organizationKey: string, query?: string) => void;
+ members: OrganizationMember[];
+ memberLogins: string[];
+ organization: Organization;
+ organizationGroups: Group[];
+ removeOrganizationMember: (organizationKey: string, member: OrganizationMember) => void;
+ status: { loading?: boolean; total?: number; pageIndex?: number; query?: string };
updateOrganizationMemberGroups: (
organization: Organization,
- member: Member,
- add: Array<string>,
- remove: Array<string>
- ) => void
-};
-*/
-
-export default class OrganizationMembers extends React.PureComponent {
- /*:: props: Props; */
+ member: OrganizationMember,
+ add: string[],
+ remove: string[]
+ ) => void;
+}
+export default class OrganizationMembers extends React.PureComponent<Props> {
componentDidMount() {
this.handleSearchMembers();
if (this.props.organization.canAdmin) {
@@ -62,7 +56,7 @@ export default class OrganizationMembers extends React.PureComponent {
}
}
- handleSearchMembers = (query /*: string | void */) => {
+ handleSearchMembers = (query?: string) => {
this.props.fetchOrganizationMembers(this.props.organization.key, query);
};
@@ -70,19 +64,15 @@ export default class OrganizationMembers extends React.PureComponent {
this.props.fetchMoreOrganizationMembers(this.props.organization.key, this.props.status.query);
};
- addMember = (member /*: Member */) => {
+ addMember = (member: OrganizationMember) => {
this.props.addOrganizationMember(this.props.organization.key, member);
};
- removeMember = (member /*: Member */) => {
+ removeMember = (member: OrganizationMember) => {
this.props.removeOrganizationMember(this.props.organization.key, member);
};
- updateMemberGroups = (
- member /*: Member */,
- add /*: Array<string> */,
- remove /*: Array<string> */
- ) => {
+ updateMemberGroups = (member: OrganizationMember, add: string[], remove: string[]) => {
this.props.updateOrganizationMemberGroups(this.props.organization, member, add, remove);
};
@@ -92,7 +82,7 @@ export default class OrganizationMembers extends React.PureComponent {
<div className="page page-limited">
<Helmet title={translate('organization.members.page')} />
<Suggestions suggestions="organization_members" />
- <MembersPageHeader loading={status.loading}>
+ <MembersPageHeader loading={Boolean(status.loading)}>
{organization.canAdmin && (
<div className="page-actions">
<AddMemberForm
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembersContainer.js b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembersContainer.tsx
index 203757e0919..cbc1d9d0d98 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembersContainer.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationMembersContainer.tsx
@@ -34,8 +34,35 @@ import {
removeOrganizationMember,
updateOrganizationMemberGroups
} from '../actions';
+import { Organization, OrganizationMember, Group } from '../../../app/types';
-const mapStateToProps = (state, ownProps) => {
+interface OwnProps {
+ params: { organizationKey: string };
+}
+
+interface StateProps {
+ memberLogins: string[];
+ members: OrganizationMember[];
+ organization?: Organization;
+ organizationGroups: Group[];
+ status: { loading?: boolean; total?: number; pageIndex?: number; query?: string };
+}
+
+interface DispatchProps {
+ addOrganizationMember: (organizationKey: string, member: OrganizationMember) => void;
+ fetchMoreOrganizationMembers: (organizationKey: string, query?: string) => void;
+ fetchOrganizationGroups: (organizationKey: string) => void;
+ fetchOrganizationMembers: (organizationKey: string, query?: string) => void;
+ removeOrganizationMember: (organizationKey: string, member: OrganizationMember) => void;
+ updateOrganizationMemberGroups: (
+ organization: Organization,
+ member: OrganizationMember,
+ add: string[],
+ remove: string[]
+ ) => void;
+}
+
+const mapStateToProps = (state: any, ownProps: OwnProps): StateProps => {
const { organizationKey } = ownProps.params;
const memberLogins = getOrganizationMembersLogins(state, organizationKey);
return {
@@ -47,11 +74,15 @@ const mapStateToProps = (state, ownProps) => {
};
};
-export default connect(mapStateToProps, {
- fetchOrganizationMembers,
+const mapDispatchToProps = {
+ addOrganizationMember,
fetchMoreOrganizationMembers,
fetchOrganizationGroups,
- addOrganizationMember,
+ fetchOrganizationMembers,
removeOrganizationMember,
updateOrganizationMemberGroups
-})(OrganizationMembers);
+};
+
+export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
+ OrganizationMembers
+);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx
index 09ae20f8151..ce54a3eea92 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationProjects.tsx
@@ -20,10 +20,11 @@
import * as React from 'react';
import AllProjectsContainer from '../../projects/components/AllProjectsContainer';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
+import { Organization } from '../../../app/types';
interface Props {
location: { pathname: string; query: { [x: string]: string } };
- organization: { key: string };
+ organization: Organization;
}
export default function OrganizationProjects(props: Props) {
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersList-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersList-test.tsx
index 6c527e19c86..0910f62995c 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersList-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersList-test.tsx
@@ -17,7 +17,7 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import MembersList from '../MembersList';
@@ -28,6 +28,14 @@ const members = [
];
it('should render a list of members of an organization', () => {
- const wrapper = shallow(<MembersList organization={organization} members={members} />);
+ const wrapper = shallow(
+ <MembersList
+ members={members}
+ organization={organization}
+ organizationGroups={[]}
+ removeMember={jest.fn()}
+ updateMemberGroups={jest.fn()}
+ />
+ );
expect(wrapper).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListHeader-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListHeader-test.tsx
index a4c3be43fd8..ffc4241d145 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListHeader-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListHeader-test.tsx
@@ -17,7 +17,7 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import MembersListHeader from '../MembersListHeader';
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListItem-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListItem-test.tsx
index 9e2455dbcdd..9838194849f 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListItem-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/MembersListItem-test.tsx
@@ -17,7 +17,7 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import MembersListItem from '../MembersListItem';
@@ -26,20 +26,40 @@ const admin = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount:
const john = { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af' };
it('should not render actions and groups for non admin', () => {
- const wrapper = shallow(<MembersListItem organization={organization} member={admin} />);
+ const wrapper = shallow(
+ <MembersListItem
+ member={admin}
+ organization={organization}
+ organizationGroups={[]}
+ removeMember={jest.fn()}
+ updateMemberGroups={jest.fn()}
+ />
+ );
expect(wrapper).toMatchSnapshot();
});
it('should render actions and groups for admin', () => {
const wrapper = shallow(
- <MembersListItem organization={{ ...organization, canAdmin: true }} member={admin} />
+ <MembersListItem
+ member={admin}
+ organization={{ ...organization, canAdmin: true }}
+ organizationGroups={[]}
+ removeMember={jest.fn()}
+ updateMemberGroups={jest.fn()}
+ />
);
expect(wrapper).toMatchSnapshot();
});
it('should groups at 0 if the groupCount field is not defined (just added user)', () => {
const wrapper = shallow(
- <MembersListItem organization={{ ...organization, canAdmin: true }} member={john} />
+ <MembersListItem
+ member={john}
+ organization={{ ...organization, canAdmin: true }}
+ organizationGroups={[]}
+ removeMember={jest.fn()}
+ updateMemberGroups={jest.fn()}
+ />
);
expect(wrapper).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx
index 17b1fd80bb1..8fcb64c11f3 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationAccessContainer-test.tsx
@@ -55,7 +55,8 @@ describe('component', () => {
currentUser={loggedInUser}
hasAccess={() => true}
location={locationMock}
- organization={adminOrganization}>
+ organization={adminOrganization}
+ userOrganizations={[]}>
<div>hello</div>
</OrganizationAccess>
)
@@ -69,7 +70,8 @@ describe('component', () => {
currentUser={loggedInUser}
hasAccess={() => false}
location={locationMock}
- organization={adminOrganization}>
+ organization={adminOrganization}
+ userOrganizations={[]}>
<div>hello</div>
</OrganizationAccess>
).type()
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx
index cd3c2b0a71c..fb4efafe103 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationEdit-test.tsx
@@ -17,13 +17,15 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
-import { UnconnectedOrganizationEdit } from '../OrganizationEdit';
+import { OrganizationEdit } from '../OrganizationEdit';
it('smoke test', () => {
const organization = { key: 'foo', name: 'Foo' };
- const wrapper = shallow(<UnconnectedOrganizationEdit organization={organization} />);
+ const wrapper = shallow(
+ <OrganizationEdit organization={organization} updateOrganization={jest.fn()} />
+ );
expect(wrapper).toMatchSnapshot();
wrapper.setState({
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx
index a092526f549..2cc4d069333 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationGroupCheckbox-test.tsx
@@ -17,12 +17,12 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox';
const group = {
- id: '7',
+ id: 7,
name: 'professionals',
description: '',
membersCount: 12,
@@ -31,32 +31,32 @@ const group = {
it('should render unchecked', () => {
const wrapper = shallow(
- <OrganizationGroupCheckbox group={group} checked={false} onCheck={jest.fn()} />
+ <OrganizationGroupCheckbox checked={false} group={group} onCheck={jest.fn()} />
);
expect(wrapper).toMatchSnapshot();
});
it('should be able to toggle check', () => {
- const onCheck = jest.fn((group, checked) => wrapper.setProps({ checked }));
+ const onCheck = jest.fn().mockImplementation((_group, checked) => wrapper.setProps({ checked }));
const wrapper = shallow(
- <OrganizationGroupCheckbox group={group} checked={true} onCheck={onCheck} />
+ <OrganizationGroupCheckbox checked={true} group={group} onCheck={onCheck} />
);
expect(wrapper).toMatchSnapshot();
- wrapper.instance().toggleCheck();
+ (wrapper.instance() as OrganizationGroupCheckbox).toggleCheck();
expect(onCheck.mock.calls).toMatchSnapshot();
expect(wrapper).toMatchSnapshot();
});
it('should disabled default groups', () => {
- const onCheck = jest.fn((group, checked) => wrapper.setProps({ checked }));
+ const onCheck = jest.fn().mockImplementation((_group, checked) => wrapper.setProps({ checked }));
const wrapper = shallow(
<OrganizationGroupCheckbox
- group={{ ...group, default: true }}
checked={true}
+ group={{ ...group, default: true }}
onCheck={onCheck}
/>
);
expect(wrapper).toMatchSnapshot();
- wrapper.instance().toggleCheck();
+ (wrapper.instance() as OrganizationGroupCheckbox).toggleCheck();
expect(onCheck.mock.calls.length).toBe(0);
});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationMembers-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationMembers-test.tsx
index f7cd21913a0..de18ce76e3b 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationMembers-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationMembers-test.tsx
@@ -17,7 +17,7 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import OrganizationMembers from '../OrganizationMembers';
@@ -31,12 +31,17 @@ const status = { total: members.length };
it('should not render actions for non admin', () => {
const wrapper = shallow(
<OrganizationMembers
- organization={organization}
+ addOrganizationMember={jest.fn()}
+ fetchMoreOrganizationMembers={jest.fn()}
+ fetchOrganizationGroups={jest.fn()}
+ fetchOrganizationMembers={jest.fn()}
+ memberLogins={[]}
members={members}
+ organization={organization}
+ organizationGroups={[]}
+ removeOrganizationMember={jest.fn()}
status={status}
- fetchOrganizationMembers={jest.fn()}
- fetchOrganizationGroups={jest.fn()}
- fetchMoreOrganizationMembers={jest.fn()}
+ updateOrganizationMemberGroups={jest.fn()}
/>
);
expect(wrapper).toMatchSnapshot();
@@ -45,12 +50,17 @@ it('should not render actions for non admin', () => {
it('should render actions for admin', () => {
const wrapper = shallow(
<OrganizationMembers
- organization={{ ...organization, canAdmin: true }}
+ addOrganizationMember={jest.fn()}
+ fetchMoreOrganizationMembers={jest.fn()}
+ fetchOrganizationGroups={jest.fn()}
+ fetchOrganizationMembers={jest.fn()}
+ memberLogins={[]}
members={members}
+ organization={{ ...organization, canAdmin: true }}
+ organizationGroups={[]}
+ removeOrganizationMember={jest.fn()}
status={{ ...status, loading: true }}
- fetchOrganizationMembers={jest.fn()}
- fetchOrganizationGroups={jest.fn()}
- fetchMoreOrganizationMembers={jest.fn()}
+ updateOrganizationMemberGroups={jest.fn()}
/>
);
expect(wrapper).toMatchSnapshot();
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.js b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx
index ad76461e499..e1230f3a18c 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationPage-test.tsx
@@ -17,7 +17,7 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import { OrganizationPage } from '../OrganizationPage';
@@ -25,7 +25,10 @@ const fetchOrganization = () => Promise.resolve();
it('smoke test', () => {
const wrapper = shallow(
- <OrganizationPage fetchOrganization={fetchOrganization} params={{ organizationKey: 'foo' }}>
+ <OrganizationPage
+ fetchOrganization={fetchOrganization}
+ location={{ pathname: 'foo' }}
+ params={{ organizationKey: 'foo' }}>
<div>hello</div>
</OrganizationPage>
);
@@ -38,7 +41,10 @@ it('smoke test', () => {
it('not found', () => {
const wrapper = shallow(
- <OrganizationPage fetchOrganization={fetchOrganization} params={{ organizationKey: 'foo' }}>
+ <OrganizationPage
+ fetchOrganization={fetchOrganization}
+ location={{ pathname: 'foo' }}
+ params={{ organizationKey: 'foo' }}>
<div>hello</div>
</OrganizationPage>
);
@@ -49,7 +55,10 @@ it('not found', () => {
it('should correctly update when the organization changes', () => {
const fetchOrganization = jest.fn(() => Promise.resolve());
const wrapper = shallow(
- <OrganizationPage params={{ organizationKey: 'foo' }} fetchOrganization={fetchOrganization}>
+ <OrganizationPage
+ fetchOrganization={fetchOrganization}
+ location={{ pathname: 'foo' }}
+ params={{ organizationKey: 'foo' }}>
<div>hello</div>
</OrganizationPage>
);
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.tsx.snap
index fc8f227d95e..57ff0c52ea6 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersList-test.tsx.snap
@@ -24,6 +24,9 @@ exports[`should render a list of members of an organization 1`] = `
"name": "Foo",
}
}
+ organizationGroups={Array []}
+ removeMember={[MockFunction]}
+ updateMemberGroups={[MockFunction]}
/>
<MembersListItem
key="john"
@@ -41,6 +44,9 @@ exports[`should render a list of members of an organization 1`] = `
"name": "Foo",
}
}
+ organizationGroups={Array []}
+ removeMember={[MockFunction]}
+ updateMemberGroups={[MockFunction]}
/>
</tbody>
</table>
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListHeader-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListHeader-test.tsx.snap
index 7bfe2725e60..7bfe2725e60 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListHeader-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListHeader-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.tsx.snap
index 2f04b608477..2f04b608477 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap
index 0abba69f78e..054e0314163 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationEdit-test.tsx.snap
@@ -40,7 +40,7 @@ exports[`smoke test 1`] = `
<input
disabled={false}
id="organization-name"
- maxLength="64"
+ maxLength={64}
name="name"
onChange={[Function]}
required={true}
@@ -64,7 +64,7 @@ exports[`smoke test 1`] = `
<input
disabled={false}
id="organization-avatar"
- maxLength="256"
+ maxLength={256}
name="avatar"
onChange={[Function]}
type="text"
@@ -87,10 +87,10 @@ exports[`smoke test 1`] = `
<textarea
disabled={false}
id="organization-description"
- maxLength="256"
+ maxLength={256}
name="description"
onChange={[Function]}
- rows="3"
+ rows={3}
value=""
/>
<div
@@ -110,7 +110,7 @@ exports[`smoke test 1`] = `
<input
disabled={false}
id="organization-url"
- maxLength="256"
+ maxLength={256}
name="url"
onChange={[Function]}
type="text"
@@ -176,7 +176,7 @@ exports[`smoke test 2`] = `
<input
disabled={false}
id="organization-name"
- maxLength="64"
+ maxLength={64}
name="name"
onChange={[Function]}
required={true}
@@ -200,7 +200,7 @@ exports[`smoke test 2`] = `
<input
disabled={false}
id="organization-avatar"
- maxLength="256"
+ maxLength={256}
name="avatar"
onChange={[Function]}
type="text"
@@ -238,10 +238,10 @@ exports[`smoke test 2`] = `
<textarea
disabled={false}
id="organization-description"
- maxLength="256"
+ maxLength={256}
name="description"
onChange={[Function]}
- rows="3"
+ rows={3}
value="foo-description"
/>
<div
@@ -261,7 +261,7 @@ exports[`smoke test 2`] = `
<input
disabled={false}
id="organization-url"
- maxLength="256"
+ maxLength={256}
name="url"
onChange={[Function]}
type="text"
@@ -327,7 +327,7 @@ exports[`smoke test 3`] = `
<input
disabled={true}
id="organization-name"
- maxLength="64"
+ maxLength={64}
name="name"
onChange={[Function]}
required={true}
@@ -351,7 +351,7 @@ exports[`smoke test 3`] = `
<input
disabled={true}
id="organization-avatar"
- maxLength="256"
+ maxLength={256}
name="avatar"
onChange={[Function]}
type="text"
@@ -389,10 +389,10 @@ exports[`smoke test 3`] = `
<textarea
disabled={true}
id="organization-description"
- maxLength="256"
+ maxLength={256}
name="description"
onChange={[Function]}
- rows="3"
+ rows={3}
value="foo-description"
/>
<div
@@ -412,7 +412,7 @@ exports[`smoke test 3`] = `
<input
disabled={true}
id="organization-url"
- maxLength="256"
+ maxLength={256}
name="url"
onChange={[Function]}
type="text"
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap
index e5126eb7157..e97cc7b40c0 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationGroupCheckbox-test.tsx.snap
@@ -3,10 +3,7 @@
exports[`should be able to toggle check 1`] = `
<li
className="capitalize list-item-checkable-link"
- disabled={false}
onClick={[Function]}
- role="listitem"
- tabIndex={0}
>
<Checkbox
checked={true}
@@ -30,10 +27,7 @@ Array [
exports[`should be able to toggle check 3`] = `
<li
className="capitalize list-item-checkable-link"
- disabled={false}
onClick={[Function]}
- role="listitem"
- tabIndex={0}
>
<Checkbox
checked={false}
@@ -47,11 +41,8 @@ exports[`should be able to toggle check 3`] = `
exports[`should disabled default groups 1`] = `
<li
- className="capitalize list-item-checkable-link"
- disabled={true}
+ className="capitalize list-item-checkable-link disabled"
onClick={[Function]}
- role="listitem"
- tabIndex={0}
>
<Checkbox
checked={true}
@@ -66,10 +57,7 @@ exports[`should disabled default groups 1`] = `
exports[`should render unchecked 1`] = `
<li
className="capitalize list-item-checkable-link"
- disabled={false}
onClick={[Function]}
- role="listitem"
- tabIndex={0}
>
<Checkbox
checked={false}
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationMembers-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
index 6fb9690cf4b..778362a0ff1 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationMembers-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationMembers-test.tsx.snap
@@ -12,7 +12,9 @@ exports[`should not render actions for non admin 1`] = `
<Suggestions
suggestions="organization_members"
/>
- <MembersPageHeader />
+ <MembersPageHeader
+ loading={false}
+ />
<MembersListHeader
handleSearch={[Function]}
total={2}
@@ -40,6 +42,7 @@ exports[`should not render actions for non admin 1`] = `
"name": "Foo",
}
}
+ organizationGroups={Array []}
removeMember={[Function]}
updateMemberGroups={[Function]}
/>
@@ -72,6 +75,7 @@ exports[`should render actions for admin 1`] = `
>
<AddMemberForm
addMember={[Function]}
+ memberLogins={Array []}
organization={
Object {
"canAdmin": true,
@@ -114,6 +118,7 @@ exports[`should render actions for admin 1`] = `
"name": "Foo",
}
}
+ organizationGroups={Array []}
removeMember={[Function]}
updateMemberGroups={[Function]}
/>
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap
index 260e3f3ffb6..9802e06cdcb 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/OrganizationPage-test.tsx.snap
@@ -25,6 +25,11 @@ exports[`smoke test 1`] = `
suggestions="organization_space"
/>
<OrganizationNavigation
+ location={
+ Object {
+ "pathname": "foo",
+ }
+ }
organization={
Object {
"canAdmin": false,
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.tsx
index 1fe1b0d7d6a..00408077132 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.tsx
@@ -17,35 +17,27 @@
* 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 * as React from 'react';
import UsersSelectSearch from '../../../users/components/UsersSelectSearch';
import { searchMembers } from '../../../../api/organizations';
import Modal from '../../../../components/controls/Modal';
import { translate } from '../../../../helpers/l10n';
import { SubmitButton, ResetButtonLink, Button } from '../../../../components/ui/buttons';
-/*:: import type { Organization } from '../../../../app/types'; */
-/*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */
+import { Organization, OrganizationMember } from '../../../../app/types';
-/*::
-type Props = {
- addMember: (member: Member) => void,
- organization: Organization,
- memberLogins: Array<string>
-};
-*/
-
-/*::
-type State = {
- open: boolean,
- selectedMember?: Member
-};
-*/
+interface Props {
+ addMember: (member: OrganizationMember) => void;
+ organization: Organization;
+ memberLogins: string[];
+}
-export default class AddMemberForm extends React.PureComponent {
- /*:: props: Props; */
+interface State {
+ open: boolean;
+ selectedMember?: OrganizationMember;
+}
- state /*: State */ = {
+export default class AddMemberForm extends React.PureComponent<Props, State> {
+ state: State = {
open: false
};
@@ -57,7 +49,7 @@ export default class AddMemberForm extends React.PureComponent {
this.setState({ open: false, selectedMember: undefined });
};
- handleSearch = (query /*: ?string */, ps /*: number */) => {
+ handleSearch = (query: string | undefined, ps: number) => {
const data = { organization: this.props.organization.key, ps, selected: 'deselected' };
if (!query) {
return searchMembers(data);
@@ -65,15 +57,15 @@ export default class AddMemberForm extends React.PureComponent {
return searchMembers({ ...data, q: query });
};
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
if (this.state.selectedMember) {
this.props.addMember(this.state.selectedMember);
this.closeForm();
}
};
- selectedMemberChange = (member /*: Member */) => {
+ selectedMemberChange = (member: OrganizationMember) => {
this.setState({ selectedMember: member });
};
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.tsx
index 563bf17505c..bef77e64000 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.tsx
@@ -17,38 +17,31 @@
* 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 * as React from 'react';
import { keyBy, pickBy } from 'lodash';
-import { getUserGroups } from '../../../../api/users';
+import { getUserGroups, UserGroup } from '../../../../api/users';
import Modal from '../../../../components/controls/Modal';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox';
import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
-/*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */
-/*:: import type { Organization, Group } from '../../../../app/types'; */
+import { Organization, OrganizationMember, Group } from '../../../../app/types';
-/*::
-type Props = {
+interface Props {
onClose: () => void;
- member: Member,
- organization: Organization,
- organizationGroups: Array<Group>,
- updateMemberGroups: (member: Member, add: Array<string>, remove: Array<string>) => void
-};
-*/
+ member: OrganizationMember;
+ organization: Organization;
+ organizationGroups: Group[];
+ updateMemberGroups: (member: OrganizationMember, add: string[], remove: string[]) => void;
+}
-/*::
-type State = {
- userGroups?: {},
- loading?: boolean
-};
-*/
+interface State {
+ userGroups?: { [k: string]: UserGroup & { status?: string } };
+ loading?: boolean;
+}
-export default class ManageMemberGroupsForm extends React.PureComponent {
- /*:: mounted: boolean */
- /*:: props: Props; */
- state /*: State */ = {};
+export default class ManageMemberGroupsForm extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = {};
componentDidMount() {
this.mounted = true;
@@ -75,7 +68,7 @@ export default class ManageMemberGroupsForm extends React.PureComponent {
);
};
- isGroupSelected = (groupName /*: string */) => {
+ isGroupSelected = (groupName: string) => {
if (this.state.userGroups) {
const group = this.state.userGroups[groupName] || {};
if (group.status) {
@@ -87,8 +80,8 @@ export default class ManageMemberGroupsForm extends React.PureComponent {
return false;
};
- onCheck = (groupName /*: string */, checked /*: boolean */) => {
- this.setState((prevState /*: State */) => {
+ onCheck = (groupName: string, checked: boolean) => {
+ this.setState((prevState: State) => {
const userGroups = prevState.userGroups || {};
const group = userGroups[groupName] || {};
let status = '';
@@ -101,8 +94,8 @@ export default class ManageMemberGroupsForm extends React.PureComponent {
});
};
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
this.props.updateMemberGroups(
this.props.member,
Object.keys(pickBy(this.state.userGroups, group => group.status === 'add')),
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.tsx
index b33c53f0907..c6e0d603dd2 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.tsx
@@ -17,27 +17,22 @@
* 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 * as React from 'react';
import Modal from '../../../../components/controls/Modal';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
-/*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */
-/*:: import type { Organization } from '../../../../app/types'; */
+import { Organization, OrganizationMember } from '../../../../app/types';
-/*::
-type Props = {
+interface Props {
onClose: () => void;
- member: Member,
- organization: Organization,
- removeMember: (member: Member) => void
-};
-*/
+ member: OrganizationMember;
+ organization: Organization;
+ removeMember: (member: OrganizationMember) => void;
+}
-export default class RemoveMemberForm extends React.PureComponent {
- /*:: props: Props; */
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
+export default class RemoveMemberForm extends React.PureComponent<Props> {
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
this.props.removeMember(this.props.member);
this.props.onClose();
};
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/AddMemberForm-test.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/AddMemberForm-test.tsx
index 308ff1f7d5e..3406cd7361d 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/AddMemberForm-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/AddMemberForm-test.tsx
@@ -17,7 +17,7 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
import { click } from '../../../../../helpers/testUtils';
import AddMemberForm from '../AddMemberForm';
@@ -25,7 +25,13 @@ import AddMemberForm from '../AddMemberForm';
const memberLogins = ['admin'];
it('should render and open the modal', () => {
- const wrapper = shallow(<AddMemberForm addMember={jest.fn()} memberLogins={memberLogins} />);
+ const wrapper = shallow(
+ <AddMemberForm
+ addMember={jest.fn()}
+ memberLogins={memberLogins}
+ organization={{ key: 'foo', name: 'Foo' }}
+ />
+ );
expect(wrapper).toMatchSnapshot();
wrapper.setState({ open: true });
@@ -34,9 +40,15 @@ it('should render and open the modal', () => {
});
it('should correctly handle user interactions', () => {
- const wrapper = shallow(<AddMemberForm addMember={jest.fn()} memberLogins={memberLogins} />);
+ const wrapper = shallow(
+ <AddMemberForm
+ addMember={jest.fn()}
+ memberLogins={memberLogins}
+ organization={{ key: 'foo', name: 'Foo' }}
+ />
+ );
click(wrapper.find('Button'));
expect(wrapper.state('open')).toBeTruthy();
- wrapper.instance().closeForm();
+ (wrapper.instance() as AddMemberForm).closeForm();
expect(wrapper.state('open')).toBeFalsy();
});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.tsx
index 579a42f96ef..32b0839c275 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.tsx
@@ -17,28 +17,28 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
-import { click, mockEvent } from '../../../../../helpers/testUtils';
+import { mockEvent } from '../../../../../helpers/testUtils';
import ManageMemberGroupsForm from '../ManageMemberGroupsForm';
const member = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
const organization = { name: 'MyOrg', key: 'myorg' };
const organizationGroups = [
{
- id: '7',
+ id: 7,
name: 'professionals',
description: '',
membersCount: 12
},
{
- id: '11',
+ id: 11,
name: 'pull-request-analysers',
description: 'Technical accounts',
membersCount: 3
},
{
- id: '1',
+ id: 1,
name: 'sonar-administrators',
description: 'System administrators',
membersCount: 17
@@ -68,6 +68,7 @@ it('should render', () => {
const wrapper = shallow(
<ManageMemberGroupsForm
member={member}
+ onClose={jest.fn()}
organization={organization}
organizationGroups={organizationGroups}
updateMemberGroups={jest.fn()}
@@ -78,21 +79,23 @@ it('should render', () => {
it('should correctly select the groups', () => {
const form = getMountedForm();
- expect(form.instance.isGroupSelected(11)).toBeTruthy();
- expect(form.instance.isGroupSelected(7)).toBeFalsy();
- form.instance.onCheck(11, false);
- form.instance.onCheck(7, true);
+ const instance = form.instance as ManageMemberGroupsForm;
+ expect(instance.isGroupSelected('11')).toBeTruthy();
+ expect(instance.isGroupSelected('7')).toBeFalsy();
+ instance.onCheck('11', false);
+ instance.onCheck('7', true);
expect(form.wrapper.state('userGroups')).toMatchSnapshot();
- expect(form.instance.isGroupSelected(11)).toBeFalsy();
- expect(form.instance.isGroupSelected(7)).toBeTruthy();
+ expect(instance.isGroupSelected('11')).toBeFalsy();
+ expect(instance.isGroupSelected('7')).toBeTruthy();
});
it('should correctly handle the submit event and close the modal', () => {
const updateMemberGroups = jest.fn();
const form = getMountedForm(updateMemberGroups);
- form.instance.onCheck(11, false);
- form.instance.onCheck(7, true);
- form.instance.handleSubmit(mockEvent);
+ const instance = form.instance as ManageMemberGroupsForm;
+ instance.onCheck('11', false);
+ instance.onCheck('7', true);
+ instance.handleSubmit(mockEvent as any);
expect(updateMemberGroups.mock.calls).toMatchSnapshot();
expect(form.wrapper.state()).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.tsx
index fca12f0187b..92fbdb9723d 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.tsx
@@ -17,17 +17,22 @@
* 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 * as React from 'react';
import { shallow } from 'enzyme';
-import { click, mockEvent } from '../../../../../helpers/testUtils';
+import { mockEvent } from '../../../../../helpers/testUtils';
import RemoveMemberForm from '../RemoveMemberForm';
const member = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
-const organization = { name: 'MyOrg' };
+const organization = { key: 'myorg', name: 'MyOrg' };
it('should render ', () => {
const wrapper = shallow(
- <RemoveMemberForm member={member} organization={organization} removeMember={jest.fn()} />
+ <RemoveMemberForm
+ member={member}
+ onClose={jest.fn()}
+ organization={organization}
+ removeMember={jest.fn()}
+ />
);
expect(wrapper).toMatchSnapshot();
});
@@ -42,7 +47,7 @@ it('should correctly handle user interactions', () => {
removeMember={removeMember}
/>
);
- wrapper.instance().handleSubmit(mockEvent);
+ (wrapper.instance() as RemoveMemberForm).handleSubmit(mockEvent as any);
expect(removeMember).toBeCalledWith({
avatar: '',
groupCount: 3,
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.tsx.snap
index d480a393f5b..d480a393f5b 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap
index 43f0bcecb5a..63f4e47e9b9 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.tsx.snap
@@ -55,6 +55,7 @@ Object {
exports[`should render 1`] = `
<Modal
contentLabel="organization.members.manage_groups"
+ onRequestClose={[MockFunction]}
>
<header
className="modal-head"
@@ -84,7 +85,9 @@ exports[`should render 1`] = `
<SubmitButton>
save
</SubmitButton>
- <ResetButtonLink>
+ <ResetButtonLink
+ onClick={[MockFunction]}
+ >
cancel
</ResetButtonLink>
</div>
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap
index ef1c3bfb9f1..c4a8afef3ef 100644
--- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.tsx.snap
@@ -4,6 +4,7 @@ exports[`should render 1`] = `
<Modal
contentLabel="users.remove"
key="remove-member-modal"
+ onRequestClose={[MockFunction]}
>
<header
className="modal-head"
@@ -30,7 +31,9 @@ exports[`should render 1`] = `
>
remove
</SubmitButton>
- <ResetButtonLink>
+ <ResetButtonLink
+ onClick={[MockFunction]}
+ >
cancel
</ResetButtonLink>
</div>
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx
index 3ee87fc0f36..112d2ef75ce 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigation.tsx
@@ -20,7 +20,7 @@
import * as React from 'react';
import OrganizationNavigationHeaderContainer from './OrganizationNavigationHeaderContainer';
import OrganizationNavigationMeta from './OrganizationNavigationMeta';
-import OrganizationNavigationMenu from './OrganizationNavigationMenu';
+import OrganizationNavigationMenuContainer from './OrganizationNavigationMenuContainer';
import * as theme from '../../../app/theme';
import ContextNavBar from '../../../components/nav/ContextNavBar';
import { Organization } from '../../../app/types';
@@ -37,7 +37,7 @@ export default function OrganizationNavigation({ location, organization }: Props
<OrganizationNavigationHeaderContainer organization={organization} />
<OrganizationNavigationMeta organization={organization} />
</div>
- <OrganizationNavigationMenu location={location} organization={organization} />
+ <OrganizationNavigationMenuContainer location={location} organization={organization} />
</ContextNavBar>
);
}
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenu.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx
index e63d8b4b0b3..1fda2012f13 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenu.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMenuContainer.tsx
@@ -18,21 +18,35 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { connect } from 'react-redux';
import { Link } from 'react-router';
import OrganizationNavigationExtensions from './OrganizationNavigationExtensions';
import OrganizationNavigationAdministration from './OrganizationNavigationAdministration';
-import { Organization } from '../../../app/types';
+import { Organization, CurrentUser } from '../../../app/types';
import NavBarTabs from '../../../components/nav/NavBarTabs';
import { translate } from '../../../helpers/l10n';
import { getQualityGatesUrl } from '../../../helpers/urls';
import { hasPrivateAccess, isCurrentUserMemberOf } from '../../../helpers/organizations';
+import { getCurrentUser, getMyOrganizations } from '../../../store/rootReducer';
-interface Props {
+interface StateToProps {
+ currentUser: CurrentUser;
+ userOrganizations: Organization[];
+}
+
+interface OwnProps {
location: { pathname: string };
organization: Organization;
}
-export default function OrganizationNavigationMenu({ location, organization }: Props) {
+type Props = OwnProps & StateToProps;
+
+export function OrganizationNavigationMenu({
+ currentUser,
+ location,
+ organization,
+ userOrganizations
+}: Props) {
return (
<NavBarTabs className="navbar-context-tabs">
<li>
@@ -50,7 +64,7 @@ export default function OrganizationNavigationMenu({ location, organization }: P
{translate('issues.page')}
</Link>
</li>
- {hasPrivateAccess(organization) && (
+ {hasPrivateAccess(currentUser, organization, userOrganizations) && (
<>
<li>
<Link
@@ -72,7 +86,7 @@ export default function OrganizationNavigationMenu({ location, organization }: P
</>
)}
- {isCurrentUserMemberOf(organization) && (
+ {isCurrentUserMemberOf(currentUser, organization, userOrganizations) && (
<li>
<Link activeClassName="active" to={`/organizations/${organization.key}/members`}>
{translate('organization.members.page')}
@@ -87,3 +101,10 @@ export default function OrganizationNavigationMenu({ location, organization }: P
</NavBarTabs>
);
}
+
+const mapStateToProps = (state: any) => ({
+ currentUser: getCurrentUser(state),
+ userOrganizations: getMyOrganizations(state)
+});
+
+export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(OrganizationNavigationMenu);
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenu-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx
index 251e41573de..ee37622b91b 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenu-test.tsx
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMenuContainer-test.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import OrganizationNavigationMenu from '../OrganizationNavigationMenu';
+import { OrganizationNavigationMenu } from '../OrganizationNavigationMenuContainer';
import { Visibility } from '../../../../app/types';
import { isCurrentUserMemberOf, hasPrivateAccess } from '../../../../helpers/organizations';
@@ -34,6 +34,13 @@ const organization = {
projectVisibility: Visibility.Public
};
+const loggedInUser = {
+ isLoggedIn: true,
+ login: 'luke',
+ name: 'Skywalker',
+ showOnboardingTutorial: false
+};
+
beforeEach(() => {
(isCurrentUserMemberOf as jest.Mock<any>).mockClear();
(hasPrivateAccess as jest.Mock<any>).mockClear();
@@ -41,7 +48,14 @@ beforeEach(() => {
it('renders', () => {
expect(
- shallow(<OrganizationNavigationMenu location={{ pathname: '' }} organization={organization} />)
+ shallow(
+ <OrganizationNavigationMenu
+ currentUser={loggedInUser}
+ location={{ pathname: '' }}
+ organization={organization}
+ userOrganizations={[organization]}
+ />
+ )
).toMatchSnapshot();
});
@@ -49,8 +63,10 @@ it('renders for admin', () => {
expect(
shallow(
<OrganizationNavigationMenu
+ currentUser={loggedInUser}
location={{ pathname: '' }}
organization={{ ...organization, canAdmin: true }}
+ userOrganizations={[organization]}
/>
)
).toMatchSnapshot();
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
index 820e5dc8611..240404ba19f 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigation-test.tsx.snap
@@ -27,7 +27,7 @@ exports[`render 1`] = `
}
/>
</div>
- <OrganizationNavigationMenu
+ <Connect(OrganizationNavigationMenu)
location={
Object {
"pathname": "/organizations/foo",
diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenu-test.tsx.snap b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap
index a51bf8cc513..a51bf8cc513 100644
--- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenu-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/__snapshots__/OrganizationNavigationMenuContainer-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
index c015b983357..cbb5d82aa9b 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
@@ -26,7 +26,7 @@ import ProjectsList from './ProjectsList';
import PageSidebar from './PageSidebar';
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import Visualizations from '../visualizations/Visualizations';
-import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { CurrentUser, isLoggedIn, Organization } from '../../../app/types';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
import ListFooter from '../../../components/controls/ListFooter';
@@ -44,7 +44,7 @@ export interface Props {
currentUser: CurrentUser;
isFavorite: boolean;
location: { pathname: string; query: RawQuery };
- organization?: { key: string };
+ organization: Organization | undefined;
organizationsEnabled: boolean;
storageOptionsSuffix?: string;
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx
index 5de80726a26..cf7600a82b6 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { connect } from 'react-redux';
-import { CurrentUser } from '../../../app/types';
+import { CurrentUser, Organization } from '../../../app/types';
import { lazyLoad } from '../../../components/lazyLoad';
import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer';
import { RawQuery } from '../../../helpers/query';
@@ -31,7 +31,7 @@ interface StateProps {
interface OwnProps {
isFavorite: boolean;
location: { pathname: string; query: RawQuery };
- organization?: { key: string };
+ organization: Organization | undefined;
storageOptionsSuffix?: string;
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx
index 1fffa7f7d3e..8b4e37b1ec6 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx
@@ -114,7 +114,13 @@ export default class DefaultPageSelector extends React.PureComponent<Props, Stat
render() {
if (isSonarCloud() && isLoggedIn(this.props.currentUser)) {
- return <AllProjectsContainer isFavorite={true} location={this.props.location} />;
+ return (
+ <AllProjectsContainer
+ isFavorite={true}
+ location={this.props.location}
+ organization={undefined}
+ />
+ );
}
const { shouldBeRedirected, shouldForceSorting } = this.state;
@@ -124,7 +130,13 @@ export default class DefaultPageSelector extends React.PureComponent<Props, Stat
shouldBeRedirected !== true &&
shouldForceSorting === undefined
) {
- return <AllProjectsContainer isFavorite={false} location={this.props.location} />;
+ return (
+ <AllProjectsContainer
+ isFavorite={false}
+ location={this.props.location}
+ organization={undefined}
+ />
+ );
}
return null;
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCard.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCard.tsx
index d572edb0d5b..e562aac058e 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCard.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCard.tsx
@@ -21,10 +21,11 @@ import * as React from 'react';
import ProjectCardLeak from './ProjectCardLeak';
import ProjectCardOverall from './ProjectCardOverall';
import { Project } from '../types';
+import { Organization } from '../../../app/types';
interface Props {
height: number;
- organization?: { key: string };
+ organization: Organization | undefined;
project: Project;
type?: string;
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx
index a019fca6cbf..23cf0206096 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx
@@ -28,12 +28,13 @@ import EmptyFavoriteSearch from './EmptyFavoriteSearch';
import EmptySearch from '../../../components/common/EmptySearch';
import { Project } from '../types';
import { Query } from '../query';
+import { Organization } from '../../../app/types';
interface Props {
cardType?: string;
isFavorite: boolean;
isFiltered: boolean;
- organization?: { key: string };
+ organization: Organization | undefined;
projects: Project[];
query: Query;
}
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx
index 7497a286fa9..babf7c999e0 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx
@@ -171,6 +171,7 @@ function shallowRender(
currentUser={{ isLoggedIn: true }}
isFavorite={false}
location={{ pathname: '/projects', query: {} }}
+ organization={undefined}
organizationsEnabled={false}
{...props}
/>,
diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsList-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsList-test.tsx
index a7dcb6ea2bc..fd28e6c2481 100644
--- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsList-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectsList-test.tsx
@@ -37,6 +37,7 @@ function shallowRender(props?: any) {
cardType="overall"
isFavorite={false}
isFiltered={false}
+ organization={undefined}
projects={[{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]}
{...props}
/>
diff --git a/server/sonar-web/src/main/js/apps/projects/utils.ts b/server/sonar-web/src/main/js/apps/projects/utils.ts
index 419ef569f9f..fe010d42316 100644
--- a/server/sonar-web/src/main/js/apps/projects/utils.ts
+++ b/server/sonar-web/src/main/js/apps/projects/utils.ts
@@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/* eslint-disable camelcase */
import { uniq } from 'lodash';
import { Query, convertToFilter } from './query';
import { translate } from '../../helpers/l10n';
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx
index 1a0e5500129..5244898544d 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx
@@ -70,11 +70,14 @@ export default class NewOrganizationForm extends React.PureComponent<Props, Stat
};
validateOrganization = (organization: string) => {
- getOrganization(organization).then(response => {
- if (this.mounted) {
- this.setState({ unique: response == null });
- }
- });
+ getOrganization(organization).then(
+ response => {
+ if (this.mounted) {
+ this.setState({ unique: response == null });
+ }
+ },
+ () => {}
+ );
};
sanitizeOrganization = (organization: string) =>
diff --git a/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.js.snap b/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.ts.snap
index c5ad9b73625..c5ad9b73625 100644
--- a/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.js.snap
+++ b/server/sonar-web/src/main/js/store/organizations/__tests__/__snapshots__/duck-test.ts.snap
diff --git a/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.js b/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.ts
index 2180d6af6f0..e9321e29f90 100644
--- a/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.js
+++ b/server/sonar-web/src/main/js/store/organizations/__tests__/duck-test.ts
@@ -19,14 +19,14 @@
*/
import organizations, { getOrganizationByKey, areThereCustomOrganizations } from '../duck';
+const state0 = { byKey: {}, my: [], groups: {} };
+
describe('Reducer', () => {
it('should have initial state', () => {
- expect(organizations(undefined, {})).toMatchSnapshot();
+ expect((organizations as any)(undefined, {})).toMatchSnapshot();
});
it('should receive organizations', () => {
- const state0 = { byKey: {} };
-
const action1 = {
type: 'RECEIVE_ORGANIZATIONS',
organizations: [{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]
@@ -46,7 +46,7 @@ describe('Reducer', () => {
describe('Selectors', () => {
it('getOrganizationByKey', () => {
const foo = { key: 'foo', name: 'Foo' };
- const state = { byKey: { foo } };
+ const state = { ...state0, byKey: { foo } };
expect(getOrganizationByKey(state, 'foo')).toBe(foo);
expect(getOrganizationByKey(state, 'bar')).toBeFalsy();
});
@@ -54,8 +54,8 @@ describe('Selectors', () => {
it('areThereCustomOrganizations', () => {
const foo = { key: 'foo', name: 'Foo' };
const bar = { key: 'bar', name: 'Bar' };
- expect(areThereCustomOrganizations({ byKey: {} }, 'foo')).toBe(false);
- expect(areThereCustomOrganizations({ byKey: { foo } }, 'foo')).toBe(false);
- expect(areThereCustomOrganizations({ byKey: { foo, bar } }, 'foo')).toBe(true);
+ expect(areThereCustomOrganizations({ ...state0, byKey: {} })).toBe(false);
+ expect(areThereCustomOrganizations({ ...state0, byKey: { foo } })).toBe(false);
+ expect(areThereCustomOrganizations({ ...state0, byKey: { foo, bar } })).toBe(true);
});
});
diff --git a/server/sonar-web/src/main/js/store/organizations/duck.ts b/server/sonar-web/src/main/js/store/organizations/duck.ts
index 8b6c76e3993..5f01ac95261 100644
--- a/server/sonar-web/src/main/js/store/organizations/duck.ts
+++ b/server/sonar-web/src/main/js/store/organizations/duck.ts
@@ -19,7 +19,7 @@
*/
import { combineReducers } from 'redux';
import { omit, uniq, without } from 'lodash';
-import { Group, Organization } from '../../app/types';
+import { Group, Organization, OrganizationBase } from '../../app/types';
interface ReceiveOrganizationsAction {
type: 'RECEIVE_ORGANIZATIONS';
@@ -108,7 +108,10 @@ export function createOrganization(organization: Organization): CreateOrganizati
};
}
-export function updateOrganization(key: string, changes: {}): UpdateOrganizationAction {
+export function updateOrganization(
+ key: string,
+ changes: OrganizationBase
+): UpdateOrganizationAction {
return {
type: 'UPDATE_ORGANIZATION',
key,
@@ -177,7 +180,7 @@ function groups(state: GroupsState = {}, action: Action) {
return state;
}
-export default combineReducers({ byKey, my, groups });
+export default combineReducers<State>({ byKey, my, groups });
export function getOrganizationByKey(state: State, key: string): Organization | undefined {
return state.byKey[key];
diff --git a/server/sonar-web/src/main/js/store/organizations/utils.js b/server/sonar-web/src/main/js/store/organizations/utils.ts
index adf5ed2c5e3..5b3957e1f6c 100644
--- a/server/sonar-web/src/main/js/store/organizations/utils.js
+++ b/server/sonar-web/src/main/js/store/organizations/utils.ts
@@ -17,14 +17,13 @@
* 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 getStore from '../../app/utils/getStore';
import {
getOrganizationByKey,
areThereCustomOrganizations as customOrganizations
} from '../rootReducer';
-export function getOrganization(key /*: string */) {
+export function getOrganization(key: string) {
const store = getStore();
const state = store.getState();
return getOrganizationByKey(state, key);