diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2019-07-11 15:15:35 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-07-11 20:21:09 +0200 |
commit | 60226e8e297485bcbe384dc766930da0a5a1c079 (patch) | |
tree | 84140c9f6d8d0828dbe4db676f8a06a5d6b4b077 /server/sonar-web/src/main/js/components/controls | |
parent | 7ae6f6f0968febebf763cf073b09cb6dd2b218d7 (diff) | |
download | sonarqube-60226e8e297485bcbe384dc766930da0a5a1c079.tar.gz sonarqube-60226e8e297485bcbe384dc766930da0a5a1c079.zip |
SC-704 Extract components into sonar-ui-common (#1714)
* SC-704 Extract icons components to sonar-ui-common
* Better typings for theme
* Use sonar-ui-common in extensions
* Extract some helpers
* Extract l10n helper to sonar-ui-common
* Extract requests helper to sonar-ui-common
* Extract part of urls helper
* Move buttons, Tooltips and ScreenPositionFixers
* Move modal related components
* Move IdentityProviderLink
* Move GenericAvatar
* Move SizeRating
* Move charts and move deps to peerDeps
* Move nav
* Move formatMeasure
* Move Rating
* Move PageActions
* Move the rest of ui components
* Move more controls components
* Include theme inside extension build
* Add missing theme context provider in extensions
* Update react to same version everywhere
* Update sonar-ui-common
* Update eslint configuration
Diffstat (limited to 'server/sonar-web/src/main/js/components/controls')
86 files changed, 33 insertions, 5467 deletions
diff --git a/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx b/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx deleted file mode 100644 index f8cca23cd06..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ActionsDropdown.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import { Link } from 'react-router'; -import { LocationDescriptor } from 'history'; -import Dropdown from './Dropdown'; -import DropdownIcon from '../icons-components/DropdownIcon'; -import SettingsIcon from '../icons-components/SettingsIcon'; -import { Button } from '../ui/buttons'; - -interface Props { - className?: string; - children: React.ReactNode; - onOpen?: () => void; - small?: boolean; - toggleClassName?: string; -} - -export default function ActionsDropdown(props: Props) { - return ( - <Dropdown - className={props.className} - onOpen={props.onOpen} - overlay={<ul className="menu">{props.children}</ul>}> - <Button - className={classNames('dropdown-toggle', props.toggleClassName, { - 'button-small': props.small - })}> - <SettingsIcon size={props.small ? 12 : 14} /> - <DropdownIcon className="little-spacer-left" /> - </Button> - </Dropdown> - ); -} - -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" />; -} diff --git a/server/sonar-web/src/main/js/components/controls/BackButton.tsx b/server/sonar-web/src/main/js/components/controls/BackButton.tsx deleted file mode 100644 index 37b20a214f5..00000000000 --- a/server/sonar-web/src/main/js/components/controls/BackButton.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import Tooltip from './Tooltip'; -import * as theme from '../../app/theme'; -import { translate } from '../../helpers/l10n'; - -interface Props { - className?: string; - disabled?: boolean; - onClick: () => void; - tooltip?: string; -} - -export default class BackButton extends React.PureComponent<Props> { - handleClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - if (!this.props.disabled) { - this.props.onClick(); - } - }; - - renderIcon = () => ( - <svg height="24" viewBox="0 0 21 24" width="21"> - <path - d="M3.845 12.9992l5.993 5.993.052.056c.049.061.093.122.129.191.082.159.121.339.111.518-.006.102-.028.203-.064.298-.149.39-.537.652-.954.644-.102-.002-.204-.019-.301-.052-.148-.05-.273-.135-.387-.241l-8.407-8.407 8.407-8.407.056-.052c.061-.048.121-.092.19-.128.116-.06.237-.091.366-.108.076-.004.075-.004.153-.003.155.015.3.052.437.129.088.051.169.115.239.19.246.266.33.656.214.999-.051.149-.135.273-.241.387l-5.983 5.984c5.287-.044 10.577-.206 15.859.013.073.009.091.009.163.027.187.047.359.15.49.292.075.081.136.175.18.276.044.101.072.209.081.319.032.391-.175.775-.521.962-.097.052-.202.089-.311.107-.073.012-.091.01-.165.013H3.845z" - fill={this.props.disabled ? theme.disableGrayText : theme.secondFontColor} - /> - </svg> - ); - - render() { - const { tooltip = translate('issues.return_to_list') } = this.props; - return ( - <Tooltip overlay={tooltip}> - <a - className={classNames( - 'link-no-underline', - { 'cursor-not-allowed': this.props.disabled }, - this.props.className - )} - href="#" - onClick={this.handleClick}> - {this.renderIcon()} - </a> - </Tooltip> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/BoxedGroupAccordion.tsx b/server/sonar-web/src/main/js/components/controls/BoxedGroupAccordion.tsx index e3a5507b7da..8e1a4cd99ad 100644 --- a/server/sonar-web/src/main/js/components/controls/BoxedGroupAccordion.tsx +++ b/server/sonar-web/src/main/js/components/controls/BoxedGroupAccordion.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import * as classNames from 'classnames'; -import OpenCloseIcon from '../icons-components/OpenCloseIcon'; +import OpenCloseIcon from 'sonar-ui-common/components/icons/OpenCloseIcon'; interface Props { children: React.ReactNode; diff --git a/server/sonar-web/src/main/js/components/controls/Checkbox.tsx b/server/sonar-web/src/main/js/components/controls/Checkbox.tsx deleted file mode 100644 index b73e3003d3b..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Checkbox.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import DeferredSpinner from '../common/DeferredSpinner'; - -interface Props { - checked: boolean; - disabled?: boolean; - children?: React.ReactNode; - className?: string; - id?: string; - loading?: boolean; - onCheck: (checked: boolean, id?: string) => void; - right?: boolean; - thirdState?: boolean; - title?: string; -} - -export default class Checkbox extends React.PureComponent<Props> { - static defaultProps = { - thirdState: false - }; - - handleClick = (event: React.SyntheticEvent<HTMLElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - if (!this.props.disabled) { - this.props.onCheck(!this.props.checked, this.props.id); - } - }; - - render() { - const { checked, children, disabled, id, loading, right, thirdState, title } = this.props; - const className = classNames('icon-checkbox', { - 'icon-checkbox-checked': checked, - 'icon-checkbox-single': thirdState, - 'icon-checkbox-disabled': disabled - }); - - if (children) { - return ( - <a - aria-checked={checked} - className={classNames('link-checkbox', this.props.className, { - note: disabled, - disabled - })} - href="#" - id={id} - onClick={this.handleClick} - role="checkbox" - title={title}> - {right && children} - <DeferredSpinner loading={Boolean(loading)}> - <i className={className} /> - </DeferredSpinner> - {!right && children} - </a> - ); - } - - if (loading) { - return <DeferredSpinner />; - } - - return ( - <a - aria-checked={checked} - className={classNames(className, this.props.className)} - href="#" - id={id} - onClick={this.handleClick} - role="checkbox" - title={title} - /> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx b/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx deleted file mode 100644 index 474d8d8c516..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ClipboardButton.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import * as Clipboard from 'clipboard'; -import Tooltip from './Tooltip'; -import { Button } from '../ui/buttons'; -import { translate } from '../../helpers/l10n'; - -interface Props { - className?: string; - copyValue: string; - label?: string; -} - -interface State { - tooltipShown: boolean; -} - -export default class ClipboardButton extends React.PureComponent<Props, State> { - clipboard?: Clipboard; - copyButton?: HTMLElement | null; - mounted = false; - state: State = { tooltipShown: false }; - - componentDidMount() { - this.mounted = true; - if (this.copyButton) { - this.clipboard = new Clipboard(this.copyButton); - this.clipboard.on('success', this.showTooltip); - } - } - - componentDidUpdate() { - if (this.clipboard) { - this.clipboard.destroy(); - } - if (this.copyButton) { - this.clipboard = new Clipboard(this.copyButton); - this.clipboard.on('success', this.showTooltip); - } - } - - componentWillUnmount() { - this.mounted = false; - if (this.clipboard) { - this.clipboard.destroy(); - } - } - - showTooltip = () => { - if (this.mounted) { - this.setState({ tooltipShown: true }); - setTimeout(() => { - if (this.mounted) { - this.setState({ tooltipShown: false }); - } - }, 1000); - } - }; - - render() { - return ( - <Tooltip overlay={translate('copied_action')} visible={this.state.tooltipShown}> - <Button - className={classNames('no-select', this.props.className)} - data-clipboard-text={this.props.copyValue} - innerRef={node => (this.copyButton = node)}> - {this.props.label ? this.props.label : translate('copy')} - </Button> - </Tooltip> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx b/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx deleted file mode 100644 index 984ff40dc6a..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ConfirmButton.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import ConfirmModal, { ConfirmModalProps } from './ConfirmModal'; -import ModalButton, { ChildrenProps, ModalProps } from './ModalButton'; - -interface Props<T> extends ConfirmModalProps<T> { - children: (props: ChildrenProps) => React.ReactNode; - modalBody: React.ReactNode; - modalHeader: string; - modalHeaderDescription?: React.ReactNode; -} - -interface State { - modal: boolean; -} - -export default class ConfirmButton<T> extends React.PureComponent<Props<T>, State> { - renderConfirmModal = ({ onClose }: ModalProps) => { - const { - children, - modalBody, - modalHeader, - modalHeaderDescription, - ...confirmModalProps - } = this.props; - return ( - <ConfirmModal - header={modalHeader} - headerDescription={modalHeaderDescription} - onClose={onClose} - {...confirmModalProps}> - {modalBody} - </ConfirmModal> - ); - }; - - render() { - return <ModalButton modal={this.renderConfirmModal}>{this.props.children}</ModalButton>; - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx b/server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx deleted file mode 100644 index 2b018709630..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ConfirmModal.tsx +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { ModalProps } from './Modal'; -import SimpleModal, { ChildrenProps } from './SimpleModal'; -import DeferredSpinner from '../common/DeferredSpinner'; -import { SubmitButton, ResetButtonLink } from '../ui/buttons'; -import { translate } from '../../helpers/l10n'; - -export interface ConfirmModalProps<T> extends ModalProps { - cancelButtonText?: string; - confirmButtonText: string; - confirmData?: T; - confirmDisable?: boolean; - isDestructive?: boolean; - onConfirm: (data?: T) => void | Promise<void | Response>; -} - -interface Props<T> extends ConfirmModalProps<T> { - header: string; - headerDescription?: React.ReactNode; - onClose: () => void; -} - -export default class ConfirmModal<T = string> extends React.PureComponent<Props<T>> { - mounted = false; - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - handleSubmit = () => { - const result = this.props.onConfirm(this.props.confirmData); - if (result) { - return result.then(this.props.onClose, () => {}); - } else { - this.props.onClose(); - return undefined; - } - }; - - renderModalContent = ({ onCloseClick, onFormSubmit, submitting }: ChildrenProps) => { - const { - children, - confirmButtonText, - confirmDisable, - header, - headerDescription, - isDestructive, - cancelButtonText = translate('cancel') - } = this.props; - return ( - <form onSubmit={onFormSubmit}> - <header className="modal-head"> - <h2>{header}</h2> - {headerDescription} - </header> - <div className="modal-body">{children}</div> - <footer className="modal-foot"> - <DeferredSpinner className="spacer-right" loading={submitting} /> - <SubmitButton - autoFocus={true} - className={isDestructive ? 'button-red' : undefined} - disabled={submitting || confirmDisable}> - {confirmButtonText} - </SubmitButton> - <ResetButtonLink disabled={submitting} onClick={onCloseClick}> - {cancelButtonText} - </ResetButtonLink> - </footer> - </form> - ); - }; - - render() { - const { header, onClose, noBackdrop, size } = this.props; - const modalProps = { header, onClose, noBackdrop, size }; - return ( - <SimpleModal onSubmit={this.handleSubmit} {...modalProps}> - {this.renderModalContent} - </SimpleModal> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/DateInput.tsx b/server/sonar-web/src/main/js/components/controls/DateInput.tsx index f7155206822..dcb777c8573 100644 --- a/server/sonar-web/src/main/js/components/controls/DateInput.tsx +++ b/server/sonar-web/src/main/js/components/controls/DateInput.tsx @@ -19,6 +19,9 @@ */ import * as React from 'react'; import * as classNames from 'classnames'; +import CalendarIcon from 'sonar-ui-common/components/icons/CalendarIcon'; +import ChevronLeftIcon from 'sonar-ui-common/components/icons/ChevronLeftIcon'; +import ChevronRightIcon from 'sonar-ui-common/components/icons/ChevronRightIcon'; import { DayModifiers, Modifier, Modifiers } from 'react-day-picker'; import { InjectedIntlProps, injectIntl } from 'react-intl'; import { range } from 'lodash'; @@ -26,14 +29,15 @@ import * as addMonths from 'date-fns/add_months'; import * as setMonth from 'date-fns/set_month'; import * as setYear from 'date-fns/set_year'; import * as subMonths from 'date-fns/sub_months'; -import OutsideClickHandler from './OutsideClickHandler'; +import { + getShortMonthName, + getWeekDayName, + getShortWeekDayName +} from 'sonar-ui-common/helpers/l10n'; +import { ButtonIcon, ClearButton } from 'sonar-ui-common/components/controls/buttons'; +import OutsideClickHandler from 'sonar-ui-common/components/controls/OutsideClickHandler'; +import { lazyLoad } from 'sonar-ui-common/components/lazyLoad'; import Select from './Select'; -import { lazyLoad } from '../lazyLoad'; -import CalendarIcon from '../icons-components/CalendarIcon'; -import ChevronLeftIcon from '../icons-components/ChevronLeftIcon'; -import ChevronRightIcon from '../icons-components/ChevronRightcon'; -import { ButtonIcon, ClearButton } from '../ui/buttons'; -import { getShortMonthName, getWeekDayName, getShortWeekDayName } from '../../helpers/l10n'; import './DayPicker.css'; import './styles.css'; diff --git a/server/sonar-web/src/main/js/components/controls/DateRangeInput.tsx b/server/sonar-web/src/main/js/components/controls/DateRangeInput.tsx index d16903836a7..1cc3a2ee2a6 100644 --- a/server/sonar-web/src/main/js/components/controls/DateRangeInput.tsx +++ b/server/sonar-web/src/main/js/components/controls/DateRangeInput.tsx @@ -19,8 +19,8 @@ */ import * as React from 'react'; import * as classNames from 'classnames'; +import { translate } from 'sonar-ui-common/helpers/l10n'; import DateInput from './DateInput'; -import { translate } from '../../helpers/l10n'; type DateRange = { from?: Date; to?: Date }; diff --git a/server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx b/server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx deleted file mode 100644 index 83543fd6b32..00000000000 --- a/server/sonar-web/src/main/js/components/controls/DocumentClickHandler.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; - -interface Props { - children: React.ReactNode; - onClick: () => void; -} - -export default class DocumentClickHandler extends React.Component<Props> { - componentDidMount() { - setTimeout(() => { - this.addClickHandler(); - }, 0); - } - - componentWillUnmount() { - this.removeClickHandler(); - } - - addClickHandler = () => { - document.addEventListener('click', this.handleDocumentClick); - }; - - removeClickHandler = () => { - document.removeEventListener('click', this.handleDocumentClick); - }; - - handleDocumentClick = () => { - this.props.onClick(); - }; - - render() { - return this.props.children; - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Dropdown.tsx b/server/sonar-web/src/main/js/components/controls/Dropdown.tsx deleted file mode 100644 index 56e583e71cb..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Dropdown.tsx +++ /dev/null @@ -1,159 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import ScreenPositionFixer from './ScreenPositionFixer'; -import Toggler from './Toggler'; -import { Popup, PopupPlacement } from '../ui/popups'; - -interface OnClickCallback { - (event?: React.SyntheticEvent<HTMLElement>): void; -} - -interface RenderProps { - closeDropdown: () => void; - onToggleClick: OnClickCallback; - open: boolean; -} - -interface Props { - children: - | ((renderProps: RenderProps) => JSX.Element) - | React.ReactElement<{ onClick: OnClickCallback }>; - className?: string; - closeOnClick?: boolean; - closeOnClickOutside?: boolean; - onOpen?: () => void; - overlay: React.ReactNode; - overlayPlacement?: PopupPlacement; - noOverlayPadding?: boolean; - tagName?: string; -} - -interface State { - open: boolean; -} - -export default class Dropdown extends React.PureComponent<Props, State> { - state: State = { open: false }; - - componentDidUpdate(_: Props, prevState: State) { - if (!prevState.open && this.state.open && this.props.onOpen) { - this.props.onOpen(); - } - } - - closeDropdown = () => this.setState({ open: false }); - - handleToggleClick = (event?: React.SyntheticEvent<HTMLElement>) => { - if (event) { - event.preventDefault(); - event.currentTarget.blur(); - } - this.setState(state => ({ open: !state.open })); - }; - - render() { - const a11yAttrs = { - 'aria-expanded': String(this.state.open), - 'aria-haspopup': 'true' - }; - - const child = React.isValidElement(this.props.children) - ? React.cloneElement(this.props.children, { onClick: this.handleToggleClick, ...a11yAttrs }) - : this.props.children({ - closeDropdown: this.closeDropdown, - onToggleClick: this.handleToggleClick, - open: this.state.open - }); - - const { closeOnClick = true, closeOnClickOutside = false } = this.props; - - const toggler = ( - <Toggler - closeOnClick={closeOnClick} - closeOnClickOutside={closeOnClickOutside} - onRequestClose={this.closeDropdown} - open={this.state.open} - overlay={ - <DropdownOverlay - noPadding={this.props.noOverlayPadding} - placement={this.props.overlayPlacement}> - {this.props.overlay} - </DropdownOverlay> - }> - {child} - </Toggler> - ); - - return React.createElement( - this.props.tagName || 'div', - { className: classNames('dropdown', this.props.className) }, - toggler - ); - } -} - -interface OverlayProps { - className?: string; - children: React.ReactNode; - noPadding?: boolean; - placement?: PopupPlacement; -} - -// TODO use the same styling for <Select /> -// TODO use the same styling for <DateInput /> - -export class DropdownOverlay extends React.Component<OverlayProps> { - get placement() { - return this.props.placement || PopupPlacement.Bottom; - } - - renderPopup = (leftFix?: number, topFix?: number) => ( - <Popup - arrowStyle={ - leftFix !== undefined && topFix !== undefined - ? { transform: `translate(${-leftFix}px, ${-topFix}px)` } - : undefined - } - className={this.props.className} - noPadding={this.props.noPadding} - placement={this.placement} - style={ - leftFix !== undefined && topFix !== undefined - ? { marginLeft: `calc(50% + ${leftFix}px)` } - : undefined - }> - {this.props.children} - </Popup> - ); - - render() { - if (this.placement === PopupPlacement.Bottom) { - return ( - <ScreenPositionFixer> - {({ leftFix, topFix }) => this.renderPopup(leftFix, topFix)} - </ScreenPositionFixer> - ); - } else { - return this.renderPopup(); - } - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Favorite.tsx b/server/sonar-web/src/main/js/components/controls/Favorite.tsx index 59e3028ac15..a75341bbe11 100644 --- a/server/sonar-web/src/main/js/components/controls/Favorite.tsx +++ b/server/sonar-web/src/main/js/components/controls/Favorite.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import FavoriteBase from './FavoriteBase'; +import FavoriteBase from 'sonar-ui-common/components/controls/FavoriteBase'; import { addFavorite, removeFavorite } from '../../api/favorites'; interface Props { diff --git a/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx b/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx deleted file mode 100644 index 45a812d5425..00000000000 --- a/server/sonar-web/src/main/js/components/controls/FavoriteBase.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import Tooltip from './Tooltip'; -import { ButtonLink } from '../ui/buttons'; -import FavoriteIcon from '../icons-components/FavoriteIcon'; -import { translate } from '../../helpers/l10n'; - -export interface Props { - addFavorite: () => Promise<void>; - className?: string; - favorite: boolean; - qualifier: string; - removeFavorite: () => Promise<void>; -} - -interface State { - favorite: boolean; -} - -export default class FavoriteBase extends React.PureComponent<Props, State> { - mounted = false; - - constructor(props: Props) { - super(props); - this.state = { favorite: this.props.favorite }; - } - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - toggleFavorite = () => { - if (this.state.favorite) { - this.removeFavorite(); - } else { - this.addFavorite(); - } - }; - - addFavorite() { - this.props.addFavorite().then( - () => { - if (this.mounted) { - this.setState({ favorite: true }); - } - }, - () => {} - ); - } - - removeFavorite() { - this.props.removeFavorite().then( - () => { - if (this.mounted) { - this.setState({ favorite: false }); - } - }, - () => {} - ); - } - - render() { - const { favorite } = this.state; - const tooltip = favorite - ? translate('favorite.current', this.props.qualifier) - : translate('favorite.check', this.props.qualifier); - const ariaLabel = translate('favorite.action', favorite ? 'remove' : 'add'); - return ( - <Tooltip overlay={tooltip}> - <ButtonLink - aria-label={ariaLabel} - className={classNames('favorite-link', 'link-no-underline', this.props.className)} - onClick={this.toggleFavorite}> - <FavoriteIcon favorite={favorite} /> - </ButtonLink> - </Tooltip> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/GlobalMessages.css b/server/sonar-web/src/main/js/components/controls/GlobalMessages.css deleted file mode 100644 index e7425fc2713..00000000000 --- a/server/sonar-web/src/main/js/components/controls/GlobalMessages.css +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.processes-container { - position: fixed; - z-index: var(--processContainerZIndex); - top: 0; - left: 50%; - width: 350px; - margin-left: -175px; -} - -.process-spinner { - position: relative; - padding: 0 10px; - line-height: var(--controlHeight); - border-radius: 0 0 3px 3px; - box-sizing: border-box; - background-color: #f0e8ac; - text-align: center; - opacity: 0; - transition: all 0.2s ease; -} - -.process-spinner.shown { - opacity: 1; -} - -.process-spinner + .process-spinner { - margin-top: 5px; - border-radius: 3px; -} - -.process-spinner-failed { - padding-right: 30px; - background-color: var(--red); - color: #ffffff; -} - -.process-spinner-success { - padding-right: 30px; - background-color: var(--green); - color: #ffffff; -} - -.process-spinner-close { - position: absolute; - top: 2px; - right: 2px; -} - -.process-spinner-close:hover path, -.process-spinner-close:focus path { - fill: var(--red) !important; -} diff --git a/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx b/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx deleted file mode 100644 index 037aabf5ff3..00000000000 --- a/server/sonar-web/src/main/js/components/controls/GlobalMessages.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import { ClearButton } from '../ui/buttons'; -import { cutLongWords } from '../../helpers/path'; -import './GlobalMessages.css'; - -interface Message { - id: string; - level: 'ERROR' | 'SUCCESS'; - message: string; -} - -export interface Props { - closeGlobalMessage: (id: string) => void; - messages: Message[]; -} - -export default function GlobalMessages({ closeGlobalMessage, messages }: Props) { - if (messages.length === 0) { - return null; - } - - return ( - <div className="processes-container"> - {messages.map(message => ( - <GlobalMessage closeGlobalMessage={closeGlobalMessage} key={message.id} message={message} /> - ))} - </div> - ); -} - -export class GlobalMessage extends React.PureComponent<{ - closeGlobalMessage: (id: string) => void; - message: Message; -}> { - handleClose = () => { - this.props.closeGlobalMessage(this.props.message.id); - }; - - render() { - const { message } = this.props; - return ( - <div - className={classNames('process-spinner', 'shown', { - 'process-spinner-failed': message.level === 'ERROR', - 'process-spinner-success': message.level === 'SUCCESS' - })} - key={message.id}> - {cutLongWords(message.message)} - <ClearButton - className="button-small process-spinner-close" - color="#fff" - onClick={this.handleClose} - /> - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/HelpTooltip.css b/server/sonar-web/src/main/js/components/controls/HelpTooltip.css deleted file mode 100644 index c2e34191ca1..00000000000 --- a/server/sonar-web/src/main/js/components/controls/HelpTooltip.css +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.help-tooltip { - display: inline-flex; - align-items: center; - vertical-align: middle; -} - -.help-toolip-link { - display: block; - width: 12px; - height: 12px; - border: none; -} diff --git a/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx b/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx deleted file mode 100644 index 9790e972d0e..00000000000 --- a/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import Tooltip, { Placement } from './Tooltip'; -import HelpIcon from '../icons-components/HelpIcon'; -import * as theme from '../../app/theme'; -import './HelpTooltip.css'; - -interface Props { - className?: string; - children?: React.ReactNode; - onShow?: () => void; - overlay: React.ReactNode; - placement?: Placement; - tagName?: string; -} - -export default function HelpTooltip(props: Props) { - const { children = <HelpIcon fill={theme.gray71} size={12} />, tagName = 'div' } = props; - - return React.createElement( - tagName, - { className: classNames('help-tooltip', props.className) }, - <Tooltip - mouseLeaveDelay={0.25} - onShow={props.onShow} - overlay={props.overlay} - placement={props.placement}> - <span className="display-inline-flex-center">{children}</span> - </Tooltip> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx index 1562f3f97d8..cf52da98d81 100644 --- a/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx +++ b/server/sonar-web/src/main/js/components/controls/HomePageSelect.tsx @@ -20,10 +20,10 @@ import * as React from 'react'; import * as classNames from 'classnames'; import { connect } from 'react-redux'; -import Tooltip from './Tooltip'; -import { ButtonLink } from '../ui/buttons'; -import HomeIcon from '../icons-components/HomeIcon'; -import { translate } from '../../helpers/l10n'; +import HomeIcon from 'sonar-ui-common/components/icons/HomeIcon'; +import { translate } from 'sonar-ui-common/helpers/l10n'; +import Tooltip from 'sonar-ui-common/components/controls/Tooltip'; +import { ButtonLink } from 'sonar-ui-common/components/controls/buttons'; import { getCurrentUser, Store } from '../../store/rootReducer'; import { setHomePage } from '../../store/users'; import { isLoggedIn } from '../../helpers/users'; diff --git a/server/sonar-web/src/main/js/components/controls/InputValidationField.tsx b/server/sonar-web/src/main/js/components/controls/InputValidationField.tsx deleted file mode 100644 index 91707869288..00000000000 --- a/server/sonar-web/src/main/js/components/controls/InputValidationField.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import ModalValidationField from './ModalValidationField'; - -interface Props { - autoFocus?: boolean; - className?: string; - description?: string; - dirty: boolean; - disabled: boolean; - error: string | undefined; - id?: string; - label?: React.ReactNode; - name: string; - onBlur: (event: React.FocusEvent<any>) => void; - onChange: (event: React.ChangeEvent<any>) => void; - placeholder?: string; - touched: boolean | undefined; - type?: string; - value: string; -} - -export default function InputValidationField({ className, ...props }: Props) { - const { description, dirty, error, label, touched, ...inputProps } = props; - const modalValidationProps = { description, dirty, error, label, touched }; - return ( - <ModalValidationField {...modalValidationProps}> - {({ className: validationClassName }) => ( - <input className={classNames(className, validationClassName)} {...inputProps} /> - )} - </ModalValidationField> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/ListFooter.tsx b/server/sonar-web/src/main/js/components/controls/ListFooter.tsx deleted file mode 100644 index 922899cd67a..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ListFooter.tsx +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import DeferredSpinner from '../common/DeferredSpinner'; -import { translate, translateWithParameters } from '../../helpers/l10n'; -import { formatMeasure } from '../../helpers/measures'; - -export interface Props { - count: number; - className?: string; - loading?: boolean; - loadMore?: () => void; - needReload?: boolean; - reload?: () => void; - ready?: boolean; - total?: number; -} - -export default function ListFooter({ ready = true, ...props }: Props) { - const handleLoadMore = (event: React.SyntheticEvent<HTMLElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - if (props.loadMore) { - props.loadMore(); - } - }; - - const handleReload = (event: React.SyntheticEvent<HTMLElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - if (props.reload) { - props.reload(); - } - }; - - const hasMore = props.total && props.total > props.count; - - const loadMoreLink = ( - <a className="spacer-left" href="#" onClick={handleLoadMore}> - {translate('show_more')} - </a> - ); - - const reloadLink = ( - <a className="spacer-left" href="#" onClick={handleReload}> - {translate('reload')} - </a> - ); - - const className = classNames( - 'spacer-top note text-center', - { 'new-loading': !ready }, - props.className - ); - - let link; - - if (props.needReload && props.reload) { - link = reloadLink; - } else if (hasMore && props.loadMore) { - link = loadMoreLink; - } - - return ( - <footer className={className}> - {translateWithParameters( - 'x_of_y_shown', - formatMeasure(props.count, 'INT', null), - formatMeasure(props.total, 'INT', null) - )} - {link} - {props.loading && <DeferredSpinner className="text-bottom spacer-left position-absolute" />} - </footer> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/Modal.tsx b/server/sonar-web/src/main/js/components/controls/Modal.tsx deleted file mode 100644 index c250470f9af..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Modal.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as ReactModal from 'react-modal'; -import * as classNames from 'classnames'; - -ReactModal.setAppElement('#content'); - -export interface ModalProps { - children: React.ReactNode; - size?: 'small' | 'medium' | 'large'; - noBackdrop?: boolean; -} - -type MandatoryProps = Pick<ReactModal.Props, 'contentLabel'>; - -type Props = Partial<ReactModal.Props> & MandatoryProps & ModalProps; - -export default function Modal(props: Props) { - return ( - <ReactModal - className={classNames('modal', { - 'modal-small': props.size === 'small', - 'modal-medium': props.size === 'medium', - 'modal-large': props.size === 'large' - })} - isOpen={true} - overlayClassName={classNames('modal-overlay', { 'modal-no-backdrop': props.noBackdrop })} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/ModalButton.tsx b/server/sonar-web/src/main/js/components/controls/ModalButton.tsx deleted file mode 100644 index 1a145044166..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ModalButton.tsx +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; - -export interface ChildrenProps { - onClick: () => void; - onFormSubmit: (event: React.FormEvent<HTMLFormElement>) => void; -} - -export interface ModalProps { - onClose: () => void; -} - -export interface Props { - children: (props: ChildrenProps) => React.ReactNode; - modal: (props: ModalProps) => React.ReactNode; -} - -interface State { - modal: boolean; -} - -export default class ModalButton extends React.PureComponent<Props, State> { - mounted = false; - state: State = { modal: false }; - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - handleButtonClick = () => { - this.setState({ modal: true }); - }; - - handleFormSubmit = (event?: React.FormEvent<HTMLFormElement>) => { - if (event) { - event.preventDefault(); - } - this.setState({ modal: true }); - }; - - handleCloseModal = () => { - if (this.mounted) { - this.setState({ modal: false }); - } - }; - - render() { - return ( - <> - {this.props.children({ - onClick: this.handleButtonClick, - onFormSubmit: this.handleFormSubmit - })} - {this.state.modal && this.props.modal({ onClose: this.handleCloseModal })} - </> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx b/server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx deleted file mode 100644 index cba79506f52..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ModalValidationField.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import AlertErrorIcon from '../icons-components/AlertErrorIcon'; -import AlertSuccessIcon from '../icons-components/AlertSuccessIcon'; - -interface Props { - children: (props: { className?: string }) => React.ReactNode; - description?: string; - dirty: boolean; - error: string | undefined; - label?: React.ReactNode; - touched: boolean | undefined; -} - -export default function ModalValidationField(props: Props) { - const { description, dirty, error } = props; - - const isValid = dirty && props.touched && error === undefined; - const showError = dirty && props.touched && error !== undefined; - return ( - <div className="modal-validation-field"> - {props.label} - {props.children({ className: classNames({ 'is-invalid': showError, 'is-valid': isValid }) })} - {showError && <AlertErrorIcon className="little-spacer-top" />} - {isValid && <AlertSuccessIcon className="little-spacer-top" />} - {showError && <p className="text-danger">{error}</p>} - {description && <div className="modal-field-description">{description}</div>} - </div> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx b/server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx deleted file mode 100644 index 2e29bf413b6..00000000000 --- a/server/sonar-web/src/main/js/components/controls/OutsideClickHandler.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { findDOMNode } from 'react-dom'; - -interface Props { - children: React.ReactNode; - onClickOutside: () => void; -} - -export default class OutsideClickHandler extends React.Component<Props> { - element?: Element | null; - - componentDidMount() { - setTimeout(() => { - this.addClickHandler(); - }, 0); - } - - componentWillUnmount() { - this.removeClickHandler(); - } - - addClickHandler = () => { - window.addEventListener('click', this.handleWindowClick); - }; - - removeClickHandler = () => { - window.removeEventListener('click', this.handleWindowClick); - }; - - handleWindowClick = (event: MouseEvent) => { - // eslint-disable-next-line react/no-find-dom-node - const node = findDOMNode(this); - if (!node || !node.contains(event.target as Node)) { - this.props.onClickOutside(); - } - }; - - render() { - return this.props.children; - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Radio.tsx b/server/sonar-web/src/main/js/components/controls/Radio.tsx deleted file mode 100644 index ba030d96b61..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Radio.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; - -interface Props { - checked: boolean; - className?: string; - onCheck: (value: string) => void; - value: string; -} - -export default class Radio extends React.PureComponent<Props> { - handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - this.props.onCheck(this.props.value); - }; - - render() { - return ( - <a - aria-checked={this.props.checked} - className={classNames('display-inline-flex-center link-checkbox', this.props.className)} - href="#" - onClick={this.handleClick} - role="radio"> - <i - className={classNames('icon-radio', 'spacer-right', { - 'is-checked': this.props.checked - })} - /> - {this.props.children} - </a> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/RadioCard.css b/server/sonar-web/src/main/js/components/controls/RadioCard.css deleted file mode 100644 index a5099a9a239..00000000000 --- a/server/sonar-web/src/main/js/components/controls/RadioCard.css +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.radio-card { - display: flex; - flex-direction: column; - width: 450px; - min-height: 210px; - background-color: #fff; - border: solid 1px var(--barBorderColor); - border-radius: 3px; - box-sizing: border-box; - margin-right: calc(2 * var(--gridSize)); - transition: all 0.2s ease; -} - -.radio-card.animated { - height: 0; - border-width: 0; - overflow: hidden; -} - -.radio-card.animated.open { - height: 210px; - border-width: 1px; -} - -.radio-card.highlight { - box-shadow: var(--defaultShadow); -} - -.radio-card:last-child { - margin-right: 0; -} - -.radio-card:focus { - outline: none; -} - -.radio-card-actionable { - cursor: pointer; -} - -.radio-card-actionable:not(.disabled):hover { - box-shadow: var(--defaultShadow); - transform: translateY(-2px); -} - -.radio-card-actionable.selected { - border-color: var(--darkBlue); -} - -.radio-card-actionable.selected .radio-card-recommended { - border: solid 1px var(--darkBlue); - border-top: none; -} - -.radio-card-actionable.disabled { - cursor: not-allowed; - background-color: var(--disableGrayBg); - border-color: var(--disableGrayBorder); -} - -.radio-card-actionable.disabled h2, -.radio-card-actionable.disabled ul { - color: var(--disableGrayText); -} - -.radio-card-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: calc(2 * var(--gridSize)) calc(2 * var(--gridSize)) 0; -} - -.radio-card-body { - flex-grow: 1; - display: flex; - flex-direction: column; - justify-content: space-between; - padding: 0 calc(2 * var(--gridSize)) calc(2 * var(--gridSize)); -} - -.radio-card-body .alert { - margin-bottom: 0; -} - -.radio-card-recommended { - position: relative; - padding: 6px calc(var(--gridSize) * 2); - left: -1px; - bottom: -1px; - width: 450px; - color: #fff; - background-color: var(--blue); - border-radius: 0 0 3px 3px; - box-sizing: border-box; - font-size: var(--smallFontSize); -} diff --git a/server/sonar-web/src/main/js/components/controls/RadioCard.tsx b/server/sonar-web/src/main/js/components/controls/RadioCard.tsx deleted file mode 100644 index 96726369abf..00000000000 --- a/server/sonar-web/src/main/js/components/controls/RadioCard.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import { FormattedMessage } from 'react-intl'; -import RecommendedIcon from '../icons-components/RecommendedIcon'; -import { translate } from '../../helpers/l10n'; -import './RadioCard.css'; - -export interface RadioCardProps { - className?: string; - disabled?: boolean; - onClick?: () => void; - selected?: boolean; -} - -interface Props extends RadioCardProps { - children: React.ReactNode; - recommended?: string; - title: React.ReactNode; - titleInfo?: React.ReactNode; -} - -export default function RadioCard(props: Props) { - const { className, disabled, onClick, recommended, selected, titleInfo } = props; - const isActionable = Boolean(onClick); - return ( - <div - aria-checked={selected} - className={classNames( - 'radio-card', - { 'radio-card-actionable': isActionable, disabled, selected }, - className - )} - onClick={isActionable && !disabled ? onClick : undefined} - role="radio" - tabIndex={0}> - <h2 className="radio-card-header big-spacer-bottom"> - <span className="display-flex-center"> - {isActionable && ( - <i className={classNames('icon-radio', 'spacer-right', { 'is-checked': selected })} /> - )} - {props.title} - </span> - {titleInfo} - </h2> - <div className="radio-card-body">{props.children}</div> - {recommended && ( - <div className="radio-card-recommended"> - <RecommendedIcon className="spacer-right" /> - <FormattedMessage - defaultMessage={recommended} - id={recommended} - values={{ recommended: <strong>{translate('recommended')}</strong> }} - /> - </div> - )} - </div> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/RadioToggle.tsx b/server/sonar-web/src/main/js/components/controls/RadioToggle.tsx deleted file mode 100644 index a114b022f8c..00000000000 --- a/server/sonar-web/src/main/js/components/controls/RadioToggle.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import Tooltip from './Tooltip'; - -interface Option { - disabled?: boolean; - label: string; - tooltip?: string; - value: string; -} - -interface Props { - className?: string; - name: string; - onCheck: (value: string) => void; - options: Option[]; - value?: string; -} - -export default class RadioToggle extends React.PureComponent<Props> { - static defaultProps = { - disabled: false, - value: null - }; - - handleChange = (e: React.SyntheticEvent<HTMLInputElement>) => { - const newValue = e.currentTarget.value; - this.props.onCheck(newValue); - }; - - renderOption = (option: Option) => { - const checked = option.value === this.props.value; - const htmlId = this.props.name + '__' + option.value; - return ( - <li key={option.value}> - <input - checked={checked} - disabled={option.disabled} - id={htmlId} - name={this.props.name} - onChange={this.handleChange} - type="radio" - value={option.value} - /> - <Tooltip overlay={option.tooltip || undefined}> - <label htmlFor={htmlId}>{option.label}</label> - </Tooltip> - </li> - ); - }; - - render() { - return ( - <ul className={classNames('radio-toggle', this.props.className)}> - {this.props.options.map(this.renderOption)} - </ul> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ReloadButton.tsx b/server/sonar-web/src/main/js/components/controls/ReloadButton.tsx deleted file mode 100644 index aa6808c18e3..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ReloadButton.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import Tooltip from './Tooltip'; -import * as theme from '../../app/theme'; -import { translate } from '../../helpers/l10n'; - -interface Props { - className?: string; - tooltip?: string; - onClick: () => void; -} - -export default class ReloadButton extends React.PureComponent<Props> { - handleClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - this.props.onClick(); - }; - - renderIcon = () => ( - <svg height="24" viewBox="0 0 18 24" width="18"> - <path - d="M16.6454 8.1084c-.3-.5-.9-.7-1.4-.4-.5.3-.7.9-.4 1.4.9 1.6 1.1 3.4.6 5.1-.5 1.7-1.7 3.2-3.2 4-3.3 1.8-7.4.6-9.1-2.7-1.8-3.1-.8-6.9 2.1-8.8v3.3h2v-7h-7v2h3.9c-3.7 2.5-5 7.5-2.8 11.4 1.6 3 4.6 4.6 7.7 4.6 1.4 0 2.8-.3 4.2-1.1 2-1.1 3.5-3 4.2-5.2.6-2.2.3-4.6-.8-6.6z" - fill={theme.secondFontColor} - /> - </svg> - ); - - render() { - const { tooltip = translate('reload') } = this.props; - return ( - <Tooltip overlay={tooltip}> - <a - className={classNames('link-no-underline', this.props.className)} - href="#" - onClick={this.handleClick}> - {this.renderIcon()} - </a> - </Tooltip> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx b/server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx deleted file mode 100644 index 7c84151eaee..00000000000 --- a/server/sonar-web/src/main/js/components/controls/ScreenPositionFixer.tsx +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { findDOMNode } from 'react-dom'; -import { throttle } from 'lodash'; -import { grid } from '../../app/theme'; - -const EDGE_MARGIN = 0.5 * grid; - -interface Props { - /** - * First time `children` are rendered with `undefined` fixes to measure the offset. - * Second time it renders with the computed fixes. - */ - children: (props: Fixes) => React.ReactNode; - - /** - * Use this flag to force re-positioning. - * Use cases: - * - when you need to measure `children` size first - * - when you load content asynchronously - */ - ready?: boolean; -} - -interface Fixes { - leftFix?: number; - topFix?: number; -} - -export default class ScreenPositionFixer extends React.Component<Props, Fixes> { - throttledPosition: () => void; - - constructor(props: Props) { - super(props); - this.state = {}; - this.throttledPosition = throttle(this.position, 50); - } - - componentDidMount() { - this.addEventListeners(); - this.position(); - } - - componentDidUpdate(prevProps: Props) { - if (!prevProps.ready && this.props.ready) { - this.position(); - } - } - - componentWillUnmount() { - this.removeEventListeners(); - } - - addEventListeners = () => { - window.addEventListener('resize', this.throttledPosition); - }; - - removeEventListeners = () => { - window.removeEventListener('resize', this.throttledPosition); - }; - - position = () => { - // eslint-disable-next-line react/no-find-dom-node - const node = findDOMNode(this); - if (node && node instanceof Element) { - const { width, height, left, top } = node.getBoundingClientRect(); - const { clientHeight, clientWidth } = document.body; - - let leftFix = 0; - if (left < EDGE_MARGIN) { - leftFix = EDGE_MARGIN - left; - } else if (left + width > clientWidth - EDGE_MARGIN) { - leftFix = clientWidth - EDGE_MARGIN - left - width; - } - - let topFix = 0; - if (top < EDGE_MARGIN) { - topFix = EDGE_MARGIN - top; - } else if (top + height > clientHeight - EDGE_MARGIN) { - topFix = clientHeight - EDGE_MARGIN - top - height; - } - - this.setState({ leftFix, topFix }); - } - }; - - render() { - return this.props.children(this.state); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/SearchBox.css b/server/sonar-web/src/main/js/components/controls/SearchBox.css deleted file mode 100644 index ea129a95b57..00000000000 --- a/server/sonar-web/src/main/js/components/controls/SearchBox.css +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.search-box { - position: relative; - display: inline-block; - vertical-align: middle; - font-size: 0; - white-space: nowrap; -} - -.search-box, -.search-box-input { - width: 100%; - max-width: 300px; -} - -.search-box-input { - /* for magnifier icon */ - padding-left: var(--controlHeight) !important; - /* for clear button */ - padding-right: var(--controlHeight) !important; - font-size: var(--baseFontSize); -} - -.search-box-input::-webkit-search-decoration, -.search-box-input::-webkit-search-cancel-button, -.search-box-input::-webkit-search-results-button, -.search-box-input::-webkit-search-results-decoration { - -webkit-appearance: none; - display: none; -} - -.search-box-input::-ms-clear, -.search-box-input::-ms-reveal { - display: none; - width: 0; - height: 0; -} - -.search-box-note { - position: absolute; - top: 1px; - left: 40px; - right: var(--controlHeight); - line-height: var(--controlHeight); - color: var(--secondFontColor); - font-size: var(--smallFontSize); - text-align: right; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - pointer-events: none; -} - -.search-box-input:focus ~ .search-box-magnifier { - color: var(--blue); -} - -.search-box-magnifier { - position: absolute; - top: 4px; - left: 4px; - color: var(--gray60); - transition: color 0.3s ease; -} - -.search-box > .spinner { - position: absolute; - top: 4px; - left: 5px; -} - -.search-box-clear { - position: absolute; - top: 4px; - right: 4px; -} - -.search-box-input-note { - position: absolute; - top: 100%; - left: 0; - line-height: 1; - color: var(--secondFontColor); - font-size: var(--smallFontSize); - white-space: nowrap; -} diff --git a/server/sonar-web/src/main/js/components/controls/SearchBox.tsx b/server/sonar-web/src/main/js/components/controls/SearchBox.tsx deleted file mode 100644 index 0a6d8e62f09..00000000000 --- a/server/sonar-web/src/main/js/components/controls/SearchBox.tsx +++ /dev/null @@ -1,172 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import { debounce, Cancelable } from 'lodash'; -import SearchIcon from '../icons-components/SearchIcon'; -import DeferredSpinner from '../common/DeferredSpinner'; -import { ClearButton } from '../ui/buttons'; -import { translateWithParameters, translate } from '../../helpers/l10n'; -import './SearchBox.css'; - -interface Props { - autoFocus?: boolean; - className?: string; - id?: string; - innerRef?: (node: HTMLInputElement | null) => void; - loading?: boolean; - minLength?: number; - onChange: (value: string) => void; - onClick?: React.MouseEventHandler<HTMLInputElement>; - onFocus?: React.FocusEventHandler<HTMLInputElement>; - onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>; - placeholder: string; - value?: string; -} - -interface State { - value: string; -} - -export default class SearchBox extends React.PureComponent<Props, State> { - debouncedOnChange: ((query: string) => void) & Cancelable; - input?: HTMLInputElement | null; - - constructor(props: Props) { - super(props); - this.state = { value: props.value || '' }; - this.debouncedOnChange = debounce(this.props.onChange, 250); - } - - componentWillReceiveProps(nextProps: Props) { - if ( - // input is controlled - nextProps.value !== undefined && - // parent is aware of last change - // can happen when previous value was less than min length - this.state.value === this.props.value && - nextProps.value !== this.state.value - ) { - this.setState({ value: nextProps.value }); - } - } - - changeValue = (value: string, debounced = true) => { - const { minLength } = this.props; - if (value.length === 0) { - // immediately notify when value is empty - this.props.onChange(''); - // and cancel scheduled callback - this.debouncedOnChange.cancel(); - } else if (!minLength || minLength <= value.length) { - if (debounced) { - this.debouncedOnChange(value); - } else { - this.props.onChange(value); - } - } - }; - - handleInputChange = (event: React.SyntheticEvent<HTMLInputElement>) => { - const { value } = event.currentTarget; - this.setState({ value }); - this.changeValue(value); - }; - - handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => { - if (event.keyCode === 27) { - // escape - event.preventDefault(); - this.handleResetClick(); - } - if (this.props.onKeyDown) { - this.props.onKeyDown(event); - } - }; - - handleResetClick = () => { - this.changeValue('', false); - if (this.props.value === undefined || this.props.value === '') { - this.setState({ value: '' }); - } - if (this.input) { - this.input.focus(); - } - }; - - ref = (node: HTMLInputElement | null) => { - this.input = node; - if (this.props.innerRef) { - this.props.innerRef(node); - } - }; - - render() { - const { loading, minLength } = this.props; - const { value } = this.state; - - const inputClassName = classNames('search-box-input', { - touched: value.length > 0 && (!minLength || minLength > value.length) - }); - - const tooShort = minLength !== undefined && value.length > 0 && value.length < minLength; - - return ( - <div - className={classNames('search-box', this.props.className)} - id={this.props.id} - title={tooShort ? translateWithParameters('select2.tooShort', minLength!) : ''}> - <input - aria-label={translate('search_verb')} - autoComplete="off" - autoFocus={this.props.autoFocus} - className={inputClassName} - maxLength={100} - onChange={this.handleInputChange} - onClick={this.props.onClick} - onFocus={this.props.onFocus} - onKeyDown={this.handleInputKeyDown} - placeholder={this.props.placeholder} - ref={this.ref} - type="search" - value={value} - /> - - <DeferredSpinner loading={loading !== undefined ? loading : false}> - <SearchIcon className="search-box-magnifier" /> - </DeferredSpinner> - - {value && ( - <ClearButton - className="button-tiny search-box-clear" - iconProps={{ size: 12 }} - onClick={this.handleResetClick} - /> - )} - - {tooShort && ( - <span className="search-box-note"> - {translateWithParameters('select2.tooShort', minLength!)} - </span> - )} - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/SearchSelect.tsx b/server/sonar-web/src/main/js/components/controls/SearchSelect.tsx index 43558ccdf90..c4b681624e6 100644 --- a/server/sonar-web/src/main/js/components/controls/SearchSelect.tsx +++ b/server/sonar-web/src/main/js/components/controls/SearchSelect.tsx @@ -19,8 +19,8 @@ */ import * as React from 'react'; import { debounce } from 'lodash'; +import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; import Select, { Creatable } from './Select'; -import { translate, translateWithParameters } from '../../helpers/l10n'; interface Props<T> { autofocus?: boolean; diff --git a/server/sonar-web/src/main/js/components/controls/Select.tsx b/server/sonar-web/src/main/js/components/controls/Select.tsx index 05be7b0c5e3..2086716ac0f 100644 --- a/server/sonar-web/src/main/js/components/controls/Select.tsx +++ b/server/sonar-web/src/main/js/components/controls/Select.tsx @@ -19,8 +19,8 @@ */ import * as React from 'react'; import { ReactSelectProps, ReactCreatableSelectProps, ReactAsyncSelectProps } from 'react-select'; -import { ClearButton } from '../ui/buttons'; -import { lazyLoad } from '../lazyLoad'; +import { ClearButton } from 'sonar-ui-common/components/controls/buttons'; +import { lazyLoad } from 'sonar-ui-common/components/lazyLoad'; import './react-select.css'; const ReactSelectLib = import('react-select'); diff --git a/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx b/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx deleted file mode 100644 index 9870f0e6ec7..00000000000 --- a/server/sonar-web/src/main/js/components/controls/SimpleModal.tsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import Modal, { ModalProps } from './Modal'; - -export interface ChildrenProps { - onCloseClick: (event?: React.SyntheticEvent<HTMLElement>) => void; - onFormSubmit: (event: React.SyntheticEvent<HTMLFormElement>) => void; - onSubmitClick: (event?: React.SyntheticEvent<HTMLElement>) => void; - submitting: boolean; -} - -interface Props extends ModalProps { - children: (props: ChildrenProps) => React.ReactNode; - header: string; - onClose: () => void; - onSubmit: () => void | Promise<void>; -} - -interface State { - submitting: boolean; -} - -export default class SimpleModal extends React.Component<Props, State> { - mounted = false; - state: State = { submitting: false }; - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; - } - - stopSubmitting = () => { - if (this.mounted) { - this.setState({ submitting: false }); - } - }; - - handleCloseClick = (event?: React.SyntheticEvent<HTMLElement>) => { - if (event) { - event.preventDefault(); - event.currentTarget.blur(); - } - this.props.onClose(); - }; - - handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => { - event.preventDefault(); - this.submit(); - }; - - handleSubmitClick = (event?: React.SyntheticEvent<HTMLElement>) => { - if (event) { - event.preventDefault(); - event.currentTarget.blur(); - } - this.submit(); - }; - - submit = () => { - const result = this.props.onSubmit(); - if (result) { - this.setState({ submitting: true }); - result.then(this.stopSubmitting, this.stopSubmitting); - } - }; - - render() { - const { children, header, onClose, onSubmit, ...modalProps } = this.props; - return ( - <Modal contentLabel={header} onRequestClose={onClose} {...modalProps}> - {children({ - onCloseClick: this.handleCloseClick, - onFormSubmit: this.handleFormSubmit, - onSubmitClick: this.handleSubmitClick, - submitting: this.state.submitting - })} - </Modal> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Tabs.css b/server/sonar-web/src/main/js/components/controls/Tabs.css deleted file mode 100644 index 971439ab61e..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Tabs.css +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.flex-tabs { - display: flex; - clear: left; - margin-bottom: calc(3 * var(--gridSize)); - border-bottom: 1px solid var(--barBorderColor); - font-size: var(--mediumFontSize); -} - -.flex-tabs > li > a { - position: relative; - display: block; - top: 1px; - height: 100%; - width: 100%; - box-sizing: border-box; - color: var(--secondFontColor); - font-weight: 600; - cursor: pointer; - padding-bottom: calc(1.5 * var(--gridSize)); - border-bottom: 3px solid transparent; - transition: color 0.2s ease; -} - -.flex-tabs > li ~ li { - margin-left: calc(4 * var(--gridSize)); -} - -.flex-tabs > li > a:hover { - color: var(--baseFontColor); -} - -.flex-tabs > li > a.selected { - color: var(--blue); - border-bottom-color: var(--blue); -} - -.flex-tabs > li > a.disabled { - color: var(--disableGrayText) !important; - cursor: not-allowed !important; - pointer-events: none !important; -} diff --git a/server/sonar-web/src/main/js/components/controls/Tabs.tsx b/server/sonar-web/src/main/js/components/controls/Tabs.tsx deleted file mode 100644 index 33d20ee4118..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Tabs.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import './Tabs.css'; - -interface Props<T extends string> { - onChange: (tab: T) => void; - selected?: T; - tabs: Array<{ disabled?: boolean; key: T; node: React.ReactNode }>; -} - -export default function Tabs<T extends string>({ onChange, selected, tabs }: Props<T>) { - return ( - <ul className="flex-tabs"> - {tabs.map(tab => ( - <Tab - disabled={tab.disabled} - key={tab.key} - name={tab.key} - onSelect={onChange} - selected={selected === tab.key}> - {tab.node} - </Tab> - ))} - </ul> - ); -} - -interface TabProps<T> { - children: React.ReactNode; - disabled?: boolean; - name: T; - onSelect: (tab: T) => void; - selected: boolean; -} - -export class Tab<T> extends React.PureComponent<TabProps<T>> { - handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.stopPropagation(); - if (!this.props.disabled) { - this.props.onSelect(this.props.name); - } - }; - - render() { - const { children, disabled, name, selected } = this.props; - return ( - <li> - <a - className={classNames('js-' + name, { disabled, selected })} - href="#" - onClick={this.handleClick}> - {children} - </a> - </li> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Toggle.tsx b/server/sonar-web/src/main/js/components/controls/Toggle.tsx deleted file mode 100644 index 337172a9980..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Toggle.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import { Button } from '../ui/buttons'; -import CheckIcon from '../icons-components/CheckIcon'; -import './styles.css'; - -export interface Props { - name?: string; - onChange?: (value: boolean) => void; - value: boolean | string; -} - -export default class Toggle extends React.PureComponent<Props> { - getValue = () => { - const { value } = this.props; - return typeof value === 'string' ? value === 'true' : value; - }; - - handleClick = () => { - if (this.props.onChange) { - const value = this.getValue(); - this.props.onChange(!value); - } - }; - - render() { - const value = this.getValue(); - const className = classNames('boolean-toggle', { 'boolean-toggle-on': value }); - - return ( - <Button className={className} name={this.props.name} onClick={this.handleClick}> - <div className="boolean-toggle-handle"> - <CheckIcon size={12} /> - </div> - </Button> - ); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Toggler.tsx b/server/sonar-web/src/main/js/components/controls/Toggler.tsx deleted file mode 100644 index 1f01d5b3a1e..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Toggler.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import DocumentClickHandler from './DocumentClickHandler'; -import OutsideClickHandler from './OutsideClickHandler'; - -export interface Props { - children?: React.ReactNode; - closeOnClick?: boolean; - closeOnClickOutside?: boolean; - closeOnEscape?: boolean; - onRequestClose: () => void; - open: boolean; - overlay: React.ReactNode; -} - -export default class Toggler extends React.Component<Props> { - componentDidMount() { - if (this.props.open && isTrueOrUndefined(this.props.closeOnEscape)) { - this.addEventListeners(); - } - } - - componentDidUpdate(prevProps: Props) { - if (!prevProps.open && this.props.open && isTrueOrUndefined(this.props.closeOnEscape)) { - this.addEventListeners(); - } else if (prevProps.open && !this.props.open) { - this.removeEventListeners(); - } else if ( - isTrueOrUndefined(prevProps.closeOnEscape) && - !isTrueOrUndefined(this.props.closeOnEscape) - ) { - this.removeEventListeners(); - } - } - - componentWillUnmount() { - this.removeEventListeners(); - } - - addEventListeners() { - document.addEventListener('keydown', this.handleKeyDown, false); - } - - removeEventListeners() { - document.removeEventListener('keydown', this.handleKeyDown, false); - } - - handleKeyDown = (event: KeyboardEvent) => { - // Escape key - if (event.keyCode === 27) { - this.props.onRequestClose(); - } - }; - - renderOverlay() { - const { - closeOnClick = false, - closeOnClickOutside = true, - onRequestClose, - overlay - } = this.props; - - if (closeOnClick) { - return <DocumentClickHandler onClick={onRequestClose}>{overlay}</DocumentClickHandler>; - } else if (closeOnClickOutside) { - return <OutsideClickHandler onClickOutside={onRequestClose}>{overlay}</OutsideClickHandler>; - } else { - return overlay; - } - } - - render() { - return ( - <> - {this.props.children} - {this.props.open && this.renderOverlay()} - </> - ); - } -} - -function isTrueOrUndefined(x: boolean | undefined) { - return x === true || x === undefined; -} diff --git a/server/sonar-web/src/main/js/components/controls/Tooltip.css b/server/sonar-web/src/main/js/components/controls/Tooltip.css deleted file mode 100644 index f41c3b096e7..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Tooltip.css +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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. - */ -.tooltip { - position: absolute; - z-index: var(--tooltipZIndex); - display: block; - height: auto; - box-sizing: border-box; -} - -.tooltip { - font-size: var(--smallFontSize); - font-weight: 300; - line-height: 1.5; - animation: fadeIn 0.3s forwards; -} - -.tooltip.top { - padding: 5px 0; - margin-top: -3px; -} - -.tooltip.right { - padding: 0 5px; - margin-left: 3px; -} - -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px; -} - -.tooltip.left { - padding: 0 5px; - margin-left: -3px; -} - -.tooltip-inner { - max-width: 300px; - text-align: left; - text-decoration: none; - border-radius: 4px; - overflow: hidden; - word-break: break-word; -} - -.tooltip-inner { - padding: 12px 17px; - color: #fff; - background-color: #475760; - letter-spacing: 0.04em; -} - -.tooltip-inner .alert { - margin-bottom: 5px; - border-radius: 4px; -} - -.tooltip-inner a { - border-bottom-color: #8da6b3; - color: #a5d0ea; -} - -.tooltip-inner hr { - background-color: #5d6d75; -} - -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border: solid transparent; -} - -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - border-width: 5px 5px 0; - transform: translateX(-5px); -} - -.tooltip.top .tooltip-arrow { - border-top-color: #475760; -} - -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - transform: translateY(-5px); - border-width: 5px 5px 5px 0; - border-right-color: #475760; -} - -.tooltip.right .tooltip-arrow { - border-right-color: #475760; -} - -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - transform: translateY(-5px); - border-width: 5px 0 5px 5px; - border-left-color: #475760; -} - -.tooltip.left .tooltip-arrow { - border-left-color: #475760; -} - -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - transform: translateX(-5px); - border-width: 0 5px 5px; - border-bottom-color: #475760; -} - -.tooltip.bottom .tooltip-arrow { - border-bottom-color: #475760; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} diff --git a/server/sonar-web/src/main/js/components/controls/Tooltip.tsx b/server/sonar-web/src/main/js/components/controls/Tooltip.tsx deleted file mode 100644 index 7917b491ff8..00000000000 --- a/server/sonar-web/src/main/js/components/controls/Tooltip.tsx +++ /dev/null @@ -1,320 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { createPortal, findDOMNode } from 'react-dom'; -import { throttle } from 'lodash'; -import ScreePositionFixer from './ScreenPositionFixer'; -import './Tooltip.css'; - -export type Placement = 'bottom' | 'right' | 'left' | 'top'; - -interface Props { - classNameSpace?: string; - children: React.ReactElement<{}>; - mouseEnterDelay?: number; - mouseLeaveDelay?: number; - onShow?: () => void; - onHide?: () => void; - overlay: React.ReactNode; - placement?: Placement; - visible?: boolean; -} - -interface Measurements { - height: number; - left: number; - top: number; - width: number; -} - -interface OwnState { - visible: boolean; -} - -type State = OwnState & Partial<Measurements>; - -function isMeasured(state: State): state is OwnState & Measurements { - return state.height !== undefined; -} - -export default function Tooltip(props: Props) { - // overlay is a ReactNode, so it can be `undefined` or `null` - // this allows to easily render a tooltip conditionally - // more generaly we avoid rendering empty tooltips - return props.overlay != null && props.overlay !== '' ? ( - <TooltipInner {...props} /> - ) : ( - props.children - ); -} - -export class TooltipInner extends React.Component<Props, State> { - throttledPositionTooltip: () => void; - mouseEnterTimeout?: number; - mouseLeaveTimeout?: number; - tooltipNode?: HTMLElement | null; - mounted = false; - mouseIn = false; - - static defaultProps = { - mouseEnterDelay: 0.1 - }; - - constructor(props: Props) { - super(props); - this.state = { - visible: props.visible !== undefined ? props.visible : false - }; - this.throttledPositionTooltip = throttle(this.positionTooltip, 10); - } - - componentDidMount() { - this.mounted = true; - if (this.props.visible === true) { - this.positionTooltip(); - this.addEventListeners(); - } - } - - componentDidUpdate(prevProps: Props, prevState: State) { - if ( - // opens - (this.props.visible === true && prevProps.visible === false) || - (this.props.visible === undefined && - this.state.visible === true && - prevState.visible === false) - ) { - this.positionTooltip(); - this.addEventListeners(); - } else if ( - // closes - (this.props.visible === false && prevProps.visible === true) || - (this.props.visible === undefined && - this.state.visible === false && - prevState.visible === true) - ) { - this.clearPosition(); - this.removeEventListeners(); - } - } - - componentWillUnmount() { - this.mounted = false; - this.removeEventListeners(); - this.clearTimeouts(); - } - - addEventListeners = () => { - window.addEventListener('resize', this.throttledPositionTooltip); - window.addEventListener('scroll', this.throttledPositionTooltip); - }; - - removeEventListeners = () => { - window.removeEventListener('resize', this.throttledPositionTooltip); - window.removeEventListener('scroll', this.throttledPositionTooltip); - }; - - clearTimeouts = () => { - window.clearTimeout(this.mouseEnterTimeout); - window.clearTimeout(this.mouseLeaveTimeout); - }; - - isVisible = () => { - return this.props.visible !== undefined ? this.props.visible : this.state.visible; - }; - - getPlacement = (): Placement => { - return this.props.placement || 'bottom'; - }; - - tooltipNodeRef = (node: HTMLElement | null) => { - this.tooltipNode = node; - }; - - positionTooltip = () => { - // `findDOMNode(this)` will search for the DOM node for the current component - // first it will find a React.Fragment (see `render`), - // so it will get the DOM node of the first child, i.e. DOM node of `this.props.children` - // docs: https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components - - // eslint-disable-next-line react/no-find-dom-node - const toggleNode = findDOMNode(this); - - if (toggleNode && toggleNode instanceof Element && this.tooltipNode) { - const toggleRect = toggleNode.getBoundingClientRect(); - const tooltipRect = this.tooltipNode.getBoundingClientRect(); - const { width, height } = tooltipRect; - - let left = 0; - let top = 0; - - switch (this.getPlacement()) { - case 'bottom': - left = toggleRect.left + toggleRect.width / 2 - width / 2; - top = toggleRect.top + toggleRect.height; - break; - case 'top': - left = toggleRect.left + toggleRect.width / 2 - width / 2; - top = toggleRect.top - height; - break; - case 'right': - left = toggleRect.left + toggleRect.width; - top = toggleRect.top + toggleRect.height / 2 - height / 2; - break; - case 'left': - left = toggleRect.left - width; - top = toggleRect.top + toggleRect.height / 2 - height / 2; - break; - } - - // save width and height (and later set in `render`) to avoid resizing the tooltip element, - // when it's placed close to the window edge - const measurements: Measurements = { - left: window.pageXOffset + left, - top: window.pageYOffset + top, - width, - height - }; - this.setState(measurements); - } - }; - - clearPosition = () => { - this.setState({ - left: undefined, - top: undefined, - width: undefined, - height: undefined - }); - }; - - handleMouseEnter = () => { - this.mouseEnterTimeout = window.setTimeout(() => { - // for some reason even after the `this.mouseEnterTimeout` is cleared, it still triggers - // to workaround this issue, check that its value is not `undefined` - // (if it's `undefined`, it means the timer has been reset) - if ( - this.mounted && - this.props.visible === undefined && - this.mouseEnterTimeout !== undefined - ) { - this.setState({ visible: true }); - } - }, (this.props.mouseEnterDelay || 0) * 1000); - - if (this.props.onShow) { - this.props.onShow(); - } - }; - - handleMouseLeave = () => { - if (this.mouseEnterTimeout !== undefined) { - window.clearTimeout(this.mouseEnterTimeout); - this.mouseEnterTimeout = undefined; - } - - if (!this.mouseIn) { - this.mouseLeaveTimeout = window.setTimeout(() => { - if (this.mounted && this.props.visible === undefined && !this.mouseIn) { - this.setState({ visible: false }); - } - }, (this.props.mouseLeaveDelay || 0) * 1000); - - if (this.props.onHide) { - this.props.onHide(); - } - } - }; - - handleOverlayMouseEnter = () => { - this.mouseIn = true; - }; - - handleOverlayMouseLeave = () => { - this.mouseIn = false; - this.handleMouseLeave(); - }; - - render() { - const { classNameSpace = 'tooltip' } = this.props; - return ( - <> - {React.cloneElement(this.props.children, { - onMouseEnter: this.handleMouseEnter, - onMouseLeave: this.handleMouseLeave - })} - {this.isVisible() && ( - <TooltipPortal> - <ScreePositionFixer ready={isMeasured(this.state)}> - {({ leftFix = 0, topFix = 0 }) => ( - <div - className={`${classNameSpace} ${this.getPlacement()}`} - onMouseEnter={this.handleOverlayMouseEnter} - onMouseLeave={this.handleOverlayMouseLeave} - ref={this.tooltipNodeRef} - style={ - isMeasured(this.state) - ? { - left: this.state.left + leftFix, - top: this.state.top + topFix, - width: this.state.width, - height: this.state.height - } - : undefined - }> - <div className={`${classNameSpace}-inner`}>{this.props.overlay}</div> - <div - className={`${classNameSpace}-arrow`} - style={ - isMeasured(this.state) - ? { marginLeft: -leftFix, marginTop: -topFix } - : undefined - } - /> - </div> - )} - </ScreePositionFixer> - </TooltipPortal> - )} - </> - ); - } -} - -class TooltipPortal extends React.Component { - el: HTMLElement; - - constructor(props: {}) { - super(props); - this.el = document.createElement('div'); - } - - componentDidMount() { - document.body.appendChild(this.el); - } - - componentWillUnmount() { - document.body.removeChild(this.el); - } - - render() { - return createPortal(this.props.children, this.el); - } -} diff --git a/server/sonar-web/src/main/js/components/controls/ValidationInput.tsx b/server/sonar-web/src/main/js/components/controls/ValidationInput.tsx index 6384d9783f8..3d7a78104a1 100644 --- a/server/sonar-web/src/main/js/components/controls/ValidationInput.tsx +++ b/server/sonar-web/src/main/js/components/controls/ValidationInput.tsx @@ -18,9 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import HelpTooltip from './HelpTooltip'; -import AlertErrorIcon from '../icons-components/AlertErrorIcon'; -import AlertSuccessIcon from '../icons-components/AlertSuccessIcon'; +import AlertErrorIcon from 'sonar-ui-common/components/icons/AlertErrorIcon'; +import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon'; +import HelpTooltip from 'sonar-ui-common/components/controls/HelpTooltip'; interface Props { description?: string; diff --git a/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx b/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx index d359d8daebf..110bbc84237 100644 --- a/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx +++ b/server/sonar-web/src/main/js/components/controls/ValidationModal.tsx @@ -18,11 +18,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import Modal, { ModalProps } from './Modal'; +import { translate } from 'sonar-ui-common/helpers/l10n'; +import { SubmitButton, ResetButtonLink } from 'sonar-ui-common/components/controls/buttons'; +import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; +import Modal, { ModalProps } from 'sonar-ui-common/components/controls/Modal'; import ValidationForm, { ChildrenProps } from './ValidationForm'; -import DeferredSpinner from '../common/DeferredSpinner'; -import { SubmitButton, ResetButtonLink } from '../ui/buttons'; -import { translate } from '../../helpers/l10n'; interface Props<V> extends ModalProps { children: (props: ChildrenProps<V>) => React.ReactNode; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/BoxedGroupAccordion-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/BoxedGroupAccordion-test.tsx index 1685dc728a8..b77c4c5bbcd 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/BoxedGroupAccordion-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/BoxedGroupAccordion-test.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import { click } from '../../../helpers/testUtils'; +import { click } from 'sonar-ui-common/helpers/testUtils'; import BoxedGroupAccordion from '../BoxedGroupAccordion'; it('should render correctly', () => { diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Checkbox-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Checkbox-test.tsx deleted file mode 100644 index 8353052c830..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Checkbox-test.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import Checkbox from '../Checkbox'; -import { click } from '../../../helpers/testUtils'; - -it('should render', () => { - const checkbox = shallow(<Checkbox checked={true} onCheck={() => {}} title="Title value" />); - expect(checkbox).toMatchSnapshot(); -}); - -it('should render unchecked', () => { - const checkbox = shallow(<Checkbox checked={false} onCheck={() => true} />); - expect(checkbox.is('.icon-checkbox-checked')).toBeFalsy(); - expect(checkbox.prop('aria-checked')).toBe(false); -}); - -it('should render checked', () => { - const checkbox = shallow(<Checkbox checked={true} onCheck={() => true} />); - expect(checkbox.is('.icon-checkbox-checked')).toBeTruthy(); - expect(checkbox.prop('aria-checked')).toBe(true); -}); - -it('should render disabled', () => { - const checkbox = shallow(<Checkbox checked={true} disabled={true} onCheck={() => true} />); - expect(checkbox.is('.icon-checkbox-disabled')).toBeTruthy(); -}); - -it('should render unchecked third state', () => { - const checkbox = shallow(<Checkbox checked={false} onCheck={() => true} thirdState={true} />); - expect(checkbox.is('.icon-checkbox-single')).toBeTruthy(); - expect(checkbox.is('.icon-checkbox-checked')).toBeFalsy(); -}); - -it('should render checked third state', () => { - const checkbox = shallow(<Checkbox checked={true} onCheck={() => true} thirdState={true} />); - expect(checkbox.is('.icon-checkbox-single')).toBeTruthy(); - expect(checkbox.is('.icon-checkbox-checked')).toBeTruthy(); -}); - -it('should render with a spinner', () => { - const checkbox = shallow(<Checkbox checked={false} loading={true} onCheck={() => true} />); - expect(checkbox.find('DeferredSpinner')).toBeTruthy(); -}); - -it('should render children', () => { - const checkbox = shallow( - <Checkbox checked={false} onCheck={() => true}> - <span>foo</span> - </Checkbox> - ); - expect(checkbox.hasClass('link-checkbox')).toBeTruthy(); - expect(checkbox.find('span').exists()).toBeTruthy(); -}); - -it('should render children with a spinner', () => { - const checkbox = shallow( - <Checkbox checked={false} loading={true} onCheck={() => true}> - <span>foo</span> - </Checkbox> - ); - expect(checkbox.hasClass('link-checkbox')).toBeTruthy(); - expect(checkbox.find('span').exists()).toBeTruthy(); - expect(checkbox.find('DeferredSpinner').exists()).toBeTruthy(); -}); - -it('should call onCheck', () => { - const onCheck = jest.fn(); - const checkbox = shallow(<Checkbox checked={false} onCheck={onCheck} />); - click(checkbox); - expect(onCheck).toBeCalledWith(true, undefined); -}); - -it('should not call onCheck when disabled', () => { - const onCheck = jest.fn(); - const checkbox = shallow(<Checkbox checked={false} disabled={true} onCheck={onCheck} />); - click(checkbox); - expect(onCheck).toHaveBeenCalledTimes(0); -}); - -it('should call onCheck with id as second parameter', () => { - const onCheck = jest.fn(); - const checkbox = shallow(<Checkbox checked={false} id="foo" onCheck={onCheck} />); - click(checkbox); - expect(onCheck).toBeCalledWith(true, 'foo'); -}); - -it('should apply custom class', () => { - const checkbox = shallow( - <Checkbox checked={true} className="customclass" onCheck={() => true} /> - ); - expect(checkbox.is('.customclass')).toBeTruthy(); -}); - -it('should render the checkbox on the right', () => { - expect(shallow(<Checkbox checked={true} onCheck={() => true} right={true} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ClipboardButton-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ClipboardButton-test.tsx deleted file mode 100644 index b9bd71c1fca..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ClipboardButton-test.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow, mount } from 'enzyme'; -import ClipboardButton from '../ClipboardButton'; - -const constructor = jest.fn(); -const destroy = jest.fn(); -const on = jest.fn(); - -jest.mock( - 'clipboard', - () => - function(...args: any) { - constructor(...args); - return { - destroy, - on - }; - } -); - -jest.useFakeTimers(); - -it('should display correctly', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); - wrapper.instance().showTooltip(); - wrapper.update(); - expect(wrapper).toMatchSnapshot(); - jest.runAllTimers(); - wrapper.update(); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render a custom label if provided', () => { - expect(shallowRender({ label: 'Foo Bar' })).toMatchSnapshot(); -}); - -it('should allow its content to be copied', () => { - const wrapper = mountRender(); - const button = wrapper.find('button').getDOMNode(); - const instance = wrapper.instance(); - - expect(constructor).toBeCalledWith(button); - expect(on).toBeCalledWith('success', instance.showTooltip); - - jest.clearAllMocks(); - - wrapper.setProps({ label: 'Some new label' }); - expect(destroy).toBeCalled(); - expect(constructor).toBeCalledWith(button); - expect(on).toBeCalledWith('success', instance.showTooltip); - - jest.clearAllMocks(); - - wrapper.unmount(); - expect(destroy).toBeCalled(); -}); - -function shallowRender(props: Partial<ClipboardButton['props']> = {}) { - return shallow<ClipboardButton>(createComponent(props)); -} - -function mountRender(props: Partial<ClipboardButton['props']> = {}) { - return mount<ClipboardButton>(createComponent(props)); -} - -function createComponent(props: Partial<ClipboardButton['props']> = {}) { - return <ClipboardButton copyValue="foo" {...props} />; -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ConfirmButton-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ConfirmButton-test.tsx deleted file mode 100644 index 2bfe5cf21b4..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ConfirmButton-test.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import ConfirmButton from '../ConfirmButton'; - -it('should display a modal button', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('should display a confirm modal', () => { - expect( - shallowRender() - .find('ModalButton') - .prop<Function>('modal')({ onClose: jest.fn() }) - ).toMatchSnapshot(); -}); - -function shallowRender() { - return shallow( - <ConfirmButton - confirmButtonText="submit" - modalBody={<div />} - modalHeader="title" - onConfirm={jest.fn()}> - {() => 'Confirm button'} - </ConfirmButton> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ConfirmModal-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ConfirmModal-test.tsx deleted file mode 100644 index 35c95c9b138..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ConfirmModal-test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import ConfirmModal from '../ConfirmModal'; -import { submit, waitAndUpdate } from '../../../helpers/testUtils'; - -it('should render correctly', () => { - const wrapper = shallow( - <ConfirmModal - confirmButtonText="confirm" - confirmData="data" - header="title" - onClose={jest.fn()} - onConfirm={jest.fn()}> - <p>My confirm message</p> - </ConfirmModal> - ); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('SimpleModal').dive()).toMatchSnapshot(); -}); - -it('should confirm and close after confirm', async () => { - const onClose = jest.fn(); - const onConfirm = jest.fn(() => Promise.resolve()); - const wrapper = shallow( - <ConfirmModal - confirmButtonText="confirm" - confirmData="data" - header="title" - onClose={onClose} - onConfirm={onConfirm}> - <p>My confirm message</p> - </ConfirmModal> - ); - const modalContent = wrapper.find('SimpleModal').dive(); - submit(modalContent.find('form')); - expect(onConfirm).toBeCalledWith('data'); - expect(modalContent.find('footer')).toMatchSnapshot(); - - await waitAndUpdate(wrapper); - expect(onClose).toHaveBeenCalled(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx index 714ea80472d..40d91a5a211 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx @@ -24,10 +24,10 @@ import * as setMonth from 'date-fns/set_month'; import * as setYear from 'date-fns/set_year'; import * as subDays from 'date-fns/sub_days'; import * as subMonths from 'date-fns/sub_months'; +import { parseDate } from 'sonar-ui-common/helpers/dates'; import DateInput from '../DateInput'; -import { parseDate } from '../../../helpers/dates'; -jest.mock('../../lazyLoad', () => ({ +jest.mock('sonar-ui-common/components/lazyLoad', () => ({ lazyLoad: () => { return function DayPicker() { return null; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/DateRangeInput-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/DateRangeInput-test.tsx index f4fd73a2bd7..f033c841e61 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/DateRangeInput-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/DateRangeInput-test.tsx @@ -19,8 +19,8 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; +import { parseDate } from 'sonar-ui-common/helpers/dates'; import DateRangeInput from '../DateRangeInput'; -import { parseDate } from '../../../helpers/dates'; const dateA = parseDate('2018-01-17T00:00:00.000Z'); const dateB = parseDate('2018-02-05T00:00:00.000Z'); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx deleted file mode 100644 index d7bf484d7f9..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Dropdown-test.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow, mount, ShallowWrapper } from 'enzyme'; -import Dropdown, { DropdownOverlay } from '../Dropdown'; -import { Button } from '../../ui/buttons'; -import { click } from '../../../helpers/testUtils'; -import { PopupPlacement } from '../../ui/popups'; - -describe('Dropdown', () => { - it('renders', () => { - expect( - shallow(<Dropdown overlay={<div id="overlay" />}>{() => <div />}</Dropdown>) - .find('div') - .exists() - ).toBeTruthy(); - }); - - it('toggles with element child', () => { - checkToggle( - shallow( - <Dropdown overlay={<div id="overlay" />}> - <Button /> - </Dropdown> - ) - ); - - checkToggle( - shallow( - <Dropdown overlay={<div id="overlay" />}> - <a href="#">click me!</a> - </Dropdown> - ), - 'a' - ); - }); - - it('toggles with render prop', () => { - checkToggle( - shallow( - <Dropdown overlay={<div id="overlay" />}> - {({ onToggleClick }) => <Button onClick={onToggleClick} />} - </Dropdown> - ) - ); - }); - - it('should call onOpen', () => { - const onOpen = jest.fn(); - const wrapper = mount( - <Dropdown onOpen={onOpen} overlay={<div id="overlay" />}> - <Button /> - </Dropdown> - ); - expect(onOpen).not.toBeCalled(); - click(wrapper.find('Button')); - expect(onOpen).toBeCalled(); - }); - - function checkToggle(wrapper: ShallowWrapper, selector = 'Button') { - expect(wrapper.state()).toEqual({ open: false }); - - click(wrapper.find(selector)); - expect(wrapper.state()).toEqual({ open: true }); - - click(wrapper.find(selector)); - expect(wrapper.state()).toEqual({ open: false }); - } -}); - -describe('DropdownOverlay', () => { - it('should render overlay with screen fixer', () => { - const wrapper = shallow( - <DropdownOverlay> - <div /> - </DropdownOverlay>, - // disable ScreenPositionFixer positioning - { disableLifecycleMethods: true } - ); - expect(wrapper.is('ScreenPositionFixer')).toBe(true); - expect(wrapper.dive().is('Popup')).toBe(true); - }); - - it('should render overlay without screen fixer', () => { - const wrapper = shallow( - <DropdownOverlay placement={PopupPlacement.BottomRight}> - <div /> - </DropdownOverlay> - ); - expect(wrapper.is('Popup')).toBe(true); - }); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx deleted file mode 100644 index 7368291c8c7..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/FavoriteBase-test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import FavoriteBase, { Props } from '../FavoriteBase'; -import { click } from '../../../helpers/testUtils'; - -it('should render favorite', () => { - const favorite = renderFavoriteBase({ favorite: true }); - expect(favorite).toMatchSnapshot(); -}); - -it('should render not favorite', () => { - const favorite = renderFavoriteBase({ favorite: false }); - expect(favorite).toMatchSnapshot(); -}); - -it('should add favorite', () => { - const addFavorite = jest.fn(() => Promise.resolve()); - const favorite = renderFavoriteBase({ favorite: false, addFavorite }); - click(favorite.find('ButtonLink')); - expect(addFavorite).toBeCalled(); -}); - -it('should remove favorite', () => { - const removeFavorite = jest.fn(() => Promise.resolve()); - const favorite = renderFavoriteBase({ favorite: true, removeFavorite }); - click(favorite.find('ButtonLink')); - expect(removeFavorite).toBeCalled(); -}); - -function renderFavoriteBase(props: Partial<Props> = {}) { - return shallow( - <FavoriteBase - addFavorite={jest.fn()} - favorite={true} - qualifier="TRK" - removeFavorite={jest.fn()} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/GlobalMessages-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/GlobalMessages-test.tsx deleted file mode 100644 index f4632492e35..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/GlobalMessages-test.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import GlobalMessages, { Props } from '../GlobalMessages'; - -it('should not render when no message', () => { - expect(shallowRender({ messages: [] }).type()).toBeNull(); -}); - -it('should render correctly with a message', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); - expect( - wrapper - .find('GlobalMessage') - .first() - .dive() - ).toMatchSnapshot(); -}); - -function shallowRender(props: Partial<Props> = {}) { - return shallow( - <GlobalMessages - closeGlobalMessage={jest.fn()} - messages={[ - { id: '1', level: 'ERROR', message: 'Test' }, - { id: '2', level: 'ERROR', message: 'Test 2' } - ]} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx index 899985011e2..b5e563f08ed 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/HomePageSelect-test.tsx @@ -19,9 +19,9 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; +import { click } from 'sonar-ui-common/helpers/testUtils'; import HomePageSelect from '../HomePageSelect'; import { setHomePage } from '../../../api/users'; -import { click } from '../../../helpers/testUtils'; import rootReducer, { getCurrentUser, Store } from '../../../store/rootReducer'; import configureStore from '../../../store/utils/configureStore'; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/InputValidationField-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/InputValidationField-test.tsx deleted file mode 100644 index 594f01d8373..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/InputValidationField-test.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import InputValidationField from '../InputValidationField'; - -it('should render correctly', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -function getWrapper(props = {}) { - return shallow( - <InputValidationField - description="Field description" - dirty={true} - disabled={false} - error="Bad formatting" - label="Foo field" - name="field" - onBlur={jest.fn()} - onChange={jest.fn()} - touched={true} - value="foo" - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx deleted file mode 100644 index 901cfb75637..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ListFooter-test.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import ListFooter, { Props } from '../ListFooter'; -import { click } from '../../../helpers/testUtils'; - -it('should render "3 of 5 shown"', () => { - const listFooter = shallowRender(); - expect(listFooter.text()).toContain('x_of_y_shown.3.5'); - expect(listFooter).toMatchSnapshot(); -}); - -it('should not render "show more"', () => { - const listFooter = shallowRender({ loadMore: undefined }); - expect(listFooter.find('a').length).toBe(0); -}); - -it('should not render "show more"', () => { - const listFooter = shallowRender({ count: 5 }); - expect(listFooter.find('a').length).toBe(0); -}); - -it('should "show more"', () => { - const loadMore = jest.fn(); - const listFooter = shallowRender({ loadMore }); - const link = listFooter.find('a'); - expect(link.length).toBe(1); - click(link); - expect(loadMore).toBeCalled(); -}); - -it('should render "reload" properly', () => { - const listFooter = shallowRender({ needReload: true }); - expect(listFooter).toMatchSnapshot(); - - const reload = jest.fn(); - - listFooter.setProps({ reload }); - expect(listFooter).toMatchSnapshot(); - - const link = listFooter.find('a'); - expect(link.length).toBe(1); - - click(link); - expect(reload).toBeCalled(); -}); - -it('should display spinner while loading', () => { - expect( - shallowRender({ loading: true }) - .find('DeferredSpinner') - .exists() - ).toBe(true); -}); - -function shallowRender(props: Partial<Props> = {}) { - return shallow(<ListFooter count={3} loadMore={jest.fn()} total={5} {...props} />); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ModalButton-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ModalButton-test.tsx deleted file mode 100644 index 0fde228795c..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ModalButton-test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import ModalButton from '../ModalButton'; -import { click } from '../../../helpers/testUtils'; - -it('should open/close modal', () => { - const wrapper = shallow( - <ModalButton modal={({ onClose }) => <button id="js-close" onClick={onClose} type="button" />}> - {({ onClick }) => <button id="js-open" onClick={onClick} type="button" />} - </ModalButton> - ); - - expect(wrapper.find('#js-open').exists()).toBeTruthy(); - expect(wrapper.find('#js-close').exists()).toBeFalsy(); - click(wrapper.find('#js-open')); - expect(wrapper.find('#js-close').exists()).toBeTruthy(); - click(wrapper.find('#js-close')); - expect(wrapper.find('#js-close').exists()).toBeFalsy(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ModalValidationField-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ModalValidationField-test.tsx deleted file mode 100644 index 4dec371480e..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ModalValidationField-test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import ModalValidationField from '../ModalValidationField'; - -it('should display the field without any error/validation', () => { - expect(getWrapper({ description: 'Describe Foo.', touched: false })).toMatchSnapshot(); - expect(getWrapper({ dirty: false })).toMatchSnapshot(); -}); - -it('should display the field as valid', () => { - expect(getWrapper({ error: undefined })).toMatchSnapshot(); -}); - -it('should display the field with an error', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -function getWrapper(props = {}) { - return shallow( - <ModalValidationField - dirty={true} - error="Is required" - label={<label>Foo</label>} - touched={true} - {...props}> - {({ className }) => <input className={className} type="text" />} - </ModalValidationField> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Radio-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Radio-test.tsx deleted file mode 100644 index a0f9eabdc8d..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Radio-test.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Radio from '../Radio'; -import { click } from '../../../helpers/testUtils'; - -it('should render and check', () => { - const onCheck = jest.fn(); - const value = 'value'; - const wrapper = shallow(<Radio checked={false} onCheck={onCheck} value={value} />); - expect(wrapper).toMatchSnapshot(); - - click(wrapper); - expect(onCheck).toBeCalledWith(value); - wrapper.setProps({ checked: true }); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/RadioCard-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/RadioCard-test.tsx deleted file mode 100644 index da11ea3458c..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/RadioCard-test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import RadioCard from '../RadioCard'; -import { click } from '../../../helpers/testUtils'; - -it('should render correctly', () => { - expect( - shallow( - <RadioCard recommended="Recommended for you" title="Radio Card" titleInfo="info"> - <div>content</div> - </RadioCard> - ) - ).toMatchSnapshot(); -}); - -it('should be actionable', () => { - const onClick = jest.fn(); - const wrapper = shallow( - <RadioCard onClick={onClick} title="Radio Card"> - <div>content</div> - </RadioCard> - ); - - expect(wrapper).toMatchSnapshot(); - click(wrapper); - wrapper.setProps({ selected: true, titleInfo: 'info' }); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/RadioToggle-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/RadioToggle-test.tsx deleted file mode 100644 index 18355b3c0f5..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/RadioToggle-test.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import RadioToggle from '../RadioToggle'; -import { change } from '../../../helpers/testUtils'; - -it('renders', () => { - expect(shallow(getSample())).toMatchSnapshot(); -}); - -it('calls onCheck', () => { - const onCheck = jest.fn(); - const wrapper = shallow(getSample({ onCheck })); - change(wrapper.find('input[value="two"]'), 'two'); - expect(onCheck).toBeCalledWith('two'); -}); - -it('accepts advanced options fields', () => { - expect( - shallow( - getSample({ - options: [ - { value: 'one', label: 'first', tooltip: 'foo' }, - { value: 'two', label: 'second', tooltip: 'bar', disabled: true } - ] - }) - ) - ).toMatchSnapshot(); -}); - -function getSample(props?: any) { - const options = [{ value: 'one', label: 'first' }, { value: 'two', label: 'second' }]; - return <RadioToggle name="sample" onCheck={() => true} options={options} {...props} />; -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/ScreenPositionFixer-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/ScreenPositionFixer-test.tsx deleted file mode 100644 index 9c97be57921..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/ScreenPositionFixer-test.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { mount } from 'enzyme'; -import ScreenPositionFixer from '../ScreenPositionFixer'; -import { resizeWindowTo, setNodeRect } from '../../../helpers/testUtils'; - -jest.mock('lodash', () => { - const lodash = require.requireActual('lodash'); - lodash.throttle = (fn: any) => () => fn(); - return lodash; -}); - -jest.mock('react-dom', () => ({ - findDOMNode: jest.fn() -})); - -beforeEach(() => { - setNodeRect({ left: 50, top: 50 }); - resizeWindowTo(1000, 1000); -}); - -it('should fix position', () => { - const renderer = jest.fn(() => <div />); - mount(<ScreenPositionFixer>{renderer}</ScreenPositionFixer>); - - setNodeRect({ left: 50, top: 50 }); - resizeWindowTo(75, 1000); - expect(renderer).toHaveBeenLastCalledWith({ leftFix: -29, topFix: 0 }); - - resizeWindowTo(1000, 75); - expect(renderer).toHaveBeenLastCalledWith({ leftFix: 0, topFix: -29 }); - - setNodeRect({ left: -10, top: 50 }); - resizeWindowTo(1000, 1000); - expect(renderer).toHaveBeenLastCalledWith({ leftFix: 14, topFix: 0 }); - - setNodeRect({ left: 50, top: -10 }); - resizeWindowTo(); - expect(renderer).toHaveBeenLastCalledWith({ leftFix: 0, topFix: 14 }); -}); - -it('should render two times', () => { - const renderer = jest.fn(() => <div />); - mount(<ScreenPositionFixer>{renderer}</ScreenPositionFixer>); - expect(renderer).toHaveBeenCalledTimes(2); - expect(renderer).toHaveBeenCalledWith({}); - expect(renderer).toHaveBeenLastCalledWith({ leftFix: 0, topFix: 0 }); -}); - -it('should re-position when `ready` turns to `true`', () => { - const renderer = jest.fn(() => <div />); - const wrapper = mount(<ScreenPositionFixer ready={false}>{renderer}</ScreenPositionFixer>); - expect(renderer).toHaveBeenCalledTimes(2); - wrapper.setProps({ ready: true }); - // 2 + 1 (props change) + 1 (new measurement) - expect(renderer).toHaveBeenCalledTimes(4); -}); - -it('should re-position when window is resized', () => { - const renderer = jest.fn(() => <div />); - const wrapper = mount(<ScreenPositionFixer>{renderer}</ScreenPositionFixer>); - expect(renderer).toHaveBeenCalledTimes(2); - - resizeWindowTo(); - // 2 + 1 (new measurement) - expect(renderer).toHaveBeenCalledTimes(3); - - wrapper.unmount(); - resizeWindowTo(); - expect(renderer).toHaveBeenCalledTimes(3); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/SearchBox-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/SearchBox-test.tsx deleted file mode 100644 index 940def409b0..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/SearchBox-test.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow, mount } from 'enzyme'; -import SearchBox from '../SearchBox'; -import { click, change } from '../../../helpers/testUtils'; - -jest.mock('lodash', () => { - const lodash = require.requireActual('lodash'); - const debounce = (fn: Function) => { - const debounced: any = (...args: any[]) => fn(...args); - debounced.cancel = jest.fn(); - return debounced; - }; - return Object.assign({}, lodash, { debounce }); -}); - -it('renders', () => { - const wrapper = shallow( - <SearchBox minLength={2} onChange={jest.fn()} placeholder="placeholder" value="foo" /> - ); - expect(wrapper).toMatchSnapshot(); -}); - -it('warns when input is too short', () => { - const wrapper = shallow( - <SearchBox minLength={2} onChange={jest.fn()} placeholder="placeholder" value="f" /> - ); - expect(wrapper.find('.search-box-note').exists()).toBeTruthy(); -}); - -it('shows clear button only when there is a value', () => { - const wrapper = shallow(<SearchBox onChange={jest.fn()} placeholder="placeholder" value="f" />); - expect(wrapper.find('.search-box-clear').exists()).toBeTruthy(); - wrapper.setProps({ value: '' }); - expect(wrapper.find('.search-box-clear').exists()).toBeFalsy(); -}); - -it('attaches ref', () => { - const ref = jest.fn(); - mount(<SearchBox innerRef={ref} onChange={jest.fn()} placeholder="placeholder" value="f" />); - expect(ref).toBeCalled(); - expect(ref.mock.calls[0][0]).toBeInstanceOf(HTMLInputElement); -}); - -it('resets', () => { - const onChange = jest.fn(); - const wrapper = shallow(<SearchBox onChange={onChange} placeholder="placeholder" value="f" />); - click(wrapper.find('.search-box-clear')); - expect(onChange).toBeCalledWith(''); -}); - -it('changes', () => { - const onChange = jest.fn(); - const wrapper = shallow(<SearchBox onChange={onChange} placeholder="placeholder" value="f" />); - change(wrapper.find('.search-box-input'), 'foo'); - expect(onChange).toBeCalledWith('foo'); -}); - -it('does not change when value is too short', () => { - const onChange = jest.fn(); - const wrapper = shallow( - <SearchBox minLength={3} onChange={onChange} placeholder="placeholder" value="" /> - ); - change(wrapper.find('.search-box-input'), 'fo'); - expect(onChange).not.toBeCalled(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx deleted file mode 100644 index 36fa5e1093a..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/SimpleModal-test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import SimpleModal, { ChildrenProps } from '../SimpleModal'; -import { Button } from '../../ui/buttons'; -import { click, waitAndUpdate } from '../../../helpers/testUtils'; - -it('renders', () => { - const inner = () => <div />; - expect( - shallow( - <SimpleModal header="" onClose={jest.fn()} onSubmit={jest.fn()}> - {inner} - </SimpleModal> - ) - ).toMatchSnapshot(); -}); - -it('closes', () => { - const onClose = jest.fn(); - const inner = ({ onCloseClick }: ChildrenProps) => <Button onClick={onCloseClick}>close</Button>; - const wrapper = shallow( - <SimpleModal header="" onClose={onClose} onSubmit={jest.fn()}> - {inner} - </SimpleModal> - ); - click(wrapper.find('Button')); - expect(onClose).toBeCalled(); -}); - -it('submits', async () => { - const onSubmit = jest.fn(() => Promise.resolve()); - const inner = ({ onSubmitClick, submitting }: ChildrenProps) => ( - <Button disabled={submitting} onClick={onSubmitClick}> - close - </Button> - ); - const wrapper = shallow( - <SimpleModal header="" onClose={jest.fn()} onSubmit={onSubmit}> - {inner} - </SimpleModal> - ); - (wrapper.instance() as SimpleModal).mounted = true; - expect(wrapper).toMatchSnapshot(); - - click(wrapper.find('Button')); - expect(onSubmit).toBeCalled(); - expect(wrapper).toMatchSnapshot(); - - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Tabs-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Tabs-test.tsx deleted file mode 100644 index 89ca62b4345..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Tabs-test.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Tabs, { Tab } from '../Tabs'; -import { click } from '../../../helpers/testUtils'; - -it('should render correctly', () => { - const wrapper = shallow( - <Tabs - onChange={jest.fn()} - selected={'bar'} - tabs={[{ key: 'foo', node: 'Foo' }, { key: 'bar', node: 'Bar' }]} - /> - ); - - expect(wrapper).toMatchSnapshot(); -}); - -it('should switch tabs', () => { - const onChange = jest.fn(); - const wrapper = shallow( - <Tabs - onChange={onChange} - selected={'bar'} - tabs={[{ key: 'foo', node: 'Foo' }, { key: 'bar', node: 'Bar' }]} - /> - ); - - click(shallow(wrapper.find('Tab').get(0)).find('.js-foo')); - expect(onChange).toBeCalledWith('foo'); - click(shallow(wrapper.find('Tab').get(1)).find('.js-bar')); - expect(onChange).toBeCalledWith('bar'); -}); - -it('should render single tab correctly', () => { - const onSelect = jest.fn(); - const wrapper = shallow( - <Tab name="foo" onSelect={onSelect} selected={true}> - <span>Foo</span> - </Tab> - ); - expect(wrapper).toMatchSnapshot(); - click(wrapper.find('a')); - expect(onSelect).toBeCalledWith('foo'); -}); - -it('should disable single tab', () => { - const onSelect = jest.fn(); - const wrapper = shallow( - <Tab disabled={true} name="foo" onSelect={onSelect} selected={true}> - <span>Foo</span> - </Tab> - ); - expect(wrapper).toMatchSnapshot(); - click(wrapper.find('a')); - expect(onSelect).not.toBeCalled(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx deleted file mode 100644 index 4f805453025..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Toggle-test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Toggle, { Props } from '../Toggle'; -import { click } from '../../../helpers/testUtils'; - -it('should render', () => { - const Toggle = shallowRender(); - expect(Toggle.is('Button')).toBe(true); -}); - -it('should call onChange', () => { - const onChange = jest.fn(); - const Toggle = shallowRender({ onChange }); - click(Toggle); - expect(onChange).toBeCalledWith(false); -}); - -function shallowRender(props?: Partial<Props>) { - return shallow(<Toggle onChange={() => true} value={true} {...props} />); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Toggler-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Toggler-test.tsx deleted file mode 100644 index a0f747c51c6..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Toggler-test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Toggler, { Props } from '../Toggler'; -import { keydown } from '../../../helpers/testUtils'; - -it('should render only children', () => { - expect(shallowRender({ open: false })).toMatchSnapshot(); -}); - -it('should render children and overlay', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('should render when closeOnClick=true', () => { - expect(shallowRender({ closeOnClick: true })).toMatchSnapshot(); -}); - -it('should not render click wrappers', () => { - expect(shallowRender({ closeOnClick: false, closeOnClickOutside: false })).toMatchSnapshot(); -}); - -it('should close on escape', () => { - const onRequestClose = jest.fn(); - const wrapper = shallowRender({ - closeOnClick: false, - closeOnClickOutside: false, - onRequestClose - }); - keydown(27); - expect(onRequestClose).toHaveBeenCalledTimes(1); - - wrapper.setProps({ closeOnEscape: false }); - keydown(27); - expect(onRequestClose).toHaveBeenCalledTimes(1); - - wrapper.setProps({ open: false }); - wrapper.setProps({ closeOnEscape: true, open: true }); - keydown(27); - expect(onRequestClose).toHaveBeenCalledTimes(2); - - wrapper.unmount(); - keydown(27); - expect(onRequestClose).toHaveBeenCalledTimes(2); -}); - -function shallowRender(props?: Partial<Props>) { - return shallow( - <Toggler onRequestClose={jest.fn()} open={true} overlay={<div id="overlay" />} {...props}> - <div id="toggle" /> - </Toggler> - ); -} diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx deleted file mode 100644 index 46ef24037ea..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Tooltip, { TooltipInner } from '../Tooltip'; - -jest.useFakeTimers(); -jest.mock('react-dom', () => { - const actual = require.requireActual('react-dom'); - return Object.assign({}, actual, { - findDOMNode: () => undefined - }); -}); - -it('should render', () => { - expect( - shallow( - <TooltipInner overlay={<span id="overlay" />} visible={false}> - <div id="tooltip" /> - </TooltipInner> - ) - ).toMatchSnapshot(); - expect( - shallow( - <TooltipInner overlay={<span id="overlay" />} visible={true}> - <div id="tooltip" /> - </TooltipInner>, - { disableLifecycleMethods: true } - ) - ).toMatchSnapshot(); -}); - -it('should open & close', () => { - const onShow = jest.fn(); - const onHide = jest.fn(); - const wrapper = shallow( - <TooltipInner onHide={onHide} onShow={onShow} overlay={<span id="overlay" />}> - <div id="tooltip" /> - </TooltipInner> - ); - wrapper.find('#tooltip').simulate('mouseenter'); - jest.runOnlyPendingTimers(); - wrapper.update(); - expect(wrapper.find('TooltipPortal').exists()).toBe(true); - expect(onShow).toBeCalled(); - - wrapper.find('#tooltip').simulate('mouseleave'); - jest.runOnlyPendingTimers(); - wrapper.update(); - expect(wrapper.find('TooltipPortal').exists()).toBe(false); - expect(onHide).toBeCalled(); -}); - -it('should not open when mouse goes away quickly', () => { - const onShow = jest.fn(); - const onHide = jest.fn(); - const wrapper = shallow( - <TooltipInner onHide={onHide} onShow={onShow} overlay={<span id="overlay" />}> - <div id="tooltip" /> - </TooltipInner> - ); - - wrapper.find('#tooltip').simulate('mouseenter'); - wrapper.find('#tooltip').simulate('mouseleave'); - jest.runOnlyPendingTimers(); - wrapper.update(); - - expect(wrapper.find('TooltipPortal').exists()).toBe(false); -}); - -it('should not render tooltip without overlay', () => { - const wrapper = shallow( - <Tooltip overlay={undefined}> - <div id="tooltip" /> - </Tooltip> - ); - expect(wrapper.type()).toBe('div'); -}); - -it('should not render empty tooltips', () => { - expect( - shallow( - <Tooltip overlay={undefined} visible={true}> - <div id="tooltip" /> - </Tooltip> - ) - ).toMatchSnapshot(); - expect( - shallow( - <Tooltip overlay="" visible={true}> - <div id="tooltip" /> - </Tooltip> - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Checkbox-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Checkbox-test.tsx.snap deleted file mode 100644 index 69c0c60af8c..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Checkbox-test.tsx.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render 1`] = ` -<a - aria-checked={true} - className="icon-checkbox icon-checkbox-checked" - href="#" - onClick={[Function]} - role="checkbox" - title="Title value" -/> -`; - -exports[`should render the checkbox on the right 1`] = ` -<a - aria-checked={true} - className="icon-checkbox icon-checkbox-checked" - href="#" - onClick={[Function]} - role="checkbox" -/> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap deleted file mode 100644 index 3c0c80d0958..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ClipboardButton-test.tsx.snap +++ /dev/null @@ -1,61 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display correctly 1`] = ` -<Tooltip - overlay="copied_action" - visible={false} -> - <Button - className="no-select" - data-clipboard-text="foo" - innerRef={[Function]} - > - copy - </Button> -</Tooltip> -`; - -exports[`should display correctly 2`] = ` -<Tooltip - overlay="copied_action" - visible={true} -> - <Button - className="no-select" - data-clipboard-text="foo" - innerRef={[Function]} - > - copy - </Button> -</Tooltip> -`; - -exports[`should display correctly 3`] = ` -<Tooltip - overlay="copied_action" - visible={false} -> - <Button - className="no-select" - data-clipboard-text="foo" - innerRef={[Function]} - > - copy - </Button> -</Tooltip> -`; - -exports[`should render a custom label if provided 1`] = ` -<Tooltip - overlay="copied_action" - visible={false} -> - <Button - className="no-select" - data-clipboard-text="foo" - innerRef={[Function]} - > - Foo Bar - </Button> -</Tooltip> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ConfirmButton-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ConfirmButton-test.tsx.snap deleted file mode 100644 index f94c3829503..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ConfirmButton-test.tsx.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display a confirm modal 1`] = ` -<ConfirmModal - confirmButtonText="submit" - header="title" - onClose={[MockFunction]} - onConfirm={[MockFunction]} -> - <div /> -</ConfirmModal> -`; - -exports[`should display a modal button 1`] = ` -<ModalButton - modal={[Function]} -> - <Component /> -</ModalButton> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ConfirmModal-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ConfirmModal-test.tsx.snap deleted file mode 100644 index 709b6ecd2a5..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ConfirmModal-test.tsx.snap +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should confirm and close after confirm 1`] = ` -<footer - className="modal-foot" -> - <DeferredSpinner - className="spacer-right" - loading={true} - timeout={100} - /> - <SubmitButton - autoFocus={true} - disabled={true} - > - confirm - </SubmitButton> - <ResetButtonLink - disabled={true} - onClick={[Function]} - > - cancel - </ResetButtonLink> -</footer> -`; - -exports[`should render correctly 1`] = ` -<SimpleModal - header="title" - onClose={[MockFunction]} - onSubmit={[Function]} -> - <Component /> -</SimpleModal> -`; - -exports[`should render correctly 2`] = ` -<Modal - contentLabel="title" - onRequestClose={[MockFunction]} -> - <form - onSubmit={[Function]} - > - <header - className="modal-head" - > - <h2> - title - </h2> - </header> - <div - className="modal-body" - > - <p> - My confirm message - </p> - </div> - <footer - className="modal-foot" - > - <DeferredSpinner - className="spacer-right" - loading={false} - timeout={100} - /> - <SubmitButton - autoFocus={true} - > - confirm - </SubmitButton> - <ResetButtonLink - disabled={false} - onClick={[Function]} - > - cancel - </ResetButtonLink> - </footer> - </form> -</Modal> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap deleted file mode 100644 index 22815684de0..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/FavoriteBase-test.tsx.snap +++ /dev/null @@ -1,33 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render favorite 1`] = ` -<Tooltip - overlay="favorite.current.TRK" -> - <ButtonLink - aria-label="favorite.action.remove" - className="favorite-link link-no-underline" - onClick={[Function]} - > - <FavoriteIcon - favorite={true} - /> - </ButtonLink> -</Tooltip> -`; - -exports[`should render not favorite 1`] = ` -<Tooltip - overlay="favorite.check.TRK" -> - <ButtonLink - aria-label="favorite.action.add" - className="favorite-link link-no-underline" - onClick={[Function]} - > - <FavoriteIcon - favorite={false} - /> - </ButtonLink> -</Tooltip> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/GlobalMessages-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/GlobalMessages-test.tsx.snap deleted file mode 100644 index cf1235d7cd2..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/GlobalMessages-test.tsx.snap +++ /dev/null @@ -1,44 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly with a message 1`] = ` -<div - className="processes-container" -> - <GlobalMessage - closeGlobalMessage={[MockFunction]} - key="1" - message={ - Object { - "id": "1", - "level": "ERROR", - "message": "Test", - } - } - /> - <GlobalMessage - closeGlobalMessage={[MockFunction]} - key="2" - message={ - Object { - "id": "2", - "level": "ERROR", - "message": "Test 2", - } - } - /> -</div> -`; - -exports[`should render correctly with a message 2`] = ` -<div - className="process-spinner shown process-spinner-failed" - key="1" -> - Test - <ClearButton - className="button-small process-spinner-close" - color="#fff" - onClick={[Function]} - /> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/InputValidationField-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/InputValidationField-test.tsx.snap deleted file mode 100644 index 16f3e1c2dfa..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/InputValidationField-test.tsx.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -<ModalValidationField - description="Field description" - dirty={true} - error="Bad formatting" - label="Foo field" - touched={true} -> - <Component /> -</ModalValidationField> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ListFooter-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ListFooter-test.tsx.snap deleted file mode 100644 index c2aa7f064fe..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ListFooter-test.tsx.snap +++ /dev/null @@ -1,46 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render "3 of 5 shown" 1`] = ` -<footer - className="spacer-top note text-center" -> - x_of_y_shown.3.5 - <a - className="spacer-left" - href="#" - onClick={[Function]} - > - show_more - </a> -</footer> -`; - -exports[`should render "reload" properly 1`] = ` -<footer - className="spacer-top note text-center" -> - x_of_y_shown.3.5 - <a - className="spacer-left" - href="#" - onClick={[Function]} - > - show_more - </a> -</footer> -`; - -exports[`should render "reload" properly 2`] = ` -<footer - className="spacer-top note text-center" -> - x_of_y_shown.3.5 - <a - className="spacer-left" - href="#" - onClick={[Function]} - > - reload - </a> -</footer> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ModalValidationField-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ModalValidationField-test.tsx.snap deleted file mode 100644 index 4b4e605c0ad..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ModalValidationField-test.tsx.snap +++ /dev/null @@ -1,73 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the field as valid 1`] = ` -<div - className="modal-validation-field" -> - <label> - Foo - </label> - <input - className="is-valid" - type="text" - /> - <AlertSuccessIcon - className="little-spacer-top" - /> -</div> -`; - -exports[`should display the field with an error 1`] = ` -<div - className="modal-validation-field" -> - <label> - Foo - </label> - <input - className="is-invalid" - type="text" - /> - <AlertErrorIcon - className="little-spacer-top" - /> - <p - className="text-danger" - > - Is required - </p> -</div> -`; - -exports[`should display the field without any error/validation 1`] = ` -<div - className="modal-validation-field" -> - <label> - Foo - </label> - <input - className="" - type="text" - /> - <div - className="modal-field-description" - > - Describe Foo. - </div> -</div> -`; - -exports[`should display the field without any error/validation 2`] = ` -<div - className="modal-validation-field" -> - <label> - Foo - </label> - <input - className="" - type="text" - /> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Radio-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Radio-test.tsx.snap deleted file mode 100644 index cd6bc65b080..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Radio-test.tsx.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render and check 1`] = ` -<a - aria-checked={false} - className="display-inline-flex-center link-checkbox" - href="#" - onClick={[Function]} - role="radio" -> - <i - className="icon-radio spacer-right" - /> -</a> -`; - -exports[`should render and check 2`] = ` -<a - aria-checked={true} - className="display-inline-flex-center link-checkbox" - href="#" - onClick={[Function]} - role="radio" -> - <i - className="icon-radio spacer-right is-checked" - /> -</a> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/RadioCard-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/RadioCard-test.tsx.snap deleted file mode 100644 index 3013f367162..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/RadioCard-test.tsx.snap +++ /dev/null @@ -1,128 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should be actionable 1`] = ` -<div - className="radio-card radio-card-actionable" - onClick={[MockFunction]} - role="radio" - tabIndex={0} -> - <h2 - className="radio-card-header big-spacer-bottom" - > - <span - className="display-flex-center" - > - <i - className="icon-radio spacer-right" - /> - Radio Card - </span> - </h2> - <div - className="radio-card-body" - > - <div> - content - </div> - </div> -</div> -`; - -exports[`should be actionable 2`] = ` -<div - aria-checked={true} - className="radio-card radio-card-actionable selected" - onClick={ - [MockFunction] { - "calls": Array [ - Array [ - Object { - "currentTarget": Object { - "blur": [Function], - }, - "preventDefault": [Function], - "stopPropagation": [Function], - "target": Object { - "blur": [Function], - }, - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - } - } - role="radio" - tabIndex={0} -> - <h2 - className="radio-card-header big-spacer-bottom" - > - <span - className="display-flex-center" - > - <i - className="icon-radio spacer-right is-checked" - /> - Radio Card - </span> - info - </h2> - <div - className="radio-card-body" - > - <div> - content - </div> - </div> -</div> -`; - -exports[`should render correctly 1`] = ` -<div - className="radio-card" - role="radio" - tabIndex={0} -> - <h2 - className="radio-card-header big-spacer-bottom" - > - <span - className="display-flex-center" - > - Radio Card - </span> - info - </h2> - <div - className="radio-card-body" - > - <div> - content - </div> - </div> - <div - className="radio-card-recommended" - > - <RecommendedIcon - className="spacer-right" - /> - <FormattedMessage - defaultMessage="Recommended for you" - id="Recommended for you" - values={ - Object { - "recommended": <strong> - recommended - </strong>, - } - } - /> - </div> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/RadioToggle-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/RadioToggle-test.tsx.snap deleted file mode 100644 index bfc31e1a9e6..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/RadioToggle-test.tsx.snap +++ /dev/null @@ -1,96 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`accepts advanced options fields 1`] = ` -<ul - className="radio-toggle" -> - <li - key="one" - > - <input - checked={false} - id="sample__one" - name="sample" - onChange={[Function]} - type="radio" - value="one" - /> - <Tooltip - overlay="foo" - > - <label - htmlFor="sample__one" - > - first - </label> - </Tooltip> - </li> - <li - key="two" - > - <input - checked={false} - disabled={true} - id="sample__two" - name="sample" - onChange={[Function]} - type="radio" - value="two" - /> - <Tooltip - overlay="bar" - > - <label - htmlFor="sample__two" - > - second - </label> - </Tooltip> - </li> -</ul> -`; - -exports[`renders 1`] = ` -<ul - className="radio-toggle" -> - <li - key="one" - > - <input - checked={false} - id="sample__one" - name="sample" - onChange={[Function]} - type="radio" - value="one" - /> - <Tooltip> - <label - htmlFor="sample__one" - > - first - </label> - </Tooltip> - </li> - <li - key="two" - > - <input - checked={false} - id="sample__two" - name="sample" - onChange={[Function]} - type="radio" - value="two" - /> - <Tooltip> - <label - htmlFor="sample__two" - > - second - </label> - </Tooltip> - </li> -</ul> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap deleted file mode 100644 index 3a61b8d4358..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SearchBox-test.tsx.snap +++ /dev/null @@ -1,37 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<div - className="search-box" - title="" -> - <input - aria-label="search_verb" - autoComplete="off" - className="search-box-input" - maxLength={100} - onChange={[Function]} - onKeyDown={[Function]} - placeholder="placeholder" - type="search" - value="foo" - /> - <DeferredSpinner - loading={false} - timeout={100} - > - <SearchIcon - className="search-box-magnifier" - /> - </DeferredSpinner> - <ClearButton - className="button-tiny search-box-clear" - iconProps={ - Object { - "size": 12, - } - } - onClick={[Function]} - /> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap deleted file mode 100644 index 49b14a9e20f..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/SimpleModal-test.tsx.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<Modal - contentLabel="" - onRequestClose={[MockFunction]} -> - <div /> -</Modal> -`; - -exports[`submits 1`] = ` -<Modal - contentLabel="" - onRequestClose={[MockFunction]} -> - <Button - disabled={false} - onClick={[Function]} - > - close - </Button> -</Modal> -`; - -exports[`submits 2`] = ` -<Modal - contentLabel="" - onRequestClose={[MockFunction]} -> - <Button - disabled={true} - onClick={[Function]} - > - close - </Button> -</Modal> -`; - -exports[`submits 3`] = ` -<Modal - contentLabel="" - onRequestClose={[MockFunction]} -> - <Button - disabled={false} - onClick={[Function]} - > - close - </Button> -</Modal> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tabs-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tabs-test.tsx.snap deleted file mode 100644 index 2db4cec05a8..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tabs-test.tsx.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should disable single tab 1`] = ` -<li> - <a - className="js-foo disabled selected" - href="#" - onClick={[Function]} - > - <span> - Foo - </span> - </a> -</li> -`; - -exports[`should render correctly 1`] = ` -<ul - className="flex-tabs" -> - <Tab - key="foo" - name="foo" - onSelect={[MockFunction]} - selected={false} - > - Foo - </Tab> - <Tab - key="bar" - name="bar" - onSelect={[MockFunction]} - selected={true} - > - Bar - </Tab> -</ul> -`; - -exports[`should render single tab correctly 1`] = ` -<li> - <a - className="js-foo selected" - href="#" - onClick={[Function]} - > - <span> - Foo - </span> - </a> -</li> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggler-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggler-test.tsx.snap deleted file mode 100644 index 727c0c70559..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Toggler-test.tsx.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should not render click wrappers 1`] = ` -<Fragment> - <div - id="toggle" - /> - <div - id="overlay" - /> -</Fragment> -`; - -exports[`should render children and overlay 1`] = ` -<Fragment> - <div - id="toggle" - /> - <OutsideClickHandler - onClickOutside={[MockFunction]} - > - <div - id="overlay" - /> - </OutsideClickHandler> -</Fragment> -`; - -exports[`should render only children 1`] = ` -<Fragment> - <div - id="toggle" - /> -</Fragment> -`; - -exports[`should render when closeOnClick=true 1`] = ` -<Fragment> - <div - id="toggle" - /> - <DocumentClickHandler - onClick={[MockFunction]} - > - <div - id="overlay" - /> - </DocumentClickHandler> -</Fragment> -`; diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap deleted file mode 100644 index de3df03b6e5..00000000000 --- a/server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap +++ /dev/null @@ -1,40 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should not render empty tooltips 1`] = ` -<div - id="tooltip" -/> -`; - -exports[`should not render empty tooltips 2`] = ` -<div - id="tooltip" -/> -`; - -exports[`should render 1`] = ` -<Fragment> - <div - id="tooltip" - onMouseEnter={[Function]} - onMouseLeave={[Function]} - /> -</Fragment> -`; - -exports[`should render 2`] = ` -<Fragment> - <div - id="tooltip" - onMouseEnter={[Function]} - onMouseLeave={[Function]} - /> - <TooltipPortal> - <ScreenPositionFixer - ready={false} - > - <Component /> - </ScreenPositionFixer> - </TooltipPortal> -</Fragment> -`; diff --git a/server/sonar-web/src/main/js/components/controls/styles.css b/server/sonar-web/src/main/js/components/controls/styles.css index 15baab3a649..2f2f4aaccfe 100644 --- a/server/sonar-web/src/main/js/components/controls/styles.css +++ b/server/sonar-web/src/main/js/components/controls/styles.css @@ -80,67 +80,3 @@ .date-input-calender-month-select { width: 70px; } - -.button.boolean-toggle { - display: inline-block; - vertical-align: middle; - width: 48px; - height: var(--controlHeight); - padding: 1px; - border: 1px solid var(--gray80); - border-radius: var(--controlHeight); - box-sizing: border-box; - background-color: #fff; - cursor: pointer; - transition: all 0.3s ease; -} - -.button.boolean-toggle:hover { - background-color: #fff; -} - -.button.boolean-toggle:focus { - border-color: var(--blue); - background-color: #f6f6f6; -} - -.boolean-toggle-handle { - display: flex; - justify-content: center; - align-items: center; - width: 20px; - height: 20px; - border: 1px solid var(--gray80); - border-radius: 22px; - box-sizing: border-box; - background-color: #f6f6f6; - transition: transform 0.3s cubic-bezier(0.87, -0.41, 0.19, 1.44), border 0.3s ease; -} - -.boolean-toggle-handle > * { - opacity: 0; - transition: opacity 0.3s ease; -} - -.button.boolean-toggle-on { - border-color: var(--darkBlue); - background-color: var(--darkBlue); - color: var(--darkBlue); -} - -.button.boolean-toggle-on:hover { - background-color: var(--darkBlue); -} - -.button.boolean-toggle-on:focus { - background-color: var(--darkBlue); -} - -.button.boolean-toggle-on .boolean-toggle-handle { - border-color: #f6f6f6; - transform: translateX(var(--controlHeight)); -} - -.button.boolean-toggle-on .boolean-toggle-handle > * { - opacity: 1; -} |