Merge pull request #866 from mattermost/mm-12205-session-expiry-notification

MM-12205: session expiry notification
This commit is contained in:
Jesse Hallam 2018-10-12 10:05:39 -04:00 committed by GitHub
commit 4b2684baa5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 43 deletions

View file

@ -39,6 +39,7 @@ export default class MainPage extends React.Component {
this.state = {
key,
sessionsExpired: new Array(this.props.teams.length),
unreadCounts: new Array(this.props.teams.length),
mentionCounts: new Array(this.props.teams.length),
unreadAtActive: new Array(this.props.teams.length),
@ -56,8 +57,6 @@ export default class MainPage extends React.Component {
this.handleOnTeamFocused = this.handleOnTeamFocused.bind(this);
this.handleSelect = this.handleSelect.bind(this);
this.handleTargetURLChange = this.handleTargetURLChange.bind(this);
this.handleUnreadCountChange = this.handleUnreadCountChange.bind(this);
this.handleUnreadCountTotalChange = this.handleUnreadCountTotalChange.bind(this);
this.inputBlur = this.inputBlur.bind(this);
this.markReadAtActive = this.markReadAtActive.bind(this);
}
@ -173,11 +172,13 @@ export default class MainPage extends React.Component {
this.handleOnTeamFocused(newKey);
}
handleUnreadCountChange(index, unreadCount, mentionCount, isUnread, isMentioned) {
handleBadgeChange = (index, sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) => {
const sessionsExpired = this.state.sessionsExpired;
const unreadCounts = this.state.unreadCounts;
const mentionCounts = this.state.mentionCounts;
const unreadAtActive = this.state.unreadAtActive;
const mentionAtActiveCounts = this.state.mentionAtActiveCounts;
sessionsExpired[index] = sessionExpired;
unreadCounts[index] = unreadCount;
mentionCounts[index] = mentionCount;
@ -189,12 +190,13 @@ export default class MainPage extends React.Component {
}
}
this.setState({
sessionsExpired,
unreadCounts,
mentionCounts,
unreadAtActive,
mentionAtActiveCounts,
});
this.handleUnreadCountTotalChange();
this.handleBadgesChange();
}
markReadAtActive(index) {
@ -206,11 +208,13 @@ export default class MainPage extends React.Component {
unreadAtActive,
mentionAtActiveCounts,
});
this.handleUnreadCountTotalChange();
this.handleBadgesChange();
}
handleUnreadCountTotalChange() {
if (this.props.onUnreadCountChange) {
handleBadgesChange = () => {
if (this.props.onBadgeChange) {
const someSessionsExpired = this.state.sessionsExpired.some((sessionExpired) => sessionExpired);
let allUnreadCount = this.state.unreadCounts.reduce((prev, curr) => {
return prev + curr;
}, 0);
@ -219,13 +223,15 @@ export default class MainPage extends React.Component {
allUnreadCount += 1;
}
});
let allMentionCount = this.state.mentionCounts.reduce((prev, curr) => {
return prev + curr;
}, 0);
this.state.mentionAtActiveCounts.forEach((count) => {
allMentionCount += count;
});
this.props.onUnreadCountChange(allUnreadCount, allMentionCount);
this.props.onBadgeChange(someSessionsExpired, allUnreadCount, allMentionCount);
}
}
@ -299,6 +305,7 @@ export default class MainPage extends React.Component {
<TabBar
id='tabBar'
teams={this.props.teams}
sessionsExpired={this.state.sessionsExpired}
unreadCounts={this.state.unreadCounts}
mentionCounts={this.state.mentionCounts}
unreadAtActive={this.state.unreadAtActive}
@ -315,8 +322,8 @@ export default class MainPage extends React.Component {
}
const views = this.props.teams.map((team, index) => {
function handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned) {
self.handleUnreadCountChange(index, unreadCount, mentionCount, isUnread, isMentioned);
function handleBadgeChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) {
self.handleBadgeChange(index, sessionExpired, unreadCount, mentionCount, isUnread, isMentioned);
}
function handleNotificationClick() {
self.handleSelect(index);
@ -340,7 +347,7 @@ export default class MainPage extends React.Component {
src={teamUrl}
name={team.name}
onTargetURLChange={self.handleTargetURLChange}
onUnreadCountChange={handleUnreadCountChange}
onBadgeChange={handleBadgeChange}
onNotificationClick={handleNotificationClick}
ref={id}
active={isActive}
@ -437,7 +444,7 @@ export default class MainPage extends React.Component {
}
MainPage.propTypes = {
onUnreadCountChange: PropTypes.func.isRequired,
onBadgeChange: PropTypes.func.isRequired,
teams: PropTypes.array.isRequired,
onTeamConfigChange: PropTypes.func.isRequired,
initialIndex: PropTypes.number.isRequired,

View file

@ -66,9 +66,9 @@ export default class MattermostView extends React.Component {
this.webviewRef = React.createRef();
}
handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned) {
if (this.props.onUnreadCountChange) {
this.props.onUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
handleUnreadCountChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) {
if (this.props.onBadgeChange) {
this.props.onBadgeChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned);
}
}
@ -158,14 +158,13 @@ export default class MattermostView extends React.Component {
isLoaded: true,
});
break;
case 'onUnreadCountChange': {
const unreadCount = event.args[0];
const mentionCount = event.args[1];
// isUnread and isMentioned is pulse flag.
const isUnread = event.args[2];
const isMentioned = event.args[3];
self.handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
case 'onBadgeChange': {
const sessionExpired = event.args[0];
const unreadCount = event.args[1];
const mentionCount = event.args[2];
const isUnread = event.args[3];
const isMentioned = event.args[4];
self.handleUnreadCountChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned);
break;
}
@ -326,7 +325,7 @@ MattermostView.propTypes = {
name: PropTypes.string,
id: PropTypes.string,
onTargetURLChange: PropTypes.func,
onUnreadCountChange: PropTypes.func,
onBadgeChange: PropTypes.func,
src: PropTypes.string,
active: PropTypes.bool,
withTab: PropTypes.bool,

View file

@ -10,6 +10,8 @@ import PermissionRequestDialog from './PermissionRequestDialog.jsx';
export default class TabBar extends React.Component { // need "this"
render() {
const tabs = this.props.teams.map((team, index) => {
const sessionExpired = this.props.sessionsExpired[index];
let unreadCount = 0;
if (this.props.unreadCounts[index] > 0) {
unreadCount = this.props.unreadCounts[index];
@ -27,11 +29,16 @@ export default class TabBar extends React.Component { // need "this"
}
let badgeDiv;
if (mentionCount !== 0) {
if (sessionExpired) {
badgeDiv = (
<div className='TabBar-badge TabBar-badge-nomention'>{'•'}</div>
);
} else if (mentionCount !== 0) {
badgeDiv = (
<div className='TabBar-badge'>
{mentionCount}
</div>);
</div>
);
}
const id = 'teamTabItem' + index;
const requestingPermission = this.props.requestingPermission[index];
@ -114,6 +121,7 @@ TabBar.propTypes = {
id: PropTypes.string,
onSelect: PropTypes.func,
teams: PropTypes.array,
sessionsExpired: PropTypes.array,
unreadCounts: PropTypes.array,
unreadAtActive: PropTypes.array,
mentionCounts: PropTypes.array,

View file

@ -53,6 +53,11 @@
border-radius: 50%;
}
.TabBar .TabBar-badge.TabBar-badge-nomention {
font-size: 22pt;
line-height: 18px;
}
.TabBar .teamTabItem-unread {
font-weight: bold;
}

View file

@ -31,19 +31,23 @@ if (teams.length === 0) {
window.location = 'settings.html';
}
function showUnreadBadgeWindows(unreadCount, mentionCount) {
function showBadgeWindows(sessionExpired, unreadCount, mentionCount) {
function sendBadge(dataURL, description) {
// window.setOverlayIcon() does't work with NativeImage across remote boundaries.
// https://github.com/atom/electron/issues/4011
ipcRenderer.send('update-unread', {
overlayDataURL: dataURL,
description,
sessionExpired,
unreadCount,
mentionCount,
});
}
if (mentionCount > 0) {
if (sessionExpired) {
const dataURL = createBadgeDataURL('•');
sendBadge(dataURL, 'Session Expired: Please sign in to continue receiving notifications.');
} else if (mentionCount > 0) {
const dataURL = createBadgeDataURL(mentionCount.toString());
sendBadge(dataURL, 'You have unread mentions (' + mentionCount + ')');
} else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) {
@ -54,8 +58,10 @@ function showUnreadBadgeWindows(unreadCount, mentionCount) {
}
}
function showUnreadBadgeOSX(unreadCount, mentionCount) {
if (mentionCount > 0) {
function showBadgeOSX(sessionExpired, unreadCount, mentionCount) {
if (sessionExpired) {
remote.app.dock.setBadge('•');
} else if (mentionCount > 0) {
remote.app.dock.setBadge(mentionCount.toString());
} else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) {
remote.app.dock.setBadge('•');
@ -64,34 +70,39 @@ function showUnreadBadgeOSX(unreadCount, mentionCount) {
}
ipcRenderer.send('update-unread', {
sessionExpired,
unreadCount,
mentionCount,
});
}
function showUnreadBadgeLinux(unreadCount, mentionCount) {
function showBadgeLinux(sessionExpired, unreadCount, mentionCount) {
if (remote.app.isUnityRunning()) {
if (sessionExpired) {
remote.app.setBadgeCount(mentionCount + 1);
} else {
remote.app.setBadgeCount(mentionCount);
}
}
ipcRenderer.send('update-unread', {
sessionExpired,
unreadCount,
mentionCount,
});
}
function showUnreadBadge(unreadCount, mentionCount) {
function showBadge(sessionExpired, unreadCount, mentionCount) {
switch (process.platform) {
case 'win32':
showUnreadBadgeWindows(unreadCount, mentionCount);
showBadgeWindows(sessionExpired, unreadCount, mentionCount);
break;
case 'darwin':
showUnreadBadgeOSX(unreadCount, mentionCount);
showBadgeOSX(sessionExpired, unreadCount, mentionCount);
break;
case 'linux':
showUnreadBadgeLinux(unreadCount, mentionCount);
showBadgeLinux(sessionExpired, unreadCount, mentionCount);
break;
default:
}
}
@ -168,7 +179,7 @@ ReactDOM.render(
<MainPage
teams={teams}
initialIndex={initialIndex}
onUnreadCountChange={showUnreadBadge}
onBadgeChange={showBadge}
onTeamConfigChange={teamConfigChange}
useSpellChecker={AppConfig.data.useSpellChecker}
onSelectSpellCheckerLocale={handleSelectSpellCheckerLocale}

View file

@ -66,9 +66,13 @@ function getUnreadCount() {
this.mentionCount = 0;
}
// LHS not found => Log out => Count should be 0.
// LHS not found => Log out => Count should be 0, but session may be expired.
if (document.getElementById('sidebar-left') === null) {
ipcRenderer.sendToHost('onUnreadCountChange', 0, 0, false, false);
const extraParam = (new URLSearchParams(window.location.search)).get('extra');
const sessionExpired = extraParam === 'expired';
ipcRenderer.sendToHost('onBadgeChange', sessionExpired, 0, 0, false, false);
this.sessionExpired = sessionExpired;
this.unreadCount = 0;
this.mentionCount = 0;
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
@ -152,11 +156,12 @@ function getUnreadCount() {
}
}
if (this.unreadCount !== unreadCount || this.mentionCount !== mentionCount || isUnread || isMentioned) {
ipcRenderer.sendToHost('onUnreadCountChange', unreadCount, mentionCount, isUnread, isMentioned);
if (this.sessionExpired || this.unreadCount !== unreadCount || this.mentionCount !== mentionCount || isUnread || isMentioned) {
ipcRenderer.sendToHost('onBadgeChange', false, unreadCount, mentionCount, isUnread, isMentioned);
}
this.unreadCount = unreadCount;
this.mentionCount = mentionCount;
this.sessionExpired = false;
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
}
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);

View file

@ -528,7 +528,14 @@ app.on('ready', () => {
}
if (trayIcon && !trayIcon.isDestroyed()) {
if (arg.mentionCount > 0) {
if (arg.sessionExpired) {
// reuse the mention icon when the session is expired
trayIcon.setImage(trayImages.mention);
if (process.platform === 'darwin') {
trayIcon.setPressedImage(trayImages.clicked.mention);
}
trayIcon.setToolTip('Session Expired: Please sign in to continue receiving notifications.');
} else if (arg.mentionCount > 0) {
trayIcon.setImage(trayImages.mention);
if (process.platform === 'darwin') {
trayIcon.setPressedImage(trayImages.clicked.mention);