line-height: var(--controlHeight);
}
-button,
-.button,
-input[type='submit'],
-input[type='button'] {
- display: inline-block;
- vertical-align: baseline;
- height: var(--controlHeight);
- line-height: calc(var(--controlHeight) - 2px);
- padding: 0 12px;
- border: 1px solid var(--darkBlue);
- border-radius: 2px;
- box-sizing: border-box;
- background: transparent;
- color: var(--darkBlue);
- font-weight: 600;
- font-size: var(--smallFontSize);
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- outline: none;
- transition: border-color 0.2s ease;
-}
-
-button:hover,
-.button:hover,
-input[type='submit']:hover,
-input[type='button']:hover,
-button:focus,
-.button:focus,
-input[type='submit']:focus,
-input[type='button']:focus,
-button.button-active,
-.button.button-active,
-input[type='submit'].button-active,
-input[type='button'].button-active {
- background: var(--darkBlue);
- color: #fff;
-}
-
-button:active,
-.button:active,
-input[type='submit']:active,
-input[type='button']:active {
- box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
-}
-
-button.disabled,
-.button.disabled,
-input[type='submit'].disabled,
-input[type='button'].disabled,
-button:disabled,
-.button:disabled,
-input[type='submit']:disabled,
-input[type='button']:disabled,
-button:disabled:hover,
-.button:disabled:hover,
-input[type='submit']:disabled:hover,
-input[type='button']:disabled:hover,
-button:disabled:active,
-.button:disabled:active,
-input[type='submit']:disabled:active,
-input[type='button']:disabled:active,
-button:disabled:focus,
-.button:disabled:focus,
-input[type='submit']:disabled:focus,
-input[type='button']:disabled:focus {
- color: var(--disableGrayText) !important;
- border-color: var(--disableGrayBorder) !important;
- background: var(--disableGrayBg) !important;
- cursor: not-allowed !important;
- box-shadow: none !important;
-}
-
-.button svg {
- margin-top: calc((var(--controlHeight) - 16px - 2px) / 2);
-}
-
-.button-red,
-input[type='submit'].button-red {
- border-color: var(--red);
- color: var(--red);
-}
-
-.button-red:hover,
-input[type='submit'].button-red:hover,
-.button-red:focus,
-input[type='submit'].button-red:focus,
-.button-red.active,
-input[type='submit'].button-red.active {
- background: var(--red);
- color: #fff;
-}
-
-.button-success,
-input[type='submit'].button-success {
- border-color: var(--green);
- color: var(--green);
-}
-
-.button-success:hover,
-input[type='submit'].button-success:hover,
-.button-success:focus,
-input[type='submit'].button-success:focus,
-.button-success.active,
-input[type='submit'].button-success.active {
- background: var(--green);
- color: #fff;
-}
-
-.button-grey,
-input[type='submit'].button-grey {
- border-color: var(--gray71);
- color: var(--secondFontColor);
-}
-
-.button-grey:hover,
-input[type='submit'].button-grey:hover,
-.button-grey:focus,
-input[type='submit'].button-grey:focus,
-.button-grey.active,
-input[type='submit'].button-grey.active {
- background: var(--gray71);
- color: #ffffff;
-}
-
-.button-grey.button-active,
-input[type='submit'].button-grey.button-active {
- background: var(--secondFontColor);
- border-color: var(--secondFontColor);
- color: #ffffff;
-}
-
-.button-clean,
-.button-clean:hover,
-.button-clean:focus {
- padding: 0;
- line-height: 1;
- border: none;
- background: transparent;
- box-shadow: none;
- color: var(--baseFontColor);
-}
-
-.button-clean path {
- transition: opacity 0.3s ease;
-}
-
-.button-clean:hover path {
- opacity: 0.8;
-}
-
-.button-link {
- display: inline;
- height: auto; /* Keep this to not inherit the height from .button */
- margin: 0;
- padding: 0;
- border: none;
- background: transparent;
- color: var(--darkBlue);
- font-weight: 400;
- font-size: inherit;
- line-height: inherit;
- transition: all 0.2s ease;
-}
-
-.button-link svg {
- margin-top: 0;
-}
-
-.button-link:hover,
-.button-link:focus {
- background: transparent;
- color: var(--blue);
-}
-
-.button-link:active {
- box-shadow: none;
- outline: thin dotted #ccc;
-}
-
-.button-link:disabled,
-.button-link:disabled:hover,
-.button-link:disabled:active,
-.button-link:disabled:focus {
- color: var(--secondFontColor);
- background: transparent !important;
- cursor: default;
-}
-
-.button-small {
- height: var(--smallControlHeight);
- line-height: 18px;
- padding: 0 6px;
- font-size: 11px;
-}
-
-.button-small > svg {
- margin-top: 2px;
-}
-
-.button-group {
- display: inline-block;
- vertical-align: middle;
- font-size: 0;
- white-space: nowrap;
-}
-
-.button-group > button,
-.button-group > .button {
- position: relative;
- z-index: var(--normalZIndex);
- display: inline-block;
- vertical-align: middle;
- margin: 0;
- cursor: pointer;
-}
-
-.button-group > button:hover:not(:disabled),
-.button-group > .button:hover:not(:disabled),
-.button-group > button:focus:not(:disabled),
-.button-group > .button:focus:not(:disabled),
-.button-group > button:active:not(:disabled),
-.button-group > .button:active:not(:disabled),
-.button-group > button.active:not(:disabled),
-.button-group > .button.active:not(:disabled) {
- z-index: var(--aboveNormalZIndex);
-}
-
-.button-group > button:disabled,
-.button-group > .button:disabled {
- z-index: var(--belowNormalZIndex);
-}
-
-.button-group > button:not(:first-child),
-.button-group > .button:not(:first-child) {
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
-}
-
-.button-group > button:not(:last-child):not(.dropdown-toggle),
-.button-group > .button:not(:last-child):not(.dropdown-toggle) {
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
-}
-
-.button-group > button + button,
-.button-group > button + .button,
-.button-group > .button + button,
-.button-group > .button + .button {
- margin-left: -1px;
-}
-
-.button-group > a:not(.button) {
- vertical-align: middle;
- margin: 0 8px;
- font-size: var(--smallFontSize);
-}
-
.input-tiny {
width: 60px !important;
}
import CoverageRating from '../../components/ui/CoverageRating';
import DuplicationsRating from '../../components/ui/DuplicationsRating';
import Level from '../../components/ui/Level';
-import { EditButton } from '../../components/ui/buttons';
+import { EditButton, Button, SubmitButton, ResetButtonLink } from '../../components/ui/buttons';
import DeferredSpinner from '../../components/common/DeferredSpinner';
import ReloadButton from '../../components/controls/ReloadButton';
global.SonarMeasures = measures;
global.SonarRequest = { ...request, throwGlobalError, addGlobalSuccessMessage };
global.SonarComponents = {
+ Button,
CoverageRating,
DateFormatter,
DateFromNow,
ListFooter,
Modal,
ReloadButton,
+ ResetButtonLink,
SearchBox,
Select,
SelectList,
+ SubmitButton,
Tooltip
};
};
*/
import React, { Component } from 'react';
import { changePassword } from '../../../api/users';
+import { SubmitButton } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
export default class Password extends Component {
{errors &&
errors.map((e, i) => (
- <div key={i} className="alert alert-danger">
+ <div className="alert alert-danger" key={i}>
{e}
</div>
))}
<em className="mandatory">*</em>
</label>
<input
- ref={elem => (this.oldPassword = elem)}
autoComplete="off"
id="old_password"
name="old_password"
+ ref={elem => (this.oldPassword = elem)}
required={true}
type="password"
/>
<em className="mandatory">*</em>
</label>
<input
- ref={elem => (this.password = elem)}
autoComplete="off"
id="password"
name="password"
+ ref={elem => (this.password = elem)}
required={true}
type="password"
/>
<em className="mandatory">*</em>
</label>
<input
- ref={elem => (this.passwordConfirmation = elem)}
autoComplete="off"
id="password_confirmation"
name="password_confirmation"
+ ref={elem => (this.passwordConfirmation = elem)}
required={true}
type="password"
/>
</div>
<div className="modal-field">
- <button id="change-password" type="submit">
+ <SubmitButton id="change-password">
{translate('my_profile.password.submit')}
- </button>
+ </SubmitButton>
</div>
</form>
</section>
import DateFilter from './DateFilter';
import { DEFAULT_FILTERS } from './../constants';
import SearchBox from '../../../components/controls/SearchBox';
+import { Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
export default class Search extends React.PureComponent {
onReload: PropTypes.func.isRequired
};
- handleStatusChange(status /*: string */) {
+ handleStatusChange = (status /*: string */) => {
this.props.onFilterUpdate({ status });
- }
+ };
- handleTypeChange(taskType /*: string */) {
+ handleTypeChange = (taskType /*: string */) => {
this.props.onFilterUpdate({ taskType });
- }
+ };
- handleCurrentsChange(currents /*: string */) {
+ handleCurrentsChange = (currents /*: string */) => {
this.props.onFilterUpdate({ currents });
- }
+ };
handleDateChange = (date /*: { maxExecutedAt?: Date; minSubmittedAt?: Date } */) => {
this.props.onFilterUpdate(date);
this.props.onFilterUpdate({ query });
};
- handleReload(e /*: Object */) {
- e.target.blur();
- this.props.onReload();
- }
-
- handleReset(e /*: Object */) {
- e.preventDefault();
- e.target.blur();
+ handleReset = () => {
this.props.onFilterUpdate(DEFAULT_FILTERS);
- }
+ };
renderSearchBox() {
const { component, query } = this.props;
<ul className="bt-search-form">
<li>
<h6 className="bt-search-form-label">{translate('status')}</h6>
- <StatusFilter value={status} onChange={this.handleStatusChange.bind(this)} />
+ <StatusFilter onChange={this.handleStatusChange} value={status} />
</li>
{types.length > 1 && (
<li>
<h6 className="bt-search-form-label">{translate('type')}</h6>
- <TypesFilter
- value={taskType}
- types={types}
- onChange={this.handleTypeChange.bind(this)}
- />
+ <TypesFilter onChange={this.handleTypeChange} types={types} value={taskType} />
</li>
)}
{!component && (
<h6 className="bt-search-form-label">
{translate('background_tasks.currents_filter.ONLY_CURRENTS')}
</h6>
- <CurrentsFilter value={currents} onChange={this.handleCurrentsChange.bind(this)} />
+ <CurrentsFilter onChange={this.handleCurrentsChange} value={currents} />
</li>
)}
<li>
{this.renderSearchBox()}
<li className="nowrap">
- <button className="js-reload" onClick={this.handleReload.bind(this)} disabled={loading}>
+ <Button className="js-reload" disabled={loading} onClick={this.props.onReload}>
{translate('reload')}
- </button>{' '}
- <button ref="resetButton" onClick={this.handleReset.bind(this)} disabled={loading}>
+ </Button>{' '}
+ <Button disabled={loading} onClick={this.handleReset}>
{translate('reset_verb')}
- </button>
+ </Button>
</li>
</ul>
</section>
/*:: import type { Organization } from '../../../store/organizations/duck'; */
import { getOrganizationByKey } from '../../../store/rootReducer';
import { updateOrganization } from '../actions';
+import { SubmitButton } from '../../../components/ui/buttons';
/*::
type Props = {
<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"
- maxLength="64"
value={this.state.name}
- disabled={this.state.loading}
- onChange={e => this.setState({ name: e.target.value })}
/>
<div className="modal-field-description">
{translate('organization.name.description')}
<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"
- maxLength="256"
value={this.state.avatar}
- disabled={this.state.loading}
- onChange={this.handleAvatarInputChange}
/>
<div className="modal-field-description">
{translate('organization.avatar.description')}
{translate('organization.avatar.preview')}
{':'}
</div>
- <img src={this.state.avatarImage} alt="" height={30} />
+ <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"
- maxLength="256"
value={this.state.description}
- disabled={this.state.loading}
- onChange={e => this.setState({ description: e.target.value })}
/>
<div className="modal-field-description">
{translate('organization.description.description')}
<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"
- maxLength="256"
value={this.state.url}
- disabled={this.state.loading}
- onChange={e => this.setState({ url: e.target.value })}
/>
<div className="modal-field-description">
{translate('organization.url.description')}
</div>
</div>
<div className="modal-field">
- <button type="submit" disabled={this.state.loading}>
- {translate('save')}
- </button>
+ <SubmitButton disabled={this.state.loading}>{translate('save')}</SubmitButton>
{this.state.loading && <i className="spinner spacer-left" />}
</div>
</form>
<div
className="modal-field"
>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
save
- </button>
+ </SubmitButton>
</div>
</form>
</div>
<div
className="modal-field"
>
- <button
+ <SubmitButton
disabled={false}
- type="submit"
>
save
- </button>
+ </SubmitButton>
</div>
</form>
</div>
<div
className="modal-field"
>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
save
- </button>
+ </SubmitButton>
<i
className="spinner spacer-left"
/>
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 '../../../../store/organizations/duck'; */
/*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */
renderModal() {
const header = translate('users.add');
return (
- <Modal key="add-member-modal" contentLabel={header} onRequestClose={this.closeForm}>
+ <Modal contentLabel={header} key="add-member-modal" onRequestClose={this.closeForm}>
<header className="modal-head">
<h2>{header}</h2>
</header>
<label>{translate('users.search_description')}</label>
<UsersSelectSearch
autoFocus={true}
- selectedUser={this.state.selectedMember}
excludedUsers={this.props.memberLogins}
- searchUsers={this.handleSearch}
handleValueChange={this.selectedMemberChange}
+ searchUsers={this.handleSearch}
+ selectedUser={this.state.selectedMember}
/>
</div>
</div>
<footer className="modal-foot">
<div>
- <button type="submit" disabled={!this.state.selectedMember}>
+ <SubmitButton disabled={!this.state.selectedMember}>
{translate('organization.members.add_to_members')}
- </button>
- <button type="reset" className="button-link" onClick={this.closeForm}>
- {translate('cancel')}
- </button>
+ </SubmitButton>
+ <ResetButtonLink onClick={this.closeForm}>{translate('cancel')}</ResetButtonLink>
</div>
</footer>
</form>
render() {
const buttonComponent = (
- <button key="add-member-button" onClick={this.openForm}>
+ <Button key="add-member-button" onClick={this.openForm}>
{translate('organization.members.add')}
- </button>
+ </Button>
);
if (this.state.open) {
return [buttonComponent, this.renderModal()];
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, OrgGroup } from '../../../../store/organizations/duck'; */
</div>
<footer className="modal-foot">
<div>
- <button type="submit">{translate('save')}</button>
- <button className="button-link" onClick={this.props.onClose} type="reset">
- {translate('cancel')}
- </button>
+ <SubmitButton>{translate('save')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</div>
</footer>
</form>
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 '../../../../store/organizations/duck'; */
</div>
<footer className="modal-foot">
<div>
- <button autoFocus={true} className="button-red" type="submit">
+ <SubmitButton autoFocus={true} className="button-red">
{translate('remove')}
- </button>
- <button className="button-link" onClick={this.props.onClose} type="reset">
- {translate('cancel')}
- </button>
+ </SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</div>
</footer>
</form>
const memberLogins = ['admin'];
it('should render and open the modal', () => {
- const wrapper = shallow(<AddMemberForm memberLogins={memberLogins} addMember={jest.fn()} />);
+ const wrapper = shallow(<AddMemberForm addMember={jest.fn()} memberLogins={memberLogins} />);
expect(wrapper).toMatchSnapshot();
wrapper.setState({ open: true });
});
it('should correctly handle user interactions', () => {
- const wrapper = shallow(<AddMemberForm memberLogins={memberLogins} addMember={jest.fn()} />);
- click(wrapper.find('button'));
+ 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();
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render and open the modal 1`] = `
-<button
+<Button
key="add-member-button"
onClick={[Function]}
>
organization.members.add
-</button>
+</Button>
`;
exports[`should render and open the modal 2`] = `
Array [
- <button
+ <Button
onClick={[Function]}
>
organization.members.add
- </button>,
+ </Button>,
<Modal
contentLabel="users.add"
onRequestClose={[Function]}
className="modal-foot"
>
<div>
- <button
+ <SubmitButton
disabled={true}
- type="submit"
>
organization.members.add_to_members
- </button>
- <button
- className="button-link"
+ </SubmitButton>
+ <ResetButtonLink
onClick={[Function]}
- type="reset"
>
cancel
- </button>
+ </ResetButtonLink>
</div>
</footer>
</form>
className="modal-foot"
>
<div>
- <button
- type="submit"
- >
+ <SubmitButton>
save
- </button>
- <button
- className="button-link"
- type="reset"
- >
+ </SubmitButton>
+ <ResetButtonLink>
cancel
- </button>
+ </ResetButtonLink>
</div>
</footer>
</form>
className="modal-foot"
>
<div>
- <button
+ <SubmitButton
autoFocus={true}
className="button-red"
- type="submit"
>
remove
- </button>
- <button
- className="button-link"
- type="reset"
- >
+ </SubmitButton>
+ <ResetButtonLink>
cancel
- </button>
+ </ResetButtonLink>
</div>
</footer>
</form>
import React from 'react';
import Modal from '../../../../components/controls/Modal';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
+import { Button, ResetButtonLink } from '../../../../components/ui/buttons';
/*::
type Props = {
export default class PublicProjectDisclaimer extends React.PureComponent {
/*:: props: Props; */
- handleCancelClick = (event /*: Event */) => {
- event.preventDefault();
- this.props.onClose();
- };
-
- handleConfirmClick = (event /*: Event */) => {
- event.preventDefault();
+ handleConfirmClick = () => {
this.props.onConfirm();
this.props.onClose();
};
</div>
<footer className="modal-foot">
- <button id="confirm-turn-to-public" onClick={this.handleConfirmClick}>
+ <Button id="confirm-turn-to-public" onClick={this.handleConfirmClick}>
{translate('projects_role.turn_project_to_public', qualifier)}
- </button>
- <a href="#" onClick={this.handleCancelClick}>
- {translate('cancel')}
- </a>
+ </Button>
+ <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</Modal>
);
import { deleteProject, deletePortfolio } from '../../../api/components';
import Modal from '../../../components/controls/Modal';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { Button, SubmitButton, ResetButtonLink } from '../../../components/ui/buttons';
export default class Form extends React.PureComponent {
static propTypes = {
this.mounted = false;
}
- handleDeleteClick = event => {
- event.preventDefault();
+ handleDeleteClick = () => {
this.setState({ modalOpen: true });
};
.catch(this.stopLoading);
};
- handleCloseClick = (event /*: Event */) => {
- event.preventDefault();
- this.closeModal();
- };
-
render() {
const { component } = this.props;
return (
<div>
- <button id="delete-project" className="button-red" onClick={this.handleDeleteClick}>
+ <Button className="button-red" id="delete-project" onClick={this.handleDeleteClick}>
{translate('delete')}
- </button>
+ </Button>
{this.state.modalOpen && (
<Modal contentLabel="project deletion" onRequestClose={this.closeModal}>
</div>
<div className="modal-foot">
{this.state.loading && <i className="js-modal-spinner spinner spacer-right" />}
- <button
- id="delete-project-confirm"
+ <SubmitButton
className="button-red"
- disabled={this.state.loading}>
+ disabled={this.state.loading}
+ id="delete-project-confirm">
{translate('delete')}
- </button>
- <a href="#" className="js-modal-close" onClick={this.handleCloseClick}>
+ </SubmitButton>
+ <ResetButtonLink className="js-modal-close" onClick={this.closeModal}>
{translate('cancel')}
- </a>
+ </ResetButtonLink>
</div>
</form>
</Modal>
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from '../../../helpers/l10n';
+import { SubmitButton } from '../../../components/ui/buttons';
export default class BulkUpdateForm extends React.PureComponent {
static propTypes = {
onSubmit: PropTypes.func.isRequired
};
- handleSubmit(e) {
+ handleSubmit = e => {
e.preventDefault();
- this.refs.submit.blur();
const replace = this.refs.replace.value;
const by = this.refs.by.value;
this.props.onSubmit(replace, by);
- }
+ };
render() {
return (
- <form onSubmit={this.handleSubmit.bind(this)}>
+ <form onSubmit={this.handleSubmit}>
<div className="modal-field">
<label htmlFor="bulk-update-replace">{translate('update_key.replace')}</label>
<input
- ref="replace"
id="bulk-update-replace"
name="replace"
- type="text"
placeholder={translate('update_key.replace_example')}
+ ref="replace"
required={true}
+ type="text"
/>
</div>
<div className="modal-field">
<label htmlFor="bulk-update-by">{translate('update_key.by')}</label>
<input
- ref="by"
id="bulk-update-by"
name="by"
- type="text"
placeholder={translate('update_key.by_example')}
+ ref="by"
required={true}
+ type="text"
/>
- <button ref="submit" id="bulk-update-see-results" className="big-spacer-left">
+ <SubmitButton className="big-spacer-left" id="bulk-update-see-results">
{translate('update_key.see_results')}
- </button>
+ </SubmitButton>
</div>
</form>
);
import PropTypes from 'prop-types';
import { some } from 'lodash';
import { translateWithParameters, translate } from '../../../helpers/l10n';
+import { Button } from '../../../components/ui/buttons';
export default class BulkUpdateResults extends React.PureComponent {
static propTypes = {
onConfirm: PropTypes.func.isRequired
};
- handleConfirm(e) {
- e.preventDefault();
- e.target.blur();
- this.props.onConfirm();
- }
-
render() {
const { results, replace, by } = this.props;
const isEmpty = results.length === 0;
const canUpdate = !isEmpty && !hasDuplications;
return (
- <div id="bulk-update-simulation" className="big-spacer-top">
+ <div className="big-spacer-top" id="bulk-update-simulation">
{isEmpty && (
- <div id="bulk-update-nothing" className="spacer-bottom">
+ <div className="spacer-bottom" id="bulk-update-nothing">
{translateWithParameters('update_key.no_key_to_update', replace)}
</div>
)}
{hasDuplications && (
- <div id="bulk-update-duplicate" className="spacer-bottom">
+ <div className="spacer-bottom" id="bulk-update-duplicate">
{translateWithParameters('update_key.cant_update_because_duplicate_keys', replace, by)}
</div>
)}
)}
{!isEmpty && (
- <table id="bulk-update-results" className="data zebra zebra-hover">
+ <table className="data zebra zebra-hover" id="bulk-update-results">
<thead>
<tr>
<th>{translate('update_key.old_key')}</th>
</thead>
<tbody>
{results.map(result => (
- <tr key={result.key} data-key={result.key}>
+ <tr data-key={result.key} key={result.key}>
<td className="js-old-key">{result.key}</td>
<td className="js-new-key">
{result.duplicate && (
<div className="big-spacer-top">
{canUpdate && (
- <button id="bulk-update-confirm" onClick={this.handleConfirm.bind(this)}>
+ <Button id="bulk-update-confirm" onClick={this.props.onConfirm}>
{translate('update_verb')}
- </button>
+ </Button>
)}
</div>
</div>
import React from 'react';
import DateRangeInput from '../../../components/controls/DateRangeInput';
import { translate } from '../../../helpers/l10n';
+import { Button } from '../../../components/ui/buttons';
/*:: import type { RawQuery } from '../../../helpers/query'; */
/*::
onChange={this.handleChange}
value={{ from: this.props.from, to: this.props.to }}
/>
- <button
+ <Button
className="spacer-left"
- onClick={this.handleResetClick}
- disabled={this.props.from == null && this.props.to == null}>
+ disabled={this.props.from == null && this.props.to == null}
+ onClick={this.handleResetClick}>
{translate('project_activity.reset_dates')}
- </button>
+ </Button>
</div>
);
}
}
}
/>
- <button
+ <Button
className="spacer-left"
disabled={false}
onClick={[Function]}
>
project_activity.reset_dates
- </button>
+ </Button>
</div>
`;
import React from 'react';
import Modal from '../../../../components/controls/Modal';
import { translate } from '../../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
/*:: import type { Analysis } from '../../types'; */
/*::
<i className="spinner" />
) : (
<div>
- <button type="submit">{translate('save')}</button>
- <button className="button-link" onClick={this.props.onClose} type="reset">
+ <SubmitButton>{translate('save')}</SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</div>
)}
</footer>
import React from 'react';
import Modal from '../../../../components/controls/Modal';
import { translate } from '../../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
/*:: import type { Event } from '../../types'; */
/*::
<div className="modal-field">
<label>{translate('name')}</label>
<input
- value={this.state.name}
autoFocus={true}
disabled={this.state.processing}
- type="text"
onChange={this.changeInput}
+ type="text"
+ value={this.state.name}
/>
</div>
</div>
<i className="spinner" />
) : (
<div>
- <button type="submit">{translate('change_verb')}</button>
- <button type="reset" className="button-link" onClick={this.closeForm}>
- {translate('cancel')}
- </button>
+ <SubmitButton>{translate('change_verb')}</SubmitButton>
+ <ResetButtonLink onClick={this.closeForm}>{translate('cancel')}</ResetButtonLink>
</div>
)}
</footer>
import React from 'react';
import Modal from '../../../../components/controls/Modal';
import { translate } from '../../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
/*:: import type { Analysis } from '../../types'; */
/*::
<i className="spinner" />
) : (
<div>
- <button autoFocus={true} className="button-red" type="submit">
+ <SubmitButton autoFocus={true} className="button-red">
{translate('delete')}
- </button>
- <button className="button-link" onClick={this.props.onClose} type="reset">
+ </SubmitButton>
+ <ResetButtonLink onClick={this.props.onClose}>
{translate('cancel')}
- </button>
+ </ResetButtonLink>
</div>
)}
</footer>
import React from 'react';
import Modal from '../../../../components/controls/Modal';
import { translate } from '../../../../helpers/l10n';
+import { SubmitButton, ResetButtonLink } from '../../../../components/ui/buttons';
/*:: import type { Event } from '../../types'; */
/*::
<i className="spinner" />
) : (
<div>
- <button type="submit" className="button-red" autoFocus={true}>
+ <SubmitButton autoFocus={true} className="button-red">
{translate('delete')}
- </button>
- <button type="reset" className="button-link" onClick={this.closeForm}>
- {translate('cancel')}
- </button>
+ </SubmitButton>
+ <ResetButtonLink onClick={this.closeForm}>{translate('cancel')}</ResetButtonLink>
</div>
)}
</footer>
import Modal from '../../../components/controls/Modal';
import { isEmptyValue, getDefaultValue, getSettingValue } from '../utils';
import { translate } from '../../../helpers/l10n';
-import { Button } from '../../../components/ui/buttons';
+import { Button, ResetButtonLink, SubmitButton } from '../../../components/ui/buttons';
import { SettingValue, Definition } from '../../../api/settings';
type Props = {
<p>{translate('settings.reset_confirm.description')}</p>
</div>
<footer className="modal-foot">
- <button className="button-red">{translate('reset_verb')}</button>
- <button className="button-link" onClick={this.handleClose} type="reset">
- {translate('cancel')}
- </button>
+ <SubmitButton className="button-red">{translate('reset_verb')}</SubmitButton>
+ <ResetButtonLink onClick={this.handleClose}>{translate('cancel')}</ResetButtonLink>
</footer>
</form>
</Modal>
import { sendTestEmail } from '../../../api/settings';
import { parseError } from '../../../helpers/request';
import { getCurrentUser } from '../../../store/rootReducer';
+import { SubmitButton } from '../../../components/ui/buttons';
class EmailForm extends React.PureComponent {
constructor(props) {
};
}
- handleFormSubmit(e) {
- e.preventDefault();
+ handleFormSubmit = event => {
+ event.preventDefault();
this.setState({ success: false, error: null, loading: true });
const { recipient, subject, message } = this.state;
sendTestEmail(recipient, subject, message).then(
() => this.setState({ success: true, loading: false }),
error => parseError(error).then(message => this.setState({ error: message, loading: false }))
);
- }
+ };
render() {
return (
<div className="huge-spacer-top">
<h3 className="spacer-bottom">{translate('email_configuration.test.title')}</h3>
- <form style={{ marginLeft: 201 }} onSubmit={e => this.handleFormSubmit(e)}>
+ <form onSubmit={this.handleFormSubmit} style={{ marginLeft: 201 }}>
{this.state.success && (
<div className="modal-field">
<div className="alert alert-success">
</label>
<input
className="settings-large-input"
+ disabled={this.state.loading}
id="test-email-to"
- type="email"
+ onChange={e => this.setState({ recipient: e.target.value })}
required={true}
+ type="email"
value={this.state.recipient}
- disabled={this.state.loading}
- onChange={e => this.setState({ recipient: e.target.value })}
/>
</div>
<div className="modal-field">
</label>
<input
className="settings-large-input"
+ disabled={this.state.loading}
id="test-email-subject"
+ onChange={e => this.setState({ subject: e.target.value })}
type="text"
value={this.state.subject}
- disabled={this.state.loading}
- onChange={e => this.setState({ subject: e.target.value })}
/>
</div>
<div className="modal-field">
</label>
<textarea
className="settings-large-input"
+ disabled={this.state.loading}
id="test-email-title"
+ onChange={e => this.setState({ message: e.target.value })}
required={true}
rows="5"
value={this.state.message}
- disabled={this.state.loading}
- onChange={e => this.setState({ message: e.target.value })}
/>
</div>
<div className="modal-field">
{this.state.loading && <i className="spacer-right spinner" />}
- <button disabled={this.state.loading}>
+ <SubmitButton disabled={this.state.loading}>
{translate('email_configuration.test.send')}
- </button>
+ </SubmitButton>
</div>
</form>
</div>
import React from 'react';
import { translate } from '../../../../helpers/l10n';
import { defaultInputPropTypes } from '../../propTypes';
+import { Button } from '../../../../components/ui/buttons';
export default class InputForPassword extends React.PureComponent {
static propTypes = defaultInputPropTypes;
this.setState({ changing: true, value: e.target.value });
}
- handleChangeClick(e) {
- e.preventDefault();
- e.target.blur();
+ handleChangeClick = () => {
this.setState({ changing: true });
- }
+ };
renderInput() {
return (
return (
<div>
<i className="big-spacer-right icon-lock icon-gray" />
- <button onClick={e => this.handleChangeClick(e)}>{translate('change_verb')}</button>
+ <Button onClick={this.handleChangeClick}>{translate('change_verb')}</Button>
</div>
);
}
it('should render lock icon, but no form', () => {
const onChange = jest.fn();
const input = shallow(
- <InputForPassword name="foo" value="bar" isDefault={false} onChange={onChange} />
+ <InputForPassword isDefault={false} name="foo" onChange={onChange} value="bar" />
);
expect(input.find('.icon-lock').length).toBe(1);
expect(input.find('form').length).toBe(0);
it('should open form', () => {
const onChange = jest.fn();
const input = shallow(
- <InputForPassword name="foo" value="bar" isDefault={false} onChange={onChange} />
+ <InputForPassword isDefault={false} name="foo" onChange={onChange} value="bar" />
);
- const button = input.find('button');
+ const button = input.find('Button');
expect(button.length).toBe(1);
click(button);
it('should set value', () => {
const onChange = jest.fn(() => Promise.resolve());
const input = shallow(
- <InputForPassword name="foo" value="bar" isDefault={false} onChange={onChange} />
+ <InputForPassword isDefault={false} name="foo" onChange={onChange} value="bar" />
);
- click(input.find('button'));
+ click(input.find('Button'));
change(input.find('.js-password-input'), 'secret');
submit(input.find('form'));
expect(onChange).toBeCalledWith('secret');
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from '../../../helpers/l10n';
+import { SubmitButton } from '../../../components/ui/buttons';
export default class EncryptionForm extends React.PureComponent {
static propTypes = {
<div className="spacer-bottom">{translate('encryption.form_intro')}</div>
<form
- id="encryption-form"
className="big-spacer-bottom"
+ id="encryption-form"
onSubmit={e => this.handleEncrypt(e)}>
<textarea
autoFocus={true}
value={this.state.value}
/>
<div className="spacer-top">
- <button>{translate('encryption.encrypt')}</button>
+ <SubmitButton>{translate('encryption.encrypt')}</SubmitButton>
</div>
</form>
{translate('encryption.encrypted_value')}
{': '}
<input
- id="encrypted-value"
className="input-clear input-code input-super-large"
- type="text"
+ id="encrypted-value"
readOnly={true}
+ type="text"
value={this.props.encryptedValue}
/>
</div>
dangerouslySetInnerHTML={{ __html: translate('encryption.form_note') }}
/>
<form id="encryption-new-key-form" onSubmit={e => this.handleGenerateNewKey(e)}>
- <button>{translate('encryption.generate_new_secret_key')}</button>
+ <SubmitButton>{translate('encryption.generate_new_secret_key')}</SubmitButton>
</form>
</div>
</div>
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from '../../../helpers/l10n';
+import { SubmitButton } from '../../../components/ui/buttons';
export default class GenerateSecretKeyForm extends React.PureComponent {
static propTypes = {
generateSecretKey: PropTypes.func.isRequired
};
- handleSubmit(e) {
+ handleSubmit = e => {
e.preventDefault();
this.props.generateSecretKey();
- }
+ };
render() {
return (
<div className="big-spacer-bottom">
<h3 className="spacer-bottom">{translate('encryption.secret_key')}</h3>
<input
- id="secret-key"
className="input-large"
- type="text"
+ id="secret-key"
readOnly={true}
+ type="text"
value={this.props.secretKey}
/>
</div>
dangerouslySetInnerHTML={{ __html: translate('ecryption.secret_key_description') }}
/>
- <form id="generate-secret-key-form" onSubmit={e => this.handleSubmit(e)}>
- <button>{translate('encryption.generate_secret_key')}s</button>
+ <form id="generate-secret-key-form" onSubmit={this.handleSubmit}>
+ <SubmitButton>{translate('encryption.generate_secret_key')}</SubmitButton>
</form>
</div>
)}
getOrganization
} from '../../../api/organizations';
import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon';
-import { DeleteButton } from '../../../components/ui/buttons';
+import { DeleteButton, SubmitButton } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
/*::
{loading ? (
<i className="spinner text-middle" />
) : (
- <button className="text-middle" disabled={!valid} type="submit">
+ <SubmitButton className="text-middle" disabled={!valid}>
{translate('create')}
- </button>
+ </SubmitButton>
)}
{!unique && (
<span className="big-spacer-left text-danger text-middle">
// @flow
import React from 'react';
import { createProject, deleteProject } from '../../../api/components';
-import { DeleteButton } from '../../../components/ui/buttons';
+import { DeleteButton, SubmitButton } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
/*::
<input
autoFocus={true}
className="input-large spacer-right text-middle"
- minLength={1}
maxLength={400}
+ minLength={1}
onChange={this.handleProjectKeyChange}
required={true}
type="text"
{loading ? (
<i className="spinner text-middle" />
) : (
- <button className="text-middle" disabled={!valid}>
+ <SubmitButton className="text-middle" disabled={!valid}>
{translate('Done')}
- </button>
+ </SubmitButton>
)}
<div className="note spacer-top abs-width-300">
{translate('onboarding.project_key_requirement')}
import { getOrganizations } from '../../../api/organizations';
import Select from '../../../components/controls/Select';
import { translate } from '../../../helpers/l10n';
+import { Button } from '../../../components/ui/buttons';
/*::
type Props = {|
this.setState({ existingOrganization: value });
};
- handleContinueClick = (event /*: Event */) => {
- event.preventDefault();
+ handleContinueClick = () => {
const organization = this.getSelectedOrganization();
if (organization) {
this.props.onContinue(organization);
{this.getSelectedOrganization() != null &&
!this.state.loading && (
<div className="big-spacer-top">
- <button className="js-continue" onClick={this.handleContinueClick} type="button">
+ <Button className="js-continue" onClick={this.handleContinueClick}>
{translate('continue')}
- </button>
+ </Button>
</div>
)}
</div>
import { getTokens, generateToken, revokeToken } from '../../../api/user-tokens';
import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon';
import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon';
-import { DeleteButton } from '../../../components/ui/buttons';
+import { DeleteButton, SubmitButton, Button } from '../../../components/ui/buttons';
import { translate } from '../../../helpers/l10n';
/*::
}
};
- handleContinueClick = (event /*: Event */) => {
- event.preventDefault();
+ handleContinueClick = () => {
const token = this.getToken();
if (token) {
this.props.onContinue(token);
{this.state.loading ? (
<i className="spinner text-middle" />
) : (
- <button className="text-middle" disabled={!this.state.tokenName} type="submit">
+ <SubmitButton className="text-middle" disabled={!this.state.tokenName}>
{translate('onboarding.token.generate')}
- </button>
+ </SubmitButton>
)}
</form>
</div>
{this.canContinue() && (
<div className="big-spacer-top">
- <button className="js-continue" onClick={this.handleContinueClick} type="button">
+ <Button className="js-continue" onClick={this.handleContinueClick}>
{translate('continue')}
- </button>
+ </Button>
</div>
)}
</div>
.first()
.prop('onChange')({ value: 'another' });
wrapper.update();
- click(wrapper.find('.js-continue'));
+ click(wrapper.find('[className="js-continue"]'));
expect(onContinue).toBeCalledWith('another');
});
click(wrapper.find('.js-new'));
wrapper.find('NewOrganizationForm').prop('onDone')('new');
wrapper.update();
- click(wrapper.find('.js-continue'));
+ click(wrapper.find('[className="js-continue"]'));
expect(onContinue).toBeCalledWith('new');
});
<TokenStep
currentUser={currentUser}
finished={false}
- open={true}
onContinue={jest.fn()}
onOpen={jest.fn()}
+ open={true}
stepNumber={1}
/>
);
<TokenStep
currentUser={currentUser}
finished={false}
- open={true}
onContinue={jest.fn()}
onOpen={jest.fn()}
+ open={true}
stepNumber={1}
/>
);
<TokenStep
currentUser={currentUser}
finished={false}
- open={true}
onContinue={onContinue}
onOpen={jest.fn()}
+ open={true}
stepNumber={1}
/>
);
await new Promise(setImmediate);
wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
- click(wrapper.find('.js-continue'));
+ click(wrapper.find('[className="js-continue"]'));
expect(onContinue).toBeCalledWith('abcd1234');
});
<TokenStep
currentUser={currentUser}
finished={false}
- open={true}
onContinue={onContinue}
onOpen={jest.fn()}
+ open={true}
stepNumber={1}
/>
);
await new Promise(setImmediate);
wrapper.setState({ existingToken: 'abcd1234', selection: 'use-existing' });
- click(wrapper.find('.js-continue'));
+ click(wrapper.find('[className="js-continue"]'));
expect(onContinue).toBeCalledWith('abcd1234');
});
type="text"
value=""
/>
- <button
+ <SubmitButton
className="text-middle"
disabled={true}
- type="submit"
>
- create
- </button>
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ create
+ </button>
+ </Button>
+ </SubmitButton>
<div
className="note spacer-top abs-width-300"
>
type="text"
value=""
/>
- <button
+ <SubmitButton
className="text-middle"
disabled={true}
- type="submit"
>
- create
- </button>
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ create
+ </button>
+ </Button>
+ </SubmitButton>
<div
className="note spacer-top abs-width-300"
>
type="text"
value=""
/>
- <button
+ <SubmitButton
className="text-middle"
disabled={true}
>
- Done
- </button>
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ Done
+ </button>
+ </Button>
+ </SubmitButton>
<div
className="note spacer-top abs-width-300"
>
type="text"
value=""
/>
- <button
+ <SubmitButton
className="text-middle"
disabled={true}
>
- Done
- </button>
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ Done
+ </button>
+ </Button>
+ </SubmitButton>
<div
className="note spacer-top abs-width-300"
>
type="text"
value=""
/>
- <button
+ <SubmitButton
className="text-middle"
disabled={true}
- type="submit"
>
- onboarding.token.generate
- </button>
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ onboarding.token.generate
+ </button>
+ </Button>
+ </SubmitButton>
</form>
</div>
</div>
<div
className="big-spacer-top"
>
- <button
+ <Button
className="js-continue"
onClick={[Function]}
- type="button"
>
- continue
- </button>
+ <button
+ className="button js-continue"
+ onClick={[Function]}
+ type="button"
+ >
+ continue
+ </button>
+ </Button>
</div>
</div>
</div>
<div
className="big-spacer-top"
>
- <button
+ <Button
className="js-continue"
onClick={[Function]}
- type="button"
>
- continue
- </button>
+ <button
+ className="button js-continue"
+ onClick={[Function]}
+ type="button"
+ >
+ continue
+ </button>
+ </Button>
</div>
</div>
</div>
<div
className="big-spacer-top"
>
- <button
+ <Button
className="js-continue"
onClick={[Function]}
- type="button"
>
- continue
- </button>
+ <button
+ className="button js-continue"
+ onClick={[Function]}
+ type="button"
+ >
+ continue
+ </button>
+ </Button>
</div>
</div>
</div>
type="text"
value=""
/>
- <button
+ <SubmitButton
className="text-middle"
disabled={true}
- type="submit"
>
- onboarding.token.generate
- </button>
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ onboarding.token.generate
+ </button>
+ </Button>
+ </SubmitButton>
</form>
</div>
</div>
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { ERROR, SUCCESS } from '../../store/globalMessages/duck';
+import { Button } from '../ui/buttons';
export default class GlobalMessages extends React.PureComponent {
static propTypes = {
'process-spinner-success': message.level === SUCCESS
});
return (
- <div key={message.id} className={className}>
+ <div className={className} key={message.id}>
{message.message}
- <button
+ <Button
className="process-spinner-close"
- type="button"
onClick={() => this.props.closeGlobalMessage(message.id)}>
<i className="icon-close" />
- </button>
+ </Button>
</div>
);
};
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
+import { Button } from '../ui/buttons';
import './styles.css';
export default class Toggle extends React.PureComponent {
onChange: PropTypes.func
};
- handleClick(e, value) {
- e.preventDefault();
- e.currentTarget.blur();
+ handleClick = value => {
if (this.props.onChange) {
this.props.onChange(!value);
}
- }
+ };
render() {
const { value } = this.props;
const className = classNames('boolean-toggle', { 'boolean-toggle-on': booleanValue });
return (
- <button
+ <Button
className={className}
name={this.props.name}
- onClick={e => this.handleClick(e, booleanValue)}>
+ onClick={() => this.handleClick(booleanValue)}>
<div className="boolean-toggle-handle" />
- </button>
+ </Button>
);
}
}
import { click } from '../../../helpers/testUtils';
function getSample(props) {
- return <Toggle value={true} onChange={() => true} {...props} />;
+ return <Toggle onChange={() => true} value={true} {...props} />;
}
it('should render', () => {
const Toggle = shallow(getSample());
- expect(Toggle.is('button')).toBe(true);
+ expect(Toggle.is('Button')).toBe(true);
});
it('should call onChange', () => {
width: 70px;
}
-.boolean-toggle {
+.button.boolean-toggle {
display: inline-block;
vertical-align: middle;
width: 48px;
transition: all 0.3s ease;
}
-.boolean-toggle:hover {
+.button.boolean-toggle:hover {
background-color: #fff;
}
-.boolean-toggle:focus {
+.button.boolean-toggle:focus {
border-color: var(--blue);
background-color: #f6f6f6;
}
transition: transform 0.3s cubic-bezier(0.87, -0.41, 0.19, 1.44), border 0.3s ease;
}
-.boolean-toggle-on {
+.button.boolean-toggle-on {
border-color: var(--darkBlue);
background-color: var(--darkBlue);
}
-.boolean-toggle-on:hover {
+.button.boolean-toggle-on:hover {
background-color: var(--darkBlue);
}
-.boolean-toggle-on:focus {
+.button.boolean-toggle-on:focus {
background-color: var(--darkBlue);
}
-.boolean-toggle-on .boolean-toggle-handle {
+.button.boolean-toggle-on .boolean-toggle-handle {
border-color: #f6f6f6;
transform: translateX(var(--controlHeight));
}
import PropTypes from 'prop-types';
import Tooltip from '../../controls/Tooltip';
import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { Button } from '../../ui/buttons';
export default class IssueMessage extends React.PureComponent {
/*:: props: {
workspace: PropTypes.object.isRequired
};
- handleClick = (e /*: MouseEvent */) => {
- e.preventDefault();
+ handleClick = () => {
this.context.workspace.openRule({
key: this.props.rule,
organization: this.props.organization
return (
<div className="issue-message">
{this.props.message}
- <button
- className="button-link issue-rule icon-ellipsis-h little-spacer-left"
+ <Button
aria-label={translate('issue.rule_details')}
+ className="button-link issue-rule icon-ellipsis-h little-spacer-left"
onClick={this.handleClick}
/>
{this.props.engine && (
className="issue-message"
>
Reduce the number of conditional operators (4) used in the expression
- <button
+ <Button
aria-label="issue.rule_details"
className="button-link issue-rule icon-ellipsis-h little-spacer-left"
onClick={[Function]}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+.button {
+ display: inline-block;
+ vertical-align: baseline;
+ height: var(--controlHeight);
+ line-height: calc(var(--controlHeight) - 2px);
+ padding: 0 12px;
+ border: 1px solid var(--darkBlue);
+ border-radius: 2px;
+ box-sizing: border-box;
+ background: transparent;
+ color: var(--darkBlue);
+ font-weight: 600;
+ font-size: var(--smallFontSize);
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ outline: none;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+}
+
+.button:hover,
+.button.button-active {
+ background: var(--darkBlue);
+ color: #fff;
+}
+
+.button:active {
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+
+.button:focus {
+ box-shadow: 0 0 0 3px rgba(35, 106, 151, 0.25);
+}
+
+.button.disabled,
+.button:disabled,
+.button:disabled:hover,
+.button:disabled:active,
+.button:disabled:focus {
+ color: var(--disableGrayText) !important;
+ border-color: var(--disableGrayBorder) !important;
+ background: var(--disableGrayBg) !important;
+ cursor: not-allowed !important;
+ box-shadow: none !important;
+}
+
+.button svg {
+ margin-top: calc((var(--controlHeight) - 16px - 2px) / 2);
+}
+
+/* #region .button-red */
+.button-red {
+ border-color: var(--red);
+ color: var(--red);
+}
+
+.button-red:hover,
+.button-red.active {
+ background: var(--red);
+ color: #fff;
+}
-/* use double selector .button-icon.button-icon to increase the specificity */
+.button-red:focus {
+ box-shadow: 0 0 0 3px rgba(212, 51, 63, 0.25);
+}
+/* #endregion */
+
+/* #region .button-success */
+.button-success {
+ border-color: var(--green);
+ color: var(--green);
+}
+
+.button-success:hover,
+.button-success.active {
+ background: var(--green);
+ color: #fff;
+}
+
+.button-success:focus {
+ box-shadow: 0 0 0 3px rgba(0, 170, 0, 0.25);
+}
+/* #endregion */
+
+/* #region .button-grey */
+.button-grey {
+ border-color: var(--gray71);
+ color: var(--secondFontColor);
+}
+
+.button-grey:hover,
+.button-grey.active {
+ background: var(--gray71);
+ color: #ffffff;
+}
+
+.button-grey:focus {
+ box-shadow: 0 0 0 3px rgba(180, 180, 180, 0.25);
+}
+/* #endregion */
+
+/* #region .button-link */
+.button-link {
+ display: inline;
+ height: auto; /* Keep this to not inherit the height from .button */
+ margin: 0;
+ padding: 0;
+ border: none;
+ background: transparent;
+ color: var(--darkBlue);
+ font-weight: 400;
+ font-size: inherit;
+ line-height: inherit;
+ transition: all 0.2s ease;
+}
+
+.button-link svg {
+ margin-top: 0;
+}
+
+.button-link:hover {
+ background: transparent;
+ color: var(--blue);
+}
+
+.button-link:active {
+ box-shadow: none;
+ outline: thin dotted #ccc;
+}
+
+.button-link:disabled,
+.button-link:disabled:hover,
+.button-link:disabled:active,
+.button-link:disabled:focus {
+ color: var(--secondFontColor);
+ background: transparent !important;
+ cursor: default;
+}
+/* #endregion */
+
+.button-small {
+ height: var(--smallControlHeight);
+ line-height: 18px;
+ padding: 0 6px;
+ font-size: 11px;
+}
+
+.button-small > svg {
+ margin-top: 2px;
+}
+
+/* #region .button-group */
+.button-group {
+ display: inline-block;
+ vertical-align: middle;
+ font-size: 0;
+ white-space: nowrap;
+}
+
+.button-group > button,
+.button-group > .button {
+ position: relative;
+ z-index: var(--normalZIndex);
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0;
+ cursor: pointer;
+}
+
+.button-group > .button:hover:not(:disabled),
+.button-group > .button:focus:not(:disabled),
+.button-group > .button:active:not(:disabled),
+.button-group > .button.active:not(:disabled) {
+ z-index: var(--aboveNormalZIndex);
+}
+
+.button-group > .button:disabled {
+ z-index: var(--belowNormalZIndex);
+}
+
+.button-group > .button:not(:first-child) {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.button-group > .button:not(:last-child):not(.dropdown-toggle) {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.button-group > .button + .button {
+ margin-left: -1px;
+}
+
+.button-group > a:not(.button) {
+ vertical-align: middle;
+ margin: 0 8px;
+ font-size: var(--smallFontSize);
+}
+/* #endregion */
-.button-icon.button-icon {
+/* #region .button-icon */
+.button-icon {
display: inline-flex;
justify-content: center;
align-items: center;
color: inherit;
}
-.button-icon.button-icon.button-small {
+.button-icon.button-small {
width: var(--smallControlHeight);
height: var(--smallControlHeight);
padding: 0;
}
-.button-icon.button-icon.button-small svg {
+.button-icon.button-small svg {
margin-top: 0;
}
-.button-icon.button-icon.button-tiny {
+.button-icon.button-tiny {
width: var(--tinyControlHeight);
height: var(--tinyControlHeight);
padding: 0;
}
-.button-icon.button-icon.button-tiny svg {
+.button-icon.button-tiny svg {
margin-top: 0;
}
-.button-icon.button-icon:hover,
-.button-icon.button-icon:focus {
+.button-icon:hover,
+.button-icon:focus {
background-color: currentColor;
}
-.button-icon.button-icon:hover svg,
-.button-icon.button-icon:focus svg {
+.button-icon:hover svg,
+.button-icon:focus svg {
color: #fff;
}
+/* #endregion */