mattermost-desktop/src/browser/index.jsx

742 lines
20 KiB
React
Raw Normal View History

2015-12-22 07:34:24 -08:00
'use strict';
2016-09-25 07:14:01 -07:00
window.eval = global.eval = () => {
throw new Error('Sorry, Mattermost does not support window.eval() for security reasons.');
};
2016-01-30 07:50:43 -08:00
const React = require('react');
const ReactDOM = require('react-dom');
const ReactBootstrap = require('react-bootstrap');
2015-12-22 07:34:24 -08:00
const Grid = ReactBootstrap.Grid;
const Row = ReactBootstrap.Row;
const Col = ReactBootstrap.Col;
2015-12-22 23:21:33 -08:00
const Nav = ReactBootstrap.Nav;
const NavItem = ReactBootstrap.NavItem;
2015-12-22 07:34:24 -08:00
2016-04-22 08:50:57 -07:00
const LoginModal = require('./components/loginModal.jsx');
2016-09-25 07:14:01 -07:00
const {remote, ipcRenderer, shell} = require('electron');
const electronContextMenu = require('electron-context-menu');
2015-12-22 07:34:24 -08:00
const osLocale = require('os-locale');
const fs = require('fs');
const url = require('url');
2015-12-22 07:34:24 -08:00
const settings = require('../common/settings');
2016-09-25 07:14:01 -07:00
const badge = require('./js/badge');
2015-12-22 07:34:24 -08:00
remote.getCurrentWindow().removeAllListeners('focus');
2016-09-25 07:14:01 -07:00
var config;
try {
var configFile = remote.getGlobal('config-file');
config = settings.readFileSync(configFile);
} catch (e) {
window.location = 'settings.html';
}
if (config.teams.length === 0) {
window.location = 'settings.html';
}
2015-12-22 07:34:24 -08:00
var MainPage = React.createClass({
2016-09-25 07:14:01 -07:00
getInitialState() {
2015-12-22 07:34:24 -08:00
return {
2015-12-22 23:21:33 -08:00
key: 0,
unreadCounts: new Array(this.props.teams.length),
mentionCounts: new Array(this.props.teams.length),
unreadAtActive: new Array(this.props.teams.length),
2016-04-22 08:50:57 -07:00
mentionAtActiveCounts: new Array(this.props.teams.length),
loginQueue: []
2015-12-22 07:34:24 -08:00
};
},
2016-09-25 07:14:01 -07:00
componentDidMount() {
var self = this;
ipcRenderer.on('login-request', (event, request, authInfo) => {
self.setState({
2016-04-22 08:50:57 -07:00
loginRequired: true
});
2016-09-25 07:14:01 -07:00
const loginQueue = self.state.loginQueue;
2016-04-22 08:50:57 -07:00
loginQueue.push({
2016-09-25 07:14:01 -07:00
request,
authInfo
2016-04-22 08:50:57 -07:00
});
2016-09-25 07:14:01 -07:00
self.setState({
loginQueue
2016-04-22 08:50:57 -07:00
});
});
2016-09-25 07:14:01 -07:00
// can't switch tabs sequencially for some reason...
ipcRenderer.on('switch-tab', (event, key) => {
this.handleSelect(key);
});
2016-09-25 07:14:01 -07:00
ipcRenderer.on('select-next-tab', () => {
this.handleSelect(this.state.key + 1);
});
2016-09-25 07:14:01 -07:00
ipcRenderer.on('select-previous-tab', () => {
this.handleSelect(this.state.key - 1);
});
2016-04-22 08:50:57 -07:00
// reload the activated tab
2016-09-25 07:14:01 -07:00
ipcRenderer.on('reload-tab', () => {
this.refs[`mattermostView${this.state.key}`].reload();
});
2016-09-25 07:14:01 -07:00
ipcRenderer.on('clear-cache-and-reload-tab', () => {
this.refs[`mattermostView${this.state.key}`].clearCacheAndReload();
});
// activate search box in current tab
2016-09-25 07:14:01 -07:00
ipcRenderer.on('activate-search-box', () => {
const webview = document.getElementById('mattermostView' + self.state.key);
webview.send('activate-search-box');
});
// activate search box in current chunnel
2016-09-25 07:14:01 -07:00
ipcRenderer.on('activate-search-box-in-channel', () => {
const webview = document.getElementById('mattermostView' + self.state.key);
webview.send('activate-search-box-in-channel');
});
2016-09-25 07:14:01 -07:00
function focusListener() {
self.handleOnTeamFocused(self.state.key);
self.refs[`mattermostView${self.state.key}`].focusOnWebView();
}
var currentWindow = remote.getCurrentWindow();
currentWindow.on('focus', focusListener);
2016-09-25 07:14:01 -07:00
window.addEventListener('beforeunload', () => {
currentWindow.removeListener('focus', focusListener);
});
//goBack and goForward
ipcRenderer.on('go-back', () => {
2016-09-25 07:14:01 -07:00
const mattermost = self.refs[`mattermostView${self.state.key}`];
if (mattermost.canGoBack()) {
mattermost.goBack();
}
});
ipcRenderer.on('go-forward', () => {
2016-09-25 07:14:01 -07:00
const mattermost = self.refs[`mattermostView${self.state.key}`];
if (mattermost.canGoForward()) {
mattermost.goForward();
}
});
},
2016-09-25 07:14:01 -07:00
componentDidUpdate(prevProps, prevState) {
if (prevState.key !== this.state.key) { // i.e. When tab has been changed
this.refs[`mattermostView${this.state.key}`].focusOnWebView();
}
},
2016-09-25 07:14:01 -07:00
handleSelect(key) {
const newKey = (this.props.teams.length + key) % this.props.teams.length;
2015-12-22 07:34:24 -08:00
this.setState({
key: newKey
2015-12-22 23:21:33 -08:00
});
this.handleOnTeamFocused(newKey);
var webview = document.getElementById('mattermostView' + newKey);
ipcRenderer.send('update-title', {
title: webview.getTitle()
});
2015-12-22 23:21:33 -08:00
},
2016-09-25 07:14:01 -07:00
handleUnreadCountChange(index, unreadCount, mentionCount, isUnread, isMentioned) {
var unreadCounts = this.state.unreadCounts;
var mentionCounts = this.state.mentionCounts;
var unreadAtActive = this.state.unreadAtActive;
2016-02-01 06:58:59 -08:00
var mentionAtActiveCounts = this.state.mentionAtActiveCounts;
unreadCounts[index] = unreadCount;
mentionCounts[index] = mentionCount;
2016-09-25 07:14:01 -07:00
// Never turn on the unreadAtActive flag at current focused tab.
if (this.state.key !== index || !remote.getCurrentWindow().isFocused()) {
unreadAtActive[index] = unreadAtActive[index] || isUnread;
2016-02-01 06:58:59 -08:00
if (isMentioned) {
mentionAtActiveCounts[index]++;
}
}
2015-12-22 23:21:33 -08:00
this.setState({
2016-09-25 07:14:01 -07:00
unreadCounts,
mentionCounts,
unreadAtActive,
mentionAtActiveCounts
2015-12-22 07:34:24 -08:00
});
this.handleUnreadCountTotalChange();
},
2016-09-25 07:14:01 -07:00
markReadAtActive(index) {
var unreadAtActive = this.state.unreadAtActive;
2016-02-01 06:58:59 -08:00
var mentionAtActiveCounts = this.state.mentionAtActiveCounts;
unreadAtActive[index] = false;
2016-02-01 06:58:59 -08:00
mentionAtActiveCounts[index] = 0;
this.setState({
2016-09-25 07:14:01 -07:00
unreadAtActive,
mentionAtActiveCounts
});
this.handleUnreadCountTotalChange();
},
2016-09-25 07:14:01 -07:00
handleUnreadCountTotalChange() {
2015-12-23 00:06:17 -08:00
if (this.props.onUnreadCountChange) {
2016-09-25 07:14:01 -07:00
var allUnreadCount = this.state.unreadCounts.reduce((prev, curr) => {
2015-12-23 00:06:17 -08:00
return prev + curr;
}, 0);
2016-09-25 07:14:01 -07:00
this.state.unreadAtActive.forEach((state) => {
if (state) {
allUnreadCount += 1;
}
2015-12-23 00:06:17 -08:00
});
2016-09-25 07:14:01 -07:00
var allMentionCount = this.state.mentionCounts.reduce((prev, curr) => {
return prev + curr;
}, 0);
2016-09-25 07:14:01 -07:00
this.state.mentionAtActiveCounts.forEach((count) => {
2016-02-01 06:58:59 -08:00
allMentionCount += count;
});
this.props.onUnreadCountChange(allUnreadCount, allMentionCount);
2015-12-23 00:06:17 -08:00
}
2015-12-22 07:34:24 -08:00
},
2016-09-25 07:14:01 -07:00
handleOnTeamFocused(index) {
// Turn off the flag to indicate whether unread message of active channel contains at current tab.
this.markReadAtActive(index);
},
2016-09-25 07:14:01 -07:00
visibleStyle(visible) {
2015-12-23 03:53:54 -08:00
var visibility = visible ? 'visible' : 'hidden';
2015-12-22 07:34:24 -08:00
return {
position: 'absolute',
top: (this.props.teams.length > 1) ? 42 : 0,
2015-12-22 07:34:24 -08:00
right: 0,
bottom: 0,
left: 0,
2016-09-25 07:14:01 -07:00
visibility
2015-12-22 07:34:24 -08:00
};
},
2016-04-22 08:50:57 -07:00
2016-09-25 07:14:01 -07:00
handleLogin(request, username, password) {
2016-04-22 08:50:57 -07:00
ipcRenderer.send('login-credentials', request, username, password);
const loginQueue = this.state.loginQueue;
loginQueue.shift();
this.setState(loginQueue);
},
2016-09-25 07:14:01 -07:00
handleLoginCancel() {
2016-04-22 08:50:57 -07:00
const loginQueue = this.state.loginQueue;
loginQueue.shift();
this.setState(loginQueue);
},
2016-09-25 07:14:01 -07:00
render() {
var self = this;
2016-09-25 07:14:01 -07:00
var tabsRow;
if (this.props.teams.length > 1) {
2016-09-25 07:14:01 -07:00
tabsRow = (
<Row>
2016-09-25 07:14:01 -07:00
<TabBar
id='tabBar'
teams={this.props.teams}
unreadCounts={this.state.unreadCounts}
mentionCounts={this.state.mentionCounts}
unreadAtActive={this.state.unreadAtActive}
mentionAtActiveCounts={this.state.mentionAtActiveCounts}
activeKey={this.state.key}
onSelect={this.handleSelect}
/>
</Row>
);
}
2016-09-25 07:14:01 -07:00
var views = this.props.teams.map((team, index) => {
function handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned) {
self.handleUnreadCountChange(index, unreadCount, mentionCount, isUnread, isMentioned);
}
function handleNotificationClick() {
self.handleSelect(index);
}
var id = 'mattermostView' + index;
2016-09-25 07:14:01 -07:00
var isActive = self.state.key === index;
return (
<MattermostView
key={id}
id={id}
style={self.visibleStyle(isActive)}
src={team.url}
name={team.name}
onUnreadCountChange={handleUnreadCountChange}
onNotificationClick={handleNotificationClick}
ref={id}
active={isActive}
/>);
2015-12-22 07:34:24 -08:00
});
2016-09-25 07:14:01 -07:00
var viewsRow = (
<Row>
{views}
</Row>);
2016-04-22 08:50:57 -07:00
var request = null;
var authServerURL = null;
2016-04-25 04:41:02 -07:00
var authInfo = null;
2016-04-22 08:50:57 -07:00
if (this.state.loginQueue.length !== 0) {
request = this.state.loginQueue[0].request;
2016-09-25 07:14:01 -07:00
const tmpURL = url.parse(this.state.loginQueue[0].request.url);
authServerURL = `${tmpURL.protocol}//${tmpURL.host}`;
2016-04-25 04:41:02 -07:00
authInfo = this.state.loginQueue[0].authInfo;
2016-04-22 08:50:57 -07:00
}
2015-12-22 07:34:24 -08:00
return (
2016-04-22 08:50:57 -07:00
<div>
2016-09-25 07:14:01 -07:00
<LoginModal
show={this.state.loginQueue.length !== 0}
request={request}
authInfo={authInfo}
authServerURL={authServerURL}
onLogin={this.handleLogin}
onCancel={this.handleLoginCancel}
/>
2016-04-22 08:50:57 -07:00
<Grid fluid>
2016-09-25 07:14:01 -07:00
{ tabsRow }
{ viewsRow }
2016-04-22 08:50:57 -07:00
</Grid>
</div>
2016-11-08 06:54:53 -08:00
);
2015-12-22 07:34:24 -08:00
}
});
var TabBar = React.createClass({
2016-09-25 07:14:01 -07:00
render() {
var self = this;
var tabs = this.props.teams.map((team, index) => {
var unreadCount = 0;
var badgeStyle = {
background: '#FF1744',
float: 'right',
color: 'white',
minWidth: '19px',
fontSize: '12px',
textAlign: 'center',
lineHeight: '20px',
height: '19px',
marginLeft: '5px',
2016-09-25 07:14:01 -07:00
borderRadius: '50%'
};
2016-09-25 07:14:01 -07:00
if (self.props.unreadCounts[index] > 0) {
unreadCount = self.props.unreadCounts[index];
}
2016-09-25 07:14:01 -07:00
if (self.props.unreadAtActive[index]) {
unreadCount += 1;
}
var mentionCount = 0;
2016-09-25 07:14:01 -07:00
if (self.props.mentionCounts[index] > 0) {
mentionCount = self.props.mentionCounts[index];
}
2016-09-25 07:14:01 -07:00
if (self.props.mentionAtActiveCounts[index] > 0) {
mentionCount += self.props.mentionAtActiveCounts[index];
}
2016-09-25 07:14:01 -07:00
var badgeDiv;
if (mentionCount !== 0) {
badgeDiv = (
<div style={badgeStyle}>
{mentionCount}
</div>);
}
2016-09-25 07:14:01 -07:00
var id = 'teamTabItem' + index;
if (unreadCount === 0) {
return (
<NavItem
className='teamTabItem'
key={id}
id={id}
eventKey={index}
>
{ team.name }
{ ' ' }
{ badgeDiv }
</NavItem>);
}
2016-09-25 07:14:01 -07:00
return (
<NavItem
className='teamTabItem'
key={id}
id={id}
eventKey={index}
>
<b>{ team.name }</b>
{ ' ' }
{ badgeDiv }
</NavItem>);
});
return (
2016-09-25 07:14:01 -07:00
<Nav
id={this.props.id}
bsStyle='tabs'
activeKey={this.props.activeKey}
onSelect={this.props.onSelect}
>
{ tabs }
</Nav>
2016-11-08 06:54:53 -08:00
);
}
});
2015-12-22 23:21:33 -08:00
2015-12-22 07:34:24 -08:00
var MattermostView = React.createClass({
2016-09-25 07:14:01 -07:00
getInitialState() {
return {
errorInfo: null
};
},
2016-09-25 07:14:01 -07:00
handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned) {
if (this.props.onUnreadCountChange) {
this.props.onUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
}
},
2016-09-25 07:14:01 -07:00
componentDidMount() {
var self = this;
var webview = ReactDOM.findDOMNode(this.refs.webview);
2016-11-04 12:28:31 -07:00
// This option allows insecure content, when set to true it is possible to
// load content via HTTP while the mattermost server serves HTTPS
2016-04-17 07:07:17 -07:00
if (config.disablewebsecurity === true) {
2016-11-04 12:28:31 -07:00
webview.setAttribute('webpreferences', 'allowDisplayingInsecureContent');
2016-04-17 07:07:17 -07:00
}
2016-09-25 07:14:01 -07:00
webview.addEventListener('did-fail-load', (e) => {
console.log(self.props.name, 'webview did-fail-load', e);
if (e.errorCode === -3) { // An operation was aborted (due to user action).
return;
}
2016-09-25 07:14:01 -07:00
self.setState({
errorInfo: e
});
2016-09-25 07:14:01 -07:00
function reload() {
window.removeEventListener('online', reload);
2016-09-25 07:14:01 -07:00
self.reload();
}
if (navigator.onLine) {
setTimeout(reload, 30000);
} else {
window.addEventListener('online', reload);
}
});
// Open link in browserWindow. for exmaple, attached files.
2016-09-25 07:14:01 -07:00
webview.addEventListener('new-window', (e) => {
var currentURL = url.parse(webview.getURL());
var destURL = url.parse(e.url);
2016-04-26 06:40:21 -07:00
if (destURL.protocol !== 'http:' && destURL.protocol !== 'https:') {
2016-05-21 21:39:52 -07:00
ipcRenderer.send('confirm-protocol', destURL.protocol, e.url);
return;
}
if (currentURL.host === destURL.host) {
// New window should disable nodeIntergration.
window.open(e.url, 'Mattermost', 'nodeIntegration=no');
} else {
// if the link is external, use default browser.
2016-06-12 06:56:22 -07:00
shell.openExternal(e.url);
}
});
2016-09-25 07:14:01 -07:00
webview.addEventListener('dom-ready', () => {
// webview.openDevTools();
// Use 'Meiryo UI' and 'MS Gothic' to prevent CJK fonts on Windows(JP).
if (process.platform === 'win32') {
2016-09-25 07:14:01 -07:00
function applyCssFile(cssFile) {
fs.readFile(cssFile, 'utf8', (err, data) => {
if (err) {
console.log(err);
return;
}
webview.insertCSS(data);
});
2016-09-25 07:14:01 -07:00
}
2016-09-25 07:14:01 -07:00
osLocale((err, locale) => {
if (err) {
console.log(err);
return;
}
if (locale === 'ja_JP') {
applyCssFile(__dirname + '/css/jp_fonts.css');
}
});
}
2016-09-25 07:14:01 -07:00
electronContextMenu({
window: webview
});
});
2016-09-25 07:14:01 -07:00
webview.addEventListener('ipc-message', (event) => {
switch (event.channel) {
2016-09-25 07:14:01 -07:00
case 'onUnreadCountChange':
var unreadCount = event.args[0];
var mentionCount = event.args[1];
// isUnread and isMentioned is pulse flag.
var isUnread = event.args[2];
var isMentioned = event.args[3];
self.handleUnreadCountChange(unreadCount, mentionCount, isUnread, isMentioned);
break;
case 'onNotificationClick':
self.props.onNotificationClick();
break;
}
});
2016-09-25 07:14:01 -07:00
webview.addEventListener('page-title-updated', (event) => {
if (self.props.active) {
ipcRenderer.send('update-title', {
title: event.title
});
}
});
webview.addEventListener('console-message', (e) => {
2016-02-13 02:30:37 -08:00
const message = `[${this.props.name}] ${e.message}`;
switch (e.level) {
2016-09-25 07:14:01 -07:00
case 0:
console.log(message);
break;
case 1:
console.warn(message);
break;
case 2:
console.error(message);
break;
default:
console.log(message);
break;
2016-02-13 02:30:37 -08:00
}
});
},
2016-09-25 07:14:01 -07:00
reload() {
this.setState({
errorInfo: null
});
var webview = ReactDOM.findDOMNode(this.refs.webview);
webview.reload();
},
clearCacheAndReload() {
this.setState({
errorInfo: null
});
var webContents = ReactDOM.findDOMNode(this.refs.webview).getWebContents();
webContents.session.clearCache(() => {
webContents.reload();
});
},
2016-09-25 07:14:01 -07:00
focusOnWebView() {
const webview = ReactDOM.findDOMNode(this.refs.webview);
if (!webview.getWebContents().isFocused()) {
webview.focus();
webview.getWebContents().focus();
}
},
canGoBack() {
const webview = ReactDOM.findDOMNode(this.refs.webview);
return webview.getWebContents().canGoBack();
},
canGoForward() {
const webview = ReactDOM.findDOMNode(this.refs.webview);
return webview.getWebContents().canGoForward();
},
goBack() {
const webview = ReactDOM.findDOMNode(this.refs.webview);
webview.getWebContents().goBack();
},
goForward() {
const webview = ReactDOM.findDOMNode(this.refs.webview);
webview.getWebContents().goForward();
},
2016-09-25 07:14:01 -07:00
render() {
const errorView = this.state.errorInfo ? (
<ErrorView
id={this.props.id + '-fail'}
style={this.props.style}
className='errorView'
errorInfo={this.state.errorInfo}
/>) : null;
2015-12-22 07:34:24 -08:00
// 'disablewebsecurity' is necessary to display external images.
// However, it allows also CSS/JavaScript.
// So webview should use 'allowDisplayingInsecureContent' as same as BrowserWindow.
// Need to keep webview mounted when failed to load.
2016-09-25 07:14:01 -07:00
return (
<div>
{ errorView }
<webview
id={this.props.id}
className='mattermostView'
style={this.props.style}
preload='webview/mattermost.js'
src={this.props.src}
ref='webview'
nodeintegration='false'
/>
</div>);
}
});
// ErrorCode: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h
const errorPage = {
tableStyle: {
display: 'table',
width: '100%',
height: '100%',
position: 'absolute',
top: '0',
left: '0'
},
cellStyle: {
display: 'table-cell',
verticalAlign: 'top',
paddingTop: '2em'
},
bullets: {
paddingLeft: '15px',
lineHeight: '1.7'
},
techInfo: {
fontSize: '12px',
color: '#aaa'
2016-09-25 07:14:01 -07:00
}
};
var ErrorView = React.createClass({
2016-09-25 07:14:01 -07:00
render() {
return (
2016-09-25 07:14:01 -07:00
<Grid
id={this.props.id}
style={this.props.style}
>
<div style={errorPage.tableStyle}>
<div style={errorPage.cellStyle}>
<Row>
2016-09-25 07:14:01 -07:00
<Col
xs={0}
sm={1}
md={1}
lg={2}
/>
<Col
xs={12}
sm={10}
md={10}
lg={8}
>
<h2>{'Cannot connect to Mattermost'}</h2>
<hr/>
<p>{'We\'re having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work please verify that:'}</p>
<br/>
<ul style={errorPage.bullets}>
<li>{'Your computer is connected to the internet.'}</li>
<li>{'The Mattermost URL '}
<a href={this.props.errorInfo.validatedURL}>
{this.props.errorInfo.validatedURL}
</a>{' is correct.'}</li>
<li>{'You can reach '}
<a href={this.props.errorInfo.validatedURL}>
{this.props.errorInfo.validatedURL}
</a>{' from a browser window.'}</li>
</ul>
<br/>
<div style={errorPage.techInfo}>
{this.props.errorInfo.errorDescription}{' ('}
{this.props.errorInfo.errorCode }{')'}</div>
</Col>
2016-09-25 07:14:01 -07:00
<Col
xs={0}
sm={1}
md={1}
lg={2}
/>
</Row>
</div>
</div>
</Grid>
2016-11-08 06:54:53 -08:00
);
2015-12-22 07:34:24 -08:00
}
});
2016-09-25 07:14:01 -07:00
function showUnreadBadgeWindows(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,
2016-09-25 07:14:01 -07:00
description,
unreadCount,
mentionCount
});
2016-09-25 07:14:01 -07:00
}
if (mentionCount > 0) {
const dataURL = badge.createDataURL(mentionCount.toString());
2016-06-03 16:41:15 -07:00
sendBadge(dataURL, 'You have unread mentions (' + mentionCount + ')');
2016-07-15 04:04:14 -07:00
} else if (unreadCount > 0 && config.showUnreadBadge) {
const dataURL = badge.createDataURL('•');
2016-06-03 16:41:15 -07:00
sendBadge(dataURL, 'You have unread channels (' + unreadCount + ')');
} else {
sendBadge(null, 'You have no unread messages');
}
}
2016-09-25 07:14:01 -07:00
function showUnreadBadgeOSX(unreadCount, mentionCount) {
if (mentionCount > 0) {
remote.app.dock.setBadge(mentionCount.toString());
2016-07-15 04:04:14 -07:00
} else if (unreadCount > 0 && config.showUnreadBadge) {
remote.app.dock.setBadge('•');
} else {
remote.app.dock.setBadge('');
}
2016-04-06 08:49:20 -07:00
ipcRenderer.send('update-unread', {
2016-09-25 07:14:01 -07:00
unreadCount,
mentionCount
2016-04-06 08:49:20 -07:00
});
}
2016-09-25 07:14:01 -07:00
function showUnreadBadgeLinux(unreadCount, mentionCount) {
2016-06-29 12:28:43 -07:00
if (remote.app.isUnityRunning()) {
remote.app.setBadgeCount(mentionCount);
}
ipcRenderer.send('update-unread', {
2016-09-25 07:14:01 -07:00
unreadCount,
mentionCount
});
}
2016-09-25 07:14:01 -07:00
function showUnreadBadge(unreadCount, mentionCount) {
2015-12-23 00:06:17 -08:00
switch (process.platform) {
2016-09-25 07:14:01 -07:00
case 'win32':
showUnreadBadgeWindows(unreadCount, mentionCount);
break;
case 'darwin':
showUnreadBadgeOSX(unreadCount, mentionCount);
break;
case 'linux':
showUnreadBadgeLinux(unreadCount, mentionCount);
break;
default:
2015-12-23 00:06:17 -08:00
}
}
ReactDOM.render(
2016-09-25 07:14:01 -07:00
<MainPage
teams={config.teams}
onUnreadCountChange={showUnreadBadge}
/>,
document.getElementById('content')
);