summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/react/components/channel_header.jsx41
-rw-r--r--web/react/components/navbar.jsx56
-rw-r--r--web/react/components/post_body.jsx38
-rw-r--r--web/react/components/rename_channel_modal.jsx51
-rw-r--r--web/react/components/rhs_thread.jsx2
-rw-r--r--web/react/components/search_results.jsx2
-rw-r--r--web/react/components/sidebar_right_menu.jsx18
-rw-r--r--web/react/components/team_general_tab.jsx3
-rw-r--r--web/react/components/tutorial/tutorial_tip.jsx27
-rw-r--r--web/react/components/user_settings/user_settings_general.jsx164
-rw-r--r--web/react/utils/channel_intro_mssages.jsx1
-rw-r--r--web/react/utils/utils.jsx6
-rw-r--r--web/sass-files/sass/partials/_content.scss1
-rw-r--r--web/sass-files/sass/partials/_files.scss8
-rw-r--r--web/sass-files/sass/partials/_forms.scss4
-rw-r--r--web/sass-files/sass/partials/_headers.scss31
-rw-r--r--web/sass-files/sass/partials/_post.scss15
-rw-r--r--web/sass-files/sass/partials/_post_right.scss17
-rw-r--r--web/sass-files/sass/partials/_responsive.scss36
-rw-r--r--web/sass-files/sass/partials/_search.scss11
-rw-r--r--web/sass-files/sass/partials/_sidebar--left.scss2
-rw-r--r--web/sass-files/sass/partials/_sidebar--menu.scss5
-rw-r--r--web/sass-files/sass/partials/_sidebar--right.scss26
-rw-r--r--web/sass-files/sass/partials/_videos.scss2
-rw-r--r--web/web.go2
25 files changed, 321 insertions, 248 deletions
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx
index a8d4ec100..79c7f90a9 100644
--- a/web/react/components/channel_header.jsx
+++ b/web/react/components/channel_header.jsx
@@ -276,26 +276,27 @@ export default class ChannelHeader extends React.Component {
</li>
);
- if (!ChannelStore.isDefault(channel)) {
- if (isAdmin) {
- dropdownContents.push(
- <li
- key='rename_channel'
- role='presentation'
+ if (isAdmin) {
+ dropdownContents.push(
+ <li
+ key='rename_channel'
+ role='presentation'
+ >
+ <a
+ role='menuitem'
+ href='#'
+ data-toggle='modal'
+ data-target='#rename_channel'
+ data-display={channel.display_name}
+ data-name={channel.name}
+ data-channelid={channel.id}
>
- <a
- role='menuitem'
- href='#'
- data-toggle='modal'
- data-target='#rename_channel'
- data-display={channel.display_name}
- data-name={channel.name}
- data-channelid={channel.id}
- >
- {'Rename '}{channelTerm}{'...'}
- </a>
- </li>
- );
+ {'Rename '}{channelTerm}{'...'}
+ </a>
+ </li>
+ );
+
+ if (!ChannelStore.isDefault(channel)) {
dropdownContents.push(
<li
key='delete_channel'
@@ -314,7 +315,9 @@ export default class ChannelHeader extends React.Component {
</li>
);
}
+ }
+ if (!ChannelStore.isDefault(channel)) {
dropdownContents.push(
<li
key='leave_channel'
diff --git a/web/react/components/navbar.jsx b/web/react/components/navbar.jsx
index af29f219e..7ad1f9305 100644
--- a/web/react/components/navbar.jsx
+++ b/web/react/components/navbar.jsx
@@ -178,18 +178,35 @@ export default class Navbar extends React.Component {
var manageMembersOption;
var renameChannelOption;
var deleteChannelOption;
- if (!isDirect && isAdmin && !ChannelStore.isDefault(channel)) {
- manageMembersOption = (
- <li role='presentation'>
- <a
- role='menuitem'
- href='#'
- onClick={() => this.setState({showMembersModal: true})}
- >
- {'Manage Members'}
- </a>
- </li>
- );
+ if (!isDirect && isAdmin) {
+ if (!ChannelStore.isDefault(channel)) {
+ manageMembersOption = (
+ <li role='presentation'>
+ <a
+ role='menuitem'
+ href='#'
+ onClick={() => this.setState({showMembersModal: true})}
+ >
+ {'Manage Members'}
+ </a>
+ </li>
+ );
+
+ deleteChannelOption = (
+ <li role='presentation'>
+ <a
+ role='menuitem'
+ href='#'
+ data-toggle='modal'
+ data-target='#delete_channel'
+ data-title={channel.display_name}
+ data-channelid={channel.id}
+ >
+ {'Delete Channel...'}
+ </a>
+ </li>
+ );
+ }
renameChannelOption = (
<li role='presentation'>
@@ -206,21 +223,6 @@ export default class Navbar extends React.Component {
</a>
</li>
);
-
- deleteChannelOption = (
- <li role='presentation'>
- <a
- role='menuitem'
- href='#'
- data-toggle='modal'
- data-target='#delete_channel'
- data-title={channel.display_name}
- data-channelid={channel.id}
- >
- {'Delete Channel...'}
- </a>
- </li>
- );
}
var notificationPreferenceOption;
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 617b4b36c..975ac64dc 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -16,13 +16,13 @@ export default class PostBody extends React.Component {
super(props);
this.receivedYoutubeData = false;
- this.isGifLoading = false;
+ this.isImgLoading = false;
this.handleUserChange = this.handleUserChange.bind(this);
this.parseEmojis = this.parseEmojis.bind(this);
this.createEmbed = this.createEmbed.bind(this);
- this.createGifEmbed = this.createGifEmbed.bind(this);
- this.loadGif = this.loadGif.bind(this);
+ this.createImageEmbed = this.createImageEmbed.bind(this);
+ this.loadImg = this.loadImg.bind(this);
this.createYoutubeEmbed = this.createYoutubeEmbed.bind(this);
const linkData = Utils.extractLinks(this.props.post.message);
@@ -117,8 +117,12 @@ export default class PostBody extends React.Component {
return embed;
}
- if (link.substring(link.length - 4) === '.gif') {
- return this.createGifEmbed(link, this.state.gifLoaded);
+ for (let i = 0; i < Constants.IMAGE_TYPES.length; i++) {
+ const imageType = Constants.IMAGE_TYPES[i];
+ const suffix = link.substring(link.length - (imageType.length + 1));
+ if (suffix === '.' + imageType || suffix === '=' + imageType) {
+ return this.createImageEmbed(link, this.state.imgLoaded);
+ }
}
return null;
@@ -135,29 +139,29 @@ export default class PostBody extends React.Component {
return false;
}
- loadGif(src) {
- if (this.isGifLoading) {
+ loadImg(src) {
+ if (this.isImgLoading) {
return;
}
- this.isGifLoading = true;
+ this.isImgLoading = true;
- const gif = new Image();
- gif.onload = (
+ const img = new Image();
+ img.onload = (
() => {
- this.embed = this.createGifEmbed(src, true);
- this.setState({gifLoaded: true});
+ this.embed = this.createImageEmbed(src, true);
+ this.setState({imgLoaded: true});
}
);
- gif.src = src;
+ img.src = src;
}
- createGifEmbed(link, isLoaded) {
+ createImageEmbed(link, isLoaded) {
if (!isLoaded) {
- this.loadGif(link);
+ this.loadImg(link);
return (
<img
- className='gif-div placeholder'
+ className='img-div placeholder'
height='500px'
/>
);
@@ -165,7 +169,7 @@ export default class PostBody extends React.Component {
return (
<img
- className='gif-div'
+ className='img-div'
src={link}
/>
);
diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx
index 9fb3af035..f47009cce 100644
--- a/web/react/components/rename_channel_modal.jsx
+++ b/web/react/components/rename_channel_modal.jsx
@@ -5,6 +5,7 @@ const Utils = require('../utils/utils.jsx');
const Client = require('../utils/client.jsx');
const AsyncClient = require('../utils/async_client.jsx');
const ChannelStore = require('../stores/channel_store.jsx');
+const Constants = require('../utils/constants.jsx');
export default class RenameChannelModal extends React.Component {
constructor(props) {
@@ -36,10 +37,10 @@ export default class RenameChannelModal extends React.Component {
return;
}
- let channel = ChannelStore.get(this.state.channelId);
+ const channel = ChannelStore.get(this.state.channelId);
const oldName = channel.name;
const oldDisplayName = channel.displayName;
- let state = {serverError: ''};
+ const state = {serverError: ''};
channel.display_name = this.state.displayName.trim();
if (!channel.display_name) {
@@ -60,7 +61,7 @@ export default class RenameChannelModal extends React.Component {
state.nameError = 'This field must be less than 22 characters';
state.invalid = true;
} else {
- let cleanedName = Utils.cleanUpUrlable(channel.name);
+ const cleanedName = Utils.cleanUpUrlable(channel.name);
if (cleanedName === channel.name) {
state.nameError = '';
} else {
@@ -76,7 +77,7 @@ export default class RenameChannelModal extends React.Component {
}
Client.updateChannel(channel,
- function handleUpdateSuccess() {
+ () => {
$(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
AsyncClient.getChannel(channel.id);
@@ -84,12 +85,12 @@ export default class RenameChannelModal extends React.Component {
ReactDOM.findDOMNode(this.refs.displayName).value = '';
ReactDOM.findDOMNode(this.refs.channelName).value = '';
- }.bind(this),
- function handleUpdateError(err) {
+ },
+ (err) => {
state.serverError = err.message;
state.invalid = true;
this.setState(state);
- }.bind(this)
+ }
);
}
onNameChange() {
@@ -99,10 +100,12 @@ export default class RenameChannelModal extends React.Component {
this.setState({displayName: ReactDOM.findDOMNode(this.refs.displayName).value});
}
displayNameKeyUp() {
- const displayName = ReactDOM.findDOMNode(this.refs.displayName).value.trim();
- const channelName = Utils.cleanUpUrlable(displayName);
- ReactDOM.findDOMNode(this.refs.channelName).value = channelName;
- this.setState({channelName: channelName});
+ if (this.state.channelName !== Constants.DEFAULT_CHANNEL) {
+ const displayName = ReactDOM.findDOMNode(this.refs.displayName).value.trim();
+ const channelName = Utils.cleanUpUrlable(displayName);
+ ReactDOM.findDOMNode(this.refs.channelName).value = channelName;
+ this.setState({channelName: channelName});
+ }
}
handleClose() {
this.setState({
@@ -150,6 +153,15 @@ export default class RenameChannelModal extends React.Component {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
}
+ let handleInputLabel = 'Handle';
+ let handleInputClass = 'form-control';
+ let readOnlyHandleInput = false;
+ if (this.state.channelName === Constants.DEFAULT_CHANNEL) {
+ handleInputLabel += ' - Cannot be changed for the default channel';
+ handleInputClass += ' disabled-input';
+ readOnlyHandleInput = true;
+ }
+
return (
<div
className='modal fade'
@@ -167,15 +179,15 @@ export default class RenameChannelModal extends React.Component {
className='close'
data-dismiss='modal'
>
- <span aria-hidden='true'>&times;</span>
- <span className='sr-only'>Close</span>
+ <span aria-hidden='true'>{'×'}</span>
+ <span className='sr-only'>{'Close'}</span>
</button>
- <h4 className='modal-title'>Rename Channel</h4>
+ <h4 className='modal-title'>{'Rename Channel'}</h4>
</div>
<form role='form'>
<div className='modal-body'>
<div className={displayNameClass}>
- <label className='control-label'>Display Name</label>
+ <label className='control-label'>{'Display Name'}</label>
<input
onKeyUp={this.displayNameKeyUp}
onChange={this.onDisplayNameChange}
@@ -190,15 +202,16 @@ export default class RenameChannelModal extends React.Component {
{displayNameError}
</div>
<div className={nameClass}>
- <label className='control-label'>Handle</label>
+ <label className='control-label'>{handleInputLabel}</label>
<input
onChange={this.onNameChange}
type='text'
- className='form-control'
+ className={handleInputClass}
ref='channelName'
placeholder='lowercase alphanumeric&#39;s only'
value={this.state.channelName}
maxLength='64'
+ readOnly={readOnlyHandleInput}
/>
{nameError}
</div>
@@ -210,14 +223,14 @@ export default class RenameChannelModal extends React.Component {
className='btn btn-default'
data-dismiss='modal'
>
- Cancel
+ {'Cancel'}
</button>
<button
onClick={this.handleSubmit}
type='submit'
className='btn btn-primary'
>
- Save
+ {'Save'}
</button>
</div>
</form>
diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx
index 7c11de7cf..cc062c538 100644
--- a/web/react/components/rhs_thread.jsx
+++ b/web/react/components/rhs_thread.jsx
@@ -117,8 +117,6 @@ export default class RhsThread extends React.Component {
}
}
resize() {
- var height = this.state.windowHeight - $('#error_bar').outerHeight() - 100;
- $('.post-right__scroll').css('height', height + 'px');
$('.post-right__scroll').scrollTop(100000);
if (this.state.windowWidth > 768) {
$('.post-right__scroll').perfectScrollbar();
diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx
index 2f0068908..f4d8647db 100644
--- a/web/react/components/search_results.jsx
+++ b/web/react/components/search_results.jsx
@@ -62,8 +62,6 @@ export default class SearchResults extends React.Component {
}
resize() {
- var height = this.state.windowHeight - $('#error_bar').outerHeight() - 100;
- $('#search-items-container').css('height', height + 'px');
$('#search-items-container').scrollTop(0);
if (this.state.windowWidth > 768) {
$('#search-items-container').perfectScrollbar();
diff --git a/web/react/components/sidebar_right_menu.jsx b/web/react/components/sidebar_right_menu.jsx
index 2135e3ef3..6a428e884 100644
--- a/web/react/components/sidebar_right_menu.jsx
+++ b/web/react/components/sidebar_right_menu.jsx
@@ -48,7 +48,7 @@ export default class SidebarRightMenu extends React.Component {
href='#'
onClick={InviteMemberModal.show}
>
- <i className='glyphicon glyphicon-user'></i>Invite New Member
+ <i className='fa fa-user'></i>Invite New Member
</a>
</li>
);
@@ -61,7 +61,7 @@ export default class SidebarRightMenu extends React.Component {
data-target='#get_link'
data-title='Team Invite'
data-value={utils.getWindowLocationOrigin() + '/signup_user_complete/?id=' + TeamStore.getCurrent().invite_id}
- ><i className='glyphicon glyphicon-link'></i>Get Team Invite Link</a>
+ ><i className='fa fa-link'></i>Get Team Invite Link</a>
</li>
);
}
@@ -74,7 +74,7 @@ export default class SidebarRightMenu extends React.Component {
href='#'
data-toggle='modal'
data-target='#team_settings'
- ><i className='glyphicon glyphicon-globe'></i>Team Settings</a>
+ ><i className='fa fa-globe'></i>Team Settings</a>
</li>
);
manageLink = (
@@ -84,7 +84,7 @@ export default class SidebarRightMenu extends React.Component {
data-toggle='modal'
data-target='#team_members'
>
- <i className='glyphicon glyphicon-wrench'></i>Manage Members</a>
+ <i className='fa fa-users'></i>Manage Members</a>
</li>
);
}
@@ -95,7 +95,7 @@ export default class SidebarRightMenu extends React.Component {
<a
href={'/admin_console?' + utils.getSessionIndex()}
>
- <i className='glyphicon glyphicon-wrench'></i>System Console</a>
+ <i className='fa fa-wrench'></i>System Console</a>
</li>
);
}
@@ -125,7 +125,7 @@ export default class SidebarRightMenu extends React.Component {
href='#'
onClick={() => this.setState({showUserSettingsModal: true})}
>
- <i className='glyphicon glyphicon-cog'></i>Account Settings
+ <i className='fa fa-cog'></i>Account Settings
</a>
</li>
{teamSettingsLink}
@@ -137,18 +137,18 @@ export default class SidebarRightMenu extends React.Component {
<a
href='#'
onClick={this.handleLogoutClick}
- ><i className='glyphicon glyphicon-log-out'></i>Logout</a></li>
+ ><i className='fa fa-sign-out'></i>Logout</a></li>
<li className='divider'></li>
<li>
<a
target='_blank'
href='/static/help/configure_links.html'
- ><i className='glyphicon glyphicon-question-sign'></i>Help</a></li>
+ ><i className='fa fa-question'></i>Help</a></li>
<li>
<a
target='_blank'
href='/static/help/configure_links.html'
- ><i className='glyphicon glyphicon-earphone'></i>Report a Problem</a></li>
+ ><i className='fa fa-phone'></i>Report a Problem</a></li>
</ul>
</div>
<UserSettingsModal
diff --git a/web/react/components/team_general_tab.jsx b/web/react/components/team_general_tab.jsx
index 587ef5ec2..a50859489 100644
--- a/web/react/components/team_general_tab.jsx
+++ b/web/react/components/team_general_tab.jsx
@@ -393,7 +393,7 @@ export default class GeneralTab extends React.Component {
</div>
</div>
</div>
- <div className='setting-list__hint'>{'When allowing open invites this code is used as part of the signup process. Changing this code will invalidate the previous open signup link.'}</div>
+ <div className='setting-list__hint'>{'Your Invite Code is used in the URL sent to people to join your team. Regenerating your Invite Code will invalidate the URLs in previous invitations, unless "Allow anyone to sign-up from login page" is enabled.'}</div>
</div>
);
@@ -452,6 +452,7 @@ export default class GeneralTab extends React.Component {
server_error={serverError}
client_error={clientError}
updateSection={this.onUpdateNameSection}
+ extraInfo='Set the name of the team as it appears on your sign-in screen and at the top of the left-hand sidebar.'
/>
);
} else {
diff --git a/web/react/components/tutorial/tutorial_tip.jsx b/web/react/components/tutorial/tutorial_tip.jsx
index 75d73e920..dd231b816 100644
--- a/web/react/components/tutorial/tutorial_tip.jsx
+++ b/web/react/components/tutorial/tutorial_tip.jsx
@@ -51,21 +51,22 @@ export default class TutorialTip extends React.Component {
const dots = [];
if (this.props.screens.length > 1) {
for (let i = 0; i < this.props.screens.length; i++) {
+ let className = 'circle';
if (i === this.state.currentScreen) {
- dots.push(
- <div
- className='circle active'
- key={'dotactive' + i}
- />
- );
- } else {
- dots.push(
- <div
- className='circle'
- key={'dotinactive' + i}
- />
- );
+ className += ' active';
}
+
+ dots.push(
+ <a
+ href='#'
+ key={'dotactive' + i}
+ className={className}
+ onClick={(e) => { //eslint-disable-line no-loop-func
+ e.preventDefault();
+ this.setState({currentScreen: i});
+ }}
+ />
+ );
}
}
diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx
index 1bfae6930..b363f0673 100644
--- a/web/react/components/user_settings/user_settings_general.jsx
+++ b/web/react/components/user_settings/user_settings_general.jsx
@@ -1,15 +1,16 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-var UserStore = require('../../stores/user_store.jsx');
-var ErrorStore = require('../../stores/error_store.jsx');
-var SettingItemMin = require('../setting_item_min.jsx');
-var SettingItemMax = require('../setting_item_max.jsx');
-var SettingPicture = require('../setting_picture.jsx');
-var client = require('../../utils/client.jsx');
-var AsyncClient = require('../../utils/async_client.jsx');
-var utils = require('../../utils/utils.jsx');
-var assign = require('object-assign');
+const SettingItemMin = require('../setting_item_min.jsx');
+const SettingItemMax = require('../setting_item_max.jsx');
+const SettingPicture = require('../setting_picture.jsx');
+
+const UserStore = require('../../stores/user_store.jsx');
+const ErrorStore = require('../../stores/error_store.jsx');
+
+const Client = require('../../utils/client.jsx');
+const AsyncClient = require('../../utils/async_client.jsx');
+const Utils = require('../../utils/utils.jsx');
export default class UserSettingsGeneralTab extends React.Component {
constructor(props) {
@@ -32,17 +33,15 @@ export default class UserSettingsGeneralTab extends React.Component {
this.updatePicture = this.updatePicture.bind(this);
this.updateSection = this.updateSection.bind(this);
- this.setupInitialState = this.setupInitialState.bind(this);
-
this.state = this.setupInitialState(props);
}
submitUsername(e) {
e.preventDefault();
- var user = this.props.user;
- var username = this.state.username.trim().toLowerCase();
+ const user = Object.assign({}, this.props.user);
+ const username = this.state.username.trim().toLowerCase();
- var usernameError = utils.isValidUsername(username);
+ const usernameError = Utils.isValidUsername(username);
if (usernameError === 'Cannot use a reserved word as a username.') {
this.setState({clientError: 'This username is reserved, please choose a new one.'});
return;
@@ -52,7 +51,7 @@ export default class UserSettingsGeneralTab extends React.Component {
}
if (user.username === username) {
- this.setState({clientError: 'You must submit a new username'});
+ this.setState({clientError: 'You must submit a new username.', emailError: '', serverError: ''});
return;
}
@@ -63,11 +62,11 @@ export default class UserSettingsGeneralTab extends React.Component {
submitNickname(e) {
e.preventDefault();
- var user = UserStore.getCurrentUser();
- var nickname = this.state.nickname.trim();
+ const user = Object.assign({}, this.props.user);
+ const nickname = this.state.nickname.trim();
if (user.nickname === nickname) {
- this.setState({clientError: 'You must submit a new nickname'});
+ this.setState({clientError: 'You must submit a new nickname.', emailError: '', serverError: ''});
return;
}
@@ -78,12 +77,12 @@ export default class UserSettingsGeneralTab extends React.Component {
submitName(e) {
e.preventDefault();
- var user = UserStore.getCurrentUser();
- var firstName = this.state.firstName.trim();
- var lastName = this.state.lastName.trim();
+ const user = Object.assign({}, this.props.user);
+ const firstName = this.state.firstName.trim();
+ const lastName = this.state.lastName.trim();
if (user.first_name === firstName && user.last_name === lastName) {
- this.setState({clientError: 'You must submit a new first or last name'});
+ this.setState({clientError: 'You must submit a new first or last name.', emailError: '', serverError: ''});
return;
}
@@ -95,21 +94,21 @@ export default class UserSettingsGeneralTab extends React.Component {
submitEmail(e) {
e.preventDefault();
- var user = UserStore.getCurrentUser();
- var email = this.state.email.trim().toLowerCase();
- var confirmEmail = this.state.confirmEmail.trim().toLowerCase();
+ const user = Object.assign({}, this.props.user);
+ const email = this.state.email.trim().toLowerCase();
+ const confirmEmail = this.state.confirmEmail.trim().toLowerCase();
if (user.email === email) {
return;
}
- if (email === '' || !utils.isEmail(email)) {
- this.setState({emailError: 'Please enter a valid email address'});
+ if (email === '' || !Utils.isEmail(email)) {
+ this.setState({emailError: 'Please enter a valid email address.', clientError: '', serverError: ''});
return;
}
if (email !== confirmEmail) {
- this.setState({emailError: 'The new emails you entered do not match'});
+ this.setState({emailError: 'The new emails you entered do not match.', clientError: '', serverError: ''});
return;
}
@@ -117,7 +116,7 @@ export default class UserSettingsGeneralTab extends React.Component {
this.submitUser(user, true);
}
submitUser(user, emailUpdated) {
- client.updateUser(user,
+ Client.updateUser(user,
() => {
this.updateSection('');
AsyncClient.getMe();
@@ -130,13 +129,13 @@ export default class UserSettingsGeneralTab extends React.Component {
}
},
(err) => {
- var state = this.setupInitialState(this.props);
+ let serverError;
if (err.message) {
- state.serverError = err.message;
+ serverError = err.message;
} else {
- state.serverError = err;
+ serverError = err;
}
- this.setState(state);
+ this.setState({serverError, emailError: '', clientError: ''});
}
);
}
@@ -151,10 +150,10 @@ export default class UserSettingsGeneralTab extends React.Component {
return;
}
- var picture = this.state.picture;
+ const picture = this.state.picture;
if (picture.type !== 'image/jpeg' && picture.type !== 'image/png') {
- this.setState({clientError: 'Only JPG or PNG images may be used for profile pictures'});
+ this.setState({clientError: 'Only JPG or PNG images may be used for profile pictures.'});
return;
}
@@ -162,17 +161,17 @@ export default class UserSettingsGeneralTab extends React.Component {
formData.append('image', picture, picture.name);
this.setState({loadingPicture: true});
- client.uploadProfileImage(formData,
- function imageUploadSuccess() {
+ Client.uploadProfileImage(formData,
+ () => {
this.submitActive = false;
AsyncClient.getMe();
window.location.reload();
- }.bind(this),
- function imageUploadFailure(err) {
+ },
+ (err) => {
var state = this.setupInitialState(this.props);
state.serverError = err.message;
this.setState(state);
- }.bind(this)
+ }
);
}
updateUsername(e) {
@@ -205,34 +204,34 @@ export default class UserSettingsGeneralTab extends React.Component {
}
updateSection(section) {
const emailChangeInProgress = this.state.emailChangeInProgress;
- this.setState(assign({}, this.setupInitialState(this.props), {emailChangeInProgress: emailChangeInProgress, clientError: '', serverError: '', emailError: ''}));
+ this.setState(Object.assign({}, this.setupInitialState(this.props), {emailChangeInProgress, clientError: '', serverError: '', emailError: ''}));
this.submitActive = false;
this.props.updateSection(section);
}
setupInitialState(props) {
- var user = props.user;
+ const user = props.user;
return {username: user.username, firstName: user.first_name, lastName: user.last_name, nickname: user.nickname,
email: user.email, confirmEmail: '', picture: null, loadingPicture: false, emailChangeInProgress: false};
}
render() {
- var user = this.props.user;
+ const user = this.props.user;
- var clientError = null;
+ let clientError = null;
if (this.state.clientError) {
clientError = this.state.clientError;
}
- var serverError = null;
+ let serverError = null;
if (this.state.serverError) {
serverError = this.state.serverError;
}
- var emailError = null;
+ let emailError = null;
if (this.state.emailError) {
emailError = this.state.emailError;
}
- var nameSection;
- var inputs = [];
+ let nameSection;
+ const inputs = [];
if (this.props.activeSection === 'name') {
inputs.push(
@@ -298,15 +297,15 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={this.submitName}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
extraInfo={extraInfo}
/>
);
} else {
- var fullName = '';
+ let fullName = '';
if (user.first_name && user.last_name) {
fullName = user.first_name + ' ' + user.last_name;
@@ -320,17 +319,17 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Full Name'
describe={fullName}
- updateSection={function updateNameSection() {
+ updateSection={() => {
this.updateSection('name');
- }.bind(this)}
+ }}
/>
);
}
- var nicknameSection;
+ let nicknameSection;
if (this.props.activeSection === 'nickname') {
let nicknameLabel = 'Nickname';
- if (utils.isMobile()) {
+ if (Utils.isMobile()) {
nicknameLabel = '';
}
@@ -364,10 +363,10 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={this.submitNickname}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
extraInfo={extraInfo}
/>
);
@@ -376,17 +375,17 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Nickname'
describe={UserStore.getCurrentUser().nickname}
- updateSection={function updateNicknameSection() {
+ updateSection={() => {
this.updateSection('nickname');
- }.bind(this)}
+ }}
/>
);
}
- var usernameSection;
+ let usernameSection;
if (this.props.activeSection === 'username') {
let usernameLabel = 'Username';
- if (utils.isMobile()) {
+ if (Utils.isMobile()) {
usernameLabel = '';
}
@@ -416,10 +415,10 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={this.submitUsername}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
extraInfo={extraInfo}
/>
);
@@ -428,13 +427,14 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Username'
describe={UserStore.getCurrentUser().username}
- updateSection={function updateUsernameSection() {
+ updateSection={() => {
this.updateSection('username');
- }.bind(this)}
+ }}
/>
);
}
- var emailSection;
+
+ let emailSection;
if (this.props.activeSection === 'email') {
const emailEnabled = global.window.mm_config.SendEmailNotifications === 'true';
const emailVerificationEnabled = global.window.mm_config.RequireEmailVerification === 'true';
@@ -507,10 +507,10 @@ export default class UserSettingsGeneralTab extends React.Component {
submit={submit}
server_error={serverError}
client_error={emailError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
/>
);
} else {
@@ -534,26 +534,26 @@ export default class UserSettingsGeneralTab extends React.Component {
<SettingItemMin
title='Email'
describe={describe}
- updateSection={function updateEmailSection() {
+ updateSection={() => {
this.updateSection('email');
- }.bind(this)}
+ }}
/>
);
}
- var pictureSection;
+ let pictureSection;
if (this.props.activeSection === 'picture') {
pictureSection = (
<SettingPicture
title='Profile Picture'
submit={this.submitPicture}
- src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + utils.getSessionIndex()}
+ src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update + '&' + Utils.getSessionIndex()}
server_error={serverError}
client_error={clientError}
- updateSection={function clearSection(e) {
+ updateSection={(e) => {
this.updateSection('');
e.preventDefault();
- }.bind(this)}
+ }}
picture={this.state.picture}
pictureChange={this.updatePicture}
submitActive={this.submitActive}
@@ -561,17 +561,17 @@ export default class UserSettingsGeneralTab extends React.Component {
/>
);
} else {
- var minMessage = 'Click \'Edit\' to upload an image.';
+ let minMessage = 'Click \'Edit\' to upload an image.';
if (user.last_picture_update) {
- minMessage = 'Image last updated ' + utils.displayDate(user.last_picture_update);
+ minMessage = 'Image last updated ' + Utils.displayDate(user.last_picture_update);
}
pictureSection = (
<SettingItemMin
title='Profile Picture'
describe={minMessage}
- updateSection={function updatePictureSection() {
+ updateSection={() => {
this.updateSection('picture');
- }.bind(this)}
+ }}
/>
);
}
@@ -619,10 +619,10 @@ export default class UserSettingsGeneralTab extends React.Component {
}
UserSettingsGeneralTab.propTypes = {
- user: React.PropTypes.object,
- updateSection: React.PropTypes.func,
- updateTab: React.PropTypes.func,
- activeSection: React.PropTypes.string,
+ user: React.PropTypes.object.isRequired,
+ updateSection: React.PropTypes.func.isRequired,
+ updateTab: React.PropTypes.func.isRequired,
+ activeSection: React.PropTypes.string.isRequired,
closeModal: React.PropTypes.func.isRequired,
collapseModal: React.PropTypes.func.isRequired
};
diff --git a/web/react/utils/channel_intro_mssages.jsx b/web/react/utils/channel_intro_mssages.jsx
index f27e23a82..11b69e28f 100644
--- a/web/react/utils/channel_intro_mssages.jsx
+++ b/web/react/utils/channel_intro_mssages.jsx
@@ -92,6 +92,7 @@ export function createOffTopicIntroMessage(channel, showInviteModal) {
</a>
<a
href='#'
+ className='intro-links'
onClick={showInviteModal}
>
<i className='fa fa-user-plus'></i>{'Invite others to this channel'}
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 6f3924829..77b3ecb57 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -616,7 +616,7 @@ export function applyTheme(theme) {
if (theme.centerChannelColor) {
changeCss('.app__content, .post-create__container .post-create-body .btn-file, .post-create__container .post-create-footer .msg-typing, .command-name, .modal .modal-content, .dropdown-menu, .popover, .mentions-name, .tip-overlay', 'color:' + theme.centerChannelColor, 1);
changeCss('#post-create', 'color:' + theme.centerChannelColor, 2);
- changeCss('.channel-header__links a', 'fill:' + changeOpacity(theme.centerChannelColor, 0.7), 1);
+ changeCss('.channel-header__links a', 'fill:' + changeOpacity(theme.centerChannelColor, 0.9), 1);
changeCss('.channel-header__links a:hover, .channel-header__links a:active', 'fill:' + theme.centerChannelColor, 2);
changeCss('.mentions--top, .command-box', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 3);
changeCss('.mentions--top, .command-box', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 2);
@@ -644,7 +644,7 @@ export function applyTheme(theme) {
changeCss('.search-bar__container .search__form .search-bar, .form-control', 'color:' + theme.centerChannelColor, 2);
changeCss('@media(max-width: 768px){.search-bar__container .search__form .search-bar', 'background:' + changeOpacity(theme.centerChannelColor, 0.2) + '; color: inherit;', 1);
changeCss('.input-group-addon, .search-bar__container .search__form, .form-control', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.form-control:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
+ changeCss('.form-control:focus, .channel-header__links', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
changeCss('.attachment .attachment__content', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
changeCss('.channel-intro .channel-intro__content, .webhooks__container', 'background:' + changeOpacity(theme.centerChannelColor, 0.05), 1);
changeCss('.date-separator .separator__text', 'color:' + theme.centerChannelColor, 2);
@@ -656,7 +656,7 @@ export function applyTheme(theme) {
changeCss('@media(max-width: 1440px){.post.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
changeCss('@media(max-width: 1440px){.post.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
changeCss('@media(max-width: 1800px){.inner__wrap.move--left .post.post--comment.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
- changeCss('.post:hover, .modal .more-table tbody>tr:hover td, .sidebar--right .sidebar--right__header, .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
+ changeCss('.post:hover, .channel-header__links a:hover, .channel-header__links a:active, .modal .more-table tbody>tr:hover td, .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
changeCss('.date-separator.hovered--before:after, .date-separator.hovered--after:before, .new-separator.hovered--after:before, .new-separator.hovered--before:after', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
changeCss('.command-name:hover, .mentions-name:hover, .mentions-focus, .dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover, .bot-indicator', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
changeCss('code', 'background:' + changeOpacity(theme.centerChannelColor, 0.1), 1);
diff --git a/web/sass-files/sass/partials/_content.scss b/web/sass-files/sass/partials/_content.scss
index 6228cc45e..44a959a9b 100644
--- a/web/sass-files/sass/partials/_content.scss
+++ b/web/sass-files/sass/partials/_content.scss
@@ -20,7 +20,6 @@
background: #fff;
@include display-flex;
@include flex-direction(column);
- flex-direction: column;
.channel__wrap & {
padding-top: 0;
}
diff --git a/web/sass-files/sass/partials/_files.scss b/web/sass-files/sass/partials/_files.scss
index 49fb8e847..168634b5e 100644
--- a/web/sass-files/sass/partials/_files.scss
+++ b/web/sass-files/sass/partials/_files.scss
@@ -1,9 +1,9 @@
.preview-container {
position: relative;
- margin-top: 10px;
+ margin-top: 25px;
width: 100%;
- max-height: 110px;
- height: 110px;
+ max-height: 100px;
+ height: 100px;
white-space: nowrap;
overflow-x: auto;
overflow-y: hidden;
@@ -11,7 +11,7 @@
display: inline-block;
width: 120px;
height: 100px;
- margin: 7px 0 0 5px;
+ margin: 0 0 0 5px;
vertical-align: top;
position: relative;
border: 1px solid #DDD;
diff --git a/web/sass-files/sass/partials/_forms.scss b/web/sass-files/sass/partials/_forms.scss
index 2d7b6cd26..685677ad0 100644
--- a/web/sass-files/sass/partials/_forms.scss
+++ b/web/sass-files/sass/partials/_forms.scss
@@ -43,3 +43,7 @@
margin: 10px 0 0;
color: #999;
}
+
+.disabled-input {
+ background-color: #dddddd !important;
+}
diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss
index 67c938b8c..69bc56841 100644
--- a/web/sass-files/sass/partials/_headers.scss
+++ b/web/sass-files/sass/partials/_headers.scss
@@ -1,8 +1,5 @@
#channel-header {
- padding: 3px 0;
- height: 58px;
- flex: 0 0 58px;
- @include flex(0 0 50px);
+ @include flex(0 0 56px);
}
.row {
&.header {
@@ -45,9 +42,9 @@
text-overflow: ellipsis;
margin-top: 2px;
max-height: 45px;
- .markdown-inline-img {
- max-height: 45px
- }
+ .markdown-inline-img {
+ max-height: 45px
+ }
}
&.popover {
white-space: normal;
@@ -97,7 +94,7 @@
.sidebar--left, .sidebar--menu {
.team__header {
position: relative;
- padding: 10px;
+ padding: 9px 10px;
@include legacy-pie-clearfix;
&:before {
@include single-transition(all, 0.05s, linear);
@@ -125,7 +122,7 @@
.navbar-right {
font-size: 0.85em;
position: absolute;
- top: 11px;
+ top: 10px;
right: 22px;
z-index: 5;
.dropdown-toggle {
@@ -217,7 +214,7 @@
width:100%;
border-left: none;
font-size: 14px;
- line-height: 50px;
+ line-height: 56px;
#member_popover {
margin-right: 5px;
width: 45px;
@@ -296,17 +293,19 @@
.channel-header__links {
height: 32px;
- vertical-align: top;
- display: inline-block;
- width: 15px;
- margin: 9px 6px 3px 0;
- a {
+ width: 32px;
+ @include border-radius(50px);
+ border: 1px solid #ccc;
+ margin-right: 10px;
+ > a {
+ @include border-radius(50px);
height: 100%;
display: block;
+ @include single-transition(all, 0.1s, ease-in);
}
svg {
vertical-align: top;
- margin-top: 8px;
+ margin: 7px 0 0 0px;
fill: inherit;
}
}
diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss
index 7b26581e9..5a7d79afe 100644
--- a/web/sass-files/sass/partials/_post.scss
+++ b/web/sass-files/sass/partials/_post.scss
@@ -332,18 +332,19 @@ body.ios {
}
.post-create-footer {
@include clearfix;
- padding: 0;
+ padding: 3px 0 0 0;
+ font-size: 13px;
.has-error {
.control-label {
+ height: 0;
+ display: block;
font-weight: normal;
margin-bottom: 0;
}
}
.msg-typing {
min-height: 25px;
- line-height: 25px;
display: block;
- font-size: 13px;
@include opacity(0.7);
}
}
@@ -425,9 +426,6 @@ body.ios {
}
}
}
- .post-create-footer {
- padding: 0;
- }
p {
margin: 0 0 1em;
line-height: 1.6em;
@@ -553,13 +551,14 @@ body.ios {
}
&.post-info {
.post-profile-time {
- color: #a8adb7;
vertical-align: top;
+ width: 150px;
max-width: 220px;
overflow: hidden;
display: block;
white-space: nowrap;
text-overflow: ellipsis;
+ margin: 0 0 0 50px;
}
}
.post-header-col {
@@ -585,7 +584,7 @@ body.ios {
}
}
.post-profile-time {
- color: #a8adb7;
+ @include opacity(0.5);
}
}
.post-comment {
diff --git a/web/sass-files/sass/partials/_post_right.scss b/web/sass-files/sass/partials/_post_right.scss
index ba41d3b95..54c3bcdf8 100644
--- a/web/sass-files/sass/partials/_post_right.scss
+++ b/web/sass-files/sass/partials/_post_right.scss
@@ -1,4 +1,7 @@
.post-right__container {
+ @include display-flex;
+ @include flex-direction(column);
+ height: 100%;
.post-right-root-message {
padding: 1em 1em 0;
@@ -19,6 +22,15 @@
margin: 1em 0 0 0;
}
}
+ .post-header {
+ .post-profile-time {
+ width: 200px;
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
}
.post-create__container {
@@ -44,7 +56,7 @@
}
.post-create-footer {
width: 100%;
- padding-top: 5px;
+ padding: 5px 0 10px;
}
.post-right-comments-upload-in-progress {
padding: 6px 0;
@@ -103,8 +115,9 @@
.post-right__scroll {
position: relative;
- overflow: scroll;
+ overflow: auto;
-webkit-overflow-scrolling: touch;
+ @include flex(1 1 auto);
}
.post-right-comment-time {
diff --git a/web/sass-files/sass/partials/_responsive.scss b/web/sass-files/sass/partials/_responsive.scss
index 3877bfaf0..aad991035 100644
--- a/web/sass-files/sass/partials/_responsive.scss
+++ b/web/sass-files/sass/partials/_responsive.scss
@@ -303,12 +303,17 @@
}
}
@media screen and (max-width: 768px) {
+ .textarea-wrapper {
+ .textbox-preview-link {
+ display: none;
+ }
+ }
.form-control {
&.min-height {
min-height: 100px;
}
}
- .gif-div {
+ .img-div {
max-width: 100%;
}
.tip-div {
@@ -535,17 +540,22 @@
.post-create__container {
.post-right__container & {
padding: 0 1em;
+ .msg-typing {
+ display: none;
+ }
}
form {
- padding: 0;
+ padding: 0.5em 0;
}
.post-create-footer {
+ padding: 0 1em;
.msg-typing {
- margin-left: 45px;
- width: 55%;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
+ display: none;
+ }
+ .has-error {
+ .control-label {
+ height: auto;
+ }
}
}
.post-create-body {
@@ -574,8 +584,8 @@
}
}
.preview-container {
- padding: 0px 10px;
- margin-top: 20px;
+ padding: 0px;
+ margin-top: 5px;
.preview-div {
margin-top: 0;
}
@@ -648,7 +658,7 @@
}
.search-bar__container {
padding: 0;
- height: 45px;
+ @include flex(0 0 44px);
background: $primary-color;
color: #fff;
&.focused {
@@ -777,6 +787,12 @@
.sidebar--right__close {
display: none;
}
+ .sidebar-right__body {
+ height: calc(100% - 44px);
+ }
+ }
+ .search-items-container {
+ height: calc(100% - 44px);
}
.inner__wrap {
&.move--right {
diff --git a/web/sass-files/sass/partials/_search.scss b/web/sass-files/sass/partials/_search.scss
index 73b69c866..bedf35376 100644
--- a/web/sass-files/sass/partials/_search.scss
+++ b/web/sass-files/sass/partials/_search.scss
@@ -1,8 +1,9 @@
#channel-header .search-bar__container {
- padding: 8px 8px 8px 0;
+ padding: 0 8px 0 0;
}
.search-bar__container {
- padding: 12px 8px 12px 0;
+ padding: 12px 8px 0 0;
+ @include flex(0 0 56px);
}
.search__clear {
display: none;
@@ -71,8 +72,10 @@
.search-items-container {
position: relative;
- overflow: scroll;
+ overflow: auto;
-webkit-overflow-scrolling: touch;
+ @include flex(1 1 auto);
+ height: calc(100% - 56px);
}
.search-results-header {
@@ -92,9 +95,11 @@
padding: 10px 1em;
margin: 0;
cursor: pointer;
+
&:first-child {
border: none;
}
+
.search-channel__name {
font-weight: 600;
margin: 0 0 10px 0;
diff --git a/web/sass-files/sass/partials/_sidebar--left.scss b/web/sass-files/sass/partials/_sidebar--left.scss
index ab13d1b42..eb7c1b83f 100644
--- a/web/sass-files/sass/partials/_sidebar--left.scss
+++ b/web/sass-files/sass/partials/_sidebar--left.scss
@@ -47,7 +47,7 @@
.nav-pills__container {
height: 100%;
position: relative;
- overflow: scroll;
+ overflow: auto;
-webkit-overflow-scrolling: touch;
}
diff --git a/web/sass-files/sass/partials/_sidebar--menu.scss b/web/sass-files/sass/partials/_sidebar--menu.scss
index 6f4a0cc38..e34cd72c1 100644
--- a/web/sass-files/sass/partials/_sidebar--menu.scss
+++ b/web/sass-files/sass/partials/_sidebar--menu.scss
@@ -57,8 +57,11 @@
color: inherit;
line-height: 40px;
padding: 0 15px;
- .glyphicon {
+ .fa ,.glyphicon {
width: 25px;
+ text-align: center;
+ left: -5px;
+ position: relative;
}
}
}
diff --git a/web/sass-files/sass/partials/_sidebar--right.scss b/web/sass-files/sass/partials/_sidebar--right.scss
index a4267294c..2527eef28 100644
--- a/web/sass-files/sass/partials/_sidebar--right.scss
+++ b/web/sass-files/sass/partials/_sidebar--right.scss
@@ -3,24 +3,38 @@
width: 400px;
height: 100%;
right: 0px;
- padding: 0 0 2em 0;
+ padding: 0;
background: #fff;
@include single-transition(transform, 0.5s, ease);
right: -320px;
+
&.move--left {
right: 0;
}
+
+ .sidebar--right__content {
+ height: 100%;
+ @include display-flex;
+ @include flex-direction(column);
+ }
+
.sidebar--right__back {
- color: #666;
- width: 20px;
+ color: inherit;
+ @include opacity(0.8);
+ width: 30px;
text-align: center;
- margin: 0 0 0 -6px;
- font-size: 12px;
+ margin: 0 0 0 -14px;
+ font-size: 13px;
display: inline-block;
}
.sidebar-right__body {
+ @include flex(1 1 auto);
border-left: $border-gray;
border-top: $border-gray;
+ @include display-flex;
+ @include flex-direction(column);
+ height: calc(100% - 56px);
+ @include border-radius(2px 0 0 0);
}
.post {
.post-header {
@@ -75,7 +89,7 @@
height: 44px;
padding: 0 1em;
line-height: 44px;
- background: #F5F5F5;
+ @include flex(0 0 44px);
border-bottom: $border-gray;
}
.sidebar--right__subheader {
diff --git a/web/sass-files/sass/partials/_videos.scss b/web/sass-files/sass/partials/_videos.scss
index bb36b6223..3f15f8f1e 100644
--- a/web/sass-files/sass/partials/_videos.scss
+++ b/web/sass-files/sass/partials/_videos.scss
@@ -51,7 +51,7 @@
border-left:60px solid rgba(255,255,255,0.4);
}
-.gif-div {
+.img-div {
-moz-force-broken-image-icon: 1;
position:relative;
max-width: 450px;
diff --git a/web/web.go b/web/web.go
index ffc791cb7..02ceb69ba 100644
--- a/web/web.go
+++ b/web/web.go
@@ -989,7 +989,7 @@ func incomingWebhook(c *api.Context, w http.ResponseWriter, r *http.Request) {
}
text := parsedRequest.Text
- if len(text) == 0 {
+ if len(text) == 0 && parsedRequest.Attachments == nil {
c.Err = model.NewAppError("incomingWebhook", "No text specified", "")
return
}