diff options
author | Philippe Perrin <philippe.perrin@sonarsource.com> | 2021-03-01 15:31:54 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-03-03 20:12:51 +0000 |
commit | 0f655c3dfabfbc3376cec41dd29e40c1bfbfe81e (patch) | |
tree | ebc8cdd9f19f8c05d03b4b680c628788e7692e4d /server/sonar-web | |
parent | a3ab233a6c989f6bea8eab0f859282bb4246970f (diff) | |
download | sonarqube-0f655c3dfabfbc3376cec41dd29e40c1bfbfe81e.tar.gz sonarqube-0f655c3dfabfbc3376cec41dd29e40c1bfbfe81e.zip |
Delete legacy SonarCloud code
Diffstat (limited to 'server/sonar-web')
12 files changed, 22 insertions, 1407 deletions
diff --git a/server/sonar-web/src/main/js/api/news.ts b/server/sonar-web/src/main/js/api/news.ts deleted file mode 100644 index 3b4e00488d0..00000000000 --- a/server/sonar-web/src/main/js/api/news.ts +++ /dev/null @@ -1,139 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 { getCorsJSON } from 'sonar-ui-common/helpers/request'; - -interface PrismicRef { - id: string; - ref: string; -} - -export interface PrismicNews { - data: { title: string }; - last_publication_date: string; - uid: string; -} - -interface PrismicResponse { - page: number; - results: PrismicResult[]; - results_per_page: number; - total_results_size: number; -} - -interface PrismicResult { - data: { - notification: string; - publication_date: string; - body: PrismicResultFeature[]; - }; -} - -interface PrismicResultFeature { - items: Array<{ - category: { - data: { - color: string; - name: string; - }; - }; - }>; - primary: { - description: string; - read_more_link: { - url?: string; - }; - }; -} - -export interface PrismicFeatureNews { - notification: string; - publicationDate: string; - features: Array<{ - categories: Array<{ - color: string; - name: string; - }>; - description: string; - readMore?: string; - }>; -} - -const PRISMIC_API_URL = 'https://sonarsource.cdn.prismic.io/api/v2'; - -export function fetchPrismicRefs() { - return getCorsJSON(PRISMIC_API_URL).then((response: { refs: PrismicRef[] }) => { - const master = response && response.refs.find(ref => ref.id === 'master'); - if (!master) { - return Promise.reject('No master ref found'); - } - return master; - }); -} - -export function fetchPrismicNews(data: { - accessToken: string; - ps?: number; - ref: string; - tag?: string; -}) { - const q = ['[[at(document.type, "blog_sonarsource_post")]]']; - if (data.tag) { - q.push(`[[at(document.tags,["${data.tag}"])]]`); - } - return getCorsJSON(PRISMIC_API_URL + '/documents/search', { - access_token: data.accessToken, - orderings: '[document.first_publication_date desc]', - pageSize: data.ps || 1, - q, - ref: data.ref - }).then(({ results }: { results: PrismicNews[] }) => results); -} - -export function fetchPrismicFeatureNews(data: { - accessToken: string; - p?: number; - ps?: number; - ref: string; -}): Promise<{ news: PrismicFeatureNews[]; paging: T.Paging }> { - return getCorsJSON(PRISMIC_API_URL + '/documents/search', { - access_token: data.accessToken, - fetchLinks: 'sc_category.color,sc_category.name', - orderings: '[my.sc_product_news.publication_date desc]', - page: data.p || 1, - pageSize: data.ps || 1, - q: ['[[at(document.type, "sc_product_news")]]'], - ref: data.ref - }).then(({ page, results, results_per_page, total_results_size }: PrismicResponse) => ({ - news: results.map(result => ({ - notification: result.data.notification, - publicationDate: result.data.publication_date, - features: result.data.body.map(feature => ({ - categories: feature.items.map(item => item.category.data).filter(Boolean), - description: feature.primary.description, - readMore: feature.primary.read_more_link.url - })) - })), - paging: { - pageIndex: page, - pageSize: results_per_page, - total: total_results_size - } - })); -} diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx index d5e145cbeea..ab3f44270e7 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx @@ -22,8 +22,6 @@ import { Link } from 'react-router'; import { DropdownOverlay } from 'sonar-ui-common/components/controls/Dropdown'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; -import { isSonarCloud } from '../../../helpers/system'; -import ProductNewsMenuItem from './ProductNewsMenuItem'; import { SuggestionsContext } from './SuggestionsContext'; interface Props { @@ -69,70 +67,6 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> { ); } - renderSonarCloudLinks() { - return ( - <> - <li className="divider" /> - <li> - <a - href="https://community.sonarsource.com/c/help/sc" - rel="noopener noreferrer" - target="_blank"> - {translate('embed_docs.get_help')} - </a> - </li> - <li className="divider" /> - {this.renderTitle(translate('embed_docs.stay_connected'))} - <li> - {this.renderIconLink( - 'https://twitter.com/sonarcloud', - 'embed-doc/twitter-icon.svg', - 'Twitter' - )} - </li> - <li> - {this.renderIconLink( - 'https://blog.sonarsource.com/product/SonarCloud', - 'sonarcloud-square-logo.svg', - translate('embed_docs.blog') - )} - </li> - <li> - <ProductNewsMenuItem tag="SonarCloud" /> - </li> - </> - ); - } - - renderSonarQubeLinks() { - return ( - <> - <li className="divider" /> - <li> - <a href="https://community.sonarsource.com/" rel="noopener noreferrer" target="_blank"> - {translate('embed_docs.get_help')} - </a> - </li> - <li className="divider" /> - {this.renderTitle(translate('embed_docs.stay_connected'))} - <li> - {this.renderIconLink( - 'https://www.sonarqube.org/whats-new/?referrer=sonarqube', - 'embed-doc/sq-icon.svg', - translate('embed_docs.news') - )} - </li> - <li> - {this.renderIconLink( - 'https://twitter.com/SonarQube', - 'embed-doc/twitter-icon.svg', - 'Twitter' - )} - </li> - </> - ); - } - render() { return ( <DropdownOverlay> @@ -148,7 +82,28 @@ export default class EmbedDocsPopup extends React.PureComponent<Props> { {translate('api_documentation.page')} </Link> </li> - {isSonarCloud() ? this.renderSonarCloudLinks() : this.renderSonarQubeLinks()} + <li className="divider" /> + <li> + <a href="https://community.sonarsource.com/" rel="noopener noreferrer" target="_blank"> + {translate('embed_docs.get_help')} + </a> + </li> + <li className="divider" /> + {this.renderTitle(translate('embed_docs.stay_connected'))} + <li> + {this.renderIconLink( + 'https://www.sonarqube.org/whats-new/?referrer=sonarqube', + 'embed-doc/sq-icon.svg', + translate('embed_docs.news') + )} + </li> + <li> + {this.renderIconLink( + 'https://twitter.com/SonarQube', + 'embed-doc/twitter-icon.svg', + 'Twitter' + )} + </li> </ul> </DropdownOverlay> ); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx deleted file mode 100644 index 62ed86eae5f..00000000000 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { connect } from 'react-redux'; -import ChevronRightIcon from 'sonar-ui-common/components/icons/ChevronRightIcon'; -import DateFormatter from 'sonar-ui-common/components/intl/DateFormatter'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import { fetchPrismicNews, fetchPrismicRefs, PrismicNews } from '../../../api/news'; -import PlaceholderBar from '../../../components/ui/PlaceholderBar'; -import { getGlobalSettingValue, Store } from '../../../store/rootReducer'; - -interface OwnProps { - tag?: string; -} - -interface StateProps { - accessToken?: string; -} - -type Props = OwnProps & StateProps; - -interface State { - loading: boolean; - news?: PrismicNews; -} - -export class ProductNewsMenuItem extends React.PureComponent<Props, State> { - mounted = false; - state: State = { loading: false }; - - componentDidMount() { - this.mounted = true; - this.fetchProductNews(); - } - - componentWillUnmount() { - this.mounted = false; - } - - fetchProductNews = () => { - const { accessToken, tag } = this.props; - if (accessToken) { - this.setState({ loading: true }); - fetchPrismicRefs() - .then(({ ref }) => fetchPrismicNews({ accessToken, ref, tag })) - .then( - news => { - if (this.mounted) { - this.setState({ news: news[0], loading: false }); - } - }, - () => { - if (this.mounted) { - this.setState({ loading: false }); - } - } - ); - } - }; - - renderPlaceholder() { - return ( - <a className="rich-item new-loading"> - <div className="flex-1"> - <div className="display-inline-flex-center"> - <h4>{translate('embed_docs.latest_blog')}</h4> - <span className="note spacer-left"> - <PlaceholderBar color="#aaa" width={60} /> - </span> - </div> - <p className="little-spacer-bottom"> - <PlaceholderBar color="#aaa" width={84} /> <PlaceholderBar color="#aaa" width={48} />{' '} - <PlaceholderBar color="#aaa" width={24} /> <PlaceholderBar color="#aaa" width={72} />{' '} - <PlaceholderBar color="#aaa" width={24} /> <PlaceholderBar color="#aaa" width={48} /> - </p> - </div> - <ChevronRightIcon className="flex-0" /> - </a> - ); - } - - render() { - const link = 'https://blog.sonarsource.com/'; - const { loading, news } = this.state; - - if (loading) { - return this.renderPlaceholder(); - } - - if (!news) { - return null; - } - - return ( - <a className="rich-item" href={link + news.uid} rel="noopener noreferrer" target="_blank"> - <div className="flex-1"> - <div className="display-inline-flex-center"> - <h4>{translate('embed_docs.latest_blog')}</h4> - <DateFormatter date={news.last_publication_date}> - {formattedDate => <span className="note spacer-left">{formattedDate}</span>} - </DateFormatter> - </div> - <p className="little-spacer-bottom">{news.data.title}</p> - </div> - <ChevronRightIcon className="flex-0" /> - </a> - ); - } -} - -const mapStateToProps = (state: Store): StateProps => { - const accessToken = getGlobalSettingValue(state, 'sonar.prismic.accessToken'); - return { - accessToken: accessToken && accessToken.value - }; -}; - -export default connect(mapStateToProps)(ProductNewsMenuItem); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/ProductNewsMenuItem-test.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/ProductNewsMenuItem-test.tsx deleted file mode 100644 index a6605fb1d6a..00000000000 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/ProductNewsMenuItem-test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; -import { fetchPrismicNews, fetchPrismicRefs } from '../../../../api/news'; -import { ProductNewsMenuItem } from '../ProductNewsMenuItem'; - -jest.mock('../../../../api/news', () => ({ - fetchPrismicRefs: jest.fn().mockResolvedValue({ id: 'master', ref: 'master-ref' }), - fetchPrismicNews: jest.fn().mockResolvedValue([ - { - data: { title: 'My Product News' }, - last_publication_date: '2018-04-06T12:07:19+0000', - uid: 'my-product-news' - } - ]) -})); - -it('should load the product news', async () => { - const wrapper = shallow(<ProductNewsMenuItem accessToken="token" tag="SonarCloud" />); - expect(wrapper).toMatchSnapshot(); - await waitAndUpdate(wrapper); - expect(fetchPrismicRefs).toHaveBeenCalled(); - expect(fetchPrismicNews).toHaveBeenCalledWith({ - accessToken: 'token', - ref: 'master-ref', - tag: 'SonarCloud' - }); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/ProductNewsMenuItem-test.tsx.snap b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/ProductNewsMenuItem-test.tsx.snap deleted file mode 100644 index 2cd910101ba..00000000000 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/ProductNewsMenuItem-test.tsx.snap +++ /dev/null @@ -1,97 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should load the product news 1`] = ` -<a - className="rich-item new-loading" -> - <div - className="flex-1" - > - <div - className="display-inline-flex-center" - > - <h4> - embed_docs.latest_blog - </h4> - <span - className="note spacer-left" - > - <PlaceholderBar - color="#aaa" - width={60} - /> - </span> - </div> - <p - className="little-spacer-bottom" - > - <PlaceholderBar - color="#aaa" - width={84} - /> - - <PlaceholderBar - color="#aaa" - width={48} - /> - - <PlaceholderBar - color="#aaa" - width={24} - /> - - <PlaceholderBar - color="#aaa" - width={72} - /> - - <PlaceholderBar - color="#aaa" - width={24} - /> - - <PlaceholderBar - color="#aaa" - width={48} - /> - </p> - </div> - <ChevronRightIcon - className="flex-0" - /> -</a> -`; - -exports[`should load the product news 2`] = ` -<a - className="rich-item" - href="https://blog.sonarsource.com/my-product-news" - rel="noopener noreferrer" - target="_blank" -> - <div - className="flex-1" - > - <div - className="display-inline-flex-center" - > - <h4> - embed_docs.latest_blog - </h4> - <DateFormatter - date="2018-04-06T12:07:19+0000" - > - <Component /> - </DateFormatter> - </div> - <p - className="little-spacer-bottom" - > - My Product News - </p> - </div> - <ChevronRightIcon - className="flex-0" - /> -</a> -`; diff --git a/server/sonar-web/src/main/js/app/components/notifications/NavLatestNotification.tsx b/server/sonar-web/src/main/js/app/components/notifications/NavLatestNotification.tsx deleted file mode 100644 index 30d49578d50..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/NavLatestNotification.tsx +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 differenceInSeconds from 'date-fns/difference_in_seconds'; -import * as React from 'react'; -import ClearIcon from 'sonar-ui-common/components/icons/ClearIcon'; -import NotificationIcon from 'sonar-ui-common/components/icons/NotificationIcon'; -import { parseDate } from 'sonar-ui-common/helpers/dates'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import { PrismicFeatureNews } from '../../../api/news'; -import './notifications.css'; - -interface Props { - lastNews: PrismicFeatureNews; - notificationsLastReadDate?: Date; - notificationsOptOut?: boolean; - onClick: () => void; - setCurrentUserSetting: (setting: T.CurrentUserSetting) => void; -} - -export default class NavLatestNotification extends React.PureComponent<Props> { - mounted = false; - - checkHasUnread = () => { - const { notificationsLastReadDate, lastNews } = this.props; - return ( - !notificationsLastReadDate || - differenceInSeconds(parseDate(lastNews.publicationDate), notificationsLastReadDate) > 0 - ); - }; - - handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.currentTarget.blur(); - this.props.onClick(); - }; - - handleDismiss = (event: React.MouseEvent<HTMLAnchorElement>) => { - event.preventDefault(); - event.stopPropagation(); - - this.props.setCurrentUserSetting({ - key: 'notifications.readDate', - value: Date.now().toString() - }); - }; - - render() { - const { notificationsOptOut, lastNews } = this.props; - const hasUnread = this.checkHasUnread(); - const showNotifications = Boolean(!notificationsOptOut && lastNews && hasUnread); - return ( - <> - {showNotifications && ( - <> - <li className="navbar-latest-notification" onClick={this.props.onClick}> - <div className="navbar-latest-notification-wrapper"> - <span className="badge badge-info">{translate('new')}</span> - <span className="label">{lastNews.notification}</span> - </div> - </li> - <li className="navbar-latest-notification-dismiss"> - <a className="navbar-icon" href="#" onClick={this.handleDismiss}> - <ClearIcon size={12} thin={true} /> - </a> - </li> - </> - )} - <li> - <a className="navbar-icon" href="#" onClick={this.handleClick}> - <NotificationIcon hasUnread={hasUnread && !notificationsOptOut} /> - </a> - </li> - </> - ); - } -} diff --git a/server/sonar-web/src/main/js/app/components/notifications/NotificationsSidebar.tsx b/server/sonar-web/src/main/js/app/components/notifications/NotificationsSidebar.tsx deleted file mode 100644 index 92536433eb9..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/NotificationsSidebar.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 classNames from 'classnames'; -import * as differenceInSeconds from 'date-fns/difference_in_seconds'; -import * as React from 'react'; -import { ClearButton } from 'sonar-ui-common/components/controls/buttons'; -import Modal from 'sonar-ui-common/components/controls/Modal'; -import DateFormatter from 'sonar-ui-common/components/intl/DateFormatter'; -import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import { PrismicFeatureNews } from '../../../api/news'; - -export interface Props { - fetchMoreFeatureNews: () => void; - loading: boolean; - loadingMore: boolean; - news: PrismicFeatureNews[]; - onClose: () => void; - notificationsLastReadDate?: Date; - paging?: T.Paging; -} - -export default function NotificationsSidebar(props: Props) { - const { loading, loadingMore, news, notificationsLastReadDate, paging } = props; - const header = translate('embed_docs.whats_new'); - return ( - <Modal contentLabel={header} onRequestClose={props.onClose}> - <div className="notifications-sidebar"> - <div className="notifications-sidebar-top"> - <h3>{header}</h3> - <ClearButton - className="button-tiny" - iconProps={{ size: 12, thin: true }} - onClick={props.onClose} - /> - </div> - <div className="notifications-sidebar-content"> - {loading ? ( - <div className="text-center"> - <DeferredSpinner className="big-spacer-top" timeout={200} /> - </div> - ) : ( - news.map((slice, index) => ( - <Notification - key={slice.publicationDate} - notification={slice} - unread={isUnread(index, slice.publicationDate, notificationsLastReadDate)} - /> - )) - )} - </div> - {!loading && paging && paging.total > news.length && ( - <div className="notifications-sidebar-footer"> - <div className="spacer-top note text-center"> - <a className="spacer-left" href="#" onClick={props.fetchMoreFeatureNews}> - {translate('show_more')} - </a> - {loadingMore && ( - <DeferredSpinner className="text-bottom spacer-left position-absolute" /> - )} - </div> - </div> - )} - </div> - </Modal> - ); -} - -export function isUnread(index: number, notificationDate: string, lastReadDate?: Date) { - return !lastReadDate ? index < 1 : differenceInSeconds(notificationDate, lastReadDate) > 0; -} - -interface NotificationProps { - notification: PrismicFeatureNews; - unread: boolean; -} - -export function Notification({ notification, unread }: NotificationProps) { - return ( - <div className={classNames('notifications-sidebar-slice', { unread })}> - <h4> - <DateFormatter date={notification.publicationDate} long={false} /> - </h4> - {notification.features.map((feature, index) => ( - <Feature feature={feature} key={index} /> - ))} - </div> - ); -} - -interface FeatureProps { - feature: PrismicFeatureNews['features'][0]; -} - -export function Feature({ feature }: FeatureProps) { - return ( - <div className="feature"> - <ul className="categories spacer-bottom"> - {feature.categories.map(category => ( - <li key={category.name} style={{ backgroundColor: category.color }}> - {category.name} - </li> - ))} - </ul> - <span>{feature.description}</span> - {feature.readMore && ( - <a - className="learn-more" - href={feature.readMore} - rel="noopener noreferrer nofollow" - target="_blank"> - {translate('learn_more')} - </a> - )} - </div> - ); -} diff --git a/server/sonar-web/src/main/js/app/components/notifications/__tests__/NavLatestNotification-test.tsx b/server/sonar-web/src/main/js/app/components/notifications/__tests__/NavLatestNotification-test.tsx deleted file mode 100644 index 334563bdced..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/__tests__/NavLatestNotification-test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 { parseDate } from 'sonar-ui-common/helpers/dates'; -import { PrismicFeatureNews } from '../../../../api/news'; -import NavLatestNotification from '../NavLatestNotification'; - -it('should render correctly if there are new features, and the user has not opted out', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('.navbar-latest-notification')).toHaveLength(1); -}); - -it('should render correctly if there are new features, but the user has opted out', () => { - const wrapper = shallowRender({ notificationsOptOut: true }); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('.navbar-latest-notification')).toHaveLength(0); -}); - -it('should render correctly if there are no new unread features', () => { - const wrapper = shallowRender({ - notificationsLastReadDate: parseDate('2018-12-31T12:07:19+0000') - }); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('.navbar-latest-notification')).toHaveLength(0); -}); - -function shallowRender(props: Partial<NavLatestNotification['props']> = {}) { - const lastNews: PrismicFeatureNews = { - notification: '10 Java rules, Github checks, Security Hotspots, BitBucket branch decoration', - publicationDate: '2018-04-06', - features: [ - { - categories: [{ color: '#ff0000', name: 'Java' }], - description: '10 new Java rules' - } - ] - }; - return shallow( - <NavLatestNotification - lastNews={lastNews} - notificationsLastReadDate={parseDate('2018-01-01T12:07:19+0000')} - notificationsOptOut={false} - onClick={jest.fn()} - setCurrentUserSetting={jest.fn()} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/app/components/notifications/__tests__/NotificationsSidebar-test.tsx b/server/sonar-web/src/main/js/app/components/notifications/__tests__/NotificationsSidebar-test.tsx deleted file mode 100644 index f9b92ec27d0..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/__tests__/NotificationsSidebar-test.tsx +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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 { parseDate } from 'sonar-ui-common/helpers/dates'; -import NotificationsSidebar, { - Feature, - isUnread, - Notification, - Props -} from '../NotificationsSidebar'; - -const news: Props['news'] = [ - { - notification: '10 Java rules, Github checks, Security Hotspots, BitBucket branch decoration', - publicationDate: '2018-04-06', - features: [ - { - categories: [ - { color: '#ff0000', name: 'Java' }, - { color: '#00ff00', name: 'Rules' } - ], - description: '10 new Java rules' - }, - { - categories: [{ color: '#0000ff', name: 'BitBucket' }], - description: 'BitBucket branch decoration', - readMore: 'http://example.com' - } - ] - }, - { - notification: 'Some other notification', - publicationDate: '2018-04-05', - features: [ - { - categories: [{ color: '#0000ff', name: 'BitBucket' }], - description: 'BitBucket branch decoration', - readMore: 'http://example.com' - } - ] - } -]; - -describe('#NotificationSidebar', () => { - it('should render correctly if there are new features', () => { - const wrapper = shallowRender({ loading: true }); - expect(wrapper).toMatchSnapshot(); - wrapper.setProps({ loading: false }); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('Notification')).toHaveLength(2); - }); - - it('should render correctly if there are no new unread features', () => { - const wrapper = shallowRender({ - notificationsLastReadDate: parseDate('2018-12-31') - }); - expect(wrapper.find('Notification')).toHaveLength(2); - expect(wrapper.find('Notification[unread=true]')).toHaveLength(0); - }); -}); - -describe('#isUnread', () => { - it('should be unread', () => { - expect(isUnread(0, '2018-12-14', undefined)).toBe(true); - expect(isUnread(1, '2018-12-14', parseDate('2018-12-12'))).toBe(true); - }); - - it('should be read', () => { - expect(isUnread(0, '2018-12-16', parseDate('2018-12-16'))).toBe(false); - expect(isUnread(1, '2018-12-15', undefined)).toBe(false); - }); -}); - -describe('#Notification', () => { - it('should render correctly', () => { - expect(shallow(<Notification notification={news[1]} unread={false} />)).toMatchSnapshot(); - expect(shallow(<Notification notification={news[1]} unread={true} />)).toMatchSnapshot(); - }); -}); - -describe('#Feature', () => { - it('should render correctly', () => { - expect(shallow(<Feature feature={news[1].features[0]} />)).toMatchSnapshot(); - expect(shallow(<Feature feature={news[0].features[0]} />)).toMatchSnapshot(); - }); -}); - -function shallowRender(props: Partial<Props> = {}) { - return shallow( - <NotificationsSidebar - fetchMoreFeatureNews={jest.fn()} - loading={false} - loadingMore={false} - news={news} - notificationsLastReadDate={parseDate('2018-01-01')} - onClose={jest.fn()} - paging={{ pageIndex: 1, pageSize: 10, total: 20 }} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/app/components/notifications/__tests__/__snapshots__/NavLatestNotification-test.tsx.snap b/server/sonar-web/src/main/js/app/components/notifications/__tests__/__snapshots__/NavLatestNotification-test.tsx.snap deleted file mode 100644 index c748dbfcf16..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/__tests__/__snapshots__/NavLatestNotification-test.tsx.snap +++ /dev/null @@ -1,82 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly if there are new features, and the user has not opted out 1`] = ` -<Fragment> - <li - className="navbar-latest-notification" - onClick={[MockFunction]} - > - <div - className="navbar-latest-notification-wrapper" - > - <span - className="badge badge-info" - > - new - </span> - <span - className="label" - > - 10 Java rules, Github checks, Security Hotspots, BitBucket branch decoration - </span> - </div> - </li> - <li - className="navbar-latest-notification-dismiss" - > - <a - className="navbar-icon" - href="#" - onClick={[Function]} - > - <ClearIcon - size={12} - thin={true} - /> - </a> - </li> - <li> - <a - className="navbar-icon" - href="#" - onClick={[Function]} - > - <NotificationIcon - hasUnread={true} - /> - </a> - </li> -</Fragment> -`; - -exports[`should render correctly if there are new features, but the user has opted out 1`] = ` -<Fragment> - <li> - <a - className="navbar-icon" - href="#" - onClick={[Function]} - > - <NotificationIcon - hasUnread={false} - /> - </a> - </li> -</Fragment> -`; - -exports[`should render correctly if there are no new unread features 1`] = ` -<Fragment> - <li> - <a - className="navbar-icon" - href="#" - onClick={[Function]} - > - <NotificationIcon - hasUnread={false} - /> - </a> - </li> -</Fragment> -`; diff --git a/server/sonar-web/src/main/js/app/components/notifications/__tests__/__snapshots__/NotificationsSidebar-test.tsx.snap b/server/sonar-web/src/main/js/app/components/notifications/__tests__/__snapshots__/NotificationsSidebar-test.tsx.snap deleted file mode 100644 index 4936ee19ea8..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/__tests__/__snapshots__/NotificationsSidebar-test.tsx.snap +++ /dev/null @@ -1,269 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`#Feature should render correctly 1`] = ` -<div - className="feature" -> - <ul - className="categories spacer-bottom" - > - <li - key="BitBucket" - style={ - Object { - "backgroundColor": "#0000ff", - } - } - > - BitBucket - </li> - </ul> - <span> - BitBucket branch decoration - </span> - <a - className="learn-more" - href="http://example.com" - rel="noopener noreferrer nofollow" - target="_blank" - > - learn_more - </a> -</div> -`; - -exports[`#Feature should render correctly 2`] = ` -<div - className="feature" -> - <ul - className="categories spacer-bottom" - > - <li - key="Java" - style={ - Object { - "backgroundColor": "#ff0000", - } - } - > - Java - </li> - <li - key="Rules" - style={ - Object { - "backgroundColor": "#00ff00", - } - } - > - Rules - </li> - </ul> - <span> - 10 new Java rules - </span> -</div> -`; - -exports[`#Notification should render correctly 1`] = ` -<div - className="notifications-sidebar-slice" -> - <h4> - <DateFormatter - date="2018-04-05" - long={false} - /> - </h4> - <Feature - feature={ - Object { - "categories": Array [ - Object { - "color": "#0000ff", - "name": "BitBucket", - }, - ], - "description": "BitBucket branch decoration", - "readMore": "http://example.com", - } - } - key="0" - /> -</div> -`; - -exports[`#Notification should render correctly 2`] = ` -<div - className="notifications-sidebar-slice unread" -> - <h4> - <DateFormatter - date="2018-04-05" - long={false} - /> - </h4> - <Feature - feature={ - Object { - "categories": Array [ - Object { - "color": "#0000ff", - "name": "BitBucket", - }, - ], - "description": "BitBucket branch decoration", - "readMore": "http://example.com", - } - } - key="0" - /> -</div> -`; - -exports[`#NotificationSidebar should render correctly if there are new features 1`] = ` -<Modal - contentLabel="embed_docs.whats_new" - onRequestClose={[MockFunction]} -> - <div - className="notifications-sidebar" - > - <div - className="notifications-sidebar-top" - > - <h3> - embed_docs.whats_new - </h3> - <ClearButton - className="button-tiny" - iconProps={ - Object { - "size": 12, - "thin": true, - } - } - onClick={[MockFunction]} - /> - </div> - <div - className="notifications-sidebar-content" - > - <div - className="text-center" - > - <DeferredSpinner - className="big-spacer-top" - timeout={200} - /> - </div> - </div> - </div> -</Modal> -`; - -exports[`#NotificationSidebar should render correctly if there are new features 2`] = ` -<Modal - contentLabel="embed_docs.whats_new" - onRequestClose={[MockFunction]} -> - <div - className="notifications-sidebar" - > - <div - className="notifications-sidebar-top" - > - <h3> - embed_docs.whats_new - </h3> - <ClearButton - className="button-tiny" - iconProps={ - Object { - "size": 12, - "thin": true, - } - } - onClick={[MockFunction]} - /> - </div> - <div - className="notifications-sidebar-content" - > - <Notification - key="2018-04-06" - notification={ - Object { - "features": Array [ - Object { - "categories": Array [ - Object { - "color": "#ff0000", - "name": "Java", - }, - Object { - "color": "#00ff00", - "name": "Rules", - }, - ], - "description": "10 new Java rules", - }, - Object { - "categories": Array [ - Object { - "color": "#0000ff", - "name": "BitBucket", - }, - ], - "description": "BitBucket branch decoration", - "readMore": "http://example.com", - }, - ], - "notification": "10 Java rules, Github checks, Security Hotspots, BitBucket branch decoration", - "publicationDate": "2018-04-06", - } - } - unread={true} - /> - <Notification - key="2018-04-05" - notification={ - Object { - "features": Array [ - Object { - "categories": Array [ - Object { - "color": "#0000ff", - "name": "BitBucket", - }, - ], - "description": "BitBucket branch decoration", - "readMore": "http://example.com", - }, - ], - "notification": "Some other notification", - "publicationDate": "2018-04-05", - } - } - unread={true} - /> - </div> - <div - className="notifications-sidebar-footer" - > - <div - className="spacer-top note text-center" - > - <a - className="spacer-left" - href="#" - onClick={[MockFunction]} - > - show_more - </a> - </div> - </div> - </div> -</Modal> -`; diff --git a/server/sonar-web/src/main/js/app/components/notifications/notifications.css b/server/sonar-web/src/main/js/app/components/notifications/notifications.css deleted file mode 100644 index ef18020bf4f..00000000000 --- a/server/sonar-web/src/main/js/app/components/notifications/notifications.css +++ /dev/null @@ -1,157 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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. - */ -.navbar-latest-notification { - flex: 0 1 240px; - text-align: right; - overflow: hidden; -} - -.navbar-latest-notification-wrapper { - position: relative; - display: inline-block; - padding: var(--gridSize); - padding-left: 50px; - height: 28px; - max-width: 100%; - box-sizing: border-box; - overflow: hidden; - vertical-align: middle; - font-size: var(--smallFontSize); - text-overflow: ellipsis; - white-space: nowrap; - color: var(--sonarcloudBlack500); - background-color: #000; - border-radius: 3px 0 0 3px; - cursor: pointer; -} - -.navbar-latest-notification-wrapper:hover { - color: var(--sonarcloudBlack300); -} - -.navbar-latest-notification-wrapper .badge-info { - position: absolute; - margin-right: var(--gridSize); - left: 6px; - top: 6px; -} - -.navbar-latest-notification-wrapper .label { - display: block; - max-width: 330px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.navbar-latest-notification-dismiss .navbar-icon { - height: 28px; - background-color: #000; - border-radius: 0 3px 3px 0; - padding: var(--gridSize) 7px !important; - margin-left: 1px; - margin-right: var(--gridSize); - color: var(--sonarcloudBlack500) !important; -} - -.navbar-latest-notification-dismiss .navbar-icon:hover { - color: var(--sonarcloudBlack300) !important; -} - -.notifications-sidebar { - position: fixed; - top: 0; - right: 0; - bottom: 0; - width: 400px; - display: flex; - flex-direction: column; - background: var(--sonarcloudBlack200); -} - -.notifications-sidebar-top { - position: relative; - display: flex; - align-items: center; - justify-content: space-between; - padding: calc(2 * var(--gridSize)); - border-bottom: 1px solid var(--sonarcloudBlack250); - background-color: var(--sonarcloudBlack100); -} - -.notifications-sidebar-top h3 { - font-weight: normal; - font-size: var(--bigFontSize); -} - -.notifications-sidebar-content { - flex: 1 1; - overflow-y: auto; -} - -.notifications-sidebar-footer { - padding-top: var(--gridSize); - border-top: 1px solid var(--sonarcloudBlack250); - flex: 0 0 40px; -} - -.notifications-sidebar-slice h4 { - padding: calc(2 * var(--gridSize)); - padding-bottom: calc(var(--gridSize) / 2); - background-color: var(--sonarcloudBlack200); - font-weight: normal; - font-size: var(--smallFontSize); - text-align: right; - color: var(--sonarcloudBlack500); -} - -.notifications-sidebar-slice .feature:last-of-type { - border-bottom: 1px solid var(--sonarcloudBlack250); -} - -.notifications-sidebar-slice .feature { - padding: calc(2 * var(--gridSize)); - background-color: var(--sonarcloudBlack100); - border-top: 1px solid var(--sonarcloudBlack250); - overflow: hidden; -} - -.notifications-sidebar-slice.unread .feature { - background-color: #e6f6ff; - border-color: #cee4f2; -} - -.notifications-sidebar-slice .learn-more { - clear: both; - float: right; - margin-top: var(--gridSize); -} - -.notifications-sidebar-slice .categories li { - display: inline-block; - padding: 4px; - margin-right: var(--gridSize); - font-size: 9px; - line-height: 8px; - text-transform: uppercase; - font-weight: bold; - color: #fff; - border-radius: 3px; -} |