summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/react/components/admin_console/email_settings.jsx2
-rw-r--r--web/react/components/admin_console/service_settings.jsx34
-rw-r--r--web/react/components/posts_view.jsx3
-rw-r--r--web/react/components/search_results_item.jsx3
-rw-r--r--web/react/components/user_settings/custom_theme_chooser.jsx35
-rw-r--r--web/react/dispatcher/event_helpers.jsx13
-rw-r--r--web/react/stores/browser_store.jsx17
-rw-r--r--web/react/stores/error_store.jsx1
-rw-r--r--web/react/utils/client.jsx1
-rw-r--r--web/react/utils/constants.jsx46
-rw-r--r--web/sass-files/sass/partials/_base.scss1
-rw-r--r--web/sass-files/sass/partials/_docs.scss19
-rw-r--r--web/sass-files/sass/partials/_popover.scss4
-rw-r--r--web/sass-files/sass/partials/_post.scss1
-rw-r--r--web/sass-files/sass/partials/_responsive.scss2
-rw-r--r--web/sass-files/sass/partials/_sidebar--right.scss6
-rw-r--r--web/sass-files/sass/styles.scss3
-rw-r--r--web/static/images/themes/code_themes/githubLarge.pngbin0 -> 83246 bytes
-rw-r--r--web/static/images/themes/code_themes/monokaiLarge.pngbin0 -> 82658 bytes
-rw-r--r--web/static/images/themes/code_themes/solarized_darkLarge.pngbin0 -> 81942 bytes
-rw-r--r--web/static/images/themes/code_themes/solarized_lightLarge.pngbin0 -> 82868 bytes
-rw-r--r--web/templates/docs.html2
-rw-r--r--web/templates/head.html15
23 files changed, 166 insertions, 42 deletions
diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx
index 238ace3da..42e3507d6 100644
--- a/web/react/components/admin_console/email_settings.jsx
+++ b/web/react/components/admin_console/email_settings.jsx
@@ -586,7 +586,7 @@ export default class EmailSettings extends React.Component {
onChange={this.handleChange}
disabled={!this.state.sendPushNotifications}
/>
- <p className='help-text'>{'Location of the push notification server.'}</p>
+ <p className='help-text'>{'Location of Mattermost push notification service you can set up behind your firewall using https://github.com/mattermost/push-proxy. For testing you can use https://push.mattermost.com, which connects to the sample Mattermost iOS app in the public Apple AppStore. Please do not use test service for production deployments.'}</p>
</div>
</div>
diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx
index 1f5faf1d4..d7582d682 100644
--- a/web/react/components/admin_console/service_settings.jsx
+++ b/web/react/components/admin_console/service_settings.jsx
@@ -40,6 +40,7 @@ export default class ServiceSettings extends React.Component {
config.ServiceSettings.EnablePostUsernameOverride = ReactDOM.findDOMNode(this.refs.EnablePostUsernameOverride).checked;
config.ServiceSettings.EnablePostIconOverride = ReactDOM.findDOMNode(this.refs.EnablePostIconOverride).checked;
config.ServiceSettings.EnableTesting = ReactDOM.findDOMNode(this.refs.EnableTesting).checked;
+ config.ServiceSettings.EnableDeveloper = ReactDOM.findDOMNode(this.refs.EnableDeveloper).checked;
config.ServiceSettings.EnableSecurityFixAlert = ReactDOM.findDOMNode(this.refs.EnableSecurityFixAlert).checked;
//config.ServiceSettings.EnableOAuthServiceProvider = ReactDOM.findDOMNode(this.refs.EnableOAuthServiceProvider).checked;
@@ -343,6 +344,39 @@ export default class ServiceSettings extends React.Component {
<div className='form-group'>
<label
className='control-label col-sm-4'
+ htmlFor='EnableDeveloper'
+ >
+ {'Enable Developer Mode: '}
+ </label>
+ <div className='col-sm-8'>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableDeveloper'
+ value='true'
+ ref='EnableDeveloper'
+ defaultChecked={this.props.config.ServiceSettings.EnableDeveloper}
+ onChange={this.handleChange}
+ />
+ {'true'}
+ </label>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableDeveloper'
+ value='false'
+ defaultChecked={!this.props.config.ServiceSettings.EnableDeveloper}
+ onChange={this.handleChange}
+ />
+ {'false'}
+ </label>
+ <p className='help-text'>{'(Developer Option) When true, extra information around errors will be displayed in the UI.'}</p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
htmlFor='EnableSecurityFixAlert'
>
{'Enable Security Alerts: '}
diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx
index b7ac92672..cc4f5e138 100644
--- a/web/react/components/posts_view.jsx
+++ b/web/react/components/posts_view.jsx
@@ -233,7 +233,8 @@ export default class PostsView extends React.Component {
window.requestAnimationFrame(() => {
// If separator exists scroll to it. Otherwise scroll to bottom.
if (this.refs.newMessageSeparator) {
- this.refs.newMessageSeparator.scrollIntoView();
+ var objDiv = this.refs.postlist;
+ objDiv.scrollTop = this.refs.newMessageSeparator.offsetTop; //scrolls node to top of Div
} else {
this.refs.postlist.scrollTop = this.refs.postlist.scrollHeight;
}
diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx
index f71abf971..f235cac0a 100644
--- a/web/react/components/search_results_item.jsx
+++ b/web/react/components/search_results_item.jsx
@@ -31,8 +31,7 @@ export default class SearchResultsItem extends React.Component {
handleFocusRHSClick(e) {
e.preventDefault();
-
- EventHelpers.emitPostFocusRightHandSideEvent(this.props.post);
+ EventHelpers.emitPostFocusRightHandSideFromSearch(this.props.post, this.props.isMentionSearch);
}
render() {
diff --git a/web/react/components/user_settings/custom_theme_chooser.jsx b/web/react/components/user_settings/custom_theme_chooser.jsx
index 35f836adb..55242ca7f 100644
--- a/web/react/components/user_settings/custom_theme_chooser.jsx
+++ b/web/react/components/user_settings/custom_theme_chooser.jsx
@@ -3,6 +3,9 @@
import Constants from '../../utils/constants.jsx';
+const OverlayTrigger = ReactBootstrap.OverlayTrigger;
+const Popover = ReactBootstrap.Popover;
+
export default class CustomThemeChooser extends React.Component {
constructor(props) {
super(props);
@@ -19,6 +22,15 @@ export default class CustomThemeChooser extends React.Component {
});
$('.color-picker').on('changeColor', this.onPickerChange);
}
+ componentDidUpdate() {
+ const theme = this.props.theme;
+ Constants.THEME_ELEMENTS.forEach((element) => {
+ if (theme.hasOwnProperty(element.id) && element.id !== 'codeTheme') {
+ $('#' + element.id).data('colorpicker').color.setColor(theme[element.id]);
+ $('#' + element.id).colorpicker('update');
+ }
+ });
+ }
onPickerChange(e) {
const theme = this.props.theme;
theme[e.target.id] = e.color.toHex();
@@ -72,6 +84,19 @@ export default class CustomThemeChooser extends React.Component {
);
});
+ var popoverContent = (
+ <Popover
+ bsStyle='info'
+ id='code-popover'
+ className='code-popover'
+ >
+ <img
+ width='200'
+ src={'/static/images/themes/code_themes/' + theme[element.id] + 'Large.png'}
+ />
+ </Popover>
+ );
+
elements.push(
<div
className='col-sm-4 form-group'
@@ -85,16 +110,22 @@ export default class CustomThemeChooser extends React.Component {
<select
className='form-control'
type='text'
- defaultValue={theme[element.id]}
+ value={theme[element.id]}
onChange={this.onInputChange}
>
{codeThemeOptions}
</select>
+ <OverlayTrigger
+ placement='top'
+ overlay={popoverContent}
+ ref='headerOverlay'
+ >
<span className='input-group-addon'>
<img
src={'/static/images/themes/code_themes/' + theme[element.id] + '.png'}
/>
</span>
+ </OverlayTrigger>
</div>
</div>
);
@@ -112,7 +143,7 @@ export default class CustomThemeChooser extends React.Component {
<input
className='form-control'
type='text'
- defaultValue={theme[element.id]}
+ value={theme[element.id]}
onChange={this.onInputChange}
/>
<span className='input-group-addon'><i></i></span>
diff --git a/web/react/dispatcher/event_helpers.jsx b/web/react/dispatcher/event_helpers.jsx
index 297367ce9..a03923c1a 100644
--- a/web/react/dispatcher/event_helpers.jsx
+++ b/web/react/dispatcher/event_helpers.jsx
@@ -4,11 +4,11 @@
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import ChannelStore from '../stores/channel_store.jsx';
import PostStore from '../stores/post_store.jsx';
+import SearchStore from '../stores/search_store.jsx';
import Constants from '../utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
import * as AsyncClient from '../utils/async_client.jsx';
import * as Client from '../utils/client.jsx';
-import * as Utils from '../utils/utils.jsx';
export function emitChannelClickEvent(channel) {
AsyncClient.getChannels(true);
@@ -39,28 +39,27 @@ export function emitPostFocusEvent(postId) {
);
}
-export function emitPostFocusRightHandSideEvent(post) {
+export function emitPostFocusRightHandSideFromSearch(post, isMentionSearch) {
Client.getPost(
post.channel_id,
post.id,
(data) => {
AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_POST_SELECTED,
- post_list: data
+ post_list: data,
+ from_search: SearchStore.getSearchTerm()
});
AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_SEARCH,
- results: null
+ results: null,
+ is_mention_search: isMentionSearch
});
},
(err) => {
AsyncClient.dispatchError(err, 'getPost');
}
);
-
- var postChannel = ChannelStore.get(post.channel_id);
- Utils.switchChannel(postChannel);
}
export function emitLoadMorePostsEvent() {
diff --git a/web/react/stores/browser_store.jsx b/web/react/stores/browser_store.jsx
index ff6ae45ea..3417faaaf 100644
--- a/web/react/stores/browser_store.jsx
+++ b/web/react/stores/browser_store.jsx
@@ -29,6 +29,8 @@ class BrowserStoreClass {
this.checkedLocalStorageSupported = '';
this.signalLogout = this.signalLogout.bind(this);
this.isSignallingLogout = this.isSignallingLogout.bind(this);
+ this.signalLogin = this.signalLogin.bind(this);
+ this.isSignallingLogin = this.isSignallingLogin.bind(this);
var currentVersion = sessionStorage.getItem('storage_version');
if (currentVersion !== global.window.mm_config.Version) {
@@ -129,6 +131,21 @@ class BrowserStoreClass {
return logoutId === sessionStorage.getItem('__logout__');
}
+ signalLogin() {
+ if (this.isLocalStorageSupported()) {
+ // PLT-1285 store an identifier in session storage so we can catch if the logout came from this tab on IE11
+ const loginId = generateId();
+
+ sessionStorage.setItem('__login__', loginId);
+ localStorage.setItem('__login__', loginId);
+ localStorage.removeItem('__login__');
+ }
+ }
+
+ isSignallingLogin(loginId) {
+ return loginId === sessionStorage.getItem('__login__');
+ }
+
/**
* Preforms the given action on each item that has the given prefix
* Signature for action is action(key, value)
diff --git a/web/react/stores/error_store.jsx b/web/react/stores/error_store.jsx
index 8fb051138..69d6cca7f 100644
--- a/web/react/stores/error_store.jsx
+++ b/web/react/stores/error_store.jsx
@@ -63,3 +63,4 @@ ErrorStore.dispatchToken = AppDispatcher.register((payload) => {
});
export default ErrorStore;
+window.ErrorStore = ErrorStore;
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
index 5d02a8c88..beabf5227 100644
--- a/web/react/utils/client.jsx
+++ b/web/react/utils/client.jsx
@@ -246,6 +246,7 @@ export function loginByEmail(name, email, password, success, error) {
data: JSON.stringify({name: name, email: email, password: password}),
success: function onSuccess(data, textStatus, xhr) {
track('api', 'api_users_login_success', data.team_id, 'email', data.email);
+ BrowserStore.signalLogin();
success(data, textStatus, xhr);
},
error: function onError(xhr, status, err) {
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index d23c18b5d..5f027a409 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -166,29 +166,6 @@ export default {
UPDATE_TYPING_MS: 5000,
THEMES: {
default: {
- type: 'Mattermost',
- sidebarBg: '#fafafa',
- sidebarText: '#333333',
- sidebarUnreadText: '#333333',
- sidebarTextHoverBg: '#e6f2fa',
- sidebarTextActiveBorder: '#378FD2',
- sidebarTextActiveColor: '#111111',
- sidebarHeaderBg: '#2389d7',
- sidebarHeaderTextColor: '#ffffff',
- onlineIndicator: '#7DBE00',
- mentionBj: '#2389d7',
- mentionColor: '#ffffff',
- centerChannelBg: '#ffffff',
- centerChannelColor: '#333333',
- newMessageSeparator: '#FF8800',
- linkColor: '#2389d7',
- buttonBg: '#2389d7',
- buttonColor: '#FFFFFF',
- mentionHighlightBg: '#fff2bb',
- mentionHighlightLink: '#2f81b7',
- codeTheme: 'github'
- },
- organization: {
type: 'Organization',
sidebarBg: '#2071a7',
sidebarText: '#fff',
@@ -211,6 +188,29 @@ export default {
mentionHighlightLink: '#2f81b7',
codeTheme: 'github'
},
+ mattermost: {
+ type: 'Mattermost',
+ sidebarBg: '#fafafa',
+ sidebarText: '#333333',
+ sidebarUnreadText: '#333333',
+ sidebarTextHoverBg: '#e6f2fa',
+ sidebarTextActiveBorder: '#378FD2',
+ sidebarTextActiveColor: '#111111',
+ sidebarHeaderBg: '#2389d7',
+ sidebarHeaderTextColor: '#ffffff',
+ onlineIndicator: '#7DBE00',
+ mentionBj: '#2389d7',
+ mentionColor: '#ffffff',
+ centerChannelBg: '#ffffff',
+ centerChannelColor: '#333333',
+ newMessageSeparator: '#FF8800',
+ linkColor: '#2389d7',
+ buttonBg: '#2389d7',
+ buttonColor: '#FFFFFF',
+ mentionHighlightBg: '#fff2bb',
+ mentionHighlightLink: '#2f81b7',
+ codeTheme: 'github'
+ },
mattermostDark: {
type: 'Mattermost Dark',
sidebarBg: '#1B2C3E',
diff --git a/web/sass-files/sass/partials/_base.scss b/web/sass-files/sass/partials/_base.scss
index 61ad186e0..4f9e1d5c7 100644
--- a/web/sass-files/sass/partials/_base.scss
+++ b/web/sass-files/sass/partials/_base.scss
@@ -9,6 +9,7 @@ body {
-webkit-font-smoothing: antialiased;
background: $body-bg;
position: relative;
+ width: 100%;
height: 100%;
&.white {
background: #fff;
diff --git a/web/sass-files/sass/partials/_docs.scss b/web/sass-files/sass/partials/_docs.scss
new file mode 100644
index 000000000..f4e7cc314
--- /dev/null
+++ b/web/sass-files/sass/partials/_docs.scss
@@ -0,0 +1,19 @@
+@charset "UTF-8";
+
+.docs__page {
+ line-height: 1.7;
+ padding-bottom: 20px;
+
+ > div {
+ width: 1170px;
+ margin: 0 auto;
+ padding: 0 15px;
+ max-width: 100%;
+ }
+
+ h1.markdown__heading {
+ border-bottom: 1px solid #ddd;
+ padding-bottom: 1rem;
+ margin: 1em 0 1em;
+ }
+} \ No newline at end of file
diff --git a/web/sass-files/sass/partials/_popover.scss b/web/sass-files/sass/partials/_popover.scss
index bc55b7ff7..1ae07fe5b 100644
--- a/web/sass-files/sass/partials/_popover.scss
+++ b/web/sass-files/sass/partials/_popover.scss
@@ -10,6 +10,10 @@
display: inline-block;
}
+.code-popover .popover-content {
+ padding: 5px;
+}
+
.user-popover__image {
margin: 0 0 10px;
@include border-radius(128px);
diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss
index 3ec1c4434..fbebb4e98 100644
--- a/web/sass-files/sass/partials/_post.scss
+++ b/web/sass-files/sass/partials/_post.scss
@@ -209,6 +209,7 @@ body.ios {
@include flex(1 1 auto);
position: relative;
overflow-y: hidden;
+ height: 100%;
.post-list-holder-by-time {
background: #fff;
diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss
index 66aaede8d..2aa130fa9 100644
--- a/web/sass-files/sass/partials/_responsive.scss
+++ b/web/sass-files/sass/partials/_responsive.scss
@@ -54,9 +54,7 @@
@media screen and (max-width: 960px) {
.sidebar--right {
- width: 400px;
z-index: 5;
- right: 0;
@include translateX(100%);
&.move--left {
diff --git a/web/sass-files/sass/partials/_sidebar--right.scss b/web/sass-files/sass/partials/_sidebar--right.scss
index f328f0971..e39f7730b 100644
--- a/web/sass-files/sass/partials/_sidebar--right.scss
+++ b/web/sass-files/sass/partials/_sidebar--right.scss
@@ -1,17 +1,17 @@
@charset "UTF-8";
.sidebar--right {
- position: absolute;
+ position: fixed;
width: 400px;
height: 100%;
right: 0px;
padding: 0;
background: #fff;
@include single-transition(transform, 0.5s, ease);
- right: -320px;
+ @include translateX(400px);
&.move--left {
- right: 0;
+ @include translateX(0);
}
.post-body {
diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss
index c93372175..7bf3574d2 100644
--- a/web/sass-files/sass/styles.scss
+++ b/web/sass-files/sass/styles.scss
@@ -49,6 +49,9 @@
// Responsive Css
@import "partials/responsive";
+// Docs Css
+@import "partials/docs";
+
// Standalone Css
@import "partials/oauth";
diff --git a/web/static/images/themes/code_themes/githubLarge.png b/web/static/images/themes/code_themes/githubLarge.png
new file mode 100644
index 000000000..cffc6e012
--- /dev/null
+++ b/web/static/images/themes/code_themes/githubLarge.png
Binary files differ
diff --git a/web/static/images/themes/code_themes/monokaiLarge.png b/web/static/images/themes/code_themes/monokaiLarge.png
new file mode 100644
index 000000000..7224950af
--- /dev/null
+++ b/web/static/images/themes/code_themes/monokaiLarge.png
Binary files differ
diff --git a/web/static/images/themes/code_themes/solarized_darkLarge.png b/web/static/images/themes/code_themes/solarized_darkLarge.png
new file mode 100644
index 000000000..582df48f9
--- /dev/null
+++ b/web/static/images/themes/code_themes/solarized_darkLarge.png
Binary files differ
diff --git a/web/static/images/themes/code_themes/solarized_lightLarge.png b/web/static/images/themes/code_themes/solarized_lightLarge.png
new file mode 100644
index 000000000..d2c2702fb
--- /dev/null
+++ b/web/static/images/themes/code_themes/solarized_lightLarge.png
Binary files differ
diff --git a/web/templates/docs.html b/web/templates/docs.html
index 21659e810..0e0f51648 100644
--- a/web/templates/docs.html
+++ b/web/templates/docs.html
@@ -7,7 +7,7 @@
<div class="inner__wrap">
<div class="row content">
<div class="col-sm-12">
- <div id="docs"></div>
+ <div class="docs__page" id="docs"></div>
</div>
<div class="footer-push"></div>
</div>
diff --git a/web/templates/head.html b/web/templates/head.html
index be4ed2b25..e80f0a24c 100644
--- a/web/templates/head.html
+++ b/web/templates/head.html
@@ -68,6 +68,16 @@
console.log('detected logout from a different tab');
window.location.href = '/' + window.mm_team.name;
}
+
+ if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) {
+ // make sure it isn't this tab that is sending the logout signal (only necessary for IE11)
+ if (window.BrowserStore.isSignallingLogin(e.originalEvent.newValue)) {
+ return;
+ }
+
+ console.log('detected login from a different tab');
+ window.location.href = '/';
+ }
});
});
</script>
@@ -85,6 +95,11 @@
type: 'POST',
data: JSON.stringify(l)
});
+
+ if (window.mm_config.EnableDeveloper === 'true') {
+ window.ErrorStore.storeLastError('DEVELOPER MODE: A javascript error has occured. Please use the javascript console to capture and report the error (row: ' + line + ' col: ' + column + ').');
+ window.ErrorStore.emitChange();
+ }
}
</script>