Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
MM-10028 Add system notice feature with API deprecation notice (#1118)
Browse files Browse the repository at this point in the history
* Add system notice feature with API deprecation notice

* Update notices.jsx

* Update en.json

* Updating css for annoucement message

* Update snapshots
  • Loading branch information
jwilander committed Apr 26, 2018
1 parent 45b3271 commit e932317
Show file tree
Hide file tree
Showing 20 changed files with 644 additions and 11 deletions.
15 changes: 15 additions & 0 deletions actions/views/notice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {ActionTypes} from 'utils/constants';

export function dismissNotice(type) {
return (dispatch) => {
dispatch({
type: ActionTypes.DISMISS_NOTICE,
data: type,
});

return {data: true};
};
}
2 changes: 2 additions & 0 deletions components/admin_console/admin_console.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';

import AnnouncementBar from 'components/announcement_bar';
import SystemNotice from 'components/system_notice';
import {reloadIfServerVersionChanged} from 'actions/global_actions.jsx';
import ClientVersionsSettings from 'components/admin_console/client_versions_settings.jsx';
import ClusterSettings from 'components/admin_console/cluster_settings.jsx';
Expand Down Expand Up @@ -151,6 +152,7 @@ export default class AdminConsole extends React.Component {
return (
<div className='admin-console__wrapper'>
<AnnouncementBar/>
<SystemNotice/>
<AdminSidebar/>
<div className='admin-console'>
<Switch>
Expand Down
2 changes: 2 additions & 0 deletions components/backstage/backstage_controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Route, Switch} from 'react-router-dom';

import Pluggable from 'plugins/pluggable';
import AnnouncementBar from 'components/announcement_bar';
import SystemNotice from 'components/system_notice';
import Integrations from 'components/integrations';
import Emoji from 'components/emoji';
import AddEmoji from 'components/emoji/add_emoji';
Expand Down Expand Up @@ -87,6 +88,7 @@ export default class BackstageController extends React.Component {
return (
<div className='backstage'>
<AnnouncementBar/>
<SystemNotice/>
<BackstageNavbar
team={this.props.team}
siteName={this.props.siteName}
Expand Down
2 changes: 2 additions & 0 deletions components/channel_layout/channel_controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Route} from 'react-router-dom';

import Pluggable from 'plugins/pluggable';
import AnnouncementBar from 'components/announcement_bar';
import SystemNotice from 'components/system_notice';
import EditPostModal from 'components/edit_post_modal';
import GetPostLinkModal from 'components/get_post_link_modal';
import GetTeamInviteLinkModal from 'components/get_team_invite_link_modal';
Expand Down Expand Up @@ -44,6 +45,7 @@ export default class ChannelController extends React.Component {
return (
<div className='channel-view'>
<AnnouncementBar/>
<SystemNotice/>
<WebrtcNotification/>

<div className='container-fluid'>
Expand Down
52 changes: 52 additions & 0 deletions components/system_notice/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import {bindActionCreators} from 'redux';
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
import {haveISystemPermission} from 'mattermost-redux/selectors/entities/roles';
import {savePreferences} from 'mattermost-redux/actions/preferences';
import {Permissions} from 'mattermost-redux/constants';

import {dismissNotice} from 'actions/views/notice';
import {Preferences} from 'utils/constants.jsx';

import Notices from './notices.jsx';
import SystemNotice from './system_notice.jsx';

function makeMapStateToProps() {
const getCategory = makeGetCategory();

const getPreferenceNameMap = createSelector(
getCategory,
(preferences) => {
const nameMap = {};
preferences.forEach((p) => {
nameMap[p.name] = p;
});
return nameMap;
}
);

return function mapStateToProps(state) {
return {
currentUserId: state.entities.users.currentUserId,
preferences: getPreferenceNameMap(state, Preferences.CATEGORY_SYSTEM_NOTICE),
dismissedNotices: state.views.notice.hasBeenDismissed,
isSystemAdmin: haveISystemPermission(state, {permission: Permissions.MANAGE_SYSTEM}),
notices: Notices,
};
};
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
savePreferences,
dismissNotice,
}, dispatch),
};
}

export default connect(makeMapStateToProps, mapDispatchToProps)(SystemNotice);
35 changes: 35 additions & 0 deletions components/system_notice/notices.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import React from 'react';
import {FormattedHTMLMessage} from 'react-intl';

import mattermostIcon from 'images/icon50x50.png';

// Notices are objects with the following fields:
// - name - string identifier
// - adminOnly - set to true if only system admins should see this message
// - icon - the image to display for the notice icon
// - title - JSX node to display for the notice title
// - body - JSX node to display for the notice body
//
// Order is important! The notices at the top are shown first.
export default [
{
name: 'apiv3_deprecation',
adminOnly: true,
title: (
<FormattedHTMLMessage
id='system_notice.title'
defaultMessage='<strong>System Message</strong> from Mattermost'
/>
),
icon: mattermostIcon,
body: (
<FormattedHTMLMessage
id='system_notice.body.api3'
defaultMessage='If you’ve created or installed integrations in the last two years, find out how <a href="https://about.mattermost.com/default-apiv3-deprecation-guide" target="_blank">upcoming changes</a> may affect them.'
/>
),
},
];
136 changes: 136 additions & 0 deletions components/system_notice/system_notice.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import React from 'react';
import PropTypes from 'prop-types';
import {FormattedMessage} from 'react-intl';

import {Preferences} from 'utils/constants.jsx';
import MattermostLogo from 'components/svg/mattermost_logo';

export default class SystemNotice extends React.PureComponent {
static propTypes = {
currentUserId: PropTypes.string.isRequired,
notices: PropTypes.arrayOf(PropTypes.object).isRequired,
preferences: PropTypes.object.isRequired,
dismissedNotices: PropTypes.object.isRequired,
isSystemAdmin: PropTypes.bool,
actions: PropTypes.shape({
savePreferences: PropTypes.func.isRequired,
dismissNotice: PropTypes.func.isRequired,
}).isRequired,
}

constructor(props) {
super(props);

this.state = {
currentNotice: null,
};
}

componentDidMount() {
this.setCurrentNotice();
}

componentWillReceiveProps(nextProps) {
this.setCurrentNotice(nextProps);
}

setCurrentNotice = (props = this.props) => {
for (const notice of props.notices) {
// Skip if dismissed previously this session
if (props.dismissedNotices[notice.name]) {
continue;
}

// Skip if dismissed forever
if (props.preferences[notice.name]) {
continue;
}

if (notice.adminOnly && !props.isSystemAdmin) {
continue;
}

this.setState({currentNotice: notice});
return;
}

this.setState({currentNotice: null});
}

hide = (remind = false) => {
const notice = this.state.currentNotice;
if (!notice) {
return;
}

if (!remind) {
this.props.actions.savePreferences(this.props.currentUserId, [{
user_id: this.props.currentUserId,
category: Preferences.CATEGORY_SYSTEM_NOTICE,
name: notice.name,
value: 'dismissed',
}]);
}

this.props.actions.dismissNotice(notice.name);
}

hideAndRemind = () => {
this.hide(true);
}

hideAndForget = () => {
this.hide(false);
}

render() {
const notice = this.state.currentNotice;

if (notice == null) {
return null;
}

return (
<div
className='system-notice bg--white shadow--2'
>
<div className='system-notice__header'>
<div className='system-notice__logo'>
<MattermostLogo/>
</div>
<div className='system-notice__title'>
{notice.title}
</div>
</div>
<div className='system-notice__body'>
{notice.body}
</div>
<div className='system-notice__footer'>
<button
id='systemnotice_remindme'
className='btn btn-transparent'
onClick={this.hideAndRemind}
>
<FormattedMessage
id='system_notice_remind_me'
defaultMessage='Remind me later'
/>
</button>
<button
id='systemnotice_dontshow'
className='btn btn-transparent'
onClick={this.hideAndForget}
>
<FormattedMessage
id='system_notice_dont_show'
defaultMessage="Don't show again"
/>
</button>
</div>
</div>
);
}
}
4 changes: 4 additions & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{
"system_notice.title": "<strong>System Message</strong><br>from Mattermost",
"system_notice.body.api3": "If you’ve created or installed integrations in the last two years, find out how <a href=\"https://about.mattermost.com/default-apiv3-deprecation-guide\" target=\"_blank\">upcoming changes</a> may affect them.",
"system_notice.remind_me": "Remind me later",
"system_notice.dont_show": "Don't show again",
"about.buildnumber": "Build Number:",
"about.close": "Close",
"about.copyright": "Copyright 2015 - {currentYear} Mattermost, Inc. All rights reserved",
Expand Down
2 changes: 2 additions & 0 deletions reducers/views/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import emoji from './emoji';
import lhs from './lhs';
import webrtc from './webrtc';
import search from './search';
import notice from './notice';

export default combineReducers({
admin,
Expand All @@ -23,4 +24,5 @@ export default combineReducers({
lhs,
webrtc,
search,
notice,
});
19 changes: 19 additions & 0 deletions reducers/views/notice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

import {combineReducers} from 'redux';

import {ActionTypes} from 'utils/constants.jsx';

function hasBeenDismissed(state = {}, action) {
switch (action.type) {
case ActionTypes.DISMISS_NOTICE:
return {...state, [action.data]: true};
default:
return state;
}
}

export default combineReducers({
hasBeenDismissed,
});
8 changes: 7 additions & 1 deletion sass/components/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ button {
}

.btn {
@include single-transition(all, .15s, ease-in);
@include single-transition(all, .3s, ease);
@include border-radius($border-rad);

&.btn-primary {
Expand Down Expand Up @@ -68,6 +68,12 @@ button {
}
}

&.btn-transparent {
background: transparent;
border: none;
padding: 7px 12px;
}

&.btn-inactive {
background: $light-gray;
border-color: transparent;
Expand Down
1 change: 1 addition & 0 deletions sass/components/_module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
@import 'videos';
@import 'webrtc';
@import 'color-input';
@import 'system-notice';
Loading

0 comments on commit e932317

Please sign in to comment.