Merge pull request #866 from mattermost/mm-12205-session-expiry-notification
MM-12205: session expiry notification
This commit is contained in:
commit
4b2684baa5
|
@ -39,6 +39,7 @@ export default class MainPage extends React.Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
key,
|
key,
|
||||||
|
sessionsExpired: new Array(this.props.teams.length),
|
||||||
unreadCounts: new Array(this.props.teams.length),
|
unreadCounts: new Array(this.props.teams.length),
|
||||||
mentionCounts: new Array(this.props.teams.length),
|
mentionCounts: new Array(this.props.teams.length),
|
||||||
unreadAtActive: 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.handleOnTeamFocused = this.handleOnTeamFocused.bind(this);
|
||||||
this.handleSelect = this.handleSelect.bind(this);
|
this.handleSelect = this.handleSelect.bind(this);
|
||||||
this.handleTargetURLChange = this.handleTargetURLChange.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.inputBlur = this.inputBlur.bind(this);
|
||||||
this.markReadAtActive = this.markReadAtActive.bind(this);
|
this.markReadAtActive = this.markReadAtActive.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -173,11 +172,13 @@ export default class MainPage extends React.Component {
|
||||||
this.handleOnTeamFocused(newKey);
|
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 unreadCounts = this.state.unreadCounts;
|
||||||
const mentionCounts = this.state.mentionCounts;
|
const mentionCounts = this.state.mentionCounts;
|
||||||
const unreadAtActive = this.state.unreadAtActive;
|
const unreadAtActive = this.state.unreadAtActive;
|
||||||
const mentionAtActiveCounts = this.state.mentionAtActiveCounts;
|
const mentionAtActiveCounts = this.state.mentionAtActiveCounts;
|
||||||
|
sessionsExpired[index] = sessionExpired;
|
||||||
unreadCounts[index] = unreadCount;
|
unreadCounts[index] = unreadCount;
|
||||||
mentionCounts[index] = mentionCount;
|
mentionCounts[index] = mentionCount;
|
||||||
|
|
||||||
|
@ -189,12 +190,13 @@ export default class MainPage extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
|
sessionsExpired,
|
||||||
unreadCounts,
|
unreadCounts,
|
||||||
mentionCounts,
|
mentionCounts,
|
||||||
unreadAtActive,
|
unreadAtActive,
|
||||||
mentionAtActiveCounts,
|
mentionAtActiveCounts,
|
||||||
});
|
});
|
||||||
this.handleUnreadCountTotalChange();
|
this.handleBadgesChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
markReadAtActive(index) {
|
markReadAtActive(index) {
|
||||||
|
@ -206,11 +208,13 @@ export default class MainPage extends React.Component {
|
||||||
unreadAtActive,
|
unreadAtActive,
|
||||||
mentionAtActiveCounts,
|
mentionAtActiveCounts,
|
||||||
});
|
});
|
||||||
this.handleUnreadCountTotalChange();
|
this.handleBadgesChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUnreadCountTotalChange() {
|
handleBadgesChange = () => {
|
||||||
if (this.props.onUnreadCountChange) {
|
if (this.props.onBadgeChange) {
|
||||||
|
const someSessionsExpired = this.state.sessionsExpired.some((sessionExpired) => sessionExpired);
|
||||||
|
|
||||||
let allUnreadCount = this.state.unreadCounts.reduce((prev, curr) => {
|
let allUnreadCount = this.state.unreadCounts.reduce((prev, curr) => {
|
||||||
return prev + curr;
|
return prev + curr;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -219,13 +223,15 @@ export default class MainPage extends React.Component {
|
||||||
allUnreadCount += 1;
|
allUnreadCount += 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let allMentionCount = this.state.mentionCounts.reduce((prev, curr) => {
|
let allMentionCount = this.state.mentionCounts.reduce((prev, curr) => {
|
||||||
return prev + curr;
|
return prev + curr;
|
||||||
}, 0);
|
}, 0);
|
||||||
this.state.mentionAtActiveCounts.forEach((count) => {
|
this.state.mentionAtActiveCounts.forEach((count) => {
|
||||||
allMentionCount += 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
|
<TabBar
|
||||||
id='tabBar'
|
id='tabBar'
|
||||||
teams={this.props.teams}
|
teams={this.props.teams}
|
||||||
|
sessionsExpired={this.state.sessionsExpired}
|
||||||
unreadCounts={this.state.unreadCounts}
|
unreadCounts={this.state.unreadCounts}
|
||||||
mentionCounts={this.state.mentionCounts}
|
mentionCounts={this.state.mentionCounts}
|
||||||
unreadAtActive={this.state.unreadAtActive}
|
unreadAtActive={this.state.unreadAtActive}
|
||||||
|
@ -315,8 +322,8 @@ export default class MainPage extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
const views = this.props.teams.map((team, index) => {
|
const views = this.props.teams.map((team, index) => {
|
||||||
function handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned) {
|
function handleBadgeChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) {
|
||||||
self.handleUnreadCountChange(index, unreadCount, mentionCount, isUnread, isMentioned);
|
self.handleBadgeChange(index, sessionExpired, unreadCount, mentionCount, isUnread, isMentioned);
|
||||||
}
|
}
|
||||||
function handleNotificationClick() {
|
function handleNotificationClick() {
|
||||||
self.handleSelect(index);
|
self.handleSelect(index);
|
||||||
|
@ -340,7 +347,7 @@ export default class MainPage extends React.Component {
|
||||||
src={teamUrl}
|
src={teamUrl}
|
||||||
name={team.name}
|
name={team.name}
|
||||||
onTargetURLChange={self.handleTargetURLChange}
|
onTargetURLChange={self.handleTargetURLChange}
|
||||||
onUnreadCountChange={handleUnreadCountChange}
|
onBadgeChange={handleBadgeChange}
|
||||||
onNotificationClick={handleNotificationClick}
|
onNotificationClick={handleNotificationClick}
|
||||||
ref={id}
|
ref={id}
|
||||||
active={isActive}
|
active={isActive}
|
||||||
|
@ -437,7 +444,7 @@ export default class MainPage extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
MainPage.propTypes = {
|
MainPage.propTypes = {
|
||||||
onUnreadCountChange: PropTypes.func.isRequired,
|
onBadgeChange: PropTypes.func.isRequired,
|
||||||
teams: PropTypes.array.isRequired,
|
teams: PropTypes.array.isRequired,
|
||||||
onTeamConfigChange: PropTypes.func.isRequired,
|
onTeamConfigChange: PropTypes.func.isRequired,
|
||||||
initialIndex: PropTypes.number.isRequired,
|
initialIndex: PropTypes.number.isRequired,
|
||||||
|
|
|
@ -66,9 +66,9 @@ export default class MattermostView extends React.Component {
|
||||||
this.webviewRef = React.createRef();
|
this.webviewRef = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned) {
|
handleUnreadCountChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) {
|
||||||
if (this.props.onUnreadCountChange) {
|
if (this.props.onBadgeChange) {
|
||||||
this.props.onUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
|
this.props.onBadgeChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,14 +158,13 @@ export default class MattermostView extends React.Component {
|
||||||
isLoaded: true,
|
isLoaded: true,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'onUnreadCountChange': {
|
case 'onBadgeChange': {
|
||||||
const unreadCount = event.args[0];
|
const sessionExpired = event.args[0];
|
||||||
const mentionCount = event.args[1];
|
const unreadCount = event.args[1];
|
||||||
|
const mentionCount = event.args[2];
|
||||||
// isUnread and isMentioned is pulse flag.
|
const isUnread = event.args[3];
|
||||||
const isUnread = event.args[2];
|
const isMentioned = event.args[4];
|
||||||
const isMentioned = event.args[3];
|
self.handleUnreadCountChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned);
|
||||||
self.handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -326,7 +325,7 @@ MattermostView.propTypes = {
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
onTargetURLChange: PropTypes.func,
|
onTargetURLChange: PropTypes.func,
|
||||||
onUnreadCountChange: PropTypes.func,
|
onBadgeChange: PropTypes.func,
|
||||||
src: PropTypes.string,
|
src: PropTypes.string,
|
||||||
active: PropTypes.bool,
|
active: PropTypes.bool,
|
||||||
withTab: PropTypes.bool,
|
withTab: PropTypes.bool,
|
||||||
|
|
|
@ -10,6 +10,8 @@ import PermissionRequestDialog from './PermissionRequestDialog.jsx';
|
||||||
export default class TabBar extends React.Component { // need "this"
|
export default class TabBar extends React.Component { // need "this"
|
||||||
render() {
|
render() {
|
||||||
const tabs = this.props.teams.map((team, index) => {
|
const tabs = this.props.teams.map((team, index) => {
|
||||||
|
const sessionExpired = this.props.sessionsExpired[index];
|
||||||
|
|
||||||
let unreadCount = 0;
|
let unreadCount = 0;
|
||||||
if (this.props.unreadCounts[index] > 0) {
|
if (this.props.unreadCounts[index] > 0) {
|
||||||
unreadCount = this.props.unreadCounts[index];
|
unreadCount = this.props.unreadCounts[index];
|
||||||
|
@ -27,11 +29,16 @@ export default class TabBar extends React.Component { // need "this"
|
||||||
}
|
}
|
||||||
|
|
||||||
let badgeDiv;
|
let badgeDiv;
|
||||||
if (mentionCount !== 0) {
|
if (sessionExpired) {
|
||||||
|
badgeDiv = (
|
||||||
|
<div className='TabBar-badge TabBar-badge-nomention'>{'•'}</div>
|
||||||
|
);
|
||||||
|
} else if (mentionCount !== 0) {
|
||||||
badgeDiv = (
|
badgeDiv = (
|
||||||
<div className='TabBar-badge'>
|
<div className='TabBar-badge'>
|
||||||
{mentionCount}
|
{mentionCount}
|
||||||
</div>);
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const id = 'teamTabItem' + index;
|
const id = 'teamTabItem' + index;
|
||||||
const requestingPermission = this.props.requestingPermission[index];
|
const requestingPermission = this.props.requestingPermission[index];
|
||||||
|
@ -114,6 +121,7 @@ TabBar.propTypes = {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
teams: PropTypes.array,
|
teams: PropTypes.array,
|
||||||
|
sessionsExpired: PropTypes.array,
|
||||||
unreadCounts: PropTypes.array,
|
unreadCounts: PropTypes.array,
|
||||||
unreadAtActive: PropTypes.array,
|
unreadAtActive: PropTypes.array,
|
||||||
mentionCounts: PropTypes.array,
|
mentionCounts: PropTypes.array,
|
||||||
|
|
|
@ -53,6 +53,11 @@
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.TabBar .TabBar-badge.TabBar-badge-nomention {
|
||||||
|
font-size: 22pt;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.TabBar .teamTabItem-unread {
|
.TabBar .teamTabItem-unread {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,19 +31,23 @@ if (teams.length === 0) {
|
||||||
window.location = 'settings.html';
|
window.location = 'settings.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUnreadBadgeWindows(unreadCount, mentionCount) {
|
function showBadgeWindows(sessionExpired, unreadCount, mentionCount) {
|
||||||
function sendBadge(dataURL, description) {
|
function sendBadge(dataURL, description) {
|
||||||
// window.setOverlayIcon() does't work with NativeImage across remote boundaries.
|
// window.setOverlayIcon() does't work with NativeImage across remote boundaries.
|
||||||
// https://github.com/atom/electron/issues/4011
|
// https://github.com/atom/electron/issues/4011
|
||||||
ipcRenderer.send('update-unread', {
|
ipcRenderer.send('update-unread', {
|
||||||
overlayDataURL: dataURL,
|
overlayDataURL: dataURL,
|
||||||
description,
|
description,
|
||||||
|
sessionExpired,
|
||||||
unreadCount,
|
unreadCount,
|
||||||
mentionCount,
|
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());
|
const dataURL = createBadgeDataURL(mentionCount.toString());
|
||||||
sendBadge(dataURL, 'You have unread mentions (' + mentionCount + ')');
|
sendBadge(dataURL, 'You have unread mentions (' + mentionCount + ')');
|
||||||
} else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) {
|
} else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) {
|
||||||
|
@ -54,8 +58,10 @@ function showUnreadBadgeWindows(unreadCount, mentionCount) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUnreadBadgeOSX(unreadCount, mentionCount) {
|
function showBadgeOSX(sessionExpired, unreadCount, mentionCount) {
|
||||||
if (mentionCount > 0) {
|
if (sessionExpired) {
|
||||||
|
remote.app.dock.setBadge('•');
|
||||||
|
} else if (mentionCount > 0) {
|
||||||
remote.app.dock.setBadge(mentionCount.toString());
|
remote.app.dock.setBadge(mentionCount.toString());
|
||||||
} else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) {
|
} else if (unreadCount > 0 && AppConfig.data.showUnreadBadge) {
|
||||||
remote.app.dock.setBadge('•');
|
remote.app.dock.setBadge('•');
|
||||||
|
@ -64,34 +70,39 @@ function showUnreadBadgeOSX(unreadCount, mentionCount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.send('update-unread', {
|
ipcRenderer.send('update-unread', {
|
||||||
|
sessionExpired,
|
||||||
unreadCount,
|
unreadCount,
|
||||||
mentionCount,
|
mentionCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUnreadBadgeLinux(unreadCount, mentionCount) {
|
function showBadgeLinux(sessionExpired, unreadCount, mentionCount) {
|
||||||
if (remote.app.isUnityRunning()) {
|
if (remote.app.isUnityRunning()) {
|
||||||
|
if (sessionExpired) {
|
||||||
|
remote.app.setBadgeCount(mentionCount + 1);
|
||||||
|
} else {
|
||||||
remote.app.setBadgeCount(mentionCount);
|
remote.app.setBadgeCount(mentionCount);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ipcRenderer.send('update-unread', {
|
ipcRenderer.send('update-unread', {
|
||||||
|
sessionExpired,
|
||||||
unreadCount,
|
unreadCount,
|
||||||
mentionCount,
|
mentionCount,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUnreadBadge(unreadCount, mentionCount) {
|
function showBadge(sessionExpired, unreadCount, mentionCount) {
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
showUnreadBadgeWindows(unreadCount, mentionCount);
|
showBadgeWindows(sessionExpired, unreadCount, mentionCount);
|
||||||
break;
|
break;
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
showUnreadBadgeOSX(unreadCount, mentionCount);
|
showBadgeOSX(sessionExpired, unreadCount, mentionCount);
|
||||||
break;
|
break;
|
||||||
case 'linux':
|
case 'linux':
|
||||||
showUnreadBadgeLinux(unreadCount, mentionCount);
|
showBadgeLinux(sessionExpired, unreadCount, mentionCount);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +179,7 @@ ReactDOM.render(
|
||||||
<MainPage
|
<MainPage
|
||||||
teams={teams}
|
teams={teams}
|
||||||
initialIndex={initialIndex}
|
initialIndex={initialIndex}
|
||||||
onUnreadCountChange={showUnreadBadge}
|
onBadgeChange={showBadge}
|
||||||
onTeamConfigChange={teamConfigChange}
|
onTeamConfigChange={teamConfigChange}
|
||||||
useSpellChecker={AppConfig.data.useSpellChecker}
|
useSpellChecker={AppConfig.data.useSpellChecker}
|
||||||
onSelectSpellCheckerLocale={handleSelectSpellCheckerLocale}
|
onSelectSpellCheckerLocale={handleSelectSpellCheckerLocale}
|
||||||
|
|
|
@ -66,9 +66,13 @@ function getUnreadCount() {
|
||||||
this.mentionCount = 0;
|
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) {
|
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.unreadCount = 0;
|
||||||
this.mentionCount = 0;
|
this.mentionCount = 0;
|
||||||
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
||||||
|
@ -152,11 +156,12 @@ function getUnreadCount() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.unreadCount !== unreadCount || this.mentionCount !== mentionCount || isUnread || isMentioned) {
|
if (this.sessionExpired || this.unreadCount !== unreadCount || this.mentionCount !== mentionCount || isUnread || isMentioned) {
|
||||||
ipcRenderer.sendToHost('onUnreadCountChange', unreadCount, mentionCount, isUnread, isMentioned);
|
ipcRenderer.sendToHost('onBadgeChange', false, unreadCount, mentionCount, isUnread, isMentioned);
|
||||||
}
|
}
|
||||||
this.unreadCount = unreadCount;
|
this.unreadCount = unreadCount;
|
||||||
this.mentionCount = mentionCount;
|
this.mentionCount = mentionCount;
|
||||||
|
this.sessionExpired = false;
|
||||||
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
||||||
}
|
}
|
||||||
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
setTimeout(getUnreadCount, UNREAD_COUNT_INTERVAL);
|
||||||
|
|
|
@ -528,7 +528,14 @@ app.on('ready', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trayIcon && !trayIcon.isDestroyed()) {
|
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);
|
trayIcon.setImage(trayImages.mention);
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
trayIcon.setPressedImage(trayImages.clicked.mention);
|
trayIcon.setPressedImage(trayImages.clicked.mention);
|
||||||
|
|
Loading…
Reference in a new issue