transition: none;
}
+.dropdown-menu > li > a.text-danger,
+.dropdown-menu > li > a.text-danger:hover {
+ color: var(--red) !important;
+}
+
.dropdown-menu .divider {
height: 1px;
margin: 6px 0;
/* @flow */
import React from 'react';
import Tooltip from '../../../components/controls/Tooltip';
+import DeleteIcon from '../../../components/icons-components/DeleteIcon';
import { translate } from '../../../helpers/l10n';
/*::
{this.props.isSystemAdmin && (
<Tooltip overlay={translate('background_tasks.cancel_all_tasks')}>
<a
- className="js-cancel-pending icon-delete spacer-left"
+ className="js-cancel-pending spacer-left link-no-underline"
href="#"
- onClick={this.handleCancelAllPending}
- />
+ onClick={this.handleCancelAllPending}>
+ <DeleteIcon className="text-text-top" />
+ </a>
</Tooltip>
)}
</span>
import { STATUSES } from './../constants';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Task } from '../types';
+import ActionsDropdown, { ActionsDropdownItem } from '../../../components/controls/ActionsDropdown';
interface Props {
component?: {};
stacktraceOpen: false
};
- handleFilterClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
+ handleFilterClick = () => {
this.props.onFilterTask(this.props.task);
};
- handleCancelClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
+ handleCancelClick = () => {
this.props.onCancelTask(this.props.task);
};
- handleShowScannerContextClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
+ handleShowScannerContextClick = () => {
this.setState({ scannerContextOpen: true });
};
closeScannerContext = () => this.setState({ scannerContextOpen: false });
- handleShowStacktraceClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
+ handleShowStacktraceClick = () => {
this.setState({ stacktraceOpen: true });
};
return (
<td className="thin nowrap">
- <div className="dropdown js-task-action">
- <button className="dropdown-toggle" data-toggle="dropdown">
- <i className="icon-dropdown" />
- </button>
- <ul className="dropdown-menu dropdown-menu-right">
- {canFilter &&
- task.componentName && (
- <li>
- <a className="js-task-filter" href="#" onClick={this.handleFilterClick}>
- <i className="spacer-right icon-filter icon-gray" />
- {translateWithParameters(
- 'background_tasks.filter_by_component_x',
- task.componentName
- )}
- </a>
- </li>
- )}
- {canCancel && (
- <li>
- <a className="js-task-cancel" href="#" onClick={this.handleCancelClick}>
- <i className="spacer-right icon-delete" />
- {translate('background_tasks.cancel_task')}
- </a>
- </li>
+ <ActionsDropdown className="js-task-action">
+ {canFilter &&
+ task.componentName && (
+ <ActionsDropdownItem className="js-task-filter" onClick={this.handleFilterClick}>
+ {translateWithParameters(
+ 'background_tasks.filter_by_component_x',
+ task.componentName
+ )}
+ </ActionsDropdownItem>
)}
- {task.hasScannerContext && (
- <li>
- <a
- className="js-task-show-scanner-context"
- href="#"
- onClick={this.handleShowScannerContextClick}>
- <i className="spacer-right icon-list icon-gray" />
- {translate('background_tasks.show_scanner_context')}
- </a>
- </li>
- )}
- {canShowStacktrace && (
- <li>
- <a
- className="js-task-show-stacktrace"
- href="#"
- onClick={this.handleShowStacktraceClick}>
- <i className="spacer-right icon-list icon-red" />
- {translate('background_tasks.show_stacktrace')}
- </a>
- </li>
- )}
- </ul>
- </div>
+ {canCancel && (
+ <ActionsDropdownItem
+ className="js-task-cancel"
+ destructive={true}
+ onClick={this.handleCancelClick}>
+ {translate('background_tasks.cancel_task')}
+ </ActionsDropdownItem>
+ )}
+ {task.hasScannerContext && (
+ <ActionsDropdownItem
+ className="js-task-show-scanner-context"
+ onClick={this.handleShowScannerContextClick}>
+ {translate('background_tasks.show_scanner_context')}
+ </ActionsDropdownItem>
+ )}
+ {canShowStacktrace && (
+ <ActionsDropdownItem
+ className="js-task-show-stacktrace"
+ onClick={this.handleShowStacktraceClick}>
+ {translate('background_tasks.show_stacktrace')}
+ </ActionsDropdownItem>
+ )}
+ </ActionsDropdown>
{this.state.scannerContextOpen && (
<ScannerContext onClose={this.closeScannerContext} task={task} />
import { translate } from '../../../helpers/l10n';
import HelpIcon from '../../../components/icons-components/HelpIcon';
import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
+import EditIcon from '../../../components/icons-components/EditIcon';
interface State {
canSetWorkerCount: boolean;
{!loading &&
canSetWorkerCount && (
<Tooltip overlay={translate('background_tasks.change_number_of_workers')}>
- <a className="icon-edit spacer-left" href="#" onClick={this.handleChangeClick} />
+ <a
+ className="js-edit link-no-underline spacer-left"
+ href="#"
+ onClick={this.handleChangeClick}>
+ <EditIcon className="text-text-top" />
+ </a>
</Tooltip>
)}
});
expect(wrapper).toMatchSnapshot();
- click(wrapper.find('.icon-edit'));
+ click(wrapper.find('.js-edit'));
expect(wrapper).toMatchSnapshot();
});
<td
className="thin nowrap"
>
- <div
- className="dropdown js-task-action"
+ <ActionsDropdown
+ className="js-task-action"
>
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
+ <ActionsDropdownItem
+ className="js-task-filter"
+ onClick={[Function]}
>
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ background_tasks.filter_by_component_x.foo
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-task-cancel"
+ destructive={true}
+ onClick={[Function]}
>
- <li>
- <a
- className="js-task-filter"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-filter icon-gray"
- />
- background_tasks.filter_by_component_x.foo
- </a>
- </li>
- <li>
- <a
- className="js-task-cancel"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-delete"
- />
- background_tasks.cancel_task
- </a>
- </li>
- </ul>
- </div>
+ background_tasks.cancel_task
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
`;
<td
className="thin nowrap"
>
- <div
- className="dropdown js-task-action"
+ <ActionsDropdown
+ className="js-task-action"
>
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
+ <ActionsDropdownItem
+ className="js-task-filter"
+ onClick={[Function]}
>
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
- >
- <li>
- <a
- className="js-task-filter"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-filter icon-gray"
- />
- background_tasks.filter_by_component_x.foo
- </a>
- </li>
- </ul>
- </div>
+ background_tasks.filter_by_component_x.foo
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
`;
<td
className="thin nowrap"
>
- <div
- className="dropdown js-task-action"
+ <ActionsDropdown
+ className="js-task-action"
>
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
+ <ActionsDropdownItem
+ className="js-task-filter"
+ onClick={[Function]}
+ >
+ background_tasks.filter_by_component_x.foo
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-task-cancel"
+ destructive={true}
+ onClick={[Function]}
>
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ background_tasks.cancel_task
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-task-show-scanner-context"
+ onClick={[Function]}
>
- <li>
- <a
- className="js-task-filter"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-filter icon-gray"
- />
- background_tasks.filter_by_component_x.foo
- </a>
- </li>
- <li>
- <a
- className="js-task-cancel"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-delete"
- />
- background_tasks.cancel_task
- </a>
- </li>
- <li>
- <a
- className="js-task-show-scanner-context"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-list icon-gray"
- />
- background_tasks.show_scanner_context
- </a>
- </li>
- </ul>
- </div>
+ background_tasks.show_scanner_context
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
`;
<td
className="thin nowrap"
>
- <div
- className="dropdown js-task-action"
+ <ActionsDropdown
+ className="js-task-action"
>
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
+ <ActionsDropdownItem
+ className="js-task-filter"
+ onClick={[Function]}
>
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ background_tasks.filter_by_component_x.foo
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-task-cancel"
+ destructive={true}
+ onClick={[Function]}
>
- <li>
- <a
- className="js-task-filter"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-filter icon-gray"
- />
- background_tasks.filter_by_component_x.foo
- </a>
- </li>
- <li>
- <a
- className="js-task-cancel"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-delete"
- />
- background_tasks.cancel_task
- </a>
- </li>
- <li>
- <a
- className="js-task-show-stacktrace"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-list icon-red"
- />
- background_tasks.show_stacktrace
- </a>
- </li>
- </ul>
- </div>
+ background_tasks.cancel_task
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-task-show-stacktrace"
+ onClick={[Function]}
+ >
+ background_tasks.show_stacktrace
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
`;
<td
className="thin nowrap"
>
- <div
- className="dropdown js-task-action"
+ <ActionsDropdown
+ className="js-task-action"
>
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
- >
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ <ActionsDropdownItem
+ className="js-task-cancel"
+ destructive={true}
+ onClick={[Function]}
>
- <li>
- <a
- className="js-task-cancel"
- href="#"
- onClick={[Function]}
- >
- <i
- className="spacer-right icon-delete"
- />
- background_tasks.cancel_task
- </a>
- </li>
- </ul>
- </div>
+ background_tasks.cancel_task
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
`;
placement="bottom"
>
<a
- className="icon-edit spacer-left"
+ className="js-edit link-no-underline spacer-left"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</Tooltip>
</div>
`;
placement="bottom"
>
<a
- className="icon-edit spacer-left"
+ className="js-edit link-no-underline spacer-left"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</Tooltip>
<WorkersForm
onClose={[Function]}
placement="bottom"
>
<a
- className="icon-edit spacer-left"
+ className="js-edit link-no-underline spacer-left"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</Tooltip>
</div>
`;
placement="bottom"
>
<a
- className="icon-edit spacer-left"
+ className="js-edit link-no-underline spacer-left"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</Tooltip>
</div>
`;
placement="bottom"
>
<a
- className="icon-edit spacer-left"
+ className="js-edit link-no-underline spacer-left"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</Tooltip>
<WorkersForm
onClose={[Function]}
placement="bottom"
>
<a
- className="icon-edit spacer-left"
+ className="js-edit link-no-underline spacer-left"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</Tooltip>
</div>
`;
</td>
<td class="thin nowrap">
- <a class="js-custom-measure-update icon-edit" title="Update" data-toggle="tooltip" href="#"></a>
- <a class="js-custom-measure-delete icon-delete" title="Delete" data-toggle="tooltip" href="#"></a>
+ <div class="dropdown">
+ <button class="dropdown-toggle" data-toggle="dropdown">
+ {{settingsIcon}}<i class="icon-dropdown little-spacer-left" />
+ </button>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li>
+ <a class="js-custom-measure-update" href="#">{{t 'update_verb'}}</a>
+ </li>
+ <li class="divider" />
+ <li>
+ <a class="js-custom-measure-delete text-danger" href="#">{{t 'delete'}}</a>
+ </li>
+ </ul>
+ </div>
</td>
<div class="pull-right big-spacer-left nowrap">
{{#unless default}}
- <a class="js-group-update icon-edit little-spacer-right" title="{{t 'update_details'}}" data-toggle="tooltip" href="#"></a>
- <a class="js-group-delete icon-delete" title="{{t 'delete'}}" data-toggle="tooltip" href="#"></a>
+ <div class="dropdown">
+ <button class="dropdown-toggle" data-toggle="dropdown">
+ {{settingsIcon}}<i class="icon-dropdown little-spacer-left" />
+ </button>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li>
+ <a class="js-group-update" href="#">{{t 'update_details'}}</a>
+ </li>
+ <li class="divider" />
+ <li>
+ <a class="js-group-delete text-danger" href="#">{{t 'delete'}}</a>
+ </li>
+ </ul>
+ </div>
{{/unless}}
</div>
<div class="pull-right big-spacer-left nowrap">
- <a class="js-metric-update icon-edit" title="{{t 'update_verb'}}" data-toggle="tooltip" href="#"></a>
- <a class="js-metric-delete icon-delete" title="{{t 'delete'}}" data-toggle="tooltip" href="#"></a>
+ <div class="dropdown">
+ <button class="dropdown-toggle" data-toggle="dropdown">
+ {{settingsIcon}}<i class="icon-dropdown little-spacer-left" />
+ </button>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li>
+ <a class="js-metric-update" href="#">{{t 'update_verb'}}</a>
+ </li>
+ <li class="divider" />
+ <li>
+ <a class="js-metric-delete text-danger" href="#">{{t 'delete'}}</a>
+ </li>
+ </ul>
+ </div>
</div>
<div class="display-inline-block text-top width-30">
import { formatMeasure } from '../../../helpers/measures';
import RemoveMemberForm from './forms/RemoveMemberForm';
import ManageMemberGroupsForm from './forms/ManageMemberGroupsForm';
-import SettingsIcon from '../../../components/icons-components/SettingsIcon';
+import ActionsDropdown, {
+ ActionsDropdownDivider
+} from '../../../components/controls/ActionsDropdown';
/*:: import type { Member } from '../../../store/organizationsMembers/actions'; */
/*:: import type { Organization, OrgGroup } from '../../../store/organizations/duck'; */
)}
{organization.canAdmin && (
<td className="nowrap text-middle text-right">
- <div className="dropdown">
- <button
- className="dropdown-toggle little-spacer-right button-compact"
- data-toggle="dropdown">
- <SettingsIcon style={{ marginTop: 4 }} /> <i className="icon-dropdown" />
- </button>
- <ul className="dropdown-menu dropdown-menu-right">
- <li>
- <ManageMemberGroupsForm
- organizationGroups={this.props.organizationGroups}
- organization={this.props.organization}
- updateMemberGroups={this.props.updateMemberGroups}
- member={this.props.member}
- />
- </li>
- <li role="separator" className="divider" />
- <li>
- <RemoveMemberForm
- organization={this.props.organization}
- removeMember={this.props.removeMember}
- member={this.props.member}
- />
- </li>
- </ul>
- </div>
+ <ActionsDropdown>
+ <ManageMemberGroupsForm
+ organizationGroups={this.props.organizationGroups}
+ organization={this.props.organization}
+ updateMemberGroups={this.props.updateMemberGroups}
+ member={this.props.member}
+ />
+ <ActionsDropdownDivider />
+ <RemoveMemberForm
+ organization={this.props.organization}
+ removeMember={this.props.removeMember}
+ member={this.props.member}
+ />
+ </ActionsDropdown>
</td>
)}
</tr>
<td
className="nowrap text-middle text-right"
>
- <div
- className="dropdown"
- >
- <button
- className="dropdown-toggle little-spacer-right button-compact"
- data-toggle="dropdown"
- >
- <SettingsIcon
- style={
- Object {
- "marginTop": 4,
- }
+ <ActionsDropdown>
+ <ManageMemberGroupsForm
+ member={
+ Object {
+ "avatar": "7daf6c79d4802916d83f6266e24850af",
+ "login": "john",
+ "name": "John Doe",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <ActionsDropdownDivider />
+ <RemoveMemberForm
+ member={
+ Object {
+ "avatar": "7daf6c79d4802916d83f6266e24850af",
+ "login": "john",
+ "name": "John Doe",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
}
- />
-
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
- >
- <li>
- <ManageMemberGroupsForm
- member={
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "login": "john",
- "name": "John Doe",
- }
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- </li>
- <li
- className="divider"
- role="separator"
- />
- <li>
- <RemoveMemberForm
- member={
- Object {
- "avatar": "7daf6c79d4802916d83f6266e24850af",
- "login": "john",
- "name": "John Doe",
- }
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- </li>
- </ul>
- </div>
+ }
+ />
+ </ActionsDropdown>
</td>
</tr>
`;
<td
className="nowrap text-middle text-right"
>
- <div
- className="dropdown"
- >
- <button
- className="dropdown-toggle little-spacer-right button-compact"
- data-toggle="dropdown"
- >
- <SettingsIcon
- style={
- Object {
- "marginTop": 4,
- }
+ <ActionsDropdown>
+ <ManageMemberGroupsForm
+ member={
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
+ }
+ }
+ />
+ <ActionsDropdownDivider />
+ <RemoveMemberForm
+ member={
+ Object {
+ "avatar": "",
+ "groupCount": 3,
+ "login": "admin",
+ "name": "Admin Istrator",
+ }
+ }
+ organization={
+ Object {
+ "canAdmin": true,
+ "key": "foo",
+ "name": "Foo",
}
- />
-
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
- >
- <li>
- <ManageMemberGroupsForm
- member={
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- }
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- </li>
- <li
- className="divider"
- role="separator"
- />
- <li>
- <RemoveMemberForm
- member={
- Object {
- "avatar": "",
- "groupCount": 3,
- "login": "admin",
- "name": "Admin Istrator",
- }
- }
- organization={
- Object {
- "canAdmin": true,
- "key": "foo",
- "name": "Foo",
- }
- }
- />
- </li>
- </ul>
- </div>
+ }
+ />
+ </ActionsDropdown>
</td>
</tr>
`;
import Modal from '../../../../components/controls/Modal';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox';
+import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown';
/*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */
/*:: import type { Organization, OrgGroup } from '../../../../store/organizations/duck'; */
*/
export default class ManageMemberGroupsForm extends React.PureComponent {
+ /*:: mounted: boolean */
/*:: props: Props; */
state /*: State */ = {
open: false
};
- openForm = (evt /*: MouseEvent */) => {
- evt.preventDefault();
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ openForm = () => {
this.loadUserGroups();
this.setState({ open: true });
};
loadUserGroups = () => {
this.setState({ loading: true });
- getUserGroups(this.props.member.login, this.props.organization.key).then(response => {
- this.setState({ loading: false, userGroups: keyBy(response.groups, 'name') });
- });
+ 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 */) => {
render() {
const buttonComponent = (
- <a key="manage-member-button" onClick={this.openForm} href="#">
+ <ActionsDropdownItem onClick={this.openForm}>
{translate('organization.members.manage_groups')}
- </a>
+ </ActionsDropdownItem>
);
if (this.state.open) {
return [buttonComponent, this.renderModal()];
// @flow
import React from 'react';
import Modal from '../../../../components/controls/Modal';
+import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
/*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */
/*:: import type { Organization } from '../../../../store/organizations/duck'; */
open: false
};
- openForm = (evt /*: MouseEvent */) => {
- evt.preventDefault();
+ openForm = () => {
this.setState({ open: true });
};
render() {
const buttonComponent = (
- <a key="remove-member-button" onClick={this.openForm} href="#">
+ <ActionsDropdownItem destructive={true} onClick={this.openForm}>
{translate('organization.members.remove')}
- </a>
+ </ActionsDropdownItem>
);
if (this.state.open) {
return [buttonComponent, this.renderModal()];
it('should correctly handle user interactions', () => {
const form = getMountedForm();
- click(form.wrapper.find('a'));
+ form.wrapper.find('ActionsDropdownItem').prop('onClick')();
expect(form.wrapper.state('open')).toBeTruthy();
expect(form.instance.loadUserGroups).toBeCalled();
expect(form.wrapper.state()).toMatchSnapshot();
<RemoveMemberForm member={member} removeMember={removeMember} organization={organization} />
);
const instance = wrapper.instance();
- click(wrapper.find('a'));
+ wrapper.find('ActionsDropdownItem').prop('onClick')();
expect(wrapper.state('open')).toBeTruthy();
instance.handleSubmit(mockEvent);
expect(removeMember.mock.calls).toMatchSnapshot();
`;
exports[`should render and open the modal 1`] = `
-<a
- href="#"
- key="manage-member-button"
+<ActionsDropdownItem
onClick={[Function]}
>
organization.members.manage_groups
-</a>
+</ActionsDropdownItem>
`;
exports[`should render and open the modal 2`] = `
Array [
- <a
- href="#"
+ <ActionsDropdownItem
onClick={[Function]}
>
organization.members.manage_groups
- </a>,
+ </ActionsDropdownItem>,
<Modal
contentLabel="organization.members.manage_groups"
onRequestClose={[Function]}
`;
exports[`should render and open the modal 1`] = `
-<a
- href="#"
- key="remove-member-button"
+<ActionsDropdownItem
+ destructive={true}
onClick={[Function]}
>
organization.members.remove
-</a>
+</ActionsDropdownItem>
`;
exports[`should render and open the modal 2`] = `
Array [
- <a
- href="#"
+ <ActionsDropdownItem
+ destructive={true}
onClick={[Function]}
>
organization.members.remove
- </a>,
+ </ActionsDropdownItem>,
<Modal
contentLabel="users.remove"
onRequestClose={[Function]}
import { difference } from 'lodash';
import Backbone from 'backbone';
import { PermissionTemplateType, CallbackType } from '../propTypes';
+import ActionsDropdown, { ActionsDropdownItem } from '../../../components/controls/ActionsDropdown';
import QualifierIcon from '../../../components/shared/QualifierIcon';
import UpdateView from '../views/UpdateView';
import DeleteView from '../views/DeleteView';
router: PropTypes.object
};
- handleUpdateClick(e) {
- e.preventDefault();
+ handleUpdateClick = () => {
new UpdateView({
model: new Backbone.Model(this.props.permissionTemplate),
refresh: this.props.refresh
}).render();
- }
+ };
- handleDeleteClick(e) {
- e.preventDefault();
+ handleDeleteClick = () => {
new DeleteView({
model: new Backbone.Model(this.props.permissionTemplate)
})
this.props.refresh();
})
.render();
- }
+ };
- setDefault(qualifier, e) {
- e.preventDefault();
+ setDefault = qualifier => () => {
setDefaultPermissionTemplate(this.props.permissionTemplate.id, qualifier).then(
- this.props.refresh
+ this.props.refresh,
+ () => {}
);
- }
+ };
getAvailableQualifiers() {
const topQualifiers =
return difference(topQualifiers, this.props.permissionTemplate.defaultFor);
}
- renderDropdownIcon(icon) {
- const style = {
- display: 'inline-block',
- width: 16,
- marginRight: 4,
- textAlign: 'center'
- };
- return <div style={style}>{icon}</div>;
- }
-
renderSetDefaultsControl() {
const availableQualifiers = this.getAvailableQualifiers();
renderSetDefaultLink(qualifier, child) {
return (
- <li key={qualifier}>
- <a
- href="#"
- className="js-set-default"
- data-qualifier={qualifier}
- onClick={this.setDefault.bind(this, qualifier)}>
- {this.renderDropdownIcon(<i className="icon-check" />)}
- {child}
- </a>
- </li>
+ <ActionsDropdownItem
+ key={qualifier}
+ className="js-set-default"
+ data-qualifier={qualifier}
+ onClick={this.setDefault(qualifier)}>
+ {child}
+ </ActionsDropdownItem>
);
}
: '/permission_templates';
return (
- <div className="dropdown">
- <button className="dropdown-toggle" data-toggle="dropdown">
- {translate('actions')} <i className="icon-dropdown" />
- </button>
-
- <ul className="dropdown-menu dropdown-menu-right">
- {this.renderSetDefaultsControl()}
-
- {!this.props.fromDetails && (
- <li>
- <Link to={{ pathname, query: { id: t.id } }}>
- {this.renderDropdownIcon(<i className="icon-edit" />)}
- {translate('edit_permissions')}
- </Link>
- </li>
- )}
-
- <li>
- <a href="#" className="js-update" onClick={this.handleUpdateClick.bind(this)}>
- {this.renderDropdownIcon(<i className="icon-edit" />)}
- {translate('update_details')}
- </a>
- </li>
-
- {t.defaultFor.length === 0 && (
- <li>
- <a href="#" className="js-delete" onClick={this.handleDeleteClick.bind(this)}>
- {this.renderDropdownIcon(<i className="icon-delete" />)}
- {translate('delete')}
- </a>
- </li>
- )}
- </ul>
- </div>
+ <ActionsDropdown>
+ {this.renderSetDefaultsControl()}
+
+ {!this.props.fromDetails && (
+ <ActionsDropdownItem to={{ pathname, query: { id: t.id } }}>
+ {translate('edit_permissions')}
+ </ActionsDropdownItem>
+ )}
+
+ <ActionsDropdownItem className="js-update" onClick={this.handleUpdateClick}>
+ {translate('update_details')}
+ </ActionsDropdownItem>
+
+ {t.defaultFor.length === 0 && (
+ <ActionsDropdownItem className="js-delete" onClick={this.handleDeleteClick}>
+ {translate('delete')}
+ </ActionsDropdownItem>
+ )}
+ </ActionsDropdown>
);
}
}
import AddEventForm from './forms/AddEventForm';
import RemoveAnalysisForm from './forms/RemoveAnalysisForm';
import TimeTooltipFormatter from '../../../components/intl/TimeTooltipFormatter';
-import SettingsIcon from '../../../components/icons-components/SettingsIcon';
+import ActionsDropdown, {
+ ActionsDropdownDivider
+} from '../../../components/controls/ActionsDropdown';
import { translate } from '../../../helpers/l10n';
/*:: import type { Analysis } from '../types'; */
{(canAddVersion || canAddEvent || canDeleteAnalyses) && (
<div className="project-activity-analysis-actions spacer-left">
- <div className="dropdown display-inline-block">
- <button
- className="js-analysis-actions button-small button-compact dropdown-toggle"
- data-toggle="dropdown"
- onClick={this.stopPropagation}>
- <SettingsIcon size={12} style={{ marginTop: 3 }} /> <i className="icon-dropdown" />
- </button>
- <ul className="dropdown-menu dropdown-menu-right">
- {canAddVersion && (
- <li>
- <AddEventForm
- addEvent={this.props.addVersion}
- analysis={analysis}
- addEventButtonText="project_activity.add_version"
- />
- </li>
- )}
- {canAddEvent && (
- <li>
- <AddEventForm
- addEvent={this.props.addCustomEvent}
- analysis={analysis}
- addEventButtonText="project_activity.add_custom_event"
- />
- </li>
- )}
- {(canAddVersion || canAddEvent) &&
- canDeleteAnalyses && <li role="separator" className="divider" />}
- {canDeleteAnalyses && (
- <li>
- <RemoveAnalysisForm
- analysis={analysis}
- deleteAnalysis={this.props.deleteAnalysis}
- />
- </li>
- )}
- </ul>
- </div>
+ <ActionsDropdown small={true} toggleClassName="js-analysis-actions">
+ {canAddVersion && (
+ <AddEventForm
+ addEvent={this.props.addVersion}
+ analysis={analysis}
+ addEventButtonText="project_activity.add_version"
+ />
+ )}
+ {canAddEvent && (
+ <AddEventForm
+ addEvent={this.props.addCustomEvent}
+ analysis={analysis}
+ addEventButtonText="project_activity.add_custom_event"
+ />
+ )}
+ {(canAddVersion || canAddEvent) && canDeleteAnalyses && <ActionsDropdownDivider />}
+ {canDeleteAnalyses && (
+ <RemoveAnalysisForm
+ analysis={analysis}
+ deleteAnalysis={this.props.deleteAnalysis}
+ />
+ )}
+ </ActionsDropdown>
</div>
)}
// @flow
import React from 'react';
import Modal from '../../../../components/controls/Modal';
+import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown';
import { translate } from '../../../../helpers/l10n';
/*:: import type { Analysis } from '../../types'; */
this.mounted = false;
}
- openForm = (e /*: Event */) => {
- e.preventDefault();
- e.stopPropagation();
- if (this.mounted) {
- this.setState({ open: true });
- }
+ openForm = () => {
+ this.setState({ open: true });
};
closeForm = () => {
render() {
const linkComponent = (
- <a key="add-event-link" className="js-add-event" href="#" onClick={this.openForm}>
+ <ActionsDropdownItem className="js-add-event" onClick={this.openForm}>
{translate(this.props.addEventButtonText)}
- </a>
+ </ActionsDropdownItem>
);
if (this.state.open) {
return [linkComponent, this.renderModal()];
// @flow
import React from 'react';
import Modal from '../../../../components/controls/Modal';
+import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown';
import { translate } from '../../../../helpers/l10n';
/*:: import type { Analysis } from '../../types'; */
this.mounted = false;
}
- openForm = (e /*: Event */) => {
- e.preventDefault();
- e.stopPropagation();
- if (this.mounted) {
- this.setState({ open: true });
- }
+ openForm = () => {
+ this.setState({ open: true });
};
closeForm = () => {
render() {
const linkComponent = (
- <a key="delete-analysis-link" className="js-delete-analysis" href="#" onClick={this.openForm}>
+ <ActionsDropdownItem
+ className="js-delete-analysis"
+ destructive={true}
+ onClick={this.openForm}>
{translate('project_activity.delete_analysis')}
- </a>
+ </ActionsDropdownItem>
);
if (this.state.open) {
return [linkComponent, this.renderModal()];
import { translate } from '../../../helpers/l10n';
import RenameBranchModal from './RenameBranchModal';
import DateFromNow from '../../../components/intl/DateFromNow';
-import SettingsIcon from '../../../components/icons-components/SettingsIcon';
+import ActionsDropdown, {
+ ActionsDropdownItem,
+ ActionsDropdownDivider
+} from '../../../components/controls/ActionsDropdown';
interface Props {
branch: Branch;
this.mounted = false;
}
- handleDeleteClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleDeleteClick = () => {
this.setState({ deleting: true });
};
this.setState({ deleting: false });
};
- handleRenameClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleRenameClick = () => {
this.setState({ renaming: true });
};
this.setState({ renaming: false });
};
- handleChangeLeakClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleChangeLeakClick = () => {
this.setState({ changingLeak: true });
};
}
};
- render() {
+ renderActions() {
const { branch, component } = this.props;
-
return (
- <tr>
- <td>
- <BranchIcon
- branch={branch}
- className={classNames('little-spacer-right', {
- 'big-spacer-left': isShortLivingBranch(branch) && !branch.isOrphan
- })}
- />
- {branch.name}
- {branch.isMain && (
- <div className="outline-badge spacer-left">{translate('branches.main_branch')}</div>
+ <td className="thin nowrap text-right">
+ <ActionsDropdown className="ig-spacer-left">
+ {isLongLivingBranch(branch) && (
+ <ActionsDropdownItem
+ className="js-change-leak-period"
+ onClick={this.handleChangeLeakClick}>
+ {translate('branches.set_leak_period')}
+ </ActionsDropdownItem>
)}
- </td>
- <td className="thin nowrap text-right">
- <BranchStatus branch={branch} />
- </td>
- <td className="thin nowrap text-right">
- {branch.analysisDate && <DateFromNow date={branch.analysisDate} />}
- </td>
- <td className="thin nowrap text-right">
- <div className="dropdown big-spacer-left">
- <button
- className="dropdown-toggle little-spacer-right button-compact"
- data-toggle="dropdown">
- <SettingsIcon style={{ marginTop: 4 }} /> <i className="icon-dropdown" />
- </button>
- <ul className="dropdown-menu dropdown-menu-right">
- {isLongLivingBranch(branch) && (
- <li>
- <a
- className="js-change-leak-period link-no-underline"
- href="#"
- onClick={this.handleChangeLeakClick}>
- {translate('branches.set_leak_period')}
- </a>
- </li>
- )}
- {branch.isMain ? (
- <li>
- <a
- className="js-rename link-no-underline"
- href="#"
- onClick={this.handleRenameClick}>
- {translate('branches.rename')}
- </a>
- </li>
- ) : (
- <li>
- <a
- className="js-delete link-no-underline"
- href="#"
- onClick={this.handleDeleteClick}>
- {translate('branches.delete')}
- </a>
- </li>
- )}
- </ul>
- </div>
- </td>
+ {isLongLivingBranch(branch) && !branch.isMain && <ActionsDropdownDivider />}
+ {branch.isMain ? (
+ <ActionsDropdownItem className="js-rename" onClick={this.handleRenameClick}>
+ {translate('branches.rename')}
+ </ActionsDropdownItem>
+ ) : (
+ <ActionsDropdownItem
+ className="js-delete"
+ destructive={true}
+ onClick={this.handleDeleteClick}>
+ {translate('branches.delete')}
+ </ActionsDropdownItem>
+ )}
+ </ActionsDropdown>
{this.state.deleting && (
<DeleteBranchModal
project={component}
/>
)}
+ </td>
+ );
+ }
+
+ render() {
+ const { branch } = this.props;
+
+ return (
+ <tr>
+ <td>
+ <BranchIcon
+ branch={branch}
+ className={classNames('little-spacer-right', {
+ 'big-spacer-left': isShortLivingBranch(branch) && !branch.isOrphan
+ })}
+ />
+ {branch.name}
+ {branch.isMain && (
+ <div className="outline-badge spacer-left">{translate('branches.main_branch')}</div>
+ )}
+ </td>
+ <td className="thin nowrap text-right">
+ <BranchStatus branch={branch} />
+ </td>
+ <td className="thin nowrap text-right">
+ {branch.analysisDate && <DateFromNow date={branch.analysisDate} />}
+ </td>
+ {this.renderActions()}
</tr>
);
}
<td
className="thin nowrap text-right"
>
- <div
- className="dropdown big-spacer-left"
+ <ActionsDropdown
+ className="ig-spacer-left"
>
- <button
- className="dropdown-toggle little-spacer-right button-compact"
- data-toggle="dropdown"
- >
- <SettingsIcon
- style={
- Object {
- "marginTop": 4,
- }
- }
- />
-
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ <ActionsDropdownItem
+ className="js-rename"
+ onClick={[Function]}
>
- <li>
- <a
- className="js-rename link-no-underline"
- href="#"
- onClick={[Function]}
- >
- branches.rename
- </a>
- </li>
- </ul>
- </div>
+ branches.rename
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
</tr>
`;
<td
className="thin nowrap text-right"
>
- <div
- className="dropdown big-spacer-left"
+ <ActionsDropdown
+ className="ig-spacer-left"
>
- <button
- className="dropdown-toggle little-spacer-right button-compact"
- data-toggle="dropdown"
- >
- <SettingsIcon
- style={
- Object {
- "marginTop": 4,
- }
- }
- />
-
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ <ActionsDropdownItem
+ className="js-delete"
+ destructive={true}
+ onClick={[Function]}
>
- <li>
- <a
- className="js-delete link-no-underline"
- href="#"
- onClick={[Function]}
- >
- branches.delete
- </a>
- </li>
- </ul>
- </div>
+ branches.delete
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
</tr>
`;
import ChangeVisibilityForm from './ChangeVisibilityForm';
import { Organization, Visibility } from '../../app/types';
import { translate } from '../../helpers/l10n';
+import EditIcon from '../../components/icons-components/EditIcon';
export interface Props {
hasProvisionPermission?: boolean;
{translate('organization.default_visibility_of_new_projects')}{' '}
<strong>{translate('visibility', organization.projectVisibility)}</strong>
<a
- className="js-change-visibility spacer-left icon-edit"
+ className="js-change-visibility spacer-left link-no-underline"
href="#"
- onClick={this.handleChangeVisibilityClick}
- />
+ onClick={this.handleChangeVisibilityClick}>
+ <EditIcon className="text-text-top" />
+ </a>
</span>
{this.props.hasProvisionPermission && (
<button id="create-project" onClick={this.handleCreateProjectClick}>
import { translate } from '../../helpers/l10n';
import { getComponentPermissionsUrl } from '../../helpers/urls';
import DateTooltipFormatter from '../../components/intl/DateTooltipFormatter';
+import ActionsDropdown, { ActionsDropdownItem } from '../../components/controls/ActionsDropdown';
interface Props {
onApplyTemplateClick: (project: Project) => void;
this.props.onProjectCheck(this.props.project, checked);
};
- handleApplyTemplateClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- event.currentTarget.blur();
+ handleApplyTemplateClick = () => {
this.props.onApplyTemplateClick(this.props.project);
};
</td>
<td className="thin nowrap">
- <div className="dropdown">
- <button className="dropdown-toggle" data-toggle="dropdown">
- {translate('actions')} <i className="icon-dropdown" />
- </button>
- <ul className="dropdown-menu dropdown-menu-right">
- <li>
- <Link to={getComponentPermissionsUrl(project.key)}>
- {translate('edit_permissions')}
- </Link>
- </li>
- <li>
- <a className="js-apply-template" href="#" onClick={this.handleApplyTemplateClick}>
- {translate('projects_role.apply_template')}
- </a>
- </li>
- </ul>
- </div>
+ <ActionsDropdown>
+ <ActionsDropdownItem to={getComponentPermissionsUrl(project.key)}>
+ {translate('edit_permissions')}
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-apply-template"
+ onClick={this.handleApplyTemplateClick}>
+ {translate('projects_role.apply_template')}
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
</tr>
);
visibility.public
</strong>
<a
- className="js-change-visibility spacer-left icon-edit"
+ className="js-change-visibility spacer-left link-no-underline"
href="#"
onClick={[Function]}
- />
+ >
+ <EditIcon
+ className="text-text-top"
+ />
+ </a>
</span>
<button
id="create-project"
<td
className="thin nowrap"
>
- <div
- className="dropdown"
- >
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
+ <ActionsDropdown>
+ <ActionsDropdownItem
+ to={
+ Object {
+ "pathname": "/project_roles",
+ "query": Object {
+ "id": "project",
+ },
+ }
+ }
>
- actions
-
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ edit_permissions
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-apply-template"
+ onClick={[Function]}
>
- <li>
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project_roles",
- "query": Object {
- "id": "project",
- },
- }
- }
- >
- edit_permissions
- </Link>
- </li>
- <li>
- <a
- className="js-apply-template"
- href="#"
- onClick={[Function]}
- >
- projects_role.apply_template
- </a>
- </li>
- </ul>
- </div>
+ projects_role.apply_template
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
</tr>
`;
<td
className="thin nowrap"
>
- <div
- className="dropdown"
- >
- <button
- className="dropdown-toggle"
- data-toggle="dropdown"
+ <ActionsDropdown>
+ <ActionsDropdownItem
+ to={
+ Object {
+ "pathname": "/project_roles",
+ "query": Object {
+ "id": "project",
+ },
+ }
+ }
>
- actions
-
- <i
- className="icon-dropdown"
- />
- </button>
- <ul
- className="dropdown-menu dropdown-menu-right"
+ edit_permissions
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ className="js-apply-template"
+ onClick={[Function]}
>
- <li>
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/project_roles",
- "query": Object {
- "id": "project",
- },
- }
- }
- >
- edit_permissions
- </Link>
- </li>
- <li>
- <a
- className="js-apply-template"
- href="#"
- onClick={[Function]}
- >
- projects_role.apply_template
- </a>
- </li>
- </ul>
- </div>
+ projects_role.apply_template
+ </ActionsDropdownItem>
+ </ActionsDropdown>
</td>
</tr>
`;
*/
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import { Link } from 'react-router';
import RenameProfileForm from './RenameProfileForm';
import CopyProfileForm from './CopyProfileForm';
import DeleteProfileForm from './DeleteProfileForm';
import { setDefaultProfile } from '../../../api/quality-profiles';
import { getProfilePath, getProfileComparePath, getProfilesPath } from '../utils';
import { Profile } from '../types';
+import ActionsDropdown, {
+ ActionsDropdownItem,
+ ActionsDropdownDivider
+} from '../../../components/controls/ActionsDropdown';
interface Props {
+ className?: string;
fromList?: boolean;
onRequestFail: (reasong: any) => void;
organization: string | null;
};
}
- handleRenameClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
+ handleRenameClick = () => {
this.setState({ renameFormOpen: true });
};
handleProfileRename = (name: string) => {
this.closeRenameForm();
- this.props.updateProfiles().then(() => {
- if (!this.props.fromList) {
- this.context.router.replace(
- getProfilePath(name, this.props.profile.language, this.props.organization)
- );
- }
- });
+ this.props.updateProfiles().then(
+ () => {
+ if (!this.props.fromList) {
+ this.context.router.replace(
+ getProfilePath(name, this.props.profile.language, this.props.organization)
+ );
+ }
+ },
+ () => {}
+ );
};
closeRenameForm = () => {
this.setState({ renameFormOpen: false });
};
- handleCopyClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
+ handleCopyClick = () => {
this.setState({ copyFormOpen: true });
};
handleProfileCopy = (name: string) => {
- this.props.updateProfiles().then(() => {
- this.context.router.push(
- getProfilePath(name, this.props.profile.language, this.props.organization)
- );
- });
+ this.props.updateProfiles().then(
+ () => {
+ this.context.router.push(
+ getProfilePath(name, this.props.profile.language, this.props.organization)
+ );
+ },
+ () => {}
+ );
};
closeCopyForm = () => {
this.setState({ copyFormOpen: false });
};
- handleSetDefaultClick = (e: React.SyntheticEvent<HTMLElement>) => {
- e.preventDefault();
- setDefaultProfile(this.props.profile.key).then(this.props.updateProfiles);
+ handleSetDefaultClick = () => {
+ setDefaultProfile(this.props.profile.key).then(this.props.updateProfiles, () => {});
};
- handleDeleteClick = (event: React.SyntheticEvent<HTMLElement>) => {
- event.preventDefault();
+ handleDeleteClick = () => {
this.setState({ deleteFormOpen: true });
};
this.props.organization
);
+ const canActivateRules = actions.edit && !profile.isBuiltIn;
+ const canRename = actions.edit && !profile.isBuiltIn;
+ const canSetAsDefault = actions.setAsDefault && !profile.isDefault;
+ const canDelete = actions.edit && !profile.isDefault && !profile.isBuiltIn;
+
return (
- <ul className="dropdown-menu dropdown-menu-right">
- {actions.edit &&
- !profile.isBuiltIn && (
- <li>
- <Link to={activateMoreUrl}>{translate('quality_profiles.activate_more_rules')}</Link>
- </li>
- )}
+ <ActionsDropdown className={this.props.className}>
+ {canActivateRules && (
+ <ActionsDropdownItem to={activateMoreUrl}>
+ {translate('quality_profiles.activate_more_rules')}
+ </ActionsDropdownItem>
+ )}
+
{!profile.isBuiltIn && (
- <li>
- <a id="quality-profile-backup" href={backupUrl}>
- {translate('backup_verb')}
- </a>
- </li>
+ <ActionsDropdownItem
+ download={`${profile.key}.xml`}
+ id="quality-profile-backup"
+ to={backupUrl}>
+ {translate('backup_verb')}
+ </ActionsDropdownItem>
)}
- <li>
- <Link
- to={getProfileComparePath(profile.name, profile.language, this.props.organization)}
- id="quality-profile-compare">
- {translate('compare')}
- </Link>
- </li>
+
+ <ActionsDropdownItem
+ id="quality-profile-compare"
+ to={getProfileComparePath(profile.name, profile.language, this.props.organization)}>
+ {translate('compare')}
+ </ActionsDropdownItem>
+
{actions.copy && (
- <li>
- <a id="quality-profile-copy" href="#" onClick={this.handleCopyClick}>
- {translate('copy')}
- </a>
- </li>
+ <ActionsDropdownItem id="quality-profile-copy" onClick={this.handleCopyClick}>
+ {translate('copy')}
+ </ActionsDropdownItem>
+ )}
+
+ {canRename && (
+ <ActionsDropdownItem id="quality-profile-rename" onClick={this.handleRenameClick}>
+ {translate('rename')}
+ </ActionsDropdownItem>
+ )}
+
+ {canSetAsDefault && (
+ <ActionsDropdownItem
+ id="quality-profile-set-as-default"
+ onClick={this.handleSetDefaultClick}>
+ {translate('set_as_default')}
+ </ActionsDropdownItem>
+ )}
+
+ {canDelete && <ActionsDropdownDivider />}
+
+ {canDelete && (
+ <ActionsDropdownItem
+ destructive={true}
+ id="quality-profile-delete"
+ onClick={this.handleDeleteClick}>
+ {translate('delete')}
+ </ActionsDropdownItem>
)}
- {actions.edit &&
- !profile.isBuiltIn && (
- <li>
- <a id="quality-profile-rename" href="#" onClick={this.handleRenameClick}>
- {translate('rename')}
- </a>
- </li>
- )}
- {actions.setAsDefault &&
- !profile.isDefault && (
- <li>
- <a id="quality-profile-set-as-default" href="#" onClick={this.handleSetDefaultClick}>
- {translate('set_as_default')}
- </a>
- </li>
- )}
- {actions.edit &&
- !profile.isDefault &&
- !profile.isBuiltIn && (
- <li>
- <a id="quality-profile-delete" href="#" onClick={this.handleDeleteClick}>
- {translate('delete')}
- </a>
- </li>
- )}
{this.state.copyFormOpen && (
<CopyProfileForm
profile={profile}
/>
)}
- </ul>
+ </ActionsDropdown>
);
}
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders with all permissions 1`] = `
-<ul
- className="dropdown-menu dropdown-menu-right"
->
- <li>
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/org/rules#qprofile=foo|activation=false"
- >
- quality_profiles.activate_more_rules
- </Link>
- </li>
- <li>
- <a
- href="/api/qualityprofiles/backup?profileKey=foo"
- id="quality-profile-backup"
- >
- backup_verb
- </a>
- </li>
- <li>
- <Link
- id="quality-profile-compare"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/org/quality_profiles/compare",
- "query": Object {
- "language": "java",
- "name": "Foo",
- },
- }
+<ActionsDropdown>
+ <ActionsDropdownItem
+ to="/organizations/org/rules#qprofile=foo|activation=false"
+ >
+ quality_profiles.activate_more_rules
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ download="foo.xml"
+ id="quality-profile-backup"
+ to="/api/qualityprofiles/backup?profileKey=foo"
+ >
+ backup_verb
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-compare"
+ to={
+ Object {
+ "pathname": "/organizations/org/quality_profiles/compare",
+ "query": Object {
+ "language": "java",
+ "name": "Foo",
+ },
}
- >
- compare
- </Link>
- </li>
- <li>
- <a
- href="#"
- id="quality-profile-copy"
- onClick={[Function]}
- >
- copy
- </a>
- </li>
- <li>
- <a
- href="#"
- id="quality-profile-rename"
- onClick={[Function]}
- >
- rename
- </a>
- </li>
- <li>
- <a
- href="#"
- id="quality-profile-set-as-default"
- onClick={[Function]}
- >
- set_as_default
- </a>
- </li>
- <li>
- <a
- href="#"
- id="quality-profile-delete"
- onClick={[Function]}
- >
- delete
- </a>
- </li>
-</ul>
+ }
+ >
+ compare
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-copy"
+ onClick={[Function]}
+ >
+ copy
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-rename"
+ onClick={[Function]}
+ >
+ rename
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-set-as-default"
+ onClick={[Function]}
+ >
+ set_as_default
+ </ActionsDropdownItem>
+ <ActionsDropdownDivider />
+ <ActionsDropdownItem
+ destructive={true}
+ id="quality-profile-delete"
+ onClick={[Function]}
+ >
+ delete
+ </ActionsDropdownItem>
+</ActionsDropdown>
`;
exports[`renders with no permissions 1`] = `
-<ul
- className="dropdown-menu dropdown-menu-right"
->
- <li>
- <a
- href="/api/qualityprofiles/backup?profileKey=foo"
- id="quality-profile-backup"
- >
- backup_verb
- </a>
- </li>
- <li>
- <Link
- id="quality-profile-compare"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/org/quality_profiles/compare",
- "query": Object {
- "language": "java",
- "name": "Foo",
- },
- }
+<ActionsDropdown>
+ <ActionsDropdownItem
+ download="foo.xml"
+ id="quality-profile-backup"
+ to="/api/qualityprofiles/backup?profileKey=foo"
+ >
+ backup_verb
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-compare"
+ to={
+ Object {
+ "pathname": "/organizations/org/quality_profiles/compare",
+ "query": Object {
+ "language": "java",
+ "name": "Foo",
+ },
}
- >
- compare
- </Link>
- </li>
-</ul>
+ }
+ >
+ compare
+ </ActionsDropdownItem>
+</ActionsDropdown>
`;
exports[`renders with permission to edit 1`] = `
-<ul
- className="dropdown-menu dropdown-menu-right"
->
- <li>
- <Link
- onlyActiveOnIndex={false}
- style={Object {}}
- to="/organizations/org/rules#qprofile=foo|activation=false"
- >
- quality_profiles.activate_more_rules
- </Link>
- </li>
- <li>
- <a
- href="/api/qualityprofiles/backup?profileKey=foo"
- id="quality-profile-backup"
- >
- backup_verb
- </a>
- </li>
- <li>
- <Link
- id="quality-profile-compare"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
- Object {
- "pathname": "/organizations/org/quality_profiles/compare",
- "query": Object {
- "language": "java",
- "name": "Foo",
- },
- }
+<ActionsDropdown>
+ <ActionsDropdownItem
+ to="/organizations/org/rules#qprofile=foo|activation=false"
+ >
+ quality_profiles.activate_more_rules
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ download="foo.xml"
+ id="quality-profile-backup"
+ to="/api/qualityprofiles/backup?profileKey=foo"
+ >
+ backup_verb
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-compare"
+ to={
+ Object {
+ "pathname": "/organizations/org/quality_profiles/compare",
+ "query": Object {
+ "language": "java",
+ "name": "Foo",
+ },
}
- >
- compare
- </Link>
- </li>
- <li>
- <a
- href="#"
- id="quality-profile-rename"
- onClick={[Function]}
- >
- rename
- </a>
- </li>
- <li>
- <a
- href="#"
- id="quality-profile-delete"
- onClick={[Function]}
- >
- delete
- </a>
- </li>
-</ul>
+ }
+ >
+ compare
+ </ActionsDropdownItem>
+ <ActionsDropdownItem
+ id="quality-profile-rename"
+ onClick={[Function]}
+ >
+ rename
+ </ActionsDropdownItem>
+ <ActionsDropdownDivider />
+ <ActionsDropdownItem
+ destructive={true}
+ id="quality-profile-delete"
+ onClick={[Function]}
+ >
+ delete
+ </ActionsDropdownItem>
+</ActionsDropdown>
`;
</Link>
</li>
<li>
- <div className="pull-left dropdown">
- <button className="dropdown-toggle" data-toggle="dropdown">
- {translate('actions')} <i className="icon-dropdown" />
- </button>
- <ProfileActions
- onRequestFail={this.props.onRequestFail}
- organization={organization}
- profile={profile}
- updateProfiles={this.props.updateProfiles}
- />
- </div>
+ <ProfileActions
+ className="pull-left"
+ onRequestFail={this.props.onRequestFail}
+ organization={organization}
+ profile={profile}
+ updateProfiles={this.props.updateProfiles}
+ />
</li>
</ul>
</div>
{this.renderUsageDate()}
</td>
<td className="quality-profiles-table-actions thin nowrap text-right">
- <div className="dropdown">
- <button className="dropdown-toggle" data-toggle="dropdown">
- <i className="icon-dropdown" />
- </button>
- <ProfileActions
- fromList={true}
- onRequestFail={this.props.onRequestFail}
- organization={this.props.organization}
- profile={this.props.profile}
- updateProfiles={this.props.updateProfiles}
- />
- </div>
+ <ProfileActions
+ fromList={true}
+ onRequestFail={this.props.onRequestFail}
+ organization={this.props.organization}
+ profile={this.props.profile}
+ updateProfiles={this.props.updateProfiles}
+ />
</td>
</tr>
);
import PropTypes from 'prop-types';
import PrimitiveInput from './PrimitiveInput';
import { getEmptyValue } from '../../utils';
+import DeleteIcon from '../../../../components/icons-components/DeleteIcon';
export default class MultiValueInput extends React.PureComponent {
static propTypes = {
<button
className="js-remove-value button-clean"
onClick={e => this.handleDeleteValue(e, index)}>
- <i className="icon-delete" />
+ <DeleteIcon />
</button>
</div>
)}
import PropTypes from 'prop-types';
import PrimitiveInput from './PrimitiveInput';
import { getEmptyValue, getUniqueName } from '../../utils';
+import DeleteIcon from '../../../../components/icons-components/DeleteIcon';
export default class PropertySetInput extends React.PureComponent {
static propTypes = {
<button
className="js-remove-value button-link"
onClick={e => this.handleDeleteValue(e, index)}>
- <i className="icon-delete" />
+ <DeleteIcon className="text-middle" />
</button>
)}
</td>
// @flow
import React from 'react';
import { createProject, deleteProject } from '../../../api/components';
+import DeleteIcon from '../../../components/icons-components/DeleteIcon';
import { translate } from '../../../helpers/l10n';
/*::
<i className="spinner" />
) : (
<button className="button-clean">
- <i className="icon-delete" />
+ <DeleteIcon />
</button>
)}
</form>
deleteProject: () => Promise.resolve()
}));
+jest.mock(
+ '../../../../components/icons-components/DeleteIcon',
+ () =>
+ function DeleteIcon() {
+ return null;
+ }
+);
+
it('creates new project', async () => {
const onDone = jest.fn();
const wrapper = mount(<ProjectKeyStep onDelete={jest.fn()} onDone={onDone} />);
<button
className="button-clean"
>
- <i
- className="icon-delete"
- />
+ <DeleteIcon />
</button>
</form>
</div>
<button
className="button-clean"
>
- <i
- className="icon-delete"
- />
+ <DeleteIcon />
</button>
</form>
</div>
{{tp 'users.deactivate_user.confirmation' name login}}
</div>
<div class="modal-foot">
- <button id="deactivate-user-submit">{{t 'users.deactivate'}}</button>
+ <button class="button-red" id="deactivate-user-submit">{{t 'users.deactivate'}}</button>
<a href="#" class="js-modal-close" id="deactivate-user-cancel">{{t 'cancel'}}</a>
</div>
</form>
</td>
<td class="thin nowrap text-right">
- <a class="js-user-update icon-edit little-spacer-right" title="{{t 'update_details'}}" data-toggle="tooltip" href="#"></a>
- {{#if local}}
- <a class="js-user-change-password icon-lock little-spacer-right" title="{{t 'my_profile.password.title'}}" data-toggle="tooltip"
- href="#"></a>
- {{/if}}
- <a class="js-user-deactivate icon-delete" title="{{t 'users.deactivate'}}" data-toggle="tooltip" href="#"></a>
+ <div class="dropdown">
+ <button class="dropdown-toggle" data-toggle="dropdown">
+ {{settingsIcon}}<i class="icon-dropdown little-spacer-left" />
+ </button>
+ <ul class="dropdown-menu dropdown-menu-right">
+ <li>
+ <a class="js-user-update" href="#">{{t 'update_details'}}</a>
+ </li>
+ {{#if local}}
+ <li>
+ <a class="js-user-change-password" href="#">{{t 'my_profile.password.title'}}</a>
+ </li>
+ {{/if}}
+ <li class="divider" />
+ <li>
+ <a class="js-user-deactivate text-danger" href="#">{{t 'users.deactivate'}}</a>
+ </li>
+ </ul>
+ </div>
</td>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:contact 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 { Link } from 'react-router';
+import { LocationDescriptor } from 'history';
+import SettingsIcon from '../icons-components/SettingsIcon';
+
+interface Props {
+ className?: string;
+ children: React.ReactNode;
+ small?: boolean;
+ toggleClassName?: string;
+}
+
+export default function ActionsDropdown(props: Props) {
+ return (
+ <div className={classNames('dropdown', props.className)}>
+ <button
+ className={classNames('dropdown-toggle', props.toggleClassName, {
+ 'button-small button-compact': props.small
+ })}
+ data-toggle="dropdown">
+ <SettingsIcon className="text-text-bottom" />
+ <i className="icon-dropdown little-spacer-left" />
+ </button>
+ <ul className="dropdown-menu dropdown-menu-right">{props.children}</ul>
+ </div>
+ );
+}
+
+interface ItemProps {
+ className?: string;
+ children: React.ReactNode;
+ destructive?: boolean;
+ /** used to pass a name of downloaded file */
+ download?: string;
+ id?: string;
+ onClick?: () => void;
+ to?: LocationDescriptor;
+}
+
+export class ActionsDropdownItem extends React.PureComponent<ItemProps> {
+ handleClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ event.currentTarget.blur();
+ if (this.props.onClick) {
+ this.props.onClick();
+ }
+ };
+
+ render() {
+ const className = classNames(this.props.className, { 'text-danger': this.props.destructive });
+
+ if (this.props.download && typeof this.props.to === 'string') {
+ return (
+ <li>
+ <a
+ className={className}
+ download={this.props.download}
+ href={this.props.to}
+ id={this.props.id}>
+ {this.props.children}
+ </a>
+ </li>
+ );
+ }
+
+ if (this.props.to) {
+ return (
+ <li>
+ <Link className={className} id={this.props.id} to={this.props.to}>
+ {this.props.children}
+ </Link>
+ </li>
+ );
+ }
+
+ return (
+ <li>
+ <a className={className} href="#" id={this.props.id} onClick={this.handleClick}>
+ {this.props.children}
+ </a>
+ </li>
+ );
+ }
+}
+
+export function ActionsDropdownDivider() {
+ return <li className="divider" />;
+}
import React from 'react';
import Avatar from '../../../components/ui/Avatar';
import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
+import EditIcon from '../../../components/icons-components/EditIcon';
+import DeleteIcon from '../../../components/icons-components/DeleteIcon';
import CommentDeletePopup from '../popups/CommentDeletePopup';
import CommentPopup from '../popups/CommentPopup';
import DateFromNow from '../../../components/intl/DateFromNow';
/>
}>
<button
- className="js-issue-comment-edit button-link icon-edit icon-half-transparent"
- onClick={this.toggleEditPopup}
- />
+ className="js-issue-comment-edit button-link icon-half-transparent"
+ onClick={this.toggleEditPopup}>
+ <EditIcon />
+ </button>
</BubblePopupHelper>
)}
{comment.updatable && (
togglePopup={this.toggleDeletePopup}
popup={<CommentDeletePopup onDelete={this.handleDelete} />}>
<button
- className="js-issue-comment-delete button-link icon-delete icon-half-transparent"
- onClick={this.toggleDeletePopup}
- />
+ className="js-issue-comment-delete button-link icon-half-transparent little-spacer-left"
+ onClick={this.toggleDeletePopup}>
+ <DeleteIcon />
+ </button>
</BubblePopupHelper>
)}
</div>
togglePopup={[Function]}
>
<button
- className="js-issue-comment-edit button-link icon-edit icon-half-transparent"
+ className="js-issue-comment-edit button-link icon-half-transparent"
onClick={[Function]}
- />
+ >
+ <EditIcon />
+ </button>
</BubblePopupHelper>
<BubblePopupHelper
className="bubble-popup-helper-inline"
togglePopup={[Function]}
>
<button
- className="js-issue-comment-delete button-link icon-delete icon-half-transparent"
+ className="js-issue-comment-delete button-link icon-half-transparent little-spacer-left"
onClick={[Function]}
- />
+ >
+ <DeleteIcon />
+ </button>
</BubblePopupHelper>
</div>
</div>
togglePopup={[Function]}
>
<button
- className="js-issue-comment-edit button-link icon-edit icon-half-transparent"
+ className="js-issue-comment-edit button-link icon-half-transparent"
onClick={[Function]}
- />
+ >
+ <EditIcon />
+ </button>
</BubblePopupHelper>
<BubblePopupHelper
className="bubble-popup-helper-inline"
togglePopup={[Function]}
>
<button
- className="js-issue-comment-delete button-link icon-delete icon-half-transparent"
+ className="js-issue-comment-delete button-link icon-half-transparent little-spacer-left"
onClick={[Function]}
- />
+ >
+ <DeleteIcon />
+ </button>
</BubblePopupHelper>
</div>
</div>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+const Handlebars = require('handlebars/runtime');
+
+module.exports = function() {
+ return new Handlebars.default.SafeString(`
+ <svg class="text-text-bottom" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" width="14" height="14">
+ <g transform="matrix(0.0364583,0,0,0.0364583,0,-1.16667)">
+ <path
+ d="M256,224C256,206.333 249.75,191.25 237.25,178.75C224.75,166.25 209.667,160 192,160C174.333,160 159.25,166.25 146.75,178.75C134.25,191.25 128,206.333 128,224C128,241.667 134.25,256.75 146.75,269.25C159.25,281.75 174.333,288 192,288C209.667,288 224.75,281.75 237.25,269.25C249.75,256.75 256,241.667 256,224ZM384,196.75L384,252.25C384,254.25 383.333,256.167 382,258C380.667,259.833 379,260.917 377,261.25L330.75,268.25C327.583,277.25 324.333,284.833 321,291C326.833,299.333 335.75,310.833 347.75,325.5C349.417,327.5 350.25,329.583 350.25,331.75C350.25,333.917 349.5,335.833 348,337.5C343.5,343.667 335.25,352.667 323.25,364.5C311.25,376.333 303.417,382.25 299.75,382.25C297.75,382.25 295.583,381.5 293.25,380L258.75,353C251.417,356.833 243.833,360 236,362.5C233.333,385.167 230.917,400.667 228.75,409C227.583,413.667 224.583,416 219.75,416L164.25,416C161.917,416 159.875,415.292 158.125,413.875C156.375,412.458 155.417,410.667 155.25,408.5L148.25,362.5C140.083,359.833 132.583,356.75 125.75,353.25L90.5,380C88.833,381.5 86.75,382.25 84.25,382.25C81.917,382.25 79.833,381.333 78,379.5C57,360.5 43.25,346.5 36.75,337.5C35.583,335.833 35,333.917 35,331.75C35,329.75 35.667,327.833 37,326C39.5,322.5 43.75,316.958 49.75,309.375C55.75,301.792 60.25,295.917 63.25,291.75C58.75,283.417 55.333,275.167 53,267L7.25,260.25C5.083,259.917 3.333,258.875 2,257.125C0.667,255.375 0,253.417 0,251.25L0,195.75C0,193.75 0.667,191.833 2,190C3.333,188.167 4.917,187.083 6.75,186.75L53.25,179.75C55.583,172.083 58.833,164.417 63,156.75C56.333,147.25 47.417,135.75 36.25,122.25C34.583,120.25 33.75,118.25 33.75,116.25C33.75,114.583 34.5,112.667 36,110.5C40.333,104.5 48.542,95.542 60.625,83.625C72.708,71.708 80.583,65.75 84.25,65.75C86.417,65.75 88.583,66.583 90.75,68.25L125.25,95C132.583,91.167 140.167,88 148,85.5C150.667,62.833 153.083,47.333 155.25,39C156.417,34.333 159.417,32 164.25,32L219.75,32C222.083,32 224.125,32.708 225.875,34.125C227.625,35.542 228.583,37.333 228.75,39.5L235.75,85.5C243.917,88.167 251.417,91.25 258.25,94.75L293.75,68C295.25,66.5 297.25,65.75 299.75,65.75C301.917,65.75 304,66.583 306,68.25C327.5,88.083 341.25,102.25 347.25,110.75C348.417,112.083 349,113.917 349,116.25C349,118.25 348.333,120.167 347,122C344.5,125.5 340.25,131.042 334.25,138.625C328.25,146.208 323.75,152.083 320.75,156.25C325.083,164.583 328.5,172.75 331,180.75L376.75,187.75C378.917,188.083 380.667,189.125 382,190.875C383.333,192.625 384,194.583 384,196.75Z"
+ style="fill: currentColor"
+ />
+ </g>
+ </svg>
+ `);
+};
<td>/organizations/test-org/quality_profiles</td>
<td></td>
</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-more-admin-actions</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=.js-more-admin-actions</td>
- <td></td>
-</tr>
<tr>
<td>click</td>
<td>css=#quality-profiles-restore</td>
<td>/profiles</td>
<td></td>
</tr>
-<tr>
- <td>waitForElementPresent</td>
- <td>css=.js-more-admin-actions</td>
- <td></td>
-</tr>
-<tr>
- <td>click</td>
- <td>css=.js-more-admin-actions</td>
- <td></td>
-</tr>
<tr>
<td>click</td>
<td>css=#quality-profiles-restore</td>
<td>id=users-list</td>
<td>*${userId}*</td>
</tr>
+<tr>
+ <td>click</td>
+ <td>css=[data-login="${userId}"] .dropdown-toggle</td>
+ <td></td>
+</tr>
<tr>
<td>click</td>
<td>css=[data-login="${userId}"] .js-user-deactivate</td>
<td>css=[data-login=admin-user]</td>
<td></td>
</tr>
+<tr>
+ <td>click</td>
+ <td>css=[data-login=admin-user] .dropdown-toggle</td>
+ <td></td>
+</tr>
<tr>
<td>click</td>
<td>css=[data-login=admin-user] .js-user-change-password</td>