+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import Checkbox from '../../../components/controls/Checkbox';
-import CheckIcon from '../../../components/icons-components/CheckIcon';
-import PluginUpdateButton from './PluginUpdateButton';
-import { Plugin, installPlugin, updatePlugin, uninstallPlugin } from '../../../api/plugins';
-import { isPluginAvailable, isPluginInstalled } from '../utils';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- plugin: Plugin;
- refreshPending: () => void;
-}
-
-interface State {
- acceptTerms: boolean;
- loading: boolean;
-}
-
-export default class PluginActions extends React.PureComponent<Props, State> {
- mounted: boolean;
- state: State = { acceptTerms: false, loading: false };
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- doPluginAction = (apiAction: (data: { key: string }) => Promise<void | Response>) => {
- this.setState({ loading: true });
- apiAction({ key: this.props.plugin.key }).then(
- () => {
- this.props.refreshPending();
- if (this.mounted) {
- this.setState({ loading: false });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- handleInstall = () => this.doPluginAction(installPlugin);
- handleUpdate = () => this.doPluginAction(updatePlugin);
- handleUninstall = () => this.doPluginAction(uninstallPlugin);
- handleTermsCheck = (checked: boolean) => this.setState({ acceptTerms: checked });
-
- render() {
- const { plugin } = this.props;
- const { loading } = this.state;
-
- if (plugin.editionBundled) {
- return (
- <div className="js-actions">
- {isPluginAvailable(plugin) && (
- <div>
- <p className="little-spacer-bottom">
- {translate('marketplace.available_under_commercial_license')}
- </p>
- <a href={plugin.homepageUrl} target="_blank">
- {translate('marketplace.learn_more')}
- </a>
- </div>
- )}
- {isPluginInstalled(plugin) && (
- <p>
- <CheckIcon className="little-spacer-right" />
- {translate('marketplace.installed')}
- </p>
- )}
- {isPluginInstalled(plugin) &&
- plugin.updates &&
- plugin.updates.length > 0 && (
- <div className="spacer-top button-group">
- {plugin.updates.map((update, idx) => (
- <PluginUpdateButton
- key={idx}
- onClick={this.handleUpdate}
- update={update}
- disabled={loading}
- />
- ))}
- </div>
- )}
- </div>
- );
- }
-
- return (
- <div className="js-actions">
- {isPluginAvailable(plugin) &&
- plugin.termsAndConditionsUrl && (
- <p className="little-spacer-bottom">
- <Checkbox
- checked={this.state.acceptTerms}
- className="js-terms"
- id={'plugin-terms-' + plugin.key}
- onCheck={this.handleTermsCheck}>
- <label className="little-spacer-left" htmlFor={'plugin-terms-' + plugin.key}>
- {translate('marketplace.i_accept_the')}
- </label>
- </Checkbox>
- <a
- className="js-plugin-terms nowrap little-spacer-left"
- href={plugin.termsAndConditionsUrl}
- target="_blank">
- {translate('marketplace.terms_and_conditions')}
- </a>
- </p>
- )}
- {loading && <i className="spinner spacer-right" />}
- {isPluginInstalled(plugin) && (
- <div className="button-group">
- {plugin.updates &&
- plugin.updates.map((update, idx) => (
- <PluginUpdateButton
- key={idx}
- onClick={this.handleUpdate}
- update={update}
- disabled={loading}
- />
- ))}
- <button
- className="js-uninstall button-red"
- disabled={loading}
- onClick={this.handleUninstall}>
- {translate('marketplace.uninstall')}
- </button>
- </div>
- )}
- {isPluginAvailable(plugin) && (
- <button
- className="js-install"
- disabled={loading || (plugin.termsAndConditionsUrl != null && !this.state.acceptTerms)}
- onClick={this.handleInstall}>
- {translate('marketplace.install')}
- </button>
- )}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import PluginChangeLogButton from './PluginChangeLogButton';
-import PluginDescription from './PluginDescription';
-import PluginLicense from './PluginLicense';
-import PluginOrganization from './PluginOrganization';
-import PluginStatus from './PluginStatus';
-import PluginUrls from './PluginUrls';
-import { PluginAvailable } from '../../api/plugins';
-import { translateWithParameters } from '../../helpers/l10n';
-import { Query } from './utils';
-
-interface Props {
- plugin: PluginAvailable;
- refreshPending: () => void;
- status?: string;
- updateQuery: (newQuery: Partial<Query>) => void;
-}
-
-export default function PluginAvailable({ plugin, refreshPending, status, updateQuery }: Props) {
- return (
- <tr>
- <PluginDescription plugin={plugin} updateQuery={updateQuery} />
- <td className="text-top big-spacer-right">
- <ul>
- <li className="diplay-flex-row little-spacer-bottom">
- <div className="pull-left spacer-right">
- <span className="badge badge-success">{plugin.release.version}</span>
- </div>
- <div>
- {plugin.release.description}
- <PluginChangeLogButton release={plugin.release} update={plugin.update} />
- {plugin.update.requires.length > 0 && (
- <p className="little-spacer-top">
- <strong>
- {translateWithParameters(
- 'marketplace.installing_this_plugin_will_also_install_x',
- plugin.update.requires.map(requiredPlugin => requiredPlugin.name).join(', ')
- )}
- </strong>
- </p>
- )}
- </div>
- </li>
- </ul>
- </td>
-
- <td className="text-top width-20 big-spacer-right">
- <ul>
- <PluginUrls plugin={plugin} />
- <PluginLicense license={plugin.license} />
- <PluginOrganization plugin={plugin} />
- </ul>
- </td>
-
- <PluginStatus plugin={plugin} status={status} refreshPending={refreshPending} />
- </tr>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import BubblePopup from '../../components/common/BubblePopup';
-import PluginChangeLogItem from './PluginChangeLogItem';
-import { Release, Update } from '../../api/plugins';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- popupPosition?: any;
- release: Release;
- update: Update;
-}
-
-export default function PluginChangeLog({ popupPosition, release, update }: Props) {
- return (
- <BubblePopup position={popupPosition} customClass="bubble-popup-bottom-right">
- <div className="abs-width-300 bubble-popup-container">
- <div className="bubble-popup-title">{translate('changelog')}</div>
- <ul className="js-plugin-changelog-list">
- {update.previousUpdates &&
- update.previousUpdates.map(
- previousUpdate =>
- previousUpdate.release ? (
- <PluginChangeLogItem
- key={previousUpdate.release.version}
- release={previousUpdate.release}
- update={previousUpdate}
- />
- ) : null
- )}
- <PluginChangeLogItem release={release} update={update} />
- </ul>
- </div>
- </BubblePopup>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import BubblePopupHelper from '../../components/common/BubblePopupHelper';
-import PluginChangeLog from './PluginChangeLog';
-import { Release, Update } from '../../api/plugins';
-
-interface Props {
- release: Release;
- update: Update;
-}
-
-interface State {
- changelogOpen: boolean;
-}
-
-export default class PluginChangeLogButton extends React.PureComponent<Props, State> {
- state: State = { changelogOpen: false };
-
- handleChangelogClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.stopPropagation();
- this.toggleChangelog();
- };
-
- toggleChangelog = (show?: boolean) => {
- if (show !== undefined) {
- this.setState({ changelogOpen: show });
- } else {
- this.setState(state => ({ changelogOpen: !state.changelogOpen }));
- }
- };
-
- render() {
- return (
- <div className="display-inline-block little-spacer-left">
- <button
- className="button-link js-changelog issue-rule icon-ellipsis-h"
- onClick={this.handleChangelogClick}
- />
- <BubblePopupHelper
- isOpen={this.state.changelogOpen}
- position="bottomright"
- popup={<PluginChangeLog release={this.props.release} update={this.props.update} />}
- togglePopup={this.toggleChangelog}
- />
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import DateFormatter from '../../components/intl/DateFormatter';
-import Tooltip from '../../components/controls/Tooltip';
-import { Release, Update } from '../../api/plugins';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-
-interface Props {
- release: Release;
- update: Update;
-}
-
-export default function PluginChangeLogItem({ release, update }: Props) {
- return (
- <li className="big-spacer-bottom">
- <div className="little-spacer-bottom">
- {update.status === 'COMPATIBLE' || !update.status ? (
- <span className="js-plugin-changelog-version badge badge-success spacer-right">
- {release.version}
- </span>
- ) : (
- <Tooltip overlay={translateWithParameters('marketplace.status', update.status)}>
- <span className="js-plugin-changelog-version badge badge-warning spacer-right">
- {release.version}
- </span>
- </Tooltip>
- )}
- <span className="js-plugin-changelog-date note spacer-right">
- <DateFormatter date={release.date} />
- </span>
- {release.changeLogUrl && (
- <a className="js-plugin-changelog-link" href={release.changeLogUrl} target="_blank">
- {translate('update_center.release_notes')}
- </a>
- )}
- </div>
- <div className="js-plugin-changelog-description">{release.description}</div>
- </li>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Plugin } from '../../api/plugins';
-import { Query } from './utils';
-
-interface Props {
- plugin: Plugin;
- updateQuery: (newQuery: Partial<Query>) => void;
-}
-
-export default class PluginDescription extends React.PureComponent<Props> {
- handleCategoryClick = (e: React.SyntheticEvent<HTMLAnchorElement>) => {
- e.preventDefault();
- this.props.updateQuery({ search: this.props.plugin.category });
- };
-
- render() {
- const { plugin } = this.props;
- return (
- <td className="text-top width-20 big-spacer-right">
- <div>
- <strong className="js-plugin-name">{plugin.name}</strong>
- {plugin.category && (
- <a
- className="js-plugin-category badge spacer-left"
- href="#"
- onClick={this.handleCategoryClick}>
- {plugin.category}
- </a>
- )}
- </div>
- <div className="js-plugin-description little-spacer-top">{plugin.description}</div>
- </td>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import PluginDescription from './PluginDescription';
-import PluginLicense from './PluginLicense';
-import PluginOrganization from './PluginOrganization';
-import PluginStatus from './PluginStatus';
-import PluginUpdates from './PluginUpdates';
-import PluginUrls from './PluginUrls';
-import { PluginInstalled } from '../../api/plugins';
-import { translate } from '../../helpers/l10n';
-import { Query } from './utils';
-
-interface Props {
- plugin: PluginInstalled;
- refreshPending: () => void;
- status?: string;
- updateQuery: (newQuery: Partial<Query>) => void;
-}
-
-export default function PluginInstalled({ plugin, refreshPending, status, updateQuery }: Props) {
- return (
- <tr>
- <PluginDescription plugin={plugin} updateQuery={updateQuery} />
- <td className="text-top big-spacer-right">
- <ul>
- <li className="little-spacer-bottom">
- <strong className="js-plugin-installed-version little-spacer-right">
- {plugin.version}
- </strong>
- {translate('marketplace._installed')}
- </li>
- <PluginUpdates updates={plugin.updates} />
- </ul>
- </td>
-
- <td className="text-top width-20 big-spacer-right">
- <ul>
- <PluginUrls plugin={plugin} />
- <PluginLicense license={plugin.license} />
- <PluginOrganization plugin={plugin} />
- </ul>
- </td>
-
- <PluginStatus plugin={plugin} status={status} refreshPending={refreshPending} />
- </tr>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- license?: string;
-}
-
-export default function PluginLicense({ license }: Props) {
- if (!license) {
- return null;
- }
- return (
- <li className="little-spacer-bottom text-limited" title={license}>
- <FormattedMessage
- defaultMessage={translate('marketplace.licensed_under_x')}
- id="marketplace.licensed_under_x"
- values={{
- license: <span className="js-plugin-license">{license}</span>
- }}
- />
- </li>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
-import { translate } from '../../helpers/l10n';
-import { Plugin } from '../../api/plugins';
-
-interface Props {
- plugin: Plugin;
-}
-
-export default function PluginOrganization({ plugin }: Props) {
- if (!plugin.organizationName) {
- return null;
- }
- return (
- <li className="little-spacer-bottom">
- <FormattedMessage
- defaultMessage={translate('marketplace.developed_by_x')}
- id="marketplace.developed_by_x"
- values={{
- organization: plugin.organizationUrl ? (
- <a className="js-plugin-organization" href={plugin.organizationUrl} target="_blank">
- {plugin.organizationName}
- </a>
- ) : (
- <span className="js-plugin-organization">{plugin.organizationName}</span>
- )
- }}
- />
- </li>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Plugin } from '../../api/plugins';
-import PluginActions from './PluginActions';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- plugin: Plugin;
- refreshPending: () => void;
- status?: string;
-}
-
-export default function PluginStatus({ plugin, refreshPending, status }: Props) {
- return (
- <td className="text-top text-right width-20">
- {status === 'installing' && (
- <p className="text-success">{translate('marketplace.install_pending')}</p>
- )}
-
- {status === 'updating' && (
- <p className="text-success">{translate('marketplace.update_pending')}</p>
- )}
-
- {status === 'removing' && (
- <p className="text-danger">{translate('marketplace.uninstall_pending')}</p>
- )}
-
- {status == null && (
- <div>
- <i className="js-spinner spinner hidden" />
- <PluginActions plugin={plugin} refreshPending={refreshPending} />
- </div>
- )}
- </td>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Update } from '../../api/plugins';
-import { translateWithParameters } from '../../helpers/l10n';
-
-interface Props {
- disabled: boolean;
- onClick: (update: Update) => void;
- update: Update;
-}
-
-export default class PluginUpdateButton extends React.PureComponent<Props> {
- handleClick = () => this.props.onClick(this.props.update);
-
- render() {
- const { disabled, update } = this.props;
- if (update.status !== 'COMPATIBLE' || !update.release) {
- return null;
- }
- return (
- <button className="js-update" onClick={this.handleClick} disabled={disabled}>
- {translateWithParameters('marketplace.update_to_x', update.release.version)}
- </button>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import PluginChangeLogButton from './PluginChangeLogButton';
-import Tooltip from '../../components/controls/Tooltip';
-import { Release, Update } from '../../api/plugins';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- update: Update;
- release: Release;
-}
-
-interface State {
- changelogOpen: boolean;
-}
-
-export default class PluginUpdateItem extends React.PureComponent<Props, State> {
- state: State = { changelogOpen: false };
-
- handleChangelogClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
- event.preventDefault();
- event.stopPropagation();
- this.toggleChangelog();
- };
-
- toggleChangelog = (show?: boolean) => {
- if (show !== undefined) {
- this.setState({ changelogOpen: show });
- } else {
- this.setState(state => ({ changelogOpen: !state.changelogOpen }));
- }
- };
-
- render() {
- const { release, update } = this.props;
- return (
- <li key={release.version} className="diplay-flex-row little-spacer-bottom">
- <div className="pull-left spacer-right">
- {update.status === 'COMPATIBLE' ? (
- <span className="js-update-version badge badge-success">{release.version}</span>
- ) : (
- <Tooltip overlay={translate('marketplace.status', update.status)}>
- <span className="js-update-version badge badge-warning">{release.version}</span>
- </Tooltip>
- )}
- </div>
- <div>
- {release.description}
- <PluginChangeLogButton release={release} update={update} />
- </div>
- </li>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import PluginUpdateItem from './PluginUpdateItem';
-import { Update } from '../../api/plugins';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- updates?: Update[];
-}
-
-export default function PluginUpdates({ updates }: Props) {
- if (!updates || updates.length <= 0) {
- return null;
- }
- return (
- <li className="spacer-top">
- <strong>{translate('marketplace.updates')}:</strong>
- <ul className="little-spacer-top">
- {updates.map(
- update =>
- update.release ? (
- <PluginUpdateItem
- key={update.release.version}
- release={update.release}
- update={update}
- />
- ) : null
- )}
- </ul>
- </li>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { Plugin } from '../../api/plugins';
-import { translate } from '../../helpers/l10n';
-
-interface Props {
- plugin: Plugin;
-}
-
-export default function PluginUrls({ plugin }: Props) {
- if (!plugin.homepageUrl && !plugin.issueTrackerUrl) {
- return null;
- }
- return (
- <li className="little-spacer-bottom">
- <ul className="list-inline">
- {plugin.homepageUrl && (
- <li>
- <a className="js-plugin-homepage" href={plugin.homepageUrl} target="_blank">
- {translate('marketplace.homepage')}
- </a>
- </li>
- )}
- {plugin.issueTrackerUrl && (
- <li>
- <a className="js-plugin-issues" href={plugin.issueTrackerUrl} target="_blank">
- {translate('marketplace.issue_tracker')}
- </a>
- </li>
- )}
- </ul>
- </li>
- );
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import PluginAvailable from './PluginAvailable';
-import PluginInstalled from './PluginInstalled';
+import PluginAvailable from './components/PluginAvailable';
+import PluginInstalled from './components/PluginInstalled';
import { isPluginAvailable, isPluginInstalled, Query } from './utils';
import { Plugin, PluginPending } from '../../api/plugins';
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Footer from '../Footer';
+
+it('should display the number of plugins', () => {
+ expect(shallow(<Footer total={3} />)).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { click } from '../../../helpers/testUtils';
+import PendingActions from '../PendingActions';
+
+jest.mock('../../../api/plugins', () => ({
+ cancelPendingPlugins: jest.fn(() => Promise.resolve())
+}));
+
+const cancelPendingPlugins = require('../../../api/plugins').cancelPendingPlugins as jest.Mock<any>;
+
+beforeEach(() => {
+ cancelPendingPlugins.mockClear();
+});
+
+it('should display pending actions', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should not display nothing', () => {
+ expect(getWrapper({ pending: { installing: [], updating: [], removing: [] } })).toMatchSnapshot();
+});
+
+it('should open the restart form', () => {
+ const wrapper = getWrapper();
+ click(wrapper.find('.js-restart'));
+ expect(wrapper.find('RestartForm')).toHaveLength(1);
+});
+
+it('should cancel all pending and refresh them', async () => {
+ const refreshPending = jest.fn();
+ const wrapper = getWrapper({ refreshPending });
+ click(wrapper.find('.js-cancel-all'));
+ expect(cancelPendingPlugins).toHaveBeenCalled();
+ await new Promise(setImmediate);
+
+ expect(refreshPending).toHaveBeenCalled();
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <PendingActions
+ pending={{
+ installing: [
+ {
+ key: 'foo',
+ name: 'Foo',
+ description: 'foo description',
+ version: 'fooversion',
+ implementationBuild: 'foobuild'
+ },
+ {
+ key: 'bar',
+ name: 'Bar',
+ description: 'bar description',
+ version: 'barversion',
+ implementationBuild: 'barbuild'
+ }
+ ],
+ updating: [],
+ removing: [
+ {
+ key: 'baz',
+ name: 'Baz',
+ description: 'baz description',
+ version: 'bazversion',
+ implementationBuild: 'bazbuild'
+ }
+ ]
+ }}
+ refreshPending={() => {}}
+ {...props}
+ />
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display the number of plugins 1`] = `
+<footer
+ className="spacer-top note text-center"
+>
+ x_show.3
+</footer>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display pending actions 1`] = `
+<div
+ className="js-pending panel panel-warning big-spacer-bottom"
+>
+ <div
+ className="display-inline-block"
+ >
+ <p>
+ marketplace.sonarqube_needs_to_be_restarted_to
+ </p>
+ <ul
+ className="list-styled spacer-top"
+ >
+ <li>
+ <FormattedMessage
+ defaultMessage="marketplace.install_x_plugins"
+ id="marketplace.install_x_plugins"
+ values={
+ Object {
+ "nb": <strong
+ className="text-success big little-spacer-left little-spacer-right"
+ >
+ 2
+ </strong>,
+ }
+ }
+ />
+ </li>
+ <li>
+ <FormattedMessage
+ defaultMessage="marketplace.uninstall_x_plugins"
+ id="marketplace.uninstall_x_plugins"
+ values={
+ Object {
+ "nb": <strong
+ className="text-danger big little-spacer-left little-spacer-right"
+ >
+ 1
+ </strong>,
+ }
+ }
+ />
+ </li>
+ </ul>
+ </div>
+ <div
+ className="pull-right button-group"
+ >
+ <button
+ className="js-restart"
+ onClick={[Function]}
+ >
+ marketplace.restart
+ </button>
+ <button
+ className="js-cancel-all button-red"
+ onClick={[Function]}
+ >
+ marketplace.revert
+ </button>
+ </div>
+</div>
+`;
+
+exports[`should not display nothing 1`] = `null`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Checkbox from '../../../components/controls/Checkbox';
+import CheckIcon from '../../../components/icons-components/CheckIcon';
+import PluginUpdateButton from './PluginUpdateButton';
+import { Plugin, installPlugin, updatePlugin, uninstallPlugin } from '../../../api/plugins';
+import { isPluginAvailable, isPluginInstalled } from '../utils';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ plugin: Plugin;
+ refreshPending: () => void;
+}
+
+interface State {
+ acceptTerms: boolean;
+ loading: boolean;
+}
+
+export default class PluginActions extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = { acceptTerms: false, loading: false };
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ doPluginAction = (apiAction: (data: { key: string }) => Promise<void | Response>) => {
+ this.setState({ loading: true });
+ apiAction({ key: this.props.plugin.key }).then(
+ () => {
+ this.props.refreshPending();
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ handleInstall = () => this.doPluginAction(installPlugin);
+ handleUpdate = () => this.doPluginAction(updatePlugin);
+ handleUninstall = () => this.doPluginAction(uninstallPlugin);
+ handleTermsCheck = (checked: boolean) => this.setState({ acceptTerms: checked });
+
+ render() {
+ const { plugin } = this.props;
+ const { loading } = this.state;
+
+ if (plugin.editionBundled) {
+ return (
+ <div className="js-actions">
+ {isPluginAvailable(plugin) && (
+ <div>
+ <p className="little-spacer-bottom">
+ {translate('marketplace.available_under_commercial_license')}
+ </p>
+ <a href={plugin.homepageUrl} target="_blank">
+ {translate('marketplace.learn_more')}
+ </a>
+ </div>
+ )}
+ {isPluginInstalled(plugin) && (
+ <p>
+ <CheckIcon className="little-spacer-right" />
+ {translate('marketplace.installed')}
+ </p>
+ )}
+ {isPluginInstalled(plugin) &&
+ plugin.updates &&
+ plugin.updates.length > 0 && (
+ <div className="spacer-top button-group">
+ {plugin.updates.map((update, idx) => (
+ <PluginUpdateButton
+ key={idx}
+ onClick={this.handleUpdate}
+ update={update}
+ disabled={loading}
+ />
+ ))}
+ </div>
+ )}
+ </div>
+ );
+ }
+
+ return (
+ <div className="js-actions">
+ {isPluginAvailable(plugin) &&
+ plugin.termsAndConditionsUrl && (
+ <p className="little-spacer-bottom">
+ <Checkbox
+ checked={this.state.acceptTerms}
+ className="js-terms"
+ id={'plugin-terms-' + plugin.key}
+ onCheck={this.handleTermsCheck}>
+ <label className="little-spacer-left" htmlFor={'plugin-terms-' + plugin.key}>
+ {translate('marketplace.i_accept_the')}
+ </label>
+ </Checkbox>
+ <a
+ className="js-plugin-terms nowrap little-spacer-left"
+ href={plugin.termsAndConditionsUrl}
+ target="_blank">
+ {translate('marketplace.terms_and_conditions')}
+ </a>
+ </p>
+ )}
+ {loading && <i className="spinner spacer-right" />}
+ {isPluginInstalled(plugin) && (
+ <div className="button-group">
+ {plugin.updates &&
+ plugin.updates.map((update, idx) => (
+ <PluginUpdateButton
+ key={idx}
+ onClick={this.handleUpdate}
+ update={update}
+ disabled={loading}
+ />
+ ))}
+ <button
+ className="js-uninstall button-red"
+ disabled={loading}
+ onClick={this.handleUninstall}>
+ {translate('marketplace.uninstall')}
+ </button>
+ </div>
+ )}
+ {isPluginAvailable(plugin) && (
+ <button
+ className="js-install"
+ disabled={loading || (plugin.termsAndConditionsUrl != null && !this.state.acceptTerms)}
+ onClick={this.handleInstall}>
+ {translate('marketplace.install')}
+ </button>
+ )}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import PluginChangeLogButton from './PluginChangeLogButton';
+import PluginDescription from './PluginDescription';
+import PluginLicense from './PluginLicense';
+import PluginOrganization from './PluginOrganization';
+import PluginStatus from './PluginStatus';
+import PluginUrls from './PluginUrls';
+import { PluginAvailable } from '../../../api/plugins';
+import { translateWithParameters } from '../../../helpers/l10n';
+import { Query } from '../utils';
+
+interface Props {
+ plugin: PluginAvailable;
+ refreshPending: () => void;
+ status?: string;
+ updateQuery: (newQuery: Partial<Query>) => void;
+}
+
+export default function PluginAvailable({ plugin, refreshPending, status, updateQuery }: Props) {
+ return (
+ <tr>
+ <PluginDescription plugin={plugin} updateQuery={updateQuery} />
+ <td className="text-top big-spacer-right">
+ <ul>
+ <li className="diplay-flex-row little-spacer-bottom">
+ <div className="pull-left spacer-right">
+ <span className="badge badge-success">{plugin.release.version}</span>
+ </div>
+ <div>
+ {plugin.release.description}
+ <PluginChangeLogButton release={plugin.release} update={plugin.update} />
+ {plugin.update.requires.length > 0 && (
+ <p className="little-spacer-top">
+ <strong>
+ {translateWithParameters(
+ 'marketplace.installing_this_plugin_will_also_install_x',
+ plugin.update.requires.map(requiredPlugin => requiredPlugin.name).join(', ')
+ )}
+ </strong>
+ </p>
+ )}
+ </div>
+ </li>
+ </ul>
+ </td>
+
+ <td className="text-top width-20 big-spacer-right">
+ <ul>
+ <PluginUrls plugin={plugin} />
+ <PluginLicense license={plugin.license} />
+ <PluginOrganization plugin={plugin} />
+ </ul>
+ </td>
+
+ <PluginStatus plugin={plugin} status={status} refreshPending={refreshPending} />
+ </tr>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import BubblePopup from '../../../components/common/BubblePopup';
+import PluginChangeLogItem from './PluginChangeLogItem';
+import { Release, Update } from '../../../api/plugins';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ popupPosition?: any;
+ release: Release;
+ update: Update;
+}
+
+export default function PluginChangeLog({ popupPosition, release, update }: Props) {
+ return (
+ <BubblePopup position={popupPosition} customClass="bubble-popup-bottom-right">
+ <div className="abs-width-300 bubble-popup-container">
+ <div className="bubble-popup-title">{translate('changelog')}</div>
+ <ul className="js-plugin-changelog-list">
+ {update.previousUpdates &&
+ update.previousUpdates.map(
+ previousUpdate =>
+ previousUpdate.release ? (
+ <PluginChangeLogItem
+ key={previousUpdate.release.version}
+ release={previousUpdate.release}
+ update={previousUpdate}
+ />
+ ) : null
+ )}
+ <PluginChangeLogItem release={release} update={update} />
+ </ul>
+ </div>
+ </BubblePopup>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import BubblePopupHelper from '../../../components/common/BubblePopupHelper';
+import PluginChangeLog from './PluginChangeLog';
+import { Release, Update } from '../../../api/plugins';
+
+interface Props {
+ release: Release;
+ update: Update;
+}
+
+interface State {
+ changelogOpen: boolean;
+}
+
+export default class PluginChangeLogButton extends React.PureComponent<Props, State> {
+ state: State = { changelogOpen: false };
+
+ handleChangelogClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.toggleChangelog();
+ };
+
+ toggleChangelog = (show?: boolean) => {
+ if (show !== undefined) {
+ this.setState({ changelogOpen: show });
+ } else {
+ this.setState(state => ({ changelogOpen: !state.changelogOpen }));
+ }
+ };
+
+ render() {
+ return (
+ <div className="display-inline-block little-spacer-left">
+ <button
+ className="button-link js-changelog issue-rule icon-ellipsis-h"
+ onClick={this.handleChangelogClick}
+ />
+ <BubblePopupHelper
+ isOpen={this.state.changelogOpen}
+ position="bottomright"
+ popup={<PluginChangeLog release={this.props.release} update={this.props.update} />}
+ togglePopup={this.toggleChangelog}
+ />
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import DateFormatter from '../../../components/intl/DateFormatter';
+import Tooltip from '../../../components/controls/Tooltip';
+import { Release, Update } from '../../../api/plugins';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+
+interface Props {
+ release: Release;
+ update: Update;
+}
+
+export default function PluginChangeLogItem({ release, update }: Props) {
+ return (
+ <li className="big-spacer-bottom">
+ <div className="little-spacer-bottom">
+ {update.status === 'COMPATIBLE' || !update.status ? (
+ <span className="js-plugin-changelog-version badge badge-success spacer-right">
+ {release.version}
+ </span>
+ ) : (
+ <Tooltip overlay={translateWithParameters('marketplace.status', update.status)}>
+ <span className="js-plugin-changelog-version badge badge-warning spacer-right">
+ {release.version}
+ </span>
+ </Tooltip>
+ )}
+ <span className="js-plugin-changelog-date note spacer-right">
+ <DateFormatter date={release.date} />
+ </span>
+ {release.changeLogUrl && (
+ <a className="js-plugin-changelog-link" href={release.changeLogUrl} target="_blank">
+ {translate('update_center.release_notes')}
+ </a>
+ )}
+ </div>
+ <div className="js-plugin-changelog-description">{release.description}</div>
+ </li>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Plugin } from '../../../api/plugins';
+import { Query } from '../utils';
+
+interface Props {
+ plugin: Plugin;
+ updateQuery: (newQuery: Partial<Query>) => void;
+}
+
+export default class PluginDescription extends React.PureComponent<Props> {
+ handleCategoryClick = (e: React.SyntheticEvent<HTMLAnchorElement>) => {
+ e.preventDefault();
+ this.props.updateQuery({ search: this.props.plugin.category });
+ };
+
+ render() {
+ const { plugin } = this.props;
+ return (
+ <td className="text-top width-20 big-spacer-right">
+ <div>
+ <strong className="js-plugin-name">{plugin.name}</strong>
+ {plugin.category && (
+ <a
+ className="js-plugin-category badge spacer-left"
+ href="#"
+ onClick={this.handleCategoryClick}>
+ {plugin.category}
+ </a>
+ )}
+ </div>
+ <div className="js-plugin-description little-spacer-top">{plugin.description}</div>
+ </td>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import PluginDescription from './PluginDescription';
+import PluginLicense from './PluginLicense';
+import PluginOrganization from './PluginOrganization';
+import PluginStatus from './PluginStatus';
+import PluginUpdates from './PluginUpdates';
+import PluginUrls from './PluginUrls';
+import { PluginInstalled } from '../../../api/plugins';
+import { translate } from '../../../helpers/l10n';
+import { Query } from '../utils';
+
+interface Props {
+ plugin: PluginInstalled;
+ refreshPending: () => void;
+ status?: string;
+ updateQuery: (newQuery: Partial<Query>) => void;
+}
+
+export default function PluginInstalled({ plugin, refreshPending, status, updateQuery }: Props) {
+ return (
+ <tr>
+ <PluginDescription plugin={plugin} updateQuery={updateQuery} />
+ <td className="text-top big-spacer-right">
+ <ul>
+ <li className="little-spacer-bottom">
+ <strong className="js-plugin-installed-version little-spacer-right">
+ {plugin.version}
+ </strong>
+ {translate('marketplace._installed')}
+ </li>
+ <PluginUpdates updates={plugin.updates} />
+ </ul>
+ </td>
+
+ <td className="text-top width-20 big-spacer-right">
+ <ul>
+ <PluginUrls plugin={plugin} />
+ <PluginLicense license={plugin.license} />
+ <PluginOrganization plugin={plugin} />
+ </ul>
+ </td>
+
+ <PluginStatus plugin={plugin} status={status} refreshPending={refreshPending} />
+ </tr>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ license?: string;
+}
+
+export default function PluginLicense({ license }: Props) {
+ if (!license) {
+ return null;
+ }
+ return (
+ <li className="little-spacer-bottom text-limited" title={license}>
+ <FormattedMessage
+ defaultMessage={translate('marketplace.licensed_under_x')}
+ id="marketplace.licensed_under_x"
+ values={{
+ license: <span className="js-plugin-license">{license}</span>
+ }}
+ />
+ </li>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from '../../../helpers/l10n';
+import { Plugin } from '../../../api/plugins';
+
+interface Props {
+ plugin: Plugin;
+}
+
+export default function PluginOrganization({ plugin }: Props) {
+ if (!plugin.organizationName) {
+ return null;
+ }
+ return (
+ <li className="little-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('marketplace.developed_by_x')}
+ id="marketplace.developed_by_x"
+ values={{
+ organization: plugin.organizationUrl ? (
+ <a className="js-plugin-organization" href={plugin.organizationUrl} target="_blank">
+ {plugin.organizationName}
+ </a>
+ ) : (
+ <span className="js-plugin-organization">{plugin.organizationName}</span>
+ )
+ }}
+ />
+ </li>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Plugin } from '../../../api/plugins';
+import PluginActions from './PluginActions';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ plugin: Plugin;
+ refreshPending: () => void;
+ status?: string;
+}
+
+export default function PluginStatus({ plugin, refreshPending, status }: Props) {
+ return (
+ <td className="text-top text-right width-20">
+ {status === 'installing' && (
+ <p className="text-success">{translate('marketplace.install_pending')}</p>
+ )}
+
+ {status === 'updating' && (
+ <p className="text-success">{translate('marketplace.update_pending')}</p>
+ )}
+
+ {status === 'removing' && (
+ <p className="text-danger">{translate('marketplace.uninstall_pending')}</p>
+ )}
+
+ {status == null && (
+ <div>
+ <i className="js-spinner spinner hidden" />
+ <PluginActions plugin={plugin} refreshPending={refreshPending} />
+ </div>
+ )}
+ </td>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Update } from '../../../api/plugins';
+import { translateWithParameters } from '../../../helpers/l10n';
+
+interface Props {
+ disabled: boolean;
+ onClick: (update: Update) => void;
+ update: Update;
+}
+
+export default class PluginUpdateButton extends React.PureComponent<Props> {
+ handleClick = () => this.props.onClick(this.props.update);
+
+ render() {
+ const { disabled, update } = this.props;
+ if (update.status !== 'COMPATIBLE' || !update.release) {
+ return null;
+ }
+ return (
+ <button className="js-update" onClick={this.handleClick} disabled={disabled}>
+ {translateWithParameters('marketplace.update_to_x', update.release.version)}
+ </button>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import PluginChangeLogButton from './PluginChangeLogButton';
+import Tooltip from '../../../components/controls/Tooltip';
+import { Release, Update } from '../../../api/plugins';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ update: Update;
+ release: Release;
+}
+
+interface State {
+ changelogOpen: boolean;
+}
+
+export default class PluginUpdateItem extends React.PureComponent<Props, State> {
+ state: State = { changelogOpen: false };
+
+ handleChangelogClick = (event: React.SyntheticEvent<HTMLButtonElement>) => {
+ event.preventDefault();
+ event.stopPropagation();
+ this.toggleChangelog();
+ };
+
+ toggleChangelog = (show?: boolean) => {
+ if (show !== undefined) {
+ this.setState({ changelogOpen: show });
+ } else {
+ this.setState(state => ({ changelogOpen: !state.changelogOpen }));
+ }
+ };
+
+ render() {
+ const { release, update } = this.props;
+ return (
+ <li key={release.version} className="diplay-flex-row little-spacer-bottom">
+ <div className="pull-left spacer-right">
+ {update.status === 'COMPATIBLE' ? (
+ <span className="js-update-version badge badge-success">{release.version}</span>
+ ) : (
+ <Tooltip overlay={translate('marketplace.status', update.status)}>
+ <span className="js-update-version badge badge-warning">{release.version}</span>
+ </Tooltip>
+ )}
+ </div>
+ <div>
+ {release.description}
+ <PluginChangeLogButton release={release} update={update} />
+ </div>
+ </li>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import PluginUpdateItem from './PluginUpdateItem';
+import { Update } from '../../../api/plugins';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ updates?: Update[];
+}
+
+export default function PluginUpdates({ updates }: Props) {
+ if (!updates || updates.length <= 0) {
+ return null;
+ }
+ return (
+ <li className="spacer-top">
+ <strong>{translate('marketplace.updates')}:</strong>
+ <ul className="little-spacer-top">
+ {updates.map(
+ update =>
+ update.release ? (
+ <PluginUpdateItem
+ key={update.release.version}
+ release={update.release}
+ update={update}
+ />
+ ) : null
+ )}
+ </ul>
+ </li>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { Plugin } from '../../../api/plugins';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ plugin: Plugin;
+}
+
+export default function PluginUrls({ plugin }: Props) {
+ if (!plugin.homepageUrl && !plugin.issueTrackerUrl) {
+ return null;
+ }
+ return (
+ <li className="little-spacer-bottom">
+ <ul className="list-inline">
+ {plugin.homepageUrl && (
+ <li>
+ <a className="js-plugin-homepage" href={plugin.homepageUrl} target="_blank">
+ {translate('marketplace.homepage')}
+ </a>
+ </li>
+ )}
+ {plugin.issueTrackerUrl && (
+ <li>
+ <a className="js-plugin-issues" href={plugin.issueTrackerUrl} target="_blank">
+ {translate('marketplace.issue_tracker')}
+ </a>
+ </li>
+ )}
+ </ul>
+ </li>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { click } from '../../../../helpers/testUtils';
+import PluginDescription from '../PluginDescription';
+
+it('should display the description and category', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should not display any category', () => {
+ expect(
+ getWrapper({ plugin: { key: 'foo', name: 'Foo', description: 'foo description' } })
+ ).toMatchSnapshot();
+});
+
+it('should update query when clicking on category', () => {
+ const updateQuery = jest.fn();
+ const wrapper = getWrapper({ updateQuery });
+ click(wrapper.find('.js-plugin-category'));
+ expect(updateQuery).toHaveBeenCalledWith({ search: 'foocategory' });
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <PluginDescription
+ plugin={{
+ key: 'foo',
+ name: 'Foo',
+ description: 'foo description',
+ category: 'foocategory'
+ }}
+ updateQuery={() => {}}
+ {...props}
+ />
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import PluginLicense from '../PluginLicense';
+
+it('should display the license field', () => {
+ expect(shallow(<PluginLicense license="SonarSource license" />)).toMatchSnapshot();
+});
+
+it('should not display anything', () => {
+ expect(shallow(<PluginLicense />)).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import PluginUrls from '../PluginUrls';
+
+it('should display the urls', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should display only one url', () => {
+ expect(getWrapper({ issueTrackerUrl: undefined })).toMatchSnapshot();
+});
+
+it('should not display anything', () => {
+ expect(getWrapper({ homepageUrl: undefined, issueTrackerUrl: undefined })).toMatchSnapshot();
+});
+
+function getWrapper(plugin = {}) {
+ return shallow(
+ <PluginUrls
+ plugin={{
+ key: 'foo',
+ name: 'Foo',
+ description: 'foo description',
+ homepageUrl: 'homepageurl',
+ issueTrackerUrl: 'issuetrackerurl',
+ ...plugin
+ }}
+ />
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display the description and category 1`] = `
+<td
+ className="text-top width-20 big-spacer-right"
+>
+ <div>
+ <strong
+ className="js-plugin-name"
+ >
+ Foo
+ </strong>
+ <a
+ className="js-plugin-category badge spacer-left"
+ href="#"
+ onClick={[Function]}
+ >
+ foocategory
+ </a>
+ </div>
+ <div
+ className="js-plugin-description little-spacer-top"
+ >
+ foo description
+ </div>
+</td>
+`;
+
+exports[`should not display any category 1`] = `
+<td
+ className="text-top width-20 big-spacer-right"
+>
+ <div>
+ <strong
+ className="js-plugin-name"
+ >
+ Foo
+ </strong>
+ </div>
+ <div
+ className="js-plugin-description little-spacer-top"
+ >
+ foo description
+ </div>
+</td>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display the license field 1`] = `
+<li
+ className="little-spacer-bottom text-limited"
+ title="SonarSource license"
+>
+ <FormattedMessage
+ defaultMessage="marketplace.licensed_under_x"
+ id="marketplace.licensed_under_x"
+ values={
+ Object {
+ "license": <span
+ className="js-plugin-license"
+ >
+ SonarSource license
+ </span>,
+ }
+ }
+ />
+</li>
+`;
+
+exports[`should not display anything 1`] = `null`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display only one url 1`] = `
+<li
+ className="little-spacer-bottom"
+>
+ <ul
+ className="list-inline"
+ >
+ <li>
+ <a
+ className="js-plugin-homepage"
+ href="homepageurl"
+ target="_blank"
+ >
+ marketplace.homepage
+ </a>
+ </li>
+ </ul>
+</li>
+`;
+
+exports[`should display the urls 1`] = `
+<li
+ className="little-spacer-bottom"
+>
+ <ul
+ className="list-inline"
+ >
+ <li>
+ <a
+ className="js-plugin-homepage"
+ href="homepageurl"
+ target="_blank"
+ >
+ marketplace.homepage
+ </a>
+ </li>
+ <li>
+ <a
+ className="js-plugin-issues"
+ href="issuetrackerurl"
+ target="_blank"
+ >
+ marketplace.issue_tracker
+ </a>
+ </li>
+ </ul>
+</li>
+`;
+
+exports[`should not display anything 1`] = `null`;