From c54e107bb8305de177d8c805d0368eaf7df3bc37 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Tue, 7 Feb 2017 13:11:07 +0100 Subject: [PATCH] SONAR-8669 Display organizations on the "Notifications" page (#1633) --- .../src/main/js/api/notifications.js | 9 ++-- .../notifications/ProjectNotifications.js | 22 ++++++---- .../js/apps/account/notifications/Projects.js | 42 ++++++++++++++----- .../ProjectNotifications-test.js.snap | 18 +++++++- .../__snapshots__/Projects-test.js.snap | 21 ++++++---- .../js/apps/account/notifications/actions.js | 20 +++++---- .../main/js/components/shared/Organization.js | 13 +++++- server/sonar-web/src/main/js/helpers/urls.js | 7 ++++ .../src/main/js/store/notifications/duck.js | 11 +++-- 9 files changed, 119 insertions(+), 44 deletions(-) diff --git a/server/sonar-web/src/main/js/api/notifications.js b/server/sonar-web/src/main/js/api/notifications.js index 4ca5b24dd65..ec433d1e1b3 100644 --- a/server/sonar-web/src/main/js/api/notifications.js +++ b/server/sonar-web/src/main/js/api/notifications.js @@ -24,8 +24,9 @@ export type GetNotificationsResponse = { notifications: Array<{ channel: string, type: string, - project: string | null, - projectName: string | null + organization?: string, + project?: string, + projectName?: string }>, channels: Array, globalTypes: Array, @@ -36,7 +37,7 @@ export const getNotifications = (): Promise => ( getJSON('/api/notifications/list') ); -export const addNotification = (channel: string, type: string, project: string | null): Promise<*> => { +export const addNotification = (channel: string, type: string, project?: string): Promise<*> => { const data: Object = { channel, type }; if (project) { Object.assign(data, { project }); @@ -44,7 +45,7 @@ export const addNotification = (channel: string, type: string, project: string | return post('/api/notifications/add', data); }; -export const removeNotification = (channel: string, type: string, project: string | null): Promise<*> => { +export const removeNotification = (channel: string, type: string, project?: string): Promise<*> => { const data: Object = { channel, type }; if (project) { Object.assign(data, { project }); diff --git a/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.js b/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.js index 828e4ec3eba..55279c4ed96 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.js +++ b/server/sonar-web/src/main/js/apps/account/notifications/ProjectNotifications.js @@ -19,20 +19,23 @@ */ import React from 'react'; import { connect } from 'react-redux'; +import { Link } from 'react-router'; import NotificationsList from './NotificationsList'; +import Organization from '../../../components/shared/Organization'; import { translate } from '../../../helpers/l10n'; import { - getProjectNotifications, - getNotificationChannels, - getNotificationPerProjectTypes +getProjectNotifications, +getNotificationChannels, +getNotificationPerProjectTypes } from '../../../store/rootReducer'; import type { - Notification, - NotificationsState, - ChannelsState, - TypesState +Notification, +NotificationsState, +ChannelsState, +TypesState } from '../../../store/notifications/duck'; import { addNotification, removeNotification } from './actions'; +import { getProjectUrl } from '../../../helpers/urls'; class ProjectNotifications extends React.Component { props: { @@ -72,7 +75,10 @@ class ProjectNotifications extends React.Component { -

{project.name}

+ +

+ {project.name} +

{channels.map(channel => ( diff --git a/server/sonar-web/src/main/js/apps/account/notifications/Projects.js b/server/sonar-web/src/main/js/apps/account/notifications/Projects.js index b9c189b4002..72153b35b29 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/Projects.js +++ b/server/sonar-web/src/main/js/apps/account/notifications/Projects.js @@ -22,8 +22,9 @@ import Select from 'react-select'; import { connect } from 'react-redux'; import differenceBy from 'lodash/differenceBy'; import ProjectNotifications from './ProjectNotifications'; +import Organization from '../../../components/shared/Organization'; import { translate } from '../../../helpers/l10n'; -import { getComponents } from '../../../api/components'; +import { getSuggestions } from '../../../api/components'; import { getProjectsWithNotifications } from '../../../store/rootReducer'; type Props = { @@ -60,19 +61,38 @@ class Projects extends React.Component { } } - loadOptions = query => { - // TODO filter existing out - return getComponents({ qualifiers: 'TRK', q: query }) - .then(r => r.components) + renderOption = option => { + return ( + + + {option.label} + + ); + } + + loadOptions = (query, cb) => { + if (query.length < 2) { + cb(null, { options: [] }); + return; + } + + getSuggestions(query) + .then(r => { + const projects = r.results.find(domain => domain.q === 'TRK'); + return projects ? projects.items : []; + }) .then(projects => projects.map(project => ({ value: project.key, - label: project.name + label: project.name, + organization: project.organization }))) - .then(options => ({ options })); + .then(options => { + cb(null, { options }); + }); }; handleAddProject = selected => { - const project = { key: selected.value, name: selected.label }; + const project = { key: selected.value, name: selected.label, organization: selected.organization }; this.setState({ addedProjects: [...this.state.addedProjects, project] }); @@ -102,13 +122,15 @@ class Projects extends React.Component { Set notifications for: + placeholder="Search Project"/> ); diff --git a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/ProjectNotifications-test.js.snap b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/ProjectNotifications-test.js.snap index 44df6e92f1a..13344ac72ae 100644 --- a/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/ProjectNotifications-test.js.snap +++ b/server/sonar-web/src/main/js/apps/account/notifications/__tests__/__snapshots__/ProjectNotifications-test.js.snap @@ -4,9 +4,25 @@ exports[`test should match snapshot 1`] = ` + + +

- Foo + + Foo +

(dispatch: Function) => { const onFulfil = (response: GetNotificationsResponse) => { - dispatch(receiveNotifications( - response.notifications, - response.channels, - response.globalTypes, - response.perProjectTypes - )); + const organizations = response.notifications + .filter(n => n.organization) + .map(n => n.organization); + + dispatch(fetchOrganizations(organizations)).then(() => { + dispatch(receiveNotifications( + response.notifications, + response.channels, + response.globalTypes, + response.perProjectTypes + )); + }); }; return api.getNotifications().then(onFulfil, onFail(dispatch)); diff --git a/server/sonar-web/src/main/js/components/shared/Organization.js b/server/sonar-web/src/main/js/components/shared/Organization.js index f803359455e..4835871864b 100644 --- a/server/sonar-web/src/main/js/components/shared/Organization.js +++ b/server/sonar-web/src/main/js/components/shared/Organization.js @@ -28,17 +28,22 @@ type OwnProps = { }; type Props = { + link?: boolean, organizationKey: string, organization: null | { key: string, name: string }, - shouldBeDisplayed: boolean + shouldBeDisplayed: boolean, }; class Organization extends React.Component { props: Props; + static defaultProps = { + link: true + }; + render () { const { organization, shouldBeDisplayed } = this.props; @@ -48,7 +53,11 @@ class Organization extends React.Component { return ( - {organization.name} + {this.props.link ? ( + {organization.name} + ) : ( + organization.name + )} ); diff --git a/server/sonar-web/src/main/js/helpers/urls.js b/server/sonar-web/src/main/js/helpers/urls.js index 6dddb630c09..42416ae5cf4 100644 --- a/server/sonar-web/src/main/js/helpers/urls.js +++ b/server/sonar-web/src/main/js/helpers/urls.js @@ -26,6 +26,13 @@ export function getComponentUrl (componentKey) { return window.baseUrl + '/dashboard?id=' + encodeURIComponent(componentKey); } +export function getProjectUrl (key) { + return { + pathname: '/dashboard', + query: { id: key } + }; +} + /** * Generate URL for a global issues page * @param {object} query diff --git a/server/sonar-web/src/main/js/store/notifications/duck.js b/server/sonar-web/src/main/js/store/notifications/duck.js index b53948850f9..e5e6a8d4520 100644 --- a/server/sonar-web/src/main/js/store/notifications/duck.js +++ b/server/sonar-web/src/main/js/store/notifications/duck.js @@ -25,8 +25,9 @@ import uniqWith from 'lodash/uniqWith'; export type Notification = { channel: string, type: string, - project: string | null, - projectName: string | null + project?: string, + projectName?: string, + organization?: string }; export type NotificationsState = Array; @@ -147,7 +148,11 @@ export const getGlobal = (state: State): NotificationsState => ( export const getProjects = (state: State): Array => ( uniqBy( - state.notifications.filter(n => n.project).map(n => ({ key: n.project, name: n.projectName })), + state.notifications.filter(n => n.project).map(n => ({ + key: n.project, + name: n.projectName, + organization: n.organization + })), project => project.key ) ); -- 2.39.5