From: Grégoire Aubert Date: Tue, 12 Jun 2018 12:58:03 +0000 (+0200) Subject: SONARCLOUD-63 Update help dropdown with product news X-Git-Tag: 7.5~961 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1d0b5d8c3ea9654bc5c83200d79dc998993b7f3f;p=sonarqube.git SONARCLOUD-63 Update help dropdown with product news --- diff --git a/server/sonar-web/src/main/js/api/news.ts b/server/sonar-web/src/main/js/api/news.ts new file mode 100644 index 00000000000..a262a9e14ea --- /dev/null +++ b/server/sonar-web/src/main/js/api/news.ts @@ -0,0 +1,63 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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. + */ +/* eslint-disable camelcase */ +import { getCorsJSON } from '../helpers/request'; + +interface PrismicRef { + id: string; + ref: string; +} + +export interface PrismicNews { + data: { title: string }; + last_publication_date: string; + uid: string; +} + +const PRISMIC_API_URL = 'https://sonarsource.cdn.prismic.io/api/v2'; + +export function fetchPrismicRefs() { + return getCorsJSON(PRISMIC_API_URL).then((response: { refs: Array }) => { + const master = response && response.refs.find(ref => ref.id === 'master'); + if (!master) { + return Promise.reject('No master ref found'); + } + return Promise.resolve(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: Array }) => results); +} 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 da65d03892e..cbaea65d18c 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 @@ -20,12 +20,13 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import { Link } from 'react-router'; +import ProductNewsMenuItem from './ProductNewsMenuItem'; import { SuggestionLink } from './SuggestionsProvider'; import { CurrentUser, isLoggedIn } from '../../types'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/urls'; -import { DropdownOverlay } from '../../../components/controls/Dropdown'; import { isSonarCloud } from '../../../helpers/system'; +import { DropdownOverlay } from '../../../components/controls/Dropdown'; interface Props { currentUser: CurrentUser; @@ -87,17 +88,27 @@ export default class EmbedDocsPopup extends React.PureComponent {
  • - + {translate('embed_docs.get_help')}
  • {this.renderTitle(translate('embed_docs.stay_connected'))}
  • - {this.renderIconLink('https://about.sonarcloud.io/news/', 'sc-icon.svg', 'Product News')} + {this.renderIconLink('https://twitter.com/sonarcloud', 'twitter-icon.svg', 'Twitter')}
  • - {this.renderIconLink('https://twitter.com/sonarcloud', 'twitter-icon.svg', 'Twitter')} + {this.renderIconLink( + 'https://blog.sonarsource.com/product/SonarCloud', + 'sc-icon.svg', + translate('embed_docs.news') + )} +
  • +
  • +
  • ); @@ -125,7 +136,7 @@ export default class EmbedDocsPopup extends React.PureComponent { {this.renderIconLink( 'https://www.sonarsource.com/resources/product-news/', 'sq-icon.svg', - 'Product News' + translate('embed_docs.news') )}
  • diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx index c2ad6cf19c5..06b7bc02b02 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopupHelper.tsx @@ -34,6 +34,7 @@ interface State { } export default class EmbedDocsPopupHelper extends React.PureComponent { + mounted = false; state: State = { helpOpen: false }; componentDidMount() { 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 new file mode 100644 index 00000000000..e87e82bad4f --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/ProductNewsMenuItem.tsx @@ -0,0 +1,131 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 { fetchPrismicRefs, fetchPrismicNews, PrismicNews } from '../../../api/news'; +import { getGlobalSettingValue } from '../../../store/rootReducer'; +import DateFormatter from '../../../components/intl/DateFormatter'; +import ChevronRightIcon from '../../../components/icons-components/ChevronRightcon'; +import PlaceholderBar from '../../../components/ui/PlaceholderBar'; + +interface OwnProps { + tag?: string; +} + +interface StateProps { + accessToken?: string; +} + +type Props = OwnProps & StateProps; + +interface State { + loading: boolean; + news?: PrismicNews; +} + +export class ProductNewsMenuItem extends React.PureComponent { + 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 ( + +
    +
    +

    Latest news

    + + + +
    +

    + {' '} + {' '} + +

    +
    + +
    + ); + } + + render() { + const link = 'https://blog.sonarsource.com/'; + const { loading, news } = this.state; + + if (loading) { + return this.renderPlaceholder(); + } + + if (!news) { + return null; + } + + return ( + +
    +
    +

    Latest news

    + + {formattedDate => {formattedDate}} + +
    +

    {news.data.title}

    +
    + +
    + ); + } +} + +const mapStateToProps = (state: any): StateProps => ({ + accessToken: (getGlobalSettingValue(state, 'sonar.prismic.accessToken') || {}).value +}); + +export default connect(mapStateToProps)(ProductNewsMenuItem); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx index 48bb8a0799a..9423f9979fa 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx @@ -19,14 +19,34 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import EmbedDocsPopups from '../EmbedDocsPopup'; +import EmbedDocsPopup from '../EmbedDocsPopup'; +import { isSonarCloud } from '../../../../helpers/system'; + +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn().mockReturnValue(false) })); const suggestions = [{ link: '#', text: 'foo' }, { link: '#', text: 'bar' }]; it('should display suggestion links', () => { const context = {}; const wrapper = shallow( - , + { + context + } + ); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); +}); + +it('should display correct links for SonarCloud', () => { + (isSonarCloud as jest.Mock).mockReturnValueOnce(true); + const context = {}; + const wrapper = shallow( + ({ + 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(); + 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__/EmbedDocsPopup-test.tsx.snap b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap index 05de0c05460..3fc1cca678d 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/EmbedDocsPopup-test.tsx.snap @@ -1,5 +1,127 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`should display correct links for SonarCloud 1`] = ` + + + +`; + exports[`should display suggestion links 1`] = `
      Product News - Product News + embed_docs.news
    • 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 new file mode 100644 index 00000000000..365de2d274a --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/__snapshots__/ProductNewsMenuItem-test.tsx.snap @@ -0,0 +1,95 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should load the product news 1`] = ` + +
      +
      +

      + Latest news +

      + + + +
      +

      + + + + + + + + + + + +

      +
      + +
      +`; + +exports[`should load the product news 2`] = ` + +
      +
      +

      + Latest news +

      + +
      +

      + My Product News +

      +
      + +
      +`; diff --git a/server/sonar-web/src/main/js/app/styles/components/menu.css b/server/sonar-web/src/main/js/app/styles/components/menu.css index e5bf1c05eda..9bead9c66d3 100644 --- a/server/sonar-web/src/main/js/app/styles/components/menu.css +++ b/server/sonar-web/src/main/js/app/styles/components/menu.css @@ -54,6 +54,16 @@ transition: none; } +.menu > li > a.rich-item { + display: flex; + align-items: center; + border: 1px solid var(--gray80); + border-radius: 4px; + margin: 4px 10px; + padding: 2px 8px; + white-space: normal; +} + .menu .divider { height: 1px; margin: 6px 0; diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css index 16e78425e0a..0e70c8dba99 100644 --- a/server/sonar-web/src/main/js/app/styles/init/misc.css +++ b/server/sonar-web/src/main/js/app/styles/init/misc.css @@ -310,6 +310,10 @@ td.big-spacer-top { flex: 1; } +.flex-0 { + flex: 0 0 auto; +} + .flex-shrink { flex-shrink: 1; min-width: 0; diff --git a/server/sonar-web/src/main/js/components/ui/PlaceholderBar.css b/server/sonar-web/src/main/js/components/ui/PlaceholderBar.css new file mode 100644 index 00000000000..a204a3434d4 --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/PlaceholderBar.css @@ -0,0 +1,25 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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. + */ +.placeholder-bar { + display: inline-block; + vertical-align: middle; + height: 8px; + background-color: currentColor; +} diff --git a/server/sonar-web/src/main/js/components/ui/PlaceholderBar.tsx b/server/sonar-web/src/main/js/components/ui/PlaceholderBar.tsx new file mode 100644 index 00000000000..c33d3b74a88 --- /dev/null +++ b/server/sonar-web/src/main/js/components/ui/PlaceholderBar.tsx @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 './PlaceholderBar.css'; + +interface Props { + color?: string; + width: number; + height?: number; +} + +export default function PlaceholderBar({ color, width, height }: Props) { + return ; +} diff --git a/server/sonar-web/src/main/js/helpers/request.ts b/server/sonar-web/src/main/js/helpers/request.ts index 1b0e075b21e..682b86d22fe 100644 --- a/server/sonar-web/src/main/js/helpers/request.ts +++ b/server/sonar-web/src/main/js/helpers/request.ts @@ -212,6 +212,23 @@ export function getJSON(url: string, data?: RequestData): Promise { .then(parseJSON); } +/** + * Shortcut to do a CORS GET request and return responsejson + */ +export function getCorsJSON(url: string, data?: RequestData): Promise { + return corsRequest(url) + .setData(data) + .submit() + .then(response => { + if (response.status >= 200 && response.status < 300) { + return Promise.resolve(response); + } else { + return Promise.reject({ response }); + } + }) + .then(parseJSON); +} + /** * Shortcut to do a POST request and return response json */ diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 7913933313a..9e09559006d 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2553,11 +2553,12 @@ organization.change_visibility_form.submit=Change Default Visibility # EMBEDED DOCS # #------------------------------------------------------------------------------ -embed_docs.suggestion=Suggestions For This Page +embed_docs.analyze_new_project=Analyze New Project embed_docs.documentation=Documentation embed_docs.get_help=Get Help +embed_docs.news=Product News embed_docs.stay_connected=Stay Connected -embed_docs.analyze_new_project=Analyze New Project +embed_docs.suggestion=Suggestions For This Page #------------------------------------------------------------------------------ #