* 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 {
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 });
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import 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'; */
-
-/*::
-type Props = {
- fetchOrganization: string => void,
- location: {},
- organization: Organization,
- params: {
- extensionKey: string,
- organizationKey: string,
- pluginKey: string
- }
-};
-*/
-
-class OrganizationPageExtension extends React.PureComponent {
- /*:: props: Props; */
-
- refreshOrganization = () => this.props.fetchOrganization(this.props.organization.key);
-
- render() {
- const { extensionKey, pluginKey } = this.props.params;
- const { organization } = this.props;
-
- let pages = organization.pages || [];
- if (organization.canAdmin && organization.adminPages) {
- pages = pages.concat(organization.adminPages);
- }
-
- const extension = pages.find(p => p.key === `${pluginKey}/${extensionKey}`);
- return extension ? (
- <ExtensionContainer
- extension={extension}
- location={this.props.location}
- options={{ organization, refreshOrganization: this.refreshOrganization }}
- />
- ) : (
- <ExtensionNotFound />
- );
- }
-}
-
-const mapStateToProps = (state, ownProps /*: Props */) => ({
- organization: getOrganizationByKey(state, ownProps.params.organizationKey)
-});
-
-const mapDispatchToProps = { fetchOrganization };
-
-export default connect(mapStateToProps, mapDispatchToProps)(OrganizationPageExtension);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { connect } from 'react-redux';
+import ExtensionContainer from './ExtensionContainer';
+import ExtensionNotFound from './ExtensionNotFound';
+import { getOrganizationByKey } from '../../../store/rootReducer';
+import { fetchOrganization } from '../../../apps/organizations/actions';
+import { Organization } from '../../../app/types';
+
+interface StateToProps {
+ organization?: Organization;
+}
+
+interface DispatchProps {
+ fetchOrganization: (organizationKey: string) => void;
+}
+
+interface OwnProps {
+ location: {};
+ params: {
+ extensionKey: string;
+ organizationKey: string;
+ pluginKey: string;
+ };
+}
+
+type Props = OwnProps & StateToProps & DispatchProps;
+
+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);
+ }
+
+ const extension = pages.find(p => p.key === `${pluginKey}/${extensionKey}`);
+ return extension ? (
+ <ExtensionContainer
+ extension={extension}
+ location={this.props.location}
+ options={{ organization, refreshOrganization: this.refreshOrganization }}
+ />
+ ) : (
+ <ExtensionNotFound />
+ );
+ }
+}
+
+const mapStateToProps = (state: any, ownProps: OwnProps) => ({
+ organization: getOrganizationByKey(state, ownProps.params.organizationKey)
+});
+
+const mapDispatchToProps = { fetchOrganization };
+
+export default connect<StateToProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
+ OrganizationPageExtension
+);
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);
}
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 {
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 {
}
export default function ExploreProjects(props: Props) {
- return <AllProjectsContainer isFavorite={false} storageOptionsSuffix="explore" {...props} />;
+ return (
+ <AllProjectsContainer
+ isFavorite={false}
+ organization={undefined}
+ storageOptionsSuffix="explore"
+ {...props}
+ />
+ );
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import * as api from '../../api/organizations';
-import * as actions from '../../store/organizations/duck';
-import * as membersActions from '../../store/organizationsMembers/actions';
-import { searchUsersGroups, addUserToGroup, removeUserFromGroup } from '../../api/user_groups';
-import { receiveUser } from '../../store/users/actions';
-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'; */
-
-const PAGE_SIZE = 50;
-
-const onRejected = (dispatch /*: Function */) => (error /*: Object */) => {
- onFail(dispatch)(error);
- return Promise.reject();
-};
-
-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]));
- }
- };
-
- return Promise.all([api.getOrganization(key), api.getOrganizationNavigation(key)]).then(
- onFulfilled,
- onFail(dispatch)
- );
-};
-
-export const fetchOrganizationGroups = (organization /*: string */) => (
- dispatch /*: Function */
-) => {
- return searchUsersGroups({ organization }).then(response => {
- dispatch(actions.receiveOrganizationGroups(organization, response.groups));
- }, onFail(dispatch));
-};
-
-export const createOrganization = (fields /*: Object */) => (dispatch /*: Function */) => {
- const onFulfilled = (organization /*: Organization */) => {
- dispatch(actions.createOrganization(organization));
- dispatch(
- addGlobalSuccessMessage(translateWithParameters('organization.created', organization.name))
- );
- return organization;
- };
-
- return api.createOrganization(fields).then(onFulfilled, onRejected(dispatch));
-};
-
-export const updateOrganization = (key /*: string */, changes /*: {} */) => (
- dispatch /*: Function */
-) => {
- const onFulfilled = () => {
- dispatch(actions.updateOrganization(key, changes));
- dispatch(addGlobalSuccessMessage(translate('organization.updated')));
- };
-
- return api.updateOrganization(key, changes).then(onFulfilled, onFail(dispatch));
-};
-
-export const deleteOrganization = (key /*: string */) => (dispatch /*: Function */) => {
- const onFulfilled = () => {
- dispatch(actions.deleteOrganization(key));
- dispatch(addGlobalSuccessMessage(translate('organization.deleted')));
- };
-
- return api.deleteOrganization(key).then(onFulfilled, onFail(dispatch));
-};
-
-const fetchMembers = (
- dispatch /*: Function */,
- receiveAction /*: Function */,
- key /*: string */,
- query /*: ?string */,
- page /*: ?number */
-) => {
- dispatch(membersActions.updateState(key, { loading: true }));
- const data /*: Object */ = {
- organization: key,
- ps: PAGE_SIZE
- };
- if (page != null) {
- data.p = page;
- }
- if (query) {
- data.q = query;
- }
- 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));
-};
-
-export const fetchOrganizationMembers = (key /*: string */, query /*: ?string */) => (
- dispatch /*: Function */
-) => fetchMembers(dispatch, membersActions.receiveMembers, key, query);
-
-export const fetchMoreOrganizationMembers = (key /*: string */, query /*: ?string */) => (
- dispatch /*: Function */,
- getState /*: Function */
-) =>
- fetchMembers(
- dispatch,
- membersActions.receiveMoreMembers,
- key,
- query,
- getOrganizationMembersState(getState(), key).pageIndex + 1
- );
-
-export const addOrganizationMember = (key /*: string */, member /*: Member */) => (
- dispatch /*: Function */
-) => {
- 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 */
-) => {
- dispatch(membersActions.removeMember(key, member));
- return api.removeMember({ login: member.login, organization: key }).catch((
- error /*: Object */
- ) => {
- onFail(dispatch)(error);
- dispatch(membersActions.addMember(key, member));
- });
-};
-
-export const updateOrganizationMemberGroups = (
- organization /*: Organization */,
- member /*: Member */,
- add /*: Array<string> */,
- remove /*: Array<string> */
-) => (dispatch /*: Function */) => {
- dispatch(
- receiveUser({
- ...member,
- groupCount: (member.groupCount || 0) + add.length - remove.length
- })
- );
- const promises = [
- ...add.map(name =>
- addUserToGroup({ name, login: member.login, organization: organization.key })
- ),
- ...remove.map(name =>
- removeUserFromGroup({ name, login: member.login, organization: organization.key })
- )
- ];
- return Promise.all(promises).catch(error => {
- dispatch(receiveUser(member));
- onFail(dispatch)(error);
- });
-};
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { Dispatch } from 'redux';
+import * as api from '../../api/organizations';
+import * as actions from '../../store/organizations/duck';
+import * as membersActions from '../../store/organizationsMembers/actions';
+import { searchUsersGroups, addUserToGroup, removeUserFromGroup } from '../../api/user_groups';
+import { receiveUser } from '../../store/users/actions';
+import { onFail } from '../../store/rootActions';
+import { getOrganizationMembersState } from '../../store/rootReducer';
+import { addGlobalSuccessMessage } from '../../store/globalMessages/duck';
+import { translate, translateWithParameters } from '../../helpers/l10n';
+import { Organization, OrganizationMember, OrganizationBase } from '../../app/types';
+
+const PAGE_SIZE = 50;
+
+const onRejected = (dispatch: Dispatch<any>) => (error: any) => {
+ onFail(dispatch)(error);
+ return Promise.reject(error);
+};
+
+export const fetchOrganization = (key: string) => (dispatch: Dispatch<any>) => {
+ return Promise.all([api.getOrganization(key), api.getOrganizationNavigation(key)]).then(
+ ([organization, navigation]) => {
+ if (organization) {
+ const organizationWithPermissions = { ...organization, ...navigation };
+ dispatch(actions.receiveOrganizations([organizationWithPermissions]));
+ }
+ },
+ onFail(dispatch)
+ );
+};
+
+export const fetchOrganizationGroups = (organization: string) => (dispatch: Dispatch<any>) => {
+ return searchUsersGroups({ organization }).then(response => {
+ dispatch(actions.receiveOrganizationGroups(organization, response.groups));
+ }, onFail(dispatch));
+};
+
+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;
+ }, onRejected(dispatch));
+};
+
+export const updateOrganization = (key: string, changes: OrganizationBase) => (
+ dispatch: Dispatch<any>
+) => {
+ return api.updateOrganization(key, changes).then(() => {
+ dispatch(actions.updateOrganization(key, changes));
+ dispatch(addGlobalSuccessMessage(translate('organization.updated')));
+ }, onFail(dispatch));
+};
+
+export const deleteOrganization = (key: string) => (dispatch: Dispatch<any>) => {
+ return api.deleteOrganization(key).then(() => {
+ dispatch(actions.deleteOrganization(key));
+ dispatch(addGlobalSuccessMessage(translate('organization.deleted')));
+ }, onFail(dispatch));
+};
+
+const fetchMembers = (
+ data: {
+ organization: string;
+ p?: number;
+ ps?: number;
+ q?: string;
+ },
+ dispatch: Dispatch<any>,
+ receiveAction: Function
+) => {
+ dispatch(membersActions.updateState(data.organization, { loading: true }));
+ if (data.ps === undefined) {
+ data.ps = PAGE_SIZE;
+ }
+ if (!data.q) {
+ data.q = undefined;
+ }
+ 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: Dispatch<any>
+) => fetchMembers({ organization: key, q: query }, dispatch, membersActions.receiveMembers);
+
+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
+ );
+
+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: OrganizationMember) => (
+ dispatch: Dispatch<any>
+) => {
+ dispatch(membersActions.removeMember(key, member));
+ 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: OrganizationMember,
+ add: string[],
+ remove: string[]
+) => (dispatch: Dispatch<any>) => {
+ dispatch(
+ receiveUser({
+ ...member,
+ groupCount: (member.groupCount || 0) + add.length - remove.length
+ })
+ );
+ const promises = [
+ ...add.map(name =>
+ addUserToGroup({ name, login: member.login, organization: organization.key })
+ ),
+ ...remove.map(name =>
+ removeUserFromGroup({ name, login: member.login, organization: organization.key })
+ )
+ ];
+ return Promise.all(promises).catch(error => {
+ dispatch(receiveUser(member));
+ onFail(dispatch)(error);
+ });
+};
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-//@flow
-import React from 'react';
-import MembersListItem from './MembersListItem';
-/*:: import type { Member } from '../../../store/organizationsMembers/actions'; */
-/*:: import type { Organization, Group } 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; */
-
- render() {
- return (
- <div className="boxed-group boxed-group-inner">
- <table className="data zebra">
- <tbody>
- {this.props.members.map(member => (
- <MembersListItem
- key={member.login}
- member={member}
- organizationGroups={this.props.organizationGroups}
- organization={this.props.organization}
- removeMember={this.props.removeMember}
- updateMemberGroups={this.props.updateMemberGroups}
- />
- ))}
- </tbody>
- </table>
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import MembersListItem from './MembersListItem';
+import { Group, Organization, OrganizationMember } from '../../../app/types';
+
+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">
+ <table className="data zebra">
+ <tbody>
+ {this.props.members.map(member => (
+ <MembersListItem
+ key={member.login}
+ member={member}
+ organization={this.props.organization}
+ organizationGroups={this.props.organizationGroups}
+ removeMember={this.props.removeMember}
+ updateMemberGroups={this.props.updateMemberGroups}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-//@flow
-import 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
-};
-*/
-
-export default function MembersListHeader({ handleSearch, total } /*: Props */) {
- return (
- <div className="panel panel-vertical bordered-bottom spacer-bottom">
- <SearchBox
- minLength={2}
- onChange={handleSearch}
- placeholder={translate('search.search_for_users')}
- />
- {total != null && (
- <span className="pull-right little-spacer-top">
- <strong>{formatMeasure(total, 'INT')}</strong> {translate('organization.members.members')}
- </span>
- )}
- </div>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import SearchBox from '../../../components/controls/SearchBox';
+import { formatMeasure } from '../../../helpers/measures';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ handleSearch: (query?: string) => void;
+ total?: number;
+}
+
+export default function MembersListHeader({ handleSearch, total }: Props) {
+ return (
+ <div className="panel panel-vertical bordered-bottom spacer-bottom">
+ <SearchBox
+ minLength={2}
+ onChange={handleSearch}
+ placeholder={translate('search.search_for_users')}
+ />
+ {total != null && (
+ <span className="pull-right little-spacer-top">
+ <strong>{formatMeasure(total, 'INT')}</strong> {translate('organization.members.members')}
+ </span>
+ )}
+ </div>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-//@flow
-import React from 'react';
-import RemoveMemberForm from './forms/RemoveMemberForm';
-import ManageMemberGroupsForm from './forms/ManageMemberGroupsForm';
-import Avatar from '../../../components/ui/Avatar';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { formatMeasure } from '../../../helpers/measures';
-import ActionsDropdown, {
- ActionsDropdownDivider,
- ActionsDropdownItem
-} from '../../../components/controls/ActionsDropdown';
-/*:: import type { Member } from '../../../store/organizationsMembers/actions'; */
-/*:: import type { Organization, Group } 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
-};
-
-type State = {
- removeMemberForm: bool,
- manageGroupsForm: bool
-}
-*/
-
-const AVATAR_SIZE /*: number */ = 36;
-
-export default class MembersListItem extends React.PureComponent {
- mounted /*: bool */ = false;
- /*:: props: Props; */
- state /*: State */ = { removeMemberForm: false, manageGroupsForm: false };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleManageGroupsClick = () => {
- this.setState({ manageGroupsForm: true });
- };
-
- closeManageGroupsForm = () => {
- if (this.mounted) {
- this.setState({ manageGroupsForm: false });
- }
- };
-
- handleRemoveMemberClick = () => {
- this.setState({ removeMemberForm: true });
- };
-
- closeRemoveMemberForm = () => {
- if (this.mounted) {
- this.setState({ removeMemberForm: false });
- }
- };
-
- render() {
- const { member, organization } = this.props;
- return (
- <tr>
- <td className="thin nowrap">
- <Avatar hash={member.avatar} name={member.name} size={AVATAR_SIZE} />
- </td>
- <td className="nowrap text-middle">
- <strong>{member.name}</strong>
- <span className="note little-spacer-left">{member.login}</span>
- </td>
- {organization.canAdmin && (
- <td className="text-right text-middle">
- {translateWithParameters(
- 'organization.members.x_groups',
- formatMeasure(member.groupCount || 0, 'INT')
- )}
- </td>
- )}
- {organization.canAdmin && (
- <React.Fragment>
- <td className="nowrap text-middle text-right">
- <ActionsDropdown>
- <ActionsDropdownItem onClick={this.handleManageGroupsClick}>
- {translate('organization.members.manage_groups')}
- </ActionsDropdownItem>
- <ActionsDropdownDivider />
- <ActionsDropdownItem destructive={true} onClick={this.handleRemoveMemberClick}>
- {translate('organization.members.remove')}
- </ActionsDropdownItem>
- </ActionsDropdown>
- </td>
-
- {this.state.manageGroupsForm && (
- <ManageMemberGroupsForm
- member={this.props.member}
- onClose={this.closeManageGroupsForm}
- organization={this.props.organization}
- organizationGroups={this.props.organizationGroups}
- updateMemberGroups={this.props.updateMemberGroups}
- />
- )}
-
- {this.state.removeMemberForm && (
- <RemoveMemberForm
- member={this.props.member}
- onClose={this.closeRemoveMemberForm}
- organization={this.props.organization}
- removeMember={this.props.removeMember}
- />
- )}
- </React.Fragment>
- )}
- </tr>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import RemoveMemberForm from './forms/RemoveMemberForm';
+import ManageMemberGroupsForm from './forms/ManageMemberGroupsForm';
+import Avatar from '../../../components/ui/Avatar';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { formatMeasure } from '../../../helpers/measures';
+import ActionsDropdown, {
+ ActionsDropdownDivider,
+ ActionsDropdownItem
+} from '../../../components/controls/ActionsDropdown';
+import { Group, Organization, OrganizationMember } from '../../../app/types';
+
+interface Props {
+ member: OrganizationMember;
+ organization: Organization;
+ organizationGroups: Group[];
+ removeMember: (member: OrganizationMember) => void;
+ updateMemberGroups: (member: OrganizationMember, add: string[], remove: string[]) => void;
+}
+
+interface State {
+ removeMemberForm: boolean;
+ manageGroupsForm: boolean;
+}
+
+const AVATAR_SIZE = 36;
+
+export default class MembersListItem extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = { removeMemberForm: false, manageGroupsForm: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleManageGroupsClick = () => {
+ this.setState({ manageGroupsForm: true });
+ };
+
+ closeManageGroupsForm = () => {
+ if (this.mounted) {
+ this.setState({ manageGroupsForm: false });
+ }
+ };
+
+ handleRemoveMemberClick = () => {
+ this.setState({ removeMemberForm: true });
+ };
+
+ closeRemoveMemberForm = () => {
+ if (this.mounted) {
+ this.setState({ removeMemberForm: false });
+ }
+ };
+
+ render() {
+ const { member, organization } = this.props;
+ return (
+ <tr>
+ <td className="thin nowrap">
+ <Avatar hash={member.avatar} name={member.name} size={AVATAR_SIZE} />
+ </td>
+ <td className="nowrap text-middle">
+ <strong>{member.name}</strong>
+ <span className="note little-spacer-left">{member.login}</span>
+ </td>
+ {organization.canAdmin && (
+ <td className="text-right text-middle">
+ {translateWithParameters(
+ 'organization.members.x_groups',
+ formatMeasure(member.groupCount || 0, 'INT')
+ )}
+ </td>
+ )}
+ {organization.canAdmin && (
+ <React.Fragment>
+ <td className="nowrap text-middle text-right">
+ <ActionsDropdown>
+ <ActionsDropdownItem onClick={this.handleManageGroupsClick}>
+ {translate('organization.members.manage_groups')}
+ </ActionsDropdownItem>
+ <ActionsDropdownDivider />
+ <ActionsDropdownItem destructive={true} onClick={this.handleRemoveMemberClick}>
+ {translate('organization.members.remove')}
+ </ActionsDropdownItem>
+ </ActionsDropdown>
+ </td>
+
+ {this.state.manageGroupsForm && (
+ <ManageMemberGroupsForm
+ member={this.props.member}
+ onClose={this.closeManageGroupsForm}
+ organization={this.props.organization}
+ organizationGroups={this.props.organizationGroups}
+ updateMemberGroups={this.props.updateMemberGroups}
+ />
+ )}
+
+ {this.state.removeMemberForm && (
+ <RemoveMemberForm
+ member={this.props.member}
+ onClose={this.closeRemoveMemberForm}
+ organization={this.props.organization}
+ removeMember={this.props.removeMember}
+ />
+ )}
+ </React.Fragment>
+ )}
+ </tr>
+ );
+ }
+}
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 {
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)(
export function OrganizationPrivateAccess(props: OwnProps) {
return (
<OrganizationAccessContainer
- hasAccess={({ organization }: StateToProps) => hasPrivateAccess(organization)}
+ hasAccess={({ currentUser, organization, userOrganizations }: StateToProps) =>
+ hasPrivateAccess(currentUser, organization, userOrganizations)
+ }
{...props}
/>
);
export function OrganizationMembersAccess(props: OwnProps) {
return (
<OrganizationAccessContainer
- hasAccess={({ organization }: StateToProps) => isCurrentUserMemberOf(organization)}
+ hasAccess={({ currentUser, organization, userOrganizations }: StateToProps) =>
+ isCurrentUserMemberOf(currentUser, organization, userOrganizations)
+ }
{...props}
/>
);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import 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
- };
-*/
-
- constructor(props /*: Props */) {
- super(props);
- this.state = {
- loading: false,
-
- avatar: props.organization.avatar || '',
- avatarImage: props.organization.avatar || '',
- description: props.organization.description || '',
- name: props.organization.name,
- url: props.organization.url || ''
- };
- this.changeAvatarImage = debounce(this.changeAvatarImage, 500);
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- handleAvatarInputChange = (e /*: Object */) => {
- const { value } = e.target;
- this.setState({ avatar: value });
- this.changeAvatarImage(value);
- };
-
- changeAvatarImage = (value /*: string */) => {
- this.setState({ avatarImage: value });
- };
-
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
- const changes = {
- avatar: this.state.avatar,
- description: this.state.description,
- name: this.state.name,
- url: this.state.url
- };
- this.setState({ loading: true });
- this.props.updateOrganization(this.props.organization.key, changes).then(() => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- });
- };
-
- render() {
- const title = translate('organization.edit');
- return (
- <div className="page page-limited">
- <Helmet title={title} />
-
- <header className="page-header">
- <h1 className="page-title">{title}</h1>
- </header>
-
- <div className="boxed-group boxed-group-inner">
- <form onSubmit={this.handleSubmit}>
- <div className="modal-field">
- <label htmlFor="organization-name">
- {translate('organization.name')}
- <em className="mandatory">*</em>
- </label>
- <input
- disabled={this.state.loading}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={e => this.setState({ name: e.target.value })}
- required={true}
- type="text"
- value={this.state.name}
- />
- <div className="modal-field-description">
- {translate('organization.name.description')}
- </div>
- </div>
- <div className="modal-field">
- <label htmlFor="organization-avatar">{translate('organization.avatar')}</label>
- <input
- disabled={this.state.loading}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={this.handleAvatarInputChange}
- type="text"
- value={this.state.avatar}
- />
- <div className="modal-field-description">
- {translate('organization.avatar.description')}
- </div>
- {!!this.state.avatarImage && (
- <div className="spacer-top spacer-bottom">
- <div className="little-spacer-bottom">
- {translate('organization.avatar.preview')}
- {':'}
- </div>
- <img alt="" height={30} src={this.state.avatarImage} />
- </div>
- )}
- </div>
- <div className="modal-field">
- <label htmlFor="organization-description">{translate('description')}</label>
- <textarea
- disabled={this.state.loading}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={e => this.setState({ description: e.target.value })}
- rows="3"
- value={this.state.description}
- />
- <div className="modal-field-description">
- {translate('organization.description.description')}
- </div>
- </div>
- <div className="modal-field">
- <label htmlFor="organization-url">{translate('organization.url')}</label>
- <input
- disabled={this.state.loading}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={e => this.setState({ url: e.target.value })}
- type="text"
- value={this.state.url}
- />
- <div className="modal-field-description">
- {translate('organization.url.description')}
- </div>
- </div>
- <div className="modal-field">
- <SubmitButton disabled={this.state.loading}>{translate('save')}</SubmitButton>
- {this.state.loading && <i className="spinner spacer-left" />}
- </div>
- </form>
- </div>
- </div>
- );
- }
-}
-
-const mapDispatchToProps = { updateOrganization };
-
-export default connect(null, mapDispatchToProps)(OrganizationEdit);
-
-export const UnconnectedOrganizationEdit = OrganizationEdit;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import 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 { Organization, OrganizationBase } from '../../../app/types';
+
+interface DispatchProps {
+ updateOrganization: (organization: string, changes: OrganizationBase) => Promise<any>;
+}
+
+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 || '',
+ name: props.organization.name,
+ url: props.organization.url || ''
+ };
+ this.changeAvatarImage = debounce(this.changeAvatarImage, 500);
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ handleAvatarInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ const { value } = event.target;
+ this.setState({ avatar: value });
+ this.changeAvatarImage(value);
+ };
+
+ changeAvatarImage = (value: string) => {
+ this.setState({ avatarImage: value });
+ };
+
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const changes = {
+ avatar: this.state.avatar,
+ description: this.state.description,
+ name: this.state.name,
+ url: this.state.url
+ };
+ this.setState({ loading: true });
+ this.props
+ .updateOrganization(this.props.organization.key, changes)
+ .then(this.stopLoading, this.stopLoading);
+ };
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
+ render() {
+ const title = translate('organization.edit');
+ return (
+ <div className="page page-limited">
+ <Helmet title={title} />
+
+ <header className="page-header">
+ <h1 className="page-title">{title}</h1>
+ </header>
+
+ <div className="boxed-group boxed-group-inner">
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-field">
+ <label htmlFor="organization-name">
+ {translate('organization.name')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ disabled={this.state.loading}
+ id="organization-name"
+ maxLength={64}
+ name="name"
+ onChange={e => this.setState({ name: e.target.value })}
+ required={true}
+ type="text"
+ value={this.state.name}
+ />
+ <div className="modal-field-description">
+ {translate('organization.name.description')}
+ </div>
+ </div>
+ <div className="modal-field">
+ <label htmlFor="organization-avatar">{translate('organization.avatar')}</label>
+ <input
+ disabled={this.state.loading}
+ id="organization-avatar"
+ maxLength={256}
+ name="avatar"
+ onChange={this.handleAvatarInputChange}
+ type="text"
+ value={this.state.avatar}
+ />
+ <div className="modal-field-description">
+ {translate('organization.avatar.description')}
+ </div>
+ {!!this.state.avatarImage && (
+ <div className="spacer-top spacer-bottom">
+ <div className="little-spacer-bottom">
+ {translate('organization.avatar.preview')}
+ {':'}
+ </div>
+ <img alt="" height={30} src={this.state.avatarImage} />
+ </div>
+ )}
+ </div>
+ <div className="modal-field">
+ <label htmlFor="organization-description">{translate('description')}</label>
+ <textarea
+ disabled={this.state.loading}
+ id="organization-description"
+ maxLength={256}
+ name="description"
+ onChange={e => this.setState({ description: e.target.value })}
+ rows={3}
+ value={this.state.description}
+ />
+ <div className="modal-field-description">
+ {translate('organization.description.description')}
+ </div>
+ </div>
+ <div className="modal-field">
+ <label htmlFor="organization-url">{translate('organization.url')}</label>
+ <input
+ disabled={this.state.loading}
+ id="organization-url"
+ maxLength={256}
+ name="url"
+ onChange={e => this.setState({ url: e.target.value })}
+ type="text"
+ value={this.state.url}
+ />
+ <div className="modal-field-description">
+ {translate('organization.url.description')}
+ </div>
+ </div>
+ <div className="modal-field">
+ <SubmitButton disabled={this.state.loading}>{translate('save')}</SubmitButton>
+ {this.state.loading && <i className="spinner spacer-left" />}
+ </div>
+ </form>
+ </div>
+ </div>
+ );
+ }
+}
+
+const mapDispatchToProps = { updateOrganization: updateOrganization as any };
+
+export default connect<{}, DispatchProps, OwnProps>(null, mapDispatchToProps)(OrganizationEdit);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-//@flow
-import React from 'react';
-import Checkbox from '../../../components/controls/Checkbox';
-/*:: import type { Group } from '../../../app/types'; */
-
-/*::
-type Props = {
- group: Group,
- checked: boolean,
- onCheck: (string, boolean) => void
-};
-*/
-
-export default class OrganizationGroupCheckbox extends React.PureComponent {
- /*:: props: Props; */
-
- onCheck = (checked /*: boolean */) => {
- const { group } = this.props;
- if (!group.default) {
- this.props.onCheck(group.name, checked);
- }
- };
-
- toggleCheck = () => {
- this.onCheck(!this.props.checked);
- };
-
- render() {
- const { group } = this.props;
- return (
- <li
- className="capitalize list-item-checkable-link"
- onClick={this.toggleCheck}
- tabIndex={0}
- role="listitem"
- disabled={group.default}>
- <Checkbox checked={this.props.checked} onCheck={this.onCheck} /> {group.name}
- </li>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import Checkbox from '../../../components/controls/Checkbox';
+import { Group } from '../../../app/types';
+
+interface Props {
+ group: Group;
+ checked: boolean;
+ onCheck: (name: string, checked: boolean) => void;
+}
+
+export default class OrganizationGroupCheckbox extends React.PureComponent<Props> {
+ onCheck = (checked: boolean) => {
+ const { group } = this.props;
+ if (!group.default) {
+ this.props.onCheck(group.name, checked);
+ }
+ };
+
+ toggleCheck = () => {
+ this.onCheck(!this.props.checked);
+ };
+
+ render() {
+ const { group } = this.props;
+ return (
+ <li
+ className={classNames('capitalize list-item-checkable-link', { disabled: group.default })}
+ onClick={this.toggleCheck}>
+ <Checkbox checked={this.props.checked} onCheck={this.onCheck} /> {group.name}
+ </li>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import React from 'react';
-import Helmet from 'react-helmet';
-import MembersPageHeader from './MembersPageHeader';
-import MembersListHeader from './MembersListHeader';
-import MembersList from './MembersList';
-import AddMemberForm from './forms/AddMemberForm';
-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'; */
-
-/*::
-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,
- updateOrganizationMemberGroups: (
- organization: Organization,
- member: Member,
- add: Array<string>,
- remove: Array<string>
- ) => void
-};
-*/
-
-export default class OrganizationMembers extends React.PureComponent {
- /*:: props: Props; */
-
- componentDidMount() {
- this.handleSearchMembers();
- if (this.props.organization.canAdmin) {
- this.props.fetchOrganizationGroups(this.props.organization.key);
- }
- }
-
- handleSearchMembers = (query /*: string | void */) => {
- this.props.fetchOrganizationMembers(this.props.organization.key, query);
- };
-
- handleLoadMoreMembers = () => {
- this.props.fetchMoreOrganizationMembers(this.props.organization.key, this.props.status.query);
- };
-
- addMember = (member /*: Member */) => {
- this.props.addOrganizationMember(this.props.organization.key, member);
- };
-
- removeMember = (member /*: Member */) => {
- this.props.removeOrganizationMember(this.props.organization.key, member);
- };
-
- updateMemberGroups = (
- member /*: Member */,
- add /*: Array<string> */,
- remove /*: Array<string> */
- ) => {
- this.props.updateOrganizationMemberGroups(this.props.organization, member, add, remove);
- };
-
- render() {
- const { organization, status, members } = this.props;
- return (
- <div className="page page-limited">
- <Helmet title={translate('organization.members.page')} />
- <Suggestions suggestions="organization_members" />
- <MembersPageHeader loading={status.loading}>
- {organization.canAdmin && (
- <div className="page-actions">
- <AddMemberForm
- addMember={this.addMember}
- memberLogins={this.props.memberLogins}
- organization={organization}
- />
- <DocTooltip className="spacer-left" doc="organizations/add-organization-member" />
- </div>
- )}
- </MembersPageHeader>
- <MembersListHeader handleSearch={this.handleSearchMembers} total={status.total} />
- <MembersList
- members={members}
- organization={organization}
- organizationGroups={this.props.organizationGroups}
- removeMember={this.removeMember}
- updateMemberGroups={this.updateMemberGroups}
- />
- {status.total != null && (
- <ListFooter
- count={members.length}
- loadMore={this.handleLoadMoreMembers}
- ready={!status.loading}
- total={status.total}
- />
- )}
- </div>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Helmet from 'react-helmet';
+import MembersPageHeader from './MembersPageHeader';
+import MembersListHeader from './MembersListHeader';
+import MembersList from './MembersList';
+import AddMemberForm from './forms/AddMemberForm';
+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 { Group, Organization, OrganizationMember } from '../../../app/types';
+
+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: OrganizationMember,
+ add: string[],
+ remove: string[]
+ ) => void;
+}
+
+export default class OrganizationMembers extends React.PureComponent<Props> {
+ componentDidMount() {
+ this.handleSearchMembers();
+ if (this.props.organization.canAdmin) {
+ this.props.fetchOrganizationGroups(this.props.organization.key);
+ }
+ }
+
+ handleSearchMembers = (query?: string) => {
+ this.props.fetchOrganizationMembers(this.props.organization.key, query);
+ };
+
+ handleLoadMoreMembers = () => {
+ this.props.fetchMoreOrganizationMembers(this.props.organization.key, this.props.status.query);
+ };
+
+ addMember = (member: OrganizationMember) => {
+ this.props.addOrganizationMember(this.props.organization.key, member);
+ };
+
+ removeMember = (member: OrganizationMember) => {
+ this.props.removeOrganizationMember(this.props.organization.key, member);
+ };
+
+ updateMemberGroups = (member: OrganizationMember, add: string[], remove: string[]) => {
+ this.props.updateOrganizationMemberGroups(this.props.organization, member, add, remove);
+ };
+
+ render() {
+ const { organization, status, members } = this.props;
+ return (
+ <div className="page page-limited">
+ <Helmet title={translate('organization.members.page')} />
+ <Suggestions suggestions="organization_members" />
+ <MembersPageHeader loading={Boolean(status.loading)}>
+ {organization.canAdmin && (
+ <div className="page-actions">
+ <AddMemberForm
+ addMember={this.addMember}
+ memberLogins={this.props.memberLogins}
+ organization={organization}
+ />
+ <DocTooltip className="spacer-left" doc="organizations/add-organization-member" />
+ </div>
+ )}
+ </MembersPageHeader>
+ <MembersListHeader handleSearch={this.handleSearchMembers} total={status.total} />
+ <MembersList
+ members={members}
+ organization={organization}
+ organizationGroups={this.props.organizationGroups}
+ removeMember={this.removeMember}
+ updateMemberGroups={this.updateMemberGroups}
+ />
+ {status.total != null && (
+ <ListFooter
+ count={members.length}
+ loadMore={this.handleLoadMoreMembers}
+ ready={!status.loading}
+ total={status.total}
+ />
+ )}
+ </div>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { connect } from 'react-redux';
-import OrganizationMembers from './OrganizationMembers';
-import {
- getOrganizationByKey,
- getOrganizationGroupsByKey,
- getOrganizationMembersLogins,
- getUsersByLogins,
- getOrganizationMembersState
-} from '../../../store/rootReducer';
-import {
- fetchOrganizationMembers,
- fetchMoreOrganizationMembers,
- fetchOrganizationGroups,
- addOrganizationMember,
- removeOrganizationMember,
- updateOrganizationMemberGroups
-} from '../actions';
-
-const mapStateToProps = (state, ownProps) => {
- const { organizationKey } = ownProps.params;
- const memberLogins = getOrganizationMembersLogins(state, organizationKey);
- return {
- memberLogins,
- members: getUsersByLogins(state, memberLogins),
- organization: getOrganizationByKey(state, organizationKey),
- organizationGroups: getOrganizationGroupsByKey(state, organizationKey),
- status: getOrganizationMembersState(state, organizationKey)
- };
-};
-
-export default connect(mapStateToProps, {
- fetchOrganizationMembers,
- fetchMoreOrganizationMembers,
- fetchOrganizationGroups,
- addOrganizationMember,
- removeOrganizationMember,
- updateOrganizationMemberGroups
-})(OrganizationMembers);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { connect } from 'react-redux';
+import OrganizationMembers from './OrganizationMembers';
+import {
+ getOrganizationByKey,
+ getOrganizationGroupsByKey,
+ getOrganizationMembersLogins,
+ getUsersByLogins,
+ getOrganizationMembersState
+} from '../../../store/rootReducer';
+import {
+ fetchOrganizationMembers,
+ fetchMoreOrganizationMembers,
+ fetchOrganizationGroups,
+ addOrganizationMember,
+ removeOrganizationMember,
+ updateOrganizationMemberGroups
+} from '../actions';
+import { Organization, OrganizationMember, Group } from '../../../app/types';
+
+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 {
+ memberLogins,
+ members: getUsersByLogins(state, memberLogins),
+ organization: getOrganizationByKey(state, organizationKey),
+ organizationGroups: getOrganizationGroupsByKey(state, organizationKey),
+ status: getOrganizationMembersState(state, organizationKey)
+ };
+};
+
+const mapDispatchToProps = {
+ addOrganizationMember,
+ fetchMoreOrganizationMembers,
+ fetchOrganizationGroups,
+ fetchOrganizationMembers,
+ removeOrganizationMember,
+ updateOrganizationMemberGroups
+};
+
+export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
+ OrganizationMembers
+);
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) {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import MembersList from '../MembersList';
-
-const organization = { key: 'foo', name: 'Foo' };
-const members = [
- { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
- { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 }
-];
-
-it('should render a list of members of an organization', () => {
- const wrapper = shallow(<MembersList organization={organization} members={members} />);
- expect(wrapper).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import MembersList from '../MembersList';
+
+const organization = { key: 'foo', name: 'Foo' };
+const members = [
+ { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
+ { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 }
+];
+
+it('should render a list of members of an organization', () => {
+ const wrapper = shallow(
+ <MembersList
+ members={members}
+ organization={organization}
+ organizationGroups={[]}
+ removeMember={jest.fn()}
+ updateMemberGroups={jest.fn()}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import MembersListHeader from '../MembersListHeader';
-
-it('should render without the total', () => {
- const wrapper = shallow(<MembersListHeader handleSearch={jest.fn()} />);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should render with the total', () => {
- const wrapper = shallow(<MembersListHeader handleSearch={jest.fn()} total={8} />);
- expect(wrapper).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import MembersListHeader from '../MembersListHeader';
+
+it('should render without the total', () => {
+ const wrapper = shallow(<MembersListHeader handleSearch={jest.fn()} />);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render with the total', () => {
+ const wrapper = shallow(<MembersListHeader handleSearch={jest.fn()} total={8} />);
+ expect(wrapper).toMatchSnapshot();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import MembersListItem from '../MembersListItem';
-
-const organization = { key: 'foo', name: 'Foo' };
-const admin = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
-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} />);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should render actions and groups for admin', () => {
- const wrapper = shallow(
- <MembersListItem organization={{ ...organization, canAdmin: true }} member={admin} />
- );
- 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} />
- );
- expect(wrapper).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import MembersListItem from '../MembersListItem';
+
+const organization = { key: 'foo', name: 'Foo' };
+const admin = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
+const john = { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af' };
+
+it('should not render actions and groups for non 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
+ 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
+ member={john}
+ organization={{ ...organization, canAdmin: true }}
+ organizationGroups={[]}
+ removeMember={jest.fn()}
+ updateMemberGroups={jest.fn()}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
currentUser={loggedInUser}
hasAccess={() => true}
location={locationMock}
- organization={adminOrganization}>
+ organization={adminOrganization}
+ userOrganizations={[]}>
<div>hello</div>
</OrganizationAccess>
)
currentUser={loggedInUser}
hasAccess={() => false}
location={locationMock}
- organization={adminOrganization}>
+ organization={adminOrganization}
+ userOrganizations={[]}>
<div>hello</div>
</OrganizationAccess>
).type()
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { UnconnectedOrganizationEdit } from '../OrganizationEdit';
-
-it('smoke test', () => {
- const organization = { key: 'foo', name: 'Foo' };
- const wrapper = shallow(<UnconnectedOrganizationEdit organization={organization} />);
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({
- avatar: 'foo-avatar',
- avatarImage: 'foo-avatar-image',
- description: 'foo-description',
- name: 'New Foo',
- url: 'foo-url'
- });
- expect(wrapper).toMatchSnapshot();
-
- wrapper.setState({ loading: true });
- expect(wrapper).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { OrganizationEdit } from '../OrganizationEdit';
+
+it('smoke test', () => {
+ const organization = { key: 'foo', name: 'Foo' };
+ const wrapper = shallow(
+ <OrganizationEdit organization={organization} updateOrganization={jest.fn()} />
+ );
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.setState({
+ avatar: 'foo-avatar',
+ avatarImage: 'foo-avatar-image',
+ description: 'foo-description',
+ name: 'New Foo',
+ url: 'foo-url'
+ });
+ expect(wrapper).toMatchSnapshot();
+
+ wrapper.setState({ loading: true });
+ expect(wrapper).toMatchSnapshot();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox';
-
-const group = {
- id: '7',
- name: 'professionals',
- description: '',
- membersCount: 12,
- default: false
-};
-
-it('should render unchecked', () => {
- const wrapper = shallow(
- <OrganizationGroupCheckbox group={group} checked={false} onCheck={jest.fn()} />
- );
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should be able to toggle check', () => {
- const onCheck = jest.fn((group, checked) => wrapper.setProps({ checked }));
- const wrapper = shallow(
- <OrganizationGroupCheckbox group={group} checked={true} onCheck={onCheck} />
- );
- expect(wrapper).toMatchSnapshot();
- wrapper.instance().toggleCheck();
- expect(onCheck.mock.calls).toMatchSnapshot();
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should disabled default groups', () => {
- const onCheck = jest.fn((group, checked) => wrapper.setProps({ checked }));
- const wrapper = shallow(
- <OrganizationGroupCheckbox
- group={{ ...group, default: true }}
- checked={true}
- onCheck={onCheck}
- />
- );
- expect(wrapper).toMatchSnapshot();
- wrapper.instance().toggleCheck();
- expect(onCheck.mock.calls.length).toBe(0);
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox';
+
+const group = {
+ id: 7,
+ name: 'professionals',
+ description: '',
+ membersCount: 12,
+ default: false
+};
+
+it('should render unchecked', () => {
+ const wrapper = shallow(
+ <OrganizationGroupCheckbox checked={false} group={group} onCheck={jest.fn()} />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should be able to toggle check', () => {
+ const onCheck = jest.fn().mockImplementation((_group, checked) => wrapper.setProps({ checked }));
+ const wrapper = shallow(
+ <OrganizationGroupCheckbox checked={true} group={group} onCheck={onCheck} />
+ );
+ expect(wrapper).toMatchSnapshot();
+ (wrapper.instance() as OrganizationGroupCheckbox).toggleCheck();
+ expect(onCheck.mock.calls).toMatchSnapshot();
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should disabled default groups', () => {
+ const onCheck = jest.fn().mockImplementation((_group, checked) => wrapper.setProps({ checked }));
+ const wrapper = shallow(
+ <OrganizationGroupCheckbox
+ checked={true}
+ group={{ ...group, default: true }}
+ onCheck={onCheck}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+ (wrapper.instance() as OrganizationGroupCheckbox).toggleCheck();
+ expect(onCheck.mock.calls.length).toBe(0);
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import OrganizationMembers from '../OrganizationMembers';
-
-const organization = { key: 'foo', name: 'Foo' };
-const members = [
- { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
- { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 }
-];
-const status = { total: members.length };
-
-it('should not render actions for non admin', () => {
- const wrapper = shallow(
- <OrganizationMembers
- organization={organization}
- members={members}
- status={status}
- fetchOrganizationMembers={jest.fn()}
- fetchOrganizationGroups={jest.fn()}
- fetchMoreOrganizationMembers={jest.fn()}
- />
- );
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should render actions for admin', () => {
- const wrapper = shallow(
- <OrganizationMembers
- organization={{ ...organization, canAdmin: true }}
- members={members}
- status={{ ...status, loading: true }}
- fetchOrganizationMembers={jest.fn()}
- fetchOrganizationGroups={jest.fn()}
- fetchMoreOrganizationMembers={jest.fn()}
- />
- );
- expect(wrapper).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import OrganizationMembers from '../OrganizationMembers';
+
+const organization = { key: 'foo', name: 'Foo' };
+const members = [
+ { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 },
+ { login: 'john', name: 'John Doe', avatar: '7daf6c79d4802916d83f6266e24850af', groupCount: 1 }
+];
+const status = { total: members.length };
+
+it('should not render actions for non admin', () => {
+ const wrapper = shallow(
+ <OrganizationMembers
+ addOrganizationMember={jest.fn()}
+ fetchMoreOrganizationMembers={jest.fn()}
+ fetchOrganizationGroups={jest.fn()}
+ fetchOrganizationMembers={jest.fn()}
+ memberLogins={[]}
+ members={members}
+ organization={organization}
+ organizationGroups={[]}
+ removeOrganizationMember={jest.fn()}
+ status={status}
+ updateOrganizationMemberGroups={jest.fn()}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should render actions for admin', () => {
+ const wrapper = shallow(
+ <OrganizationMembers
+ 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 }}
+ updateOrganizationMemberGroups={jest.fn()}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { OrganizationPage } from '../OrganizationPage';
-
-const fetchOrganization = () => Promise.resolve();
-
-it('smoke test', () => {
- const wrapper = shallow(
- <OrganizationPage fetchOrganization={fetchOrganization} params={{ organizationKey: 'foo' }}>
- <div>hello</div>
- </OrganizationPage>
- );
- expect(wrapper.type()).toBeNull();
-
- const organization = { key: 'foo', name: 'Foo', isDefault: false, canAdmin: false };
- wrapper.setProps({ organization });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('not found', () => {
- const wrapper = shallow(
- <OrganizationPage fetchOrganization={fetchOrganization} params={{ organizationKey: 'foo' }}>
- <div>hello</div>
- </OrganizationPage>
- );
- wrapper.setState({ loading: false });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should correctly update when the organization changes', () => {
- const fetchOrganization = jest.fn(() => Promise.resolve());
- const wrapper = shallow(
- <OrganizationPage params={{ organizationKey: 'foo' }} fetchOrganization={fetchOrganization}>
- <div>hello</div>
- </OrganizationPage>
- );
- wrapper.setProps({ params: { organizationKey: 'bar' } });
- expect(fetchOrganization).toHaveBeenCalledTimes(2);
- expect(fetchOrganization.mock.calls).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { OrganizationPage } from '../OrganizationPage';
+
+const fetchOrganization = () => Promise.resolve();
+
+it('smoke test', () => {
+ const wrapper = shallow(
+ <OrganizationPage
+ fetchOrganization={fetchOrganization}
+ location={{ pathname: 'foo' }}
+ params={{ organizationKey: 'foo' }}>
+ <div>hello</div>
+ </OrganizationPage>
+ );
+ expect(wrapper.type()).toBeNull();
+
+ const organization = { key: 'foo', name: 'Foo', isDefault: false, canAdmin: false };
+ wrapper.setProps({ organization });
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('not found', () => {
+ const wrapper = shallow(
+ <OrganizationPage
+ fetchOrganization={fetchOrganization}
+ location={{ pathname: 'foo' }}
+ params={{ organizationKey: 'foo' }}>
+ <div>hello</div>
+ </OrganizationPage>
+ );
+ wrapper.setState({ loading: false });
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should correctly update when the organization changes', () => {
+ const fetchOrganization = jest.fn(() => Promise.resolve());
+ const wrapper = shallow(
+ <OrganizationPage
+ fetchOrganization={fetchOrganization}
+ location={{ pathname: 'foo' }}
+ params={{ organizationKey: 'foo' }}>
+ <div>hello</div>
+ </OrganizationPage>
+ );
+ wrapper.setProps({ params: { organizationKey: 'bar' } });
+ expect(fetchOrganization).toHaveBeenCalledTimes(2);
+ expect(fetchOrganization.mock.calls).toMatchSnapshot();
+});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render a list of members of an organization 1`] = `
-<div
- className="boxed-group boxed-group-inner"
->
- <table
- className="data zebra"
- >
- <tbody>
- <MembersListItem
- key="admin"
- member={
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <MembersListItem
- key="john"
- member={
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- </tbody>
- </table>
-</div>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render a list of members of an organization 1`] = `
+<div
+ className="boxed-group boxed-group-inner"
+>
+ <table
+ className="data zebra"
+ >
+ <tbody>
+ <MembersListItem
+ key="admin"
+ member={
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ }
+ }
+ organization={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ organizationGroups={Array []}
+ removeMember={[MockFunction]}
+ updateMemberGroups={[MockFunction]}
+ />
+ <MembersListItem
+ key="john"
+ member={
+ Object {
+ "avatar": "7daf6c79d4802916d83f6266e24850af",
+ "groupCount": 1,
+ "login": "john",
+ "name": "John Doe",
+ }
+ }
+ organization={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ organizationGroups={Array []}
+ removeMember={[MockFunction]}
+ updateMemberGroups={[MockFunction]}
+ />
+ </tbody>
+ </table>
+</div>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render with the total 1`] = `
-<div
- className="panel panel-vertical bordered-bottom spacer-bottom"
->
- <SearchBox
- minLength={2}
- onChange={[MockFunction]}
- placeholder="search.search_for_users"
- />
- <span
- className="pull-right little-spacer-top"
- >
- <strong>
- 8
- </strong>
-
- organization.members.members
- </span>
-</div>
-`;
-
-exports[`should render without the total 1`] = `
-<div
- className="panel panel-vertical bordered-bottom spacer-bottom"
->
- <SearchBox
- minLength={2}
- onChange={[MockFunction]}
- placeholder="search.search_for_users"
- />
-</div>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render with the total 1`] = `
+<div
+ className="panel panel-vertical bordered-bottom spacer-bottom"
+>
+ <SearchBox
+ minLength={2}
+ onChange={[MockFunction]}
+ placeholder="search.search_for_users"
+ />
+ <span
+ className="pull-right little-spacer-top"
+ >
+ <strong>
+ 8
+ </strong>
+
+ organization.members.members
+ </span>
+</div>
+`;
+
+exports[`should render without the total 1`] = `
+<div
+ className="panel panel-vertical bordered-bottom spacer-bottom"
+>
+ <SearchBox
+ minLength={2}
+ onChange={[MockFunction]}
+ placeholder="search.search_for_users"
+ />
+</div>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should groups at 0 if the groupCount field is not defined (just added user) 1`] = `
-<tr>
- <td
- className="thin nowrap"
- >
- <Connect(Avatar)
- hash="7daf6c79d4802916d83f6266e24850af"
- name="John Doe"
- size={36}
- />
- </td>
- <td
- className="nowrap text-middle"
- >
- <strong>
- John Doe
- </strong>
- <span
- className="note little-spacer-left"
- >
- john
- </span>
- </td>
- <td
- className="text-right text-middle"
- >
- organization.members.x_groups.0
- </td>
- <React.Fragment>
- <td
- className="nowrap text-middle text-right"
- >
- <ActionsDropdown>
- <ActionsDropdownItem
- onClick={[Function]}
- >
- organization.members.manage_groups
- </ActionsDropdownItem>
- <ActionsDropdownDivider />
- <ActionsDropdownItem
- destructive={true}
- onClick={[Function]}
- >
- organization.members.remove
- </ActionsDropdownItem>
- </ActionsDropdown>
- </td>
- </React.Fragment>
-</tr>
-`;
-
-exports[`should not render actions and groups for non admin 1`] = `
-<tr>
- <td
- className="thin nowrap"
- >
- <Connect(Avatar)
- hash=""
- name="Admin Istrator"
- size={36}
- />
- </td>
- <td
- className="nowrap text-middle"
- >
- <strong>
- Admin Istrator
- </strong>
- <span
- className="note little-spacer-left"
- >
- admin
- </span>
- </td>
-</tr>
-`;
-
-exports[`should render actions and groups for admin 1`] = `
-<tr>
- <td
- className="thin nowrap"
- >
- <Connect(Avatar)
- hash=""
- name="Admin Istrator"
- size={36}
- />
- </td>
- <td
- className="nowrap text-middle"
- >
- <strong>
- Admin Istrator
- </strong>
- <span
- className="note little-spacer-left"
- >
- admin
- </span>
- </td>
- <td
- className="text-right text-middle"
- >
- organization.members.x_groups.3
- </td>
- <React.Fragment>
- <td
- className="nowrap text-middle text-right"
- >
- <ActionsDropdown>
- <ActionsDropdownItem
- onClick={[Function]}
- >
- organization.members.manage_groups
- </ActionsDropdownItem>
- <ActionsDropdownDivider />
- <ActionsDropdownItem
- destructive={true}
- onClick={[Function]}
- >
- organization.members.remove
- </ActionsDropdownItem>
- </ActionsDropdown>
- </td>
- </React.Fragment>
-</tr>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should groups at 0 if the groupCount field is not defined (just added user) 1`] = `
+<tr>
+ <td
+ className="thin nowrap"
+ >
+ <Connect(Avatar)
+ hash="7daf6c79d4802916d83f6266e24850af"
+ name="John Doe"
+ size={36}
+ />
+ </td>
+ <td
+ className="nowrap text-middle"
+ >
+ <strong>
+ John Doe
+ </strong>
+ <span
+ className="note little-spacer-left"
+ >
+ john
+ </span>
+ </td>
+ <td
+ className="text-right text-middle"
+ >
+ organization.members.x_groups.0
+ </td>
+ <React.Fragment>
+ <td
+ className="nowrap text-middle text-right"
+ >
+ <ActionsDropdown>
+ <ActionsDropdownItem
+ onClick={[Function]}
+ >
+ organization.members.manage_groups
+ </ActionsDropdownItem>
+ <ActionsDropdownDivider />
+ <ActionsDropdownItem
+ destructive={true}
+ onClick={[Function]}
+ >
+ organization.members.remove
+ </ActionsDropdownItem>
+ </ActionsDropdown>
+ </td>
+ </React.Fragment>
+</tr>
+`;
+
+exports[`should not render actions and groups for non admin 1`] = `
+<tr>
+ <td
+ className="thin nowrap"
+ >
+ <Connect(Avatar)
+ hash=""
+ name="Admin Istrator"
+ size={36}
+ />
+ </td>
+ <td
+ className="nowrap text-middle"
+ >
+ <strong>
+ Admin Istrator
+ </strong>
+ <span
+ className="note little-spacer-left"
+ >
+ admin
+ </span>
+ </td>
+</tr>
+`;
+
+exports[`should render actions and groups for admin 1`] = `
+<tr>
+ <td
+ className="thin nowrap"
+ >
+ <Connect(Avatar)
+ hash=""
+ name="Admin Istrator"
+ size={36}
+ />
+ </td>
+ <td
+ className="nowrap text-middle"
+ >
+ <strong>
+ Admin Istrator
+ </strong>
+ <span
+ className="note little-spacer-left"
+ >
+ admin
+ </span>
+ </td>
+ <td
+ className="text-right text-middle"
+ >
+ organization.members.x_groups.3
+ </td>
+ <React.Fragment>
+ <td
+ className="nowrap text-middle text-right"
+ >
+ <ActionsDropdown>
+ <ActionsDropdownItem
+ onClick={[Function]}
+ >
+ organization.members.manage_groups
+ </ActionsDropdownItem>
+ <ActionsDropdownDivider />
+ <ActionsDropdownItem
+ destructive={true}
+ onClick={[Function]}
+ >
+ organization.members.remove
+ </ActionsDropdownItem>
+ </ActionsDropdown>
+ </td>
+ </React.Fragment>
+</tr>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`smoke test 1`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.edit"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.edit
- </h1>
- </header>
- <div
- className="boxed-group boxed-group-inner"
- >
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- disabled={false}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="Foo"
- />
- <div
- className="modal-field-description"
- >
- organization.name.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- disabled={false}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={[Function]}
- type="text"
- value=""
- />
- <div
- className="modal-field-description"
- >
- organization.avatar.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- disabled={false}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={[Function]}
- rows="3"
- value=""
- />
- <div
- className="modal-field-description"
- >
- organization.description.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- disabled={false}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={[Function]}
- type="text"
- value=""
- />
- <div
- className="modal-field-description"
- >
- organization.url.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <SubmitButton
- disabled={false}
- >
- save
- </SubmitButton>
- </div>
- </form>
- </div>
-</div>
-`;
-
-exports[`smoke test 2`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.edit"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.edit
- </h1>
- </header>
- <div
- className="boxed-group boxed-group-inner"
- >
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- disabled={false}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="New Foo"
- />
- <div
- className="modal-field-description"
- >
- organization.name.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- disabled={false}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={[Function]}
- type="text"
- value="foo-avatar"
- />
- <div
- className="modal-field-description"
- >
- organization.avatar.description
- </div>
- <div
- className="spacer-top spacer-bottom"
- >
- <div
- className="little-spacer-bottom"
- >
- organization.avatar.preview
- :
- </div>
- <img
- alt=""
- height={30}
- src="foo-avatar-image"
- />
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- disabled={false}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={[Function]}
- rows="3"
- value="foo-description"
- />
- <div
- className="modal-field-description"
- >
- organization.description.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- disabled={false}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={[Function]}
- type="text"
- value="foo-url"
- />
- <div
- className="modal-field-description"
- >
- organization.url.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <SubmitButton
- disabled={false}
- >
- save
- </SubmitButton>
- </div>
- </form>
- </div>
-</div>
-`;
-
-exports[`smoke test 3`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.edit"
- />
- <header
- className="page-header"
- >
- <h1
- className="page-title"
- >
- organization.edit
- </h1>
- </header>
- <div
- className="boxed-group boxed-group-inner"
- >
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-name"
- >
- organization.name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- disabled={true}
- id="organization-name"
- maxLength="64"
- name="name"
- onChange={[Function]}
- required={true}
- type="text"
- value="New Foo"
- />
- <div
- className="modal-field-description"
- >
- organization.name.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-avatar"
- >
- organization.avatar
- </label>
- <input
- disabled={true}
- id="organization-avatar"
- maxLength="256"
- name="avatar"
- onChange={[Function]}
- type="text"
- value="foo-avatar"
- />
- <div
- className="modal-field-description"
- >
- organization.avatar.description
- </div>
- <div
- className="spacer-top spacer-bottom"
- >
- <div
- className="little-spacer-bottom"
- >
- organization.avatar.preview
- :
- </div>
- <img
- alt=""
- height={30}
- src="foo-avatar-image"
- />
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-description"
- >
- description
- </label>
- <textarea
- disabled={true}
- id="organization-description"
- maxLength="256"
- name="description"
- onChange={[Function]}
- rows="3"
- value="foo-description"
- />
- <div
- className="modal-field-description"
- >
- organization.description.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <label
- htmlFor="organization-url"
- >
- organization.url
- </label>
- <input
- disabled={true}
- id="organization-url"
- maxLength="256"
- name="url"
- onChange={[Function]}
- type="text"
- value="foo-url"
- />
- <div
- className="modal-field-description"
- >
- organization.url.description
- </div>
- </div>
- <div
- className="modal-field"
- >
- <SubmitButton
- disabled={true}
- >
- save
- </SubmitButton>
- <i
- className="spinner spacer-left"
- />
- </div>
- </form>
- </div>
-</div>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`smoke test 1`] = `
+<div
+ className="page page-limited"
+>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.edit"
+ />
+ <header
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ organization.edit
+ </h1>
+ </header>
+ <div
+ className="boxed-group boxed-group-inner"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-name"
+ >
+ organization.name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ disabled={false}
+ id="organization-name"
+ maxLength={64}
+ name="name"
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="Foo"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.name.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-avatar"
+ >
+ organization.avatar
+ </label>
+ <input
+ disabled={false}
+ id="organization-avatar"
+ maxLength={256}
+ name="avatar"
+ onChange={[Function]}
+ type="text"
+ value=""
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.avatar.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-description"
+ >
+ description
+ </label>
+ <textarea
+ disabled={false}
+ id="organization-description"
+ maxLength={256}
+ name="description"
+ onChange={[Function]}
+ rows={3}
+ value=""
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.description.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-url"
+ >
+ organization.url
+ </label>
+ <input
+ disabled={false}
+ id="organization-url"
+ maxLength={256}
+ name="url"
+ onChange={[Function]}
+ type="text"
+ value=""
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.url.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <SubmitButton
+ disabled={false}
+ >
+ save
+ </SubmitButton>
+ </div>
+ </form>
+ </div>
+</div>
+`;
+
+exports[`smoke test 2`] = `
+<div
+ className="page page-limited"
+>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.edit"
+ />
+ <header
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ organization.edit
+ </h1>
+ </header>
+ <div
+ className="boxed-group boxed-group-inner"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-name"
+ >
+ organization.name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ disabled={false}
+ id="organization-name"
+ maxLength={64}
+ name="name"
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="New Foo"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.name.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-avatar"
+ >
+ organization.avatar
+ </label>
+ <input
+ disabled={false}
+ id="organization-avatar"
+ maxLength={256}
+ name="avatar"
+ onChange={[Function]}
+ type="text"
+ value="foo-avatar"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.avatar.description
+ </div>
+ <div
+ className="spacer-top spacer-bottom"
+ >
+ <div
+ className="little-spacer-bottom"
+ >
+ organization.avatar.preview
+ :
+ </div>
+ <img
+ alt=""
+ height={30}
+ src="foo-avatar-image"
+ />
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-description"
+ >
+ description
+ </label>
+ <textarea
+ disabled={false}
+ id="organization-description"
+ maxLength={256}
+ name="description"
+ onChange={[Function]}
+ rows={3}
+ value="foo-description"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.description.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-url"
+ >
+ organization.url
+ </label>
+ <input
+ disabled={false}
+ id="organization-url"
+ maxLength={256}
+ name="url"
+ onChange={[Function]}
+ type="text"
+ value="foo-url"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.url.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <SubmitButton
+ disabled={false}
+ >
+ save
+ </SubmitButton>
+ </div>
+ </form>
+ </div>
+</div>
+`;
+
+exports[`smoke test 3`] = `
+<div
+ className="page page-limited"
+>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.edit"
+ />
+ <header
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ organization.edit
+ </h1>
+ </header>
+ <div
+ className="boxed-group boxed-group-inner"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-name"
+ >
+ organization.name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ disabled={true}
+ id="organization-name"
+ maxLength={64}
+ name="name"
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="New Foo"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.name.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-avatar"
+ >
+ organization.avatar
+ </label>
+ <input
+ disabled={true}
+ id="organization-avatar"
+ maxLength={256}
+ name="avatar"
+ onChange={[Function]}
+ type="text"
+ value="foo-avatar"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.avatar.description
+ </div>
+ <div
+ className="spacer-top spacer-bottom"
+ >
+ <div
+ className="little-spacer-bottom"
+ >
+ organization.avatar.preview
+ :
+ </div>
+ <img
+ alt=""
+ height={30}
+ src="foo-avatar-image"
+ />
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-description"
+ >
+ description
+ </label>
+ <textarea
+ disabled={true}
+ id="organization-description"
+ maxLength={256}
+ name="description"
+ onChange={[Function]}
+ rows={3}
+ value="foo-description"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.description.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <label
+ htmlFor="organization-url"
+ >
+ organization.url
+ </label>
+ <input
+ disabled={true}
+ id="organization-url"
+ maxLength={256}
+ name="url"
+ onChange={[Function]}
+ type="text"
+ value="foo-url"
+ />
+ <div
+ className="modal-field-description"
+ >
+ organization.url.description
+ </div>
+ </div>
+ <div
+ className="modal-field"
+ >
+ <SubmitButton
+ disabled={true}
+ >
+ save
+ </SubmitButton>
+ <i
+ className="spinner spacer-left"
+ />
+ </div>
+ </form>
+ </div>
+</div>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-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}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
-
-exports[`should be able to toggle check 2`] = `
-Array [
- Array [
- "professionals",
- false,
- ],
-]
-`;
-
-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}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
-
-exports[`should disabled default groups 1`] = `
-<li
- className="capitalize list-item-checkable-link"
- disabled={true}
- onClick={[Function]}
- role="listitem"
- tabIndex={0}
->
- <Checkbox
- checked={true}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
-
-exports[`should render unchecked 1`] = `
-<li
- className="capitalize list-item-checkable-link"
- disabled={false}
- onClick={[Function]}
- role="listitem"
- tabIndex={0}
->
- <Checkbox
- checked={false}
- onCheck={[Function]}
- thirdState={false}
- />
-
- professionals
-</li>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should be able to toggle check 1`] = `
+<li
+ className="capitalize list-item-checkable-link"
+ onClick={[Function]}
+>
+ <Checkbox
+ checked={true}
+ onCheck={[Function]}
+ thirdState={false}
+ />
+
+ professionals
+</li>
+`;
+
+exports[`should be able to toggle check 2`] = `
+Array [
+ Array [
+ "professionals",
+ false,
+ ],
+]
+`;
+
+exports[`should be able to toggle check 3`] = `
+<li
+ className="capitalize list-item-checkable-link"
+ onClick={[Function]}
+>
+ <Checkbox
+ checked={false}
+ onCheck={[Function]}
+ thirdState={false}
+ />
+
+ professionals
+</li>
+`;
+
+exports[`should disabled default groups 1`] = `
+<li
+ className="capitalize list-item-checkable-link disabled"
+ onClick={[Function]}
+>
+ <Checkbox
+ checked={true}
+ onCheck={[Function]}
+ thirdState={false}
+ />
+
+ professionals
+</li>
+`;
+
+exports[`should render unchecked 1`] = `
+<li
+ className="capitalize list-item-checkable-link"
+ onClick={[Function]}
+>
+ <Checkbox
+ checked={false}
+ onCheck={[Function]}
+ thirdState={false}
+ />
+
+ professionals
+</li>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should not render actions for non admin 1`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.members.page"
- />
- <Suggestions
- suggestions="organization_members"
- />
- <MembersPageHeader />
- <MembersListHeader
- handleSearch={[Function]}
- total={2}
- />
- <MembersList
- members={
- Array [
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- },
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
- },
- ]
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- }
- }
- removeMember={[Function]}
- updateMemberGroups={[Function]}
- />
- <ListFooter
- count={2}
- loadMore={[Function]}
- ready={true}
- total={2}
- />
-</div>
-`;
-
-exports[`should render actions for admin 1`] = `
-<div
- className="page page-limited"
->
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="organization.members.page"
- />
- <Suggestions
- suggestions="organization_members"
- />
- <MembersPageHeader
- loading={true}
- >
- <div
- className="page-actions"
- >
- <AddMemberForm
- addMember={[Function]}
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <DocTooltip
- className="spacer-left"
- doc="organizations/add-organization-member"
- />
- </div>
- </MembersPageHeader>
- <MembersListHeader
- handleSearch={[Function]}
- total={2}
- />
- <MembersList
- members={
- Array [
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- },
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "groupCount": 1,
- "login": "john",
- "name": "John Doe",
- },
- ]
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- }
- }
- removeMember={[Function]}
- updateMemberGroups={[Function]}
- />
- <ListFooter
- count={2}
- loadMore={[Function]}
- ready={false}
- total={2}
- />
-</div>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should not render actions for non admin 1`] = `
+<div
+ className="page page-limited"
+>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.members.page"
+ />
+ <Suggestions
+ suggestions="organization_members"
+ />
+ <MembersPageHeader
+ loading={false}
+ />
+ <MembersListHeader
+ handleSearch={[Function]}
+ total={2}
+ />
+ <MembersList
+ members={
+ Array [
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ },
+ Object {
+ "avatar": "7daf6c79d4802916d83f6266e24850af",
+ "groupCount": 1,
+ "login": "john",
+ "name": "John Doe",
+ },
+ ]
+ }
+ organization={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ organizationGroups={Array []}
+ removeMember={[Function]}
+ updateMemberGroups={[Function]}
+ />
+ <ListFooter
+ count={2}
+ loadMore={[Function]}
+ ready={true}
+ total={2}
+ />
+</div>
+`;
+
+exports[`should render actions for admin 1`] = `
+<div
+ className="page page-limited"
+>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="organization.members.page"
+ />
+ <Suggestions
+ suggestions="organization_members"
+ />
+ <MembersPageHeader
+ loading={true}
+ >
+ <div
+ className="page-actions"
+ >
+ <AddMemberForm
+ addMember={[Function]}
+ memberLogins={Array []}
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <DocTooltip
+ className="spacer-left"
+ doc="organizations/add-organization-member"
+ />
+ </div>
+ </MembersPageHeader>
+ <MembersListHeader
+ handleSearch={[Function]}
+ total={2}
+ />
+ <MembersList
+ members={
+ Array [
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ },
+ Object {
+ "avatar": "7daf6c79d4802916d83f6266e24850af",
+ "groupCount": 1,
+ "login": "john",
+ "name": "John Doe",
+ },
+ ]
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ organizationGroups={Array []}
+ removeMember={[Function]}
+ updateMemberGroups={[Function]}
+ />
+ <ListFooter
+ count={2}
+ loadMore={[Function]}
+ ready={false}
+ total={2}
+ />
+</div>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`not found 1`] = `<NotFound />`;
-
-exports[`should correctly update when the organization changes 1`] = `
-Array [
- Array [
- "foo",
- ],
- Array [
- "bar",
- ],
-]
-`;
-
-exports[`smoke test 1`] = `
-<div>
- <HelmetWrapper
- defaultTitle="Foo"
- defer={true}
- encodeSpecialCharacters={true}
- titleTemplate="%s - Foo"
- />
- <Suggestions
- suggestions="organization_space"
- />
- <OrganizationNavigation
- organization={
- Object {
- "canAdmin": false,
- "isDefault": false,
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- <div>
- hello
- </div>
-</div>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`not found 1`] = `<NotFound />`;
+
+exports[`should correctly update when the organization changes 1`] = `
+Array [
+ Array [
+ "foo",
+ ],
+ Array [
+ "bar",
+ ],
+]
+`;
+
+exports[`smoke test 1`] = `
+<div>
+ <HelmetWrapper
+ defaultTitle="Foo"
+ defer={true}
+ encodeSpecialCharacters={true}
+ titleTemplate="%s - Foo"
+ />
+ <Suggestions
+ suggestions="organization_space"
+ />
+ <OrganizationNavigation
+ location={
+ Object {
+ "pathname": "foo",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": false,
+ "isDefault": false,
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <div>
+ hello
+ </div>
+</div>
+`;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import 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'; */
-
-/*::
-type Props = {
- addMember: (member: Member) => void,
- organization: Organization,
- memberLogins: Array<string>
-};
-*/
-
-/*::
-type State = {
- open: boolean,
- selectedMember?: Member
-};
-*/
-
-export default class AddMemberForm extends React.PureComponent {
- /*:: props: Props; */
-
- state /*: State */ = {
- open: false
- };
-
- openForm = () => {
- this.setState({ open: true });
- };
-
- closeForm = () => {
- this.setState({ open: false, selectedMember: undefined });
- };
-
- handleSearch = (query /*: ?string */, ps /*: number */) => {
- const data = { organization: this.props.organization.key, ps, selected: 'deselected' };
- if (!query) {
- return searchMembers(data);
- }
- return searchMembers({ ...data, q: query });
- };
-
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
- if (this.state.selectedMember) {
- this.props.addMember(this.state.selectedMember);
- this.closeForm();
- }
- };
-
- selectedMemberChange = (member /*: Member */) => {
- this.setState({ selectedMember: member });
- };
-
- renderModal() {
- const header = translate('users.add');
- return (
- <Modal contentLabel={header} key="add-member-modal" onRequestClose={this.closeForm}>
- <header className="modal-head">
- <h2>{header}</h2>
- </header>
- <form onSubmit={this.handleSubmit}>
- <div className="modal-body">
- <div className="modal-large-field">
- <label>{translate('users.search_description')}</label>
- <UsersSelectSearch
- autoFocus={true}
- excludedUsers={this.props.memberLogins}
- handleValueChange={this.selectedMemberChange}
- searchUsers={this.handleSearch}
- selectedUser={this.state.selectedMember}
- />
- </div>
- </div>
- <footer className="modal-foot">
- <div>
- <SubmitButton disabled={!this.state.selectedMember}>
- {translate('organization.members.add_to_members')}
- </SubmitButton>
- <ResetButtonLink onClick={this.closeForm}>{translate('cancel')}</ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>
- );
- }
-
- render() {
- const buttonComponent = (
- <Button key="add-member-button" onClick={this.openForm}>
- {translate('organization.members.add')}
- </Button>
- );
- if (this.state.open) {
- return [buttonComponent, this.renderModal()];
- }
- return buttonComponent;
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import 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 { Organization, OrganizationMember } from '../../../../app/types';
+
+interface Props {
+ addMember: (member: OrganizationMember) => void;
+ organization: Organization;
+ memberLogins: string[];
+}
+
+interface State {
+ open: boolean;
+ selectedMember?: OrganizationMember;
+}
+
+export default class AddMemberForm extends React.PureComponent<Props, State> {
+ state: State = {
+ open: false
+ };
+
+ openForm = () => {
+ this.setState({ open: true });
+ };
+
+ closeForm = () => {
+ this.setState({ open: false, selectedMember: undefined });
+ };
+
+ handleSearch = (query: string | undefined, ps: number) => {
+ const data = { organization: this.props.organization.key, ps, selected: 'deselected' };
+ if (!query) {
+ return searchMembers(data);
+ }
+ return searchMembers({ ...data, q: query });
+ };
+
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ if (this.state.selectedMember) {
+ this.props.addMember(this.state.selectedMember);
+ this.closeForm();
+ }
+ };
+
+ selectedMemberChange = (member: OrganizationMember) => {
+ this.setState({ selectedMember: member });
+ };
+
+ renderModal() {
+ const header = translate('users.add');
+ return (
+ <Modal contentLabel={header} key="add-member-modal" onRequestClose={this.closeForm}>
+ <header className="modal-head">
+ <h2>{header}</h2>
+ </header>
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ <div className="modal-large-field">
+ <label>{translate('users.search_description')}</label>
+ <UsersSelectSearch
+ autoFocus={true}
+ excludedUsers={this.props.memberLogins}
+ handleValueChange={this.selectedMemberChange}
+ searchUsers={this.handleSearch}
+ selectedUser={this.state.selectedMember}
+ />
+ </div>
+ </div>
+ <footer className="modal-foot">
+ <div>
+ <SubmitButton disabled={!this.state.selectedMember}>
+ {translate('organization.members.add_to_members')}
+ </SubmitButton>
+ <ResetButtonLink onClick={this.closeForm}>{translate('cancel')}</ResetButtonLink>
+ </div>
+ </footer>
+ </form>
+ </Modal>
+ );
+ }
+
+ render() {
+ const buttonComponent = (
+ <Button key="add-member-button" onClick={this.openForm}>
+ {translate('organization.members.add')}
+ </Button>
+ );
+ if (this.state.open) {
+ return [buttonComponent, this.renderModal()];
+ }
+ return buttonComponent;
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import React from 'react';
-import { keyBy, pickBy } from 'lodash';
-import { getUserGroups } 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'; */
-
-/*::
-type Props = {
- onClose: () => void;
- member: Member,
- organization: Organization,
- organizationGroups: Array<Group>,
- updateMemberGroups: (member: Member, add: Array<string>, remove: Array<string>) => void
-};
-*/
-
-/*::
-type State = {
- userGroups?: {},
- loading?: boolean
-};
-*/
-
-export default class ManageMemberGroupsForm extends React.PureComponent {
- /*:: mounted: boolean */
- /*:: props: Props; */
- state /*: State */ = {};
-
- componentDidMount() {
- this.mounted = true;
- this.loadUserGroups();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- loadUserGroups = () => {
- this.setState({ loading: true });
- getUserGroups(this.props.member.login, this.props.organization.key).then(
- response => {
- if (this.mounted) {
- this.setState({ loading: false, userGroups: keyBy(response.groups, 'name') });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- isGroupSelected = (groupName /*: string */) => {
- if (this.state.userGroups) {
- const group = this.state.userGroups[groupName] || {};
- if (group.status) {
- return group.status === 'add';
- } else {
- return group.selected === true;
- }
- }
- return false;
- };
-
- onCheck = (groupName /*: string */, checked /*: boolean */) => {
- this.setState((prevState /*: State */) => {
- const userGroups = prevState.userGroups || {};
- const group = userGroups[groupName] || {};
- let status = '';
- if (group.selected && !checked) {
- status = 'remove';
- } else if (!group.selected && checked) {
- status = 'add';
- }
- return { userGroups: { ...userGroups, [groupName]: { ...group, status } } };
- });
- };
-
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
- this.props.updateMemberGroups(
- this.props.member,
- Object.keys(pickBy(this.state.userGroups, group => group.status === 'add')),
- Object.keys(pickBy(this.state.userGroups, group => group.status === 'remove'))
- );
- this.props.onClose();
- };
-
- render() {
- const header = translate('organization.members.manage_groups');
- return (
- <Modal contentLabel={header} onRequestClose={this.props.onClose}>
- <header className="modal-head">
- <h2>{header}</h2>
- </header>
- <form onSubmit={this.handleSubmit}>
- <div className="modal-body">
- <strong>
- {translateWithParameters(
- 'organization.members.members_groups',
- this.props.member.name
- )}
- </strong>{' '}
- {this.state.loading && <i className="spinner" />}
- {!this.state.loading && (
- <ul className="list-spaced">
- {this.props.organizationGroups.map(group => (
- <OrganizationGroupCheckbox
- checked={this.isGroupSelected(group.name)}
- group={group}
- key={group.id}
- onCheck={this.onCheck}
- />
- ))}
- </ul>
- )}
- </div>
- <footer className="modal-foot">
- <div>
- <SubmitButton>{translate('save')}</SubmitButton>
- <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { keyBy, pickBy } from 'lodash';
+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 { Organization, OrganizationMember, Group } from '../../../../app/types';
+
+interface Props {
+ onClose: () => void;
+ member: OrganizationMember;
+ organization: Organization;
+ organizationGroups: Group[];
+ updateMemberGroups: (member: OrganizationMember, add: string[], remove: string[]) => void;
+}
+
+interface State {
+ userGroups?: { [k: string]: UserGroup & { status?: string } };
+ loading?: boolean;
+}
+
+export default class ManageMemberGroupsForm extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = {};
+
+ componentDidMount() {
+ this.mounted = true;
+ this.loadUserGroups();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ loadUserGroups = () => {
+ this.setState({ loading: true });
+ getUserGroups(this.props.member.login, this.props.organization.key).then(
+ response => {
+ if (this.mounted) {
+ this.setState({ loading: false, userGroups: keyBy(response.groups, 'name') });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ isGroupSelected = (groupName: string) => {
+ if (this.state.userGroups) {
+ const group = this.state.userGroups[groupName] || {};
+ if (group.status) {
+ return group.status === 'add';
+ } else {
+ return group.selected === true;
+ }
+ }
+ return false;
+ };
+
+ onCheck = (groupName: string, checked: boolean) => {
+ this.setState((prevState: State) => {
+ const userGroups = prevState.userGroups || {};
+ const group = userGroups[groupName] || {};
+ let status = '';
+ if (group.selected && !checked) {
+ status = 'remove';
+ } else if (!group.selected && checked) {
+ status = 'add';
+ }
+ return { userGroups: { ...userGroups, [groupName]: { ...group, status } } };
+ });
+ };
+
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ this.props.updateMemberGroups(
+ this.props.member,
+ Object.keys(pickBy(this.state.userGroups, group => group.status === 'add')),
+ Object.keys(pickBy(this.state.userGroups, group => group.status === 'remove'))
+ );
+ this.props.onClose();
+ };
+
+ render() {
+ const header = translate('organization.members.manage_groups');
+ return (
+ <Modal contentLabel={header} onRequestClose={this.props.onClose}>
+ <header className="modal-head">
+ <h2>{header}</h2>
+ </header>
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ <strong>
+ {translateWithParameters(
+ 'organization.members.members_groups',
+ this.props.member.name
+ )}
+ </strong>{' '}
+ {this.state.loading && <i className="spinner" />}
+ {!this.state.loading && (
+ <ul className="list-spaced">
+ {this.props.organizationGroups.map(group => (
+ <OrganizationGroupCheckbox
+ checked={this.isGroupSelected(group.name)}
+ group={group}
+ key={group.id}
+ onCheck={this.onCheck}
+ />
+ ))}
+ </ul>
+ )}
+ </div>
+ <footer className="modal-foot">
+ <div>
+ <SubmitButton>{translate('save')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
+ </div>
+ </footer>
+ </form>
+ </Modal>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import 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'; */
-
-/*::
-type Props = {
- onClose: () => void;
- member: Member,
- organization: Organization,
- removeMember: (member: Member) => void
-};
-*/
-
-export default class RemoveMemberForm extends React.PureComponent {
- /*:: props: Props; */
- handleSubmit = (e /*: Object */) => {
- e.preventDefault();
- this.props.removeMember(this.props.member);
- this.props.onClose();
- };
-
- render() {
- const header = translate('users.remove');
- return (
- <Modal contentLabel={header} key="remove-member-modal" onRequestClose={this.props.onClose}>
- <header className="modal-head">
- <h2>{header}</h2>
- </header>
- <form onSubmit={this.handleSubmit}>
- <div className="modal-body">
- {translateWithParameters(
- 'organization.members.remove_x',
- this.props.member.name,
- this.props.organization.name
- )}
- </div>
- <footer className="modal-foot">
- <div>
- <SubmitButton autoFocus={true} className="button-red">
- {translate('remove')}
- </SubmitButton>
- <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Modal from '../../../../components/controls/Modal';
+import { translate, translateWithParameters } from '../../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
+import { Organization, OrganizationMember } from '../../../../app/types';
+
+interface Props {
+ onClose: () => void;
+ member: OrganizationMember;
+ organization: Organization;
+ removeMember: (member: OrganizationMember) => void;
+}
+
+export default class RemoveMemberForm extends React.PureComponent<Props> {
+ handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ this.props.removeMember(this.props.member);
+ this.props.onClose();
+ };
+
+ render() {
+ const header = translate('users.remove');
+ return (
+ <Modal contentLabel={header} key="remove-member-modal" onRequestClose={this.props.onClose}>
+ <header className="modal-head">
+ <h2>{header}</h2>
+ </header>
+ <form onSubmit={this.handleSubmit}>
+ <div className="modal-body">
+ {translateWithParameters(
+ 'organization.members.remove_x',
+ this.props.member.name,
+ this.props.organization.name
+ )}
+ </div>
+ <footer className="modal-foot">
+ <div>
+ <SubmitButton autoFocus={true} className="button-red">
+ {translate('remove')}
+ </SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
+ </div>
+ </footer>
+ </form>
+ </Modal>
+ );
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { click } from '../../../../../helpers/testUtils';
-import AddMemberForm from '../AddMemberForm';
-
-const memberLogins = ['admin'];
-
-it('should render and open the modal', () => {
- const wrapper = shallow(<AddMemberForm addMember={jest.fn()} memberLogins={memberLogins} />);
- expect(wrapper).toMatchSnapshot();
- wrapper.setState({ open: true });
-
- // FIXME Can probably be removed when https://github.com/airbnb/enzyme/issues/1149 is resolved
- expect(wrapper.first().getElements()).toMatchSnapshot();
-});
-
-it('should correctly handle user interactions', () => {
- const wrapper = shallow(<AddMemberForm addMember={jest.fn()} memberLogins={memberLogins} />);
- click(wrapper.find('Button'));
- expect(wrapper.state('open')).toBeTruthy();
- wrapper.instance().closeForm();
- expect(wrapper.state('open')).toBeFalsy();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { click } from '../../../../../helpers/testUtils';
+import AddMemberForm from '../AddMemberForm';
+
+const memberLogins = ['admin'];
+
+it('should render and open the modal', () => {
+ const wrapper = shallow(
+ <AddMemberForm
+ addMember={jest.fn()}
+ memberLogins={memberLogins}
+ organization={{ key: 'foo', name: 'Foo' }}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+ wrapper.setState({ open: true });
+
+ // FIXME Can probably be removed when https://github.com/airbnb/enzyme/issues/1149 is resolved
+ expect(wrapper.first().getElements()).toMatchSnapshot();
+});
+
+it('should correctly handle user interactions', () => {
+ 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() as AddMemberForm).closeForm();
+ expect(wrapper.state('open')).toBeFalsy();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { click, 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',
- name: 'professionals',
- description: '',
- membersCount: 12
- },
- {
- id: '11',
- name: 'pull-request-analysers',
- description: 'Technical accounts',
- membersCount: 3
- },
- {
- id: '1',
- name: 'sonar-administrators',
- description: 'System administrators',
- membersCount: 17
- }
-];
-const userGroups = {
- 11: { id: 11, name: 'pull-request-analysers', description: 'Technical accounts', selected: true }
-};
-
-function getMountedForm(updateFunc = jest.fn()) {
- const wrapper = shallow(
- <ManageMemberGroupsForm
- member={member}
- onClose={jest.fn()}
- organization={organization}
- organizationGroups={organizationGroups}
- updateMemberGroups={updateFunc}
- />,
- { disableLifecycleMethods: true }
- );
- const instance = wrapper.instance();
- wrapper.setState({ loading: false, userGroups });
- return { wrapper, instance };
-}
-
-it('should render', () => {
- const wrapper = shallow(
- <ManageMemberGroupsForm
- member={member}
- organization={organization}
- organizationGroups={organizationGroups}
- updateMemberGroups={jest.fn()}
- />
- );
- expect(wrapper).toMatchSnapshot();
-});
-
-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);
- expect(form.wrapper.state('userGroups')).toMatchSnapshot();
- expect(form.instance.isGroupSelected(11)).toBeFalsy();
- expect(form.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);
- expect(updateMemberGroups.mock.calls).toMatchSnapshot();
- expect(form.wrapper.state()).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { 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,
+ name: 'professionals',
+ description: '',
+ membersCount: 12
+ },
+ {
+ id: 11,
+ name: 'pull-request-analysers',
+ description: 'Technical accounts',
+ membersCount: 3
+ },
+ {
+ id: 1,
+ name: 'sonar-administrators',
+ description: 'System administrators',
+ membersCount: 17
+ }
+];
+const userGroups = {
+ 11: { id: 11, name: 'pull-request-analysers', description: 'Technical accounts', selected: true }
+};
+
+function getMountedForm(updateFunc = jest.fn()) {
+ const wrapper = shallow(
+ <ManageMemberGroupsForm
+ member={member}
+ onClose={jest.fn()}
+ organization={organization}
+ organizationGroups={organizationGroups}
+ updateMemberGroups={updateFunc}
+ />,
+ { disableLifecycleMethods: true }
+ );
+ const instance = wrapper.instance();
+ wrapper.setState({ loading: false, userGroups });
+ return { wrapper, instance };
+}
+
+it('should render', () => {
+ const wrapper = shallow(
+ <ManageMemberGroupsForm
+ member={member}
+ onClose={jest.fn()}
+ organization={organization}
+ organizationGroups={organizationGroups}
+ updateMemberGroups={jest.fn()}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should correctly select the groups', () => {
+ const form = getMountedForm();
+ 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(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);
+ 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();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import { click, mockEvent } from '../../../../../helpers/testUtils';
-import RemoveMemberForm from '../RemoveMemberForm';
-
-const member = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
-const organization = { name: 'MyOrg' };
-
-it('should render ', () => {
- const wrapper = shallow(
- <RemoveMemberForm member={member} organization={organization} removeMember={jest.fn()} />
- );
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should correctly handle user interactions', () => {
- const removeMember = jest.fn();
- const wrapper = shallow(
- <RemoveMemberForm
- member={member}
- onClose={jest.fn()}
- organization={organization}
- removeMember={removeMember}
- />
- );
- wrapper.instance().handleSubmit(mockEvent);
- expect(removeMember).toBeCalledWith({
- avatar: '',
- groupCount: 3,
- login: 'admin',
- name: 'Admin Istrator'
- });
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { mockEvent } from '../../../../../helpers/testUtils';
+import RemoveMemberForm from '../RemoveMemberForm';
+
+const member = { login: 'admin', name: 'Admin Istrator', avatar: '', groupCount: 3 };
+const organization = { key: 'myorg', name: 'MyOrg' };
+
+it('should render ', () => {
+ const wrapper = shallow(
+ <RemoveMemberForm
+ member={member}
+ onClose={jest.fn()}
+ organization={organization}
+ removeMember={jest.fn()}
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should correctly handle user interactions', () => {
+ const removeMember = jest.fn();
+ const wrapper = shallow(
+ <RemoveMemberForm
+ member={member}
+ onClose={jest.fn()}
+ organization={organization}
+ removeMember={removeMember}
+ />
+ );
+ (wrapper.instance() as RemoveMemberForm).handleSubmit(mockEvent as any);
+ expect(removeMember).toBeCalledWith({
+ avatar: '',
+ groupCount: 3,
+ login: 'admin',
+ name: 'Admin Istrator'
+ });
+});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render and open the modal 1`] = `
-<Button
- key="add-member-button"
- onClick={[Function]}
->
- organization.members.add
-</Button>
-`;
-
-exports[`should render and open the modal 2`] = `
-Array [
- <Button
- onClick={[Function]}
- >
- organization.members.add
- </Button>,
- <Modal
- contentLabel="users.add"
- onRequestClose={[Function]}
- >
- <header
- className="modal-head"
- >
- <h2>
- users.add
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- <div
- className="modal-large-field"
- >
- <label>
- users.search_description
- </label>
- <UsersSelectSearch
- autoFocus={true}
- excludedUsers={
- Array [
- "admin",
- ]
- }
- handleValueChange={[Function]}
- searchUsers={[Function]}
- />
- </div>
- </div>
- <footer
- className="modal-foot"
- >
- <div>
- <SubmitButton
- disabled={true}
- >
- organization.members.add_to_members
- </SubmitButton>
- <ResetButtonLink
- onClick={[Function]}
- >
- cancel
- </ResetButtonLink>
- </div>
- </footer>
- </form>
- </Modal>,
-]
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render and open the modal 1`] = `
+<Button
+ key="add-member-button"
+ onClick={[Function]}
+>
+ organization.members.add
+</Button>
+`;
+
+exports[`should render and open the modal 2`] = `
+Array [
+ <Button
+ onClick={[Function]}
+ >
+ organization.members.add
+ </Button>,
+ <Modal
+ contentLabel="users.add"
+ onRequestClose={[Function]}
+ >
+ <header
+ className="modal-head"
+ >
+ <h2>
+ users.add
+ </h2>
+ </header>
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-body"
+ >
+ <div
+ className="modal-large-field"
+ >
+ <label>
+ users.search_description
+ </label>
+ <UsersSelectSearch
+ autoFocus={true}
+ excludedUsers={
+ Array [
+ "admin",
+ ]
+ }
+ handleValueChange={[Function]}
+ searchUsers={[Function]}
+ />
+ </div>
+ </div>
+ <footer
+ className="modal-foot"
+ >
+ <div>
+ <SubmitButton
+ disabled={true}
+ >
+ organization.members.add_to_members
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[Function]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+ </footer>
+ </form>
+ </Modal>,
+]
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly handle the submit event and close the modal 1`] = `
-Array [
- Array [
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- },
- Array [
- "7",
- ],
- Array [
- "11",
- ],
- ],
-]
-`;
-
-exports[`should correctly handle the submit event and close the modal 2`] = `
-Object {
- "loading": false,
- "userGroups": Object {
- "11": Object {
- "description": "Technical accounts",
- "id": 11,
- "name": "pull-request-analysers",
- "selected": true,
- "status": "remove",
- },
- "7": Object {
- "status": "add",
- },
- },
-}
-`;
-
-exports[`should correctly select the groups 1`] = `
-Object {
- "11": Object {
- "description": "Technical accounts",
- "id": 11,
- "name": "pull-request-analysers",
- "selected": true,
- "status": "remove",
- },
- "7": Object {
- "status": "add",
- },
-}
-`;
-
-exports[`should render 1`] = `
-<Modal
- contentLabel="organization.members.manage_groups"
->
- <header
- className="modal-head"
- >
- <h2>
- organization.members.manage_groups
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- <strong>
- organization.members.members_groups.Admin Istrator
- </strong>
-
- <i
- className="spinner"
- />
- </div>
- <footer
- className="modal-foot"
- >
- <div>
- <SubmitButton>
- save
- </SubmitButton>
- <ResetButtonLink>
- cancel
- </ResetButtonLink>
- </div>
- </footer>
- </form>
-</Modal>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should correctly handle the submit event and close the modal 1`] = `
+Array [
+ Array [
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ },
+ Array [
+ "7",
+ ],
+ Array [
+ "11",
+ ],
+ ],
+]
+`;
+
+exports[`should correctly handle the submit event and close the modal 2`] = `
+Object {
+ "loading": false,
+ "userGroups": Object {
+ "11": Object {
+ "description": "Technical accounts",
+ "id": 11,
+ "name": "pull-request-analysers",
+ "selected": true,
+ "status": "remove",
+ },
+ "7": Object {
+ "status": "add",
+ },
+ },
+}
+`;
+
+exports[`should correctly select the groups 1`] = `
+Object {
+ "11": Object {
+ "description": "Technical accounts",
+ "id": 11,
+ "name": "pull-request-analysers",
+ "selected": true,
+ "status": "remove",
+ },
+ "7": Object {
+ "status": "add",
+ },
+}
+`;
+
+exports[`should render 1`] = `
+<Modal
+ contentLabel="organization.members.manage_groups"
+ onRequestClose={[MockFunction]}
+>
+ <header
+ className="modal-head"
+ >
+ <h2>
+ organization.members.manage_groups
+ </h2>
+ </header>
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-body"
+ >
+ <strong>
+ organization.members.members_groups.Admin Istrator
+ </strong>
+
+ <i
+ className="spinner"
+ />
+ </div>
+ <footer
+ className="modal-foot"
+ >
+ <div>
+ <SubmitButton>
+ save
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+ </footer>
+ </form>
+</Modal>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<Modal
- contentLabel="users.remove"
- key="remove-member-modal"
->
- <header
- className="modal-head"
- >
- <h2>
- users.remove
- </h2>
- </header>
- <form
- onSubmit={[Function]}
- >
- <div
- className="modal-body"
- >
- organization.members.remove_x.Admin Istrator.MyOrg
- </div>
- <footer
- className="modal-foot"
- >
- <div>
- <SubmitButton
- autoFocus={true}
- className="button-red"
- >
- remove
- </SubmitButton>
- <ResetButtonLink>
- cancel
- </ResetButtonLink>
- </div>
- </footer>
- </form>
-</Modal>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<Modal
+ contentLabel="users.remove"
+ key="remove-member-modal"
+ onRequestClose={[MockFunction]}
+>
+ <header
+ className="modal-head"
+ >
+ <h2>
+ users.remove
+ </h2>
+ </header>
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-body"
+ >
+ organization.members.remove_x.Admin Istrator.MyOrg
+ </div>
+ <footer
+ className="modal-foot"
+ >
+ <div>
+ <SubmitButton
+ autoFocus={true}
+ className="button-red"
+ >
+ remove
+ </SubmitButton>
+ <ResetButtonLink
+ onClick={[MockFunction]}
+ >
+ cancel
+ </ResetButtonLink>
+ </div>
+ </footer>
+ </form>
+</Modal>
+`;
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';
<OrganizationNavigationHeaderContainer organization={organization} />
<OrganizationNavigationMeta organization={organization} />
</div>
- <OrganizationNavigationMenu location={location} organization={organization} />
+ <OrganizationNavigationMenuContainer location={location} organization={organization} />
</ContextNavBar>
);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Link } from 'react-router';
-import OrganizationNavigationExtensions from './OrganizationNavigationExtensions';
-import OrganizationNavigationAdministration from './OrganizationNavigationAdministration';
-import { Organization } 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';
-
-interface Props {
- location: { pathname: string };
- organization: Organization;
-}
-
-export default function OrganizationNavigationMenu({ location, organization }: Props) {
- return (
- <NavBarTabs className="navbar-context-tabs">
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/projects`}>
- {translate('projects.page')}
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- to={{
- pathname: `/organizations/${organization.key}/issues`,
- query: { resolved: 'false' }
- }}>
- {translate('issues.page')}
- </Link>
- </li>
- {hasPrivateAccess(organization) && (
- <>
- <li>
- <Link
- activeClassName="active"
- to={`/organizations/${organization.key}/quality_profiles`}>
- {translate('quality_profiles.page')}
- </Link>
- </li>
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/rules`}>
- {translate('coding_rules.page')}
- </Link>
- </li>
- <li>
- <Link activeClassName="active" to={getQualityGatesUrl(organization.key)}>
- {translate('quality_gates.page')}
- </Link>
- </li>
- </>
- )}
-
- {isCurrentUserMemberOf(organization) && (
- <li>
- <Link activeClassName="active" to={`/organizations/${organization.key}/members`}>
- {translate('organization.members.page')}
- </Link>
- </li>
- )}
-
- <OrganizationNavigationExtensions location={location} organization={organization} />
- {organization.canAdmin && (
- <OrganizationNavigationAdministration location={location} organization={organization} />
- )}
- </NavBarTabs>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { Link } from 'react-router';
+import OrganizationNavigationExtensions from './OrganizationNavigationExtensions';
+import OrganizationNavigationAdministration from './OrganizationNavigationAdministration';
+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 StateToProps {
+ currentUser: CurrentUser;
+ userOrganizations: Organization[];
+}
+
+interface OwnProps {
+ location: { pathname: string };
+ organization: Organization;
+}
+
+type Props = OwnProps & StateToProps;
+
+export function OrganizationNavigationMenu({
+ currentUser,
+ location,
+ organization,
+ userOrganizations
+}: Props) {
+ return (
+ <NavBarTabs className="navbar-context-tabs">
+ <li>
+ <Link activeClassName="active" to={`/organizations/${organization.key}/projects`}>
+ {translate('projects.page')}
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ to={{
+ pathname: `/organizations/${organization.key}/issues`,
+ query: { resolved: 'false' }
+ }}>
+ {translate('issues.page')}
+ </Link>
+ </li>
+ {hasPrivateAccess(currentUser, organization, userOrganizations) && (
+ <>
+ <li>
+ <Link
+ activeClassName="active"
+ to={`/organizations/${organization.key}/quality_profiles`}>
+ {translate('quality_profiles.page')}
+ </Link>
+ </li>
+ <li>
+ <Link activeClassName="active" to={`/organizations/${organization.key}/rules`}>
+ {translate('coding_rules.page')}
+ </Link>
+ </li>
+ <li>
+ <Link activeClassName="active" to={getQualityGatesUrl(organization.key)}>
+ {translate('quality_gates.page')}
+ </Link>
+ </li>
+ </>
+ )}
+
+ {isCurrentUserMemberOf(currentUser, organization, userOrganizations) && (
+ <li>
+ <Link activeClassName="active" to={`/organizations/${organization.key}/members`}>
+ {translate('organization.members.page')}
+ </Link>
+ </li>
+ )}
+
+ <OrganizationNavigationExtensions location={location} organization={organization} />
+ {organization.canAdmin && (
+ <OrganizationNavigationAdministration location={location} organization={organization} />
+ )}
+ </NavBarTabs>
+ );
+}
+
+const mapStateToProps = (state: any) => ({
+ currentUser: getCurrentUser(state),
+ userOrganizations: getMyOrganizations(state)
+});
+
+export default connect<StateToProps, {}, OwnProps>(mapStateToProps)(OrganizationNavigationMenu);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import OrganizationNavigationMenu from '../OrganizationNavigationMenu';
-import { Visibility } from '../../../../app/types';
-import { isCurrentUserMemberOf, hasPrivateAccess } from '../../../../helpers/organizations';
-
-jest.mock('../../../../helpers/organizations', () => ({
- isCurrentUserMemberOf: jest.fn().mockReturnValue(true),
- hasPrivateAccess: jest.fn().mockReturnValue(true)
-}));
-
-const organization = {
- key: 'foo',
- name: 'Foo',
- projectVisibility: Visibility.Public
-};
-
-beforeEach(() => {
- (isCurrentUserMemberOf as jest.Mock<any>).mockClear();
- (hasPrivateAccess as jest.Mock<any>).mockClear();
-});
-
-it('renders', () => {
- expect(
- shallow(<OrganizationNavigationMenu location={{ pathname: '' }} organization={organization} />)
- ).toMatchSnapshot();
-});
-
-it('renders for admin', () => {
- expect(
- shallow(
- <OrganizationNavigationMenu
- location={{ pathname: '' }}
- organization={{ ...organization, canAdmin: true }}
- />
- )
- ).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { OrganizationNavigationMenu } from '../OrganizationNavigationMenuContainer';
+import { Visibility } from '../../../../app/types';
+import { isCurrentUserMemberOf, hasPrivateAccess } from '../../../../helpers/organizations';
+
+jest.mock('../../../../helpers/organizations', () => ({
+ isCurrentUserMemberOf: jest.fn().mockReturnValue(true),
+ hasPrivateAccess: jest.fn().mockReturnValue(true)
+}));
+
+const organization = {
+ key: 'foo',
+ name: 'Foo',
+ 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();
+});
+
+it('renders', () => {
+ expect(
+ shallow(
+ <OrganizationNavigationMenu
+ currentUser={loggedInUser}
+ location={{ pathname: '' }}
+ organization={organization}
+ userOrganizations={[organization]}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('renders for admin', () => {
+ expect(
+ shallow(
+ <OrganizationNavigationMenu
+ currentUser={loggedInUser}
+ location={{ pathname: '' }}
+ organization={{ ...organization, canAdmin: true }}
+ userOrganizations={[organization]}
+ />
+ )
+ ).toMatchSnapshot();
+});
}
/>
</div>
- <OrganizationNavigationMenu
+ <Connect(OrganizationNavigationMenu)
location={
Object {
"pathname": "/organizations/foo",
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<NavBarTabs
- className="navbar-context-tabs"
->
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/projects"
- >
- projects.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/issues",
- "query": Object {
- "resolved": "false",
- },
- }
- }
- >
- issues.page
- </Link>
- </li>
- <React.Fragment>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/quality_profiles"
- >
- quality_profiles.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/rules"
- >
- coding_rules.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/quality_gates",
- }
- }
- >
- quality_gates.page
- </Link>
- </li>
- </React.Fragment>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/members"
- >
- organization.members.page
- </Link>
- </li>
- <OrganizationNavigationExtensions
- location={
- Object {
- "pathname": "",
- }
- }
- organization={
- Object {
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
-</NavBarTabs>
-`;
-
-exports[`renders for admin 1`] = `
-<NavBarTabs
- className="navbar-context-tabs"
->
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/projects"
- >
- projects.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/issues",
- "query": Object {
- "resolved": "false",
- },
- }
- }
- >
- issues.page
- </Link>
- </li>
- <React.Fragment>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/quality_profiles"
- >
- quality_profiles.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/rules"
- >
- coding_rules.page
- </Link>
- </li>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/foo/quality_gates",
- }
- }
- >
- quality_gates.page
- </Link>
- </li>
- </React.Fragment>
- <li>
- <Link
- activeClassName="active"
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/foo/members"
- >
- organization.members.page
- </Link>
- </li>
- <OrganizationNavigationExtensions
- location={
- Object {
- "pathname": "",
- }
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
- <OrganizationNavigationAdministration
- location={
- Object {
- "pathname": "",
- }
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- "projectVisibility": "public",
- }
- }
- />
-</NavBarTabs>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders 1`] = `
+<NavBarTabs
+ className="navbar-context-tabs"
+>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/projects"
+ >
+ projects.page
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/foo/issues",
+ "query": Object {
+ "resolved": "false",
+ },
+ }
+ }
+ >
+ issues.page
+ </Link>
+ </li>
+ <React.Fragment>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/quality_profiles"
+ >
+ quality_profiles.page
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/rules"
+ >
+ coding_rules.page
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/foo/quality_gates",
+ }
+ }
+ >
+ quality_gates.page
+ </Link>
+ </li>
+ </React.Fragment>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/members"
+ >
+ organization.members.page
+ </Link>
+ </li>
+ <OrganizationNavigationExtensions
+ location={
+ Object {
+ "pathname": "",
+ }
+ }
+ organization={
+ Object {
+ "key": "foo",
+ "name": "Foo",
+ "projectVisibility": "public",
+ }
+ }
+ />
+</NavBarTabs>
+`;
+
+exports[`renders for admin 1`] = `
+<NavBarTabs
+ className="navbar-context-tabs"
+>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/projects"
+ >
+ projects.page
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/foo/issues",
+ "query": Object {
+ "resolved": "false",
+ },
+ }
+ }
+ >
+ issues.page
+ </Link>
+ </li>
+ <React.Fragment>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/quality_profiles"
+ >
+ quality_profiles.page
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/rules"
+ >
+ coding_rules.page
+ </Link>
+ </li>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/foo/quality_gates",
+ }
+ }
+ >
+ quality_gates.page
+ </Link>
+ </li>
+ </React.Fragment>
+ <li>
+ <Link
+ activeClassName="active"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to="/organizations/foo/members"
+ >
+ organization.members.page
+ </Link>
+ </li>
+ <OrganizationNavigationExtensions
+ location={
+ Object {
+ "pathname": "",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
+ "projectVisibility": "public",
+ }
+ }
+ />
+ <OrganizationNavigationAdministration
+ location={
+ Object {
+ "pathname": "",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
+ "projectVisibility": "public",
+ }
+ }
+ />
+</NavBarTabs>
+`;
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';
currentUser: CurrentUser;
isFavorite: boolean;
location: { pathname: string; query: RawQuery };
- organization?: { key: string };
+ organization: Organization | undefined;
organizationsEnabled: boolean;
storageOptionsSuffix?: string;
}
* 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';
interface OwnProps {
isFavorite: boolean;
location: { pathname: string; query: RawQuery };
- organization?: { key: string };
+ organization: Organization | undefined;
storageOptionsSuffix?: string;
}
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;
shouldBeRedirected !== true &&
shouldForceSorting === undefined
) {
- return <AllProjectsContainer isFavorite={false} location={this.props.location} />;
+ return (
+ <AllProjectsContainer
+ isFavorite={false}
+ location={this.props.location}
+ organization={undefined}
+ />
+ );
}
return null;
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;
}
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;
}
currentUser={{ isLoggedIn: true }}
isFavorite={false}
location={{ pathname: '/projects', query: {} }}
+ organization={undefined}
organizationsEnabled={false}
{...props}
/>,
cardType="overall"
isFavorite={false}
isFiltered={false}
+ organization={undefined}
projects={[{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]}
{...props}
/>
* 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';
};
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) =>
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Reducer should have initial state 1`] = `
-Object {
- "byKey": Object {},
- "groups": Object {},
- "my": Array [],
-}
-`;
-
-exports[`Reducer should receive organizations 1`] = `
-Object {
- "byKey": Object {
- "bar": Object {
- "key": "bar",
- "name": "Bar",
- },
- "foo": Object {
- "key": "foo",
- "name": "Foo",
- },
- },
- "groups": Object {},
- "my": Array [],
-}
-`;
-
-exports[`Reducer should receive organizations 2`] = `
-Object {
- "byKey": Object {
- "bar": Object {
- "key": "bar",
- "name": "Bar",
- },
- "foo": Object {
- "key": "foo",
- "name": "Qwe",
- },
- },
- "groups": Object {},
- "my": Array [],
-}
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Reducer should have initial state 1`] = `
+Object {
+ "byKey": Object {},
+ "groups": Object {},
+ "my": Array [],
+}
+`;
+
+exports[`Reducer should receive organizations 1`] = `
+Object {
+ "byKey": Object {
+ "bar": Object {
+ "key": "bar",
+ "name": "Bar",
+ },
+ "foo": Object {
+ "key": "foo",
+ "name": "Foo",
+ },
+ },
+ "groups": Object {},
+ "my": Array [],
+}
+`;
+
+exports[`Reducer should receive organizations 2`] = `
+Object {
+ "byKey": Object {
+ "bar": Object {
+ "key": "bar",
+ "name": "Bar",
+ },
+ "foo": Object {
+ "key": "foo",
+ "name": "Qwe",
+ },
+ },
+ "groups": Object {},
+ "my": Array [],
+}
+`;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import organizations, { getOrganizationByKey, areThereCustomOrganizations } from '../duck';
-
-describe('Reducer', () => {
- it('should have initial state', () => {
- expect(organizations(undefined, {})).toMatchSnapshot();
- });
-
- it('should receive organizations', () => {
- const state0 = { byKey: {} };
-
- const action1 = {
- type: 'RECEIVE_ORGANIZATIONS',
- organizations: [{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]
- };
- const state1 = organizations(state0, action1);
- expect(state1).toMatchSnapshot();
-
- const action2 = {
- type: 'RECEIVE_ORGANIZATIONS',
- organizations: [{ key: 'foo', name: 'Qwe' }]
- };
- const state2 = organizations(state1, action2);
- expect(state2).toMatchSnapshot();
- });
-});
-
-describe('Selectors', () => {
- it('getOrganizationByKey', () => {
- const foo = { key: 'foo', name: 'Foo' };
- const state = { byKey: { foo } };
- expect(getOrganizationByKey(state, 'foo')).toBe(foo);
- expect(getOrganizationByKey(state, 'bar')).toBeFalsy();
- });
-
- 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);
- });
-});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import organizations, { getOrganizationByKey, areThereCustomOrganizations } from '../duck';
+
+const state0 = { byKey: {}, my: [], groups: {} };
+
+describe('Reducer', () => {
+ it('should have initial state', () => {
+ expect((organizations as any)(undefined, {})).toMatchSnapshot();
+ });
+
+ it('should receive organizations', () => {
+ const action1 = {
+ type: 'RECEIVE_ORGANIZATIONS',
+ organizations: [{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]
+ };
+ const state1 = organizations(state0, action1);
+ expect(state1).toMatchSnapshot();
+
+ const action2 = {
+ type: 'RECEIVE_ORGANIZATIONS',
+ organizations: [{ key: 'foo', name: 'Qwe' }]
+ };
+ const state2 = organizations(state1, action2);
+ expect(state2).toMatchSnapshot();
+ });
+});
+
+describe('Selectors', () => {
+ it('getOrganizationByKey', () => {
+ const foo = { key: 'foo', name: 'Foo' };
+ const state = { ...state0, byKey: { foo } };
+ expect(getOrganizationByKey(state, 'foo')).toBe(foo);
+ expect(getOrganizationByKey(state, 'bar')).toBeFalsy();
+ });
+
+ it('areThereCustomOrganizations', () => {
+ const foo = { key: 'foo', name: 'Foo' };
+ const bar = { key: 'bar', name: 'Bar' };
+ expect(areThereCustomOrganizations({ ...state0, byKey: {} })).toBe(false);
+ expect(areThereCustomOrganizations({ ...state0, byKey: { foo } })).toBe(false);
+ expect(areThereCustomOrganizations({ ...state0, byKey: { foo, bar } })).toBe(true);
+ });
+});
*/
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';
};
}
-export function updateOrganization(key: string, changes: {}): UpdateOrganizationAction {
+export function updateOrganization(
+ key: string,
+ changes: OrganizationBase
+): UpdateOrganizationAction {
return {
type: 'UPDATE_ORGANIZATION',
key,
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];
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// @flow
-import getStore from '../../app/utils/getStore';
-import {
- getOrganizationByKey,
- areThereCustomOrganizations as customOrganizations
-} from '../rootReducer';
-
-export function getOrganization(key /*: string */) {
- const store = getStore();
- const state = store.getState();
- return getOrganizationByKey(state, key);
-}
-
-export function areThereCustomOrganizations() {
- const store = getStore();
- const state = store.getState();
- return customOrganizations(state);
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import getStore from '../../app/utils/getStore';
+import {
+ getOrganizationByKey,
+ areThereCustomOrganizations as customOrganizations
+} from '../rootReducer';
+
+export function getOrganization(key: string) {
+ const store = getStore();
+ const state = store.getState();
+ return getOrganizationByKey(state, key);
+}
+
+export function areThereCustomOrganizations() {
+ const store = getStore();
+ const state = store.getState();
+ return customOrganizations(state);
+}