aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src')
-rw-r--r--server/sonar-web/src/main/js/api/users.ts4
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.css4
-rw-r--r--server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx28
-rw-r--r--server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx35
-rw-r--r--server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/__snapshots__/PromotionNotification-test.tsx.snap17
-rw-r--r--server/sonar-web/src/main/js/store/__tests__/users-test.tsx10
-rw-r--r--server/sonar-web/src/main/js/store/users.ts13
8 files changed, 98 insertions, 15 deletions
diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts
index 9d8282ba5be..73cee845733 100644
--- a/server/sonar-web/src/main/js/api/users.ts
+++ b/server/sonar-web/src/main/js/api/users.ts
@@ -97,3 +97,7 @@ export function setHomePage(homepage: T.HomePage): Promise<void | Response> {
export function setUserSetting(setting: T.CurrentUserSetting): Promise<void | Response> {
return post('/api/users/set_setting', setting).catch(throwGlobalError);
}
+
+export function dismissSonarlintAd(): Promise<void | Response> {
+ return post('/api/users/dismiss_sonarlint_ad').catch(throwGlobalError);
+}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap
index 03e12641665..5f47fc1d4a2 100644
--- a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalContainer-test.tsx.snap
@@ -37,7 +37,7 @@ exports[`should render correctly 1`] = `
</Connect(withAppState(IndexationContextProvider))>
</Workspace>
</div>
- <Connect(withCurrentUser(PromotionNotification)) />
+ <Connect(Connect(withCurrentUser(PromotionNotification))) />
</div>
<Connect(GlobalFooter) />
</div>
diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.css b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.css
index 52217e8226d..313f1500416 100644
--- a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.css
+++ b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.css
@@ -32,3 +32,7 @@
.toaster-content {
border-right: 1px solid var(--darkBackgroundSeparator);
}
+
+.toaster-link {
+ color: var(--darkBackgroundFontColor);
+}
diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx
index 92765402c3c..3e907843a69 100644
--- a/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx
+++ b/server/sonar-web/src/main/js/app/components/promotion-notification/PromotionNotification.tsx
@@ -18,12 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { connect } from 'react-redux';
+import { dismissSonarlintAd } from '../../../api/users';
+import { ButtonLink } from '../../../components/controls/buttons';
import { withCurrentUser } from '../../../components/hoc/withCurrentUser';
import { translate } from '../../../helpers/l10n';
import { isLoggedIn } from '../../../helpers/users';
+import { setSonarlintAd } from '../../../store/users';
import './PromotionNotification.css';
export interface PromotionNotificationProps {
+ setSonarlintAd: () => void;
currentUser: T.CurrentUser;
}
@@ -34,28 +39,39 @@ export function PromotionNotification(props: PromotionNotificationProps) {
return null;
}
+ const onClick = () => {
+ dismissSonarlintAd();
+ props.setSonarlintAd();
+ };
+
return (
- <div className="toaster display-flex-center big-padded">
+ <div className="toaster display-flex-center big-padded-left big-padded-right">
<div className="toaster-icon spacer-right">
<img alt="SonarQube + SonarLint" src="/images/sq-sl.png" />
</div>
- <div className="toaster-content flex-1 padded-left padded-right">
+ <div className="toaster-content flex-1 padded-left padded-right big-padded-top big-padded-bottom">
<span className="toaster-title text-bold medium">
{translate('promotion.sonarlint.title')}
</span>
<p className="spacer-top">{translate('promotion.sonarlint.content')}</p>
</div>
- <div className="toaster-actions spacer-left padded-left">
+ <div className="toaster-actions spacer-left padded-left display-flex-column display-flex-center">
<a
- className="button"
- href="https://www.sonarqube.org/sonarlint/"
+ className="button button-primary big-spacer-bottom"
+ href="https://www.sonarqube.org/sonarlint/?referrer=sonarqube-welcome"
rel="noreferrer"
+ onClick={onClick}
target="_blank">
{translate('learn_more')}
</a>
+ <ButtonLink className="toaster-link" onClick={onClick}>
+ {translate('dismiss')}
+ </ButtonLink>
</div>
</div>
);
}
-export default withCurrentUser(PromotionNotification);
+const dispatchToProps = { setSonarlintAd };
+
+export default connect(null, dispatchToProps)(withCurrentUser(PromotionNotification));
diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx
index cbc90b77fc1..1168776e576 100644
--- a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/PromotionNotification-test.tsx
@@ -20,9 +20,18 @@
import { shallow } from 'enzyme';
import React from 'react';
+import { dismissSonarlintAd } from '../../../../api/users';
import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks';
import { PromotionNotification, PromotionNotificationProps } from '../PromotionNotification';
+jest.mock('../../../../api/users', () => ({
+ dismissSonarlintAd: jest.fn()
+}));
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
+
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('anonymous');
expect(
@@ -31,6 +40,30 @@ it('should render correctly', () => {
expect(shallowRender({ currentUser: mockLoggedInUser() })).toMatchSnapshot('loggedIn');
});
+it('should remove the toaster when click on dismiss', () => {
+ const setSonarlintAd = jest.fn();
+ const wrapper = shallowRender({
+ currentUser: mockLoggedInUser({ sonarLintAdSeen: false }),
+ setSonarlintAd
+ });
+ wrapper.find('.toaster-actions ButtonLink').simulate('click');
+ expect(dismissSonarlintAd).toBeCalled();
+ expect(setSonarlintAd).toBeCalled();
+});
+
+it('should remove the toaster and navigate to sonarlint when click on learn more', () => {
+ const setSonarlintAd = jest.fn();
+ const wrapper = shallowRender({
+ currentUser: mockLoggedInUser({ sonarLintAdSeen: false }),
+ setSonarlintAd
+ });
+ wrapper.find('.toaster-actions .button-primary').simulate('click');
+ expect(dismissSonarlintAd).toBeCalled();
+ expect(setSonarlintAd).toBeCalled();
+});
+
function shallowRender(props: Partial<PromotionNotificationProps> = {}) {
- return shallow(<PromotionNotification currentUser={mockCurrentUser()} {...props} />);
+ return shallow(
+ <PromotionNotification currentUser={mockCurrentUser()} setSonarlintAd={jest.fn()} {...props} />
+ );
}
diff --git a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/__snapshots__/PromotionNotification-test.tsx.snap b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/__snapshots__/PromotionNotification-test.tsx.snap
index 2726d40d53e..d2daa0ec162 100644
--- a/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/__snapshots__/PromotionNotification-test.tsx.snap
+++ b/server/sonar-web/src/main/js/app/components/promotion-notification/__tests__/__snapshots__/PromotionNotification-test.tsx.snap
@@ -6,7 +6,7 @@ exports[`should render correctly: anonymous 1`] = `""`;
exports[`should render correctly: loggedIn 1`] = `
<div
- className="toaster display-flex-center big-padded"
+ className="toaster display-flex-center big-padded-left big-padded-right"
>
<div
className="toaster-icon spacer-right"
@@ -17,7 +17,7 @@ exports[`should render correctly: loggedIn 1`] = `
/>
</div>
<div
- className="toaster-content flex-1 padded-left padded-right"
+ className="toaster-content flex-1 padded-left padded-right big-padded-top big-padded-bottom"
>
<span
className="toaster-title text-bold medium"
@@ -31,16 +31,23 @@ exports[`should render correctly: loggedIn 1`] = `
</p>
</div>
<div
- className="toaster-actions spacer-left padded-left"
+ className="toaster-actions spacer-left padded-left display-flex-column display-flex-center"
>
<a
- className="button"
- href="https://www.sonarqube.org/sonarlint/"
+ className="button button-primary big-spacer-bottom"
+ href="https://www.sonarqube.org/sonarlint/?referrer=sonarqube-welcome"
+ onClick={[Function]}
rel="noreferrer"
target="_blank"
>
learn_more
</a>
+ <ButtonLink
+ className="toaster-link"
+ onClick={[Function]}
+ >
+ dismiss
+ </ButtonLink>
</div>
</div>
`;
diff --git a/server/sonar-web/src/main/js/store/__tests__/users-test.tsx b/server/sonar-web/src/main/js/store/__tests__/users-test.tsx
index cf2615fd0ab..2547c9aca88 100644
--- a/server/sonar-web/src/main/js/store/__tests__/users-test.tsx
+++ b/server/sonar-web/src/main/js/store/__tests__/users-test.tsx
@@ -19,6 +19,7 @@
*/
import { mockCurrentUser, mockLoggedInUser, mockUser } from '../../helpers/testMocks';
+import { isLoggedIn } from '../../helpers/users';
import reducer, {
getCurrentUser,
getCurrentUserSetting,
@@ -27,6 +28,7 @@ import reducer, {
receiveCurrentUser,
setCurrentUserSettingAction,
setHomePageAction,
+ setSonarlintAd,
State
} from '../users';
@@ -76,6 +78,14 @@ describe('reducer and actions', () => {
})
);
});
+
+ it('should allow to set the sonarLintAdSeen flag', () => {
+ const currentUser = mockLoggedInUser();
+ const initialState: State = createState({ currentUser });
+
+ const newState = reducer(initialState, setSonarlintAd());
+ expect(isLoggedIn(newState.currentUser) && newState.currentUser.sonarLintAdSeen).toBe(true);
+ });
});
describe('getters', () => {
diff --git a/server/sonar-web/src/main/js/store/users.ts b/server/sonar-web/src/main/js/store/users.ts
index 31b3a329eee..e637a551f63 100644
--- a/server/sonar-web/src/main/js/store/users.ts
+++ b/server/sonar-web/src/main/js/store/users.ts
@@ -26,13 +26,15 @@ import { ActionType } from './utils/actions';
const enum Actions {
ReceiveCurrentUser = 'RECEIVE_CURRENT_USER',
SetCurrentUserSetting = 'SET_CURRENT_USER_SETTING',
- SetHomePageAction = 'SET_HOMEPAGE'
+ SetHomePageAction = 'SET_HOMEPAGE',
+ SetSonarlintAd = 'SET_SONARLINT_AD'
}
type Action =
| ActionType<typeof receiveCurrentUser, Actions.ReceiveCurrentUser>
| ActionType<typeof setCurrentUserSettingAction, Actions.SetCurrentUserSetting>
- | ActionType<typeof setHomePageAction, Actions.SetHomePageAction>;
+ | ActionType<typeof setHomePageAction, Actions.SetHomePageAction>
+ | ActionType<typeof setSonarlintAd, Actions.SetSonarlintAd>;
export interface State {
usersByLogin: T.Dict<any>;
@@ -52,6 +54,10 @@ export function setCurrentUserSettingAction(setting: T.CurrentUserSetting) {
return { type: Actions.SetCurrentUserSetting, setting };
}
+export function setSonarlintAd() {
+ return { type: Actions.SetSonarlintAd };
+}
+
export function setHomePage(homepage: T.HomePage) {
return (dispatch: Dispatch) => {
api.setHomePage(homepage).then(
@@ -117,6 +123,9 @@ function currentUser(
}
return { ...state, settings } as T.LoggedInUser;
}
+ if (action.type === Actions.SetSonarlintAd && isLoggedIn(state)) {
+ return { ...state, sonarLintAdSeen: true } as T.LoggedInUser;
+ }
return state;
}