Conflicts:
	web/react/components/popover_list_members.jsx
	web/react/components/user_profile.jsx
Этот коммит содержится в:
Asaad Mahmood
2015-10-16 23:19:23 +05:00
родитель e840cb612f 3bd0a15341
Коммит 7849a48a85
15 изменённых файлов: 152 добавлений и 102 удалений

Просмотреть файл

@@ -60,9 +60,10 @@ func TestGetAllPreferences(t *testing.T) {
Client.LoginByEmail(team.Name, user2.Email, "pwd")
// note that user2 will automatically have a preference set for them to show user1 for direct messages
if result, err := Client.GetAllPreferences(); err != nil {
t.Fatal(err)
} else if data := result.Data.(model.Preferences); len(data) != 0 {
} else if data := result.Data.(model.Preferences); len(data) != 1 {
t.Fatal("received the wrong number of preferences")
}
}

Просмотреть файл

@@ -2,6 +2,13 @@
The following install instructions are for single-container installs of Mattermost using Docker for exploring product functionality and upgrading to newer versions.
### One-line Docker Install ###
If you have Docker set up, Mattermost installs in one-line:
`docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform`
Otherwise, see step-by-step available:
### Mac OSX ###
1. Install Docker Toolbox using instructions at: http://docs.docker.com/installation/mac/

Просмотреть файл

@@ -8,6 +8,11 @@ import (
"io"
)
const (
DEFAULT_WEBHOOK_USERNAME = "webhook"
DEFAULT_WEBHOOK_ICON = "/static/images/webhook_icon.jpg"
)
type IncomingWebhook struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`

Просмотреть файл

@@ -440,9 +440,11 @@ export default class EmailSettings extends React.Component {
className='table table-bordered'
cellPadding='5'
>
<tr><td className='help-text'>{'None'}</td><td className='help-text'>{'Mattermost will send email over an unsecure connection.'}</td></tr>
<tr><td className='help-text'>{'TLS'}</td><td className='help-text'>{'Encrypts the communication between Mattermost and your email server.'}</td></tr>
<tr><td className='help-text'>{'STARTTLS'}</td><td className='help-text'>{'Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.'}</td></tr>
<tbody>
<tr><td className='help-text'>{'None'}</td><td className='help-text'>{'Mattermost will send email over an unsecure connection.'}</td></tr>
<tr><td className='help-text'>{'TLS'}</td><td className='help-text'>{'Encrypts the communication between Mattermost and your email server.'}</td></tr>
<tr><td className='help-text'>{'STARTTLS'}</td><td className='help-text'>{'Takes an existing insecure connection and attempts to upgrade it to a secure connection using TLS.'}</td></tr>
</tbody>
</table>
</div>
<div className='help-text'>

Просмотреть файл

@@ -249,22 +249,24 @@ export default class LogSettings extends React.Component {
onChange={this.handleChange}
disabled={!this.state.fileEnable}
/>
<p className='help-text'>
<div className='help-text'>
{'Format of log message output. If blank will be set to "[%D %T] [%L] %M", where:'}
<div className='help-text'>
<table
className='table table-bordered'
cellPadding='5'
>
<tr><td className='help-text'>{'%T'}</td><td className='help-text'>{'Time (15:04:05 MST)'}</td></tr>
<tr><td className='help-text'>{'%D'}</td><td className='help-text'>{'Date (2006/01/02)'}</td></tr>
<tr><td className='help-text'>{'%d'}</td><td className='help-text'>{'Date (01/02/06)'}</td></tr>
<tr><td className='help-text'>{'%L'}</td><td className='help-text'>{'Level (DEBG, INFO, EROR)'}</td></tr>
<tr><td className='help-text'>{'%S'}</td><td className='help-text'>{'Source'}</td></tr>
<tr><td className='help-text'>{'%M'}</td><td className='help-text'>{'Message'}</td></tr>
<tbody>
<tr><td className='help-text'>{'%T'}</td><td className='help-text'>{'Time (15:04:05 MST)'}</td></tr>
<tr><td className='help-text'>{'%D'}</td><td className='help-text'>{'Date (2006/01/02)'}</td></tr>
<tr><td className='help-text'>{'%d'}</td><td className='help-text'>{'Date (01/02/06)'}</td></tr>
<tr><td className='help-text'>{'%L'}</td><td className='help-text'>{'Level (DEBG, INFO, EROR)'}</td></tr>
<tr><td className='help-text'>{'%S'}</td><td className='help-text'>{'Source'}</td></tr>
<tr><td className='help-text'>{'%M'}</td><td className='help-text'>{'Message'}</td></tr>
</tbody>
</table>
</div>
</p>
</div>
</div>
</div>

Просмотреть файл

@@ -70,7 +70,7 @@ export default class EditPostModal extends React.Component {
refocusId: options.refocusId || ''
});
$(React.findDOMNode(this.refs.modal)).modal('show');
$(ReactDOM.findDOMNode(this.refs.modal)).modal('show');
}
componentDidMount() {
var self = this;
@@ -92,7 +92,7 @@ export default class EditPostModal extends React.Component {
$('#edit_textbox').get(0).focus();
});
$(React.findDOMNode(this.refs.modal)).on('hide.bs.modal', function onShown() {
$(ReactDOM.findDOMNode(this.refs.modal)).on('hide.bs.modal', function onShown() {
if (self.state.refocusId !== '') {
setTimeout(() => {
$(self.state.refocusId).get(0).focus();

Просмотреть файл

@@ -35,13 +35,20 @@ export default class PopoverListMembers extends React.Component {
const teamMembers = UserStore.getProfilesUsernameMap();
if (members && teamMembers) {
members.sort(function compareByLocal(a, b) {
members.sort((a, b) => {
return a.username.localeCompare(b.username);
});
members.forEach(function addMemberElement(m) {
members.forEach((m, i) => {
if (teamMembers[m.username] && teamMembers[m.username].delete_at <= 0) {
popoverHtml.push(<div className='text--nowrap'>{m.username}</div>);
popoverHtml.push(
<div
className='text--nowrap'
key={'popover-member-' + i}
>
{m.username}
</div>
);
count++;
}
});
@@ -58,7 +65,14 @@ export default class PopoverListMembers extends React.Component {
trigger='click'
placement='bottom'
rootClose={true}
overlay={<Popover title='Members'>{popoverHtml}</Popover>}
overlay={
<Popover
title='Members'
id='member-list-popover'
>
{popoverHtml}
</Popover>
}
>
<div id='member_popover'>
<div>

Просмотреть файл

@@ -29,7 +29,7 @@ export default class RhsComment extends React.Component {
var post = this.props.post;
Client.createPost(post, post.channel_id,
function success(data) {
(data) => {
AsyncClient.getPosts(post.channel_id);
var channel = ChannelStore.get(post.channel_id);
@@ -43,11 +43,11 @@ export default class RhsComment extends React.Component {
post: data
});
},
function fail() {
() => {
post.state = Constants.POST_FAILED;
PostStore.updatePendingPost(post);
this.forceUpdate();
}.bind(this)
}
);
post.state = Constants.POST_LOADING;
@@ -84,7 +84,10 @@ export default class RhsComment extends React.Component {
if (isOwner) {
dropdownContents.push(
<li role='presentation'>
<li
role='presentation'
key='edit-button'
>
<a
href='#'
role='menuitem'
@@ -95,7 +98,7 @@ export default class RhsComment extends React.Component {
data-postid={post.id}
data-channelid={post.channel_id}
>
Edit
{'Edit'}
</a>
</li>
);
@@ -103,7 +106,10 @@ export default class RhsComment extends React.Component {
if (isOwner || isAdmin) {
dropdownContents.push(
<li role='presentation'>
<li
role='presentation'
key='delete-button'
>
<a
href='#'
role='menuitem'
@@ -114,7 +120,7 @@ export default class RhsComment extends React.Component {
data-channelid={post.channel_id}
data-comments={0}
>
Delete
{'Delete'}
</a>
</li>
);
@@ -162,7 +168,7 @@ export default class RhsComment extends React.Component {
href='#'
onClick={this.retryComment}
>
Retry
{'Retry'}
</a>
);
} else if (post.state === Constants.POST_LOADING) {
@@ -213,14 +219,14 @@ export default class RhsComment extends React.Component {
</li>
</ul>
<div className='post-body'>
<p className={postClass}>
<div className={postClass}>
{loading}
<div
ref='message_holder'
onClick={TextFormatting.handleClick}
dangerouslySetInnerHTML={{__html: TextFormatting.formatText(post.message)}}
/>
</p>
</div>
{fileAttachment}
</div>
</div>

Просмотреть файл

@@ -46,7 +46,7 @@ export default class Sidebar extends React.Component {
const state = this.getStateFromStores();
state.newChannelModalType = '';
state.showMoreDirectChannelsModal = false;
state.showDirectChannelsModal = false;
state.loadingDMChannel = -1;
this.state = state;
@@ -471,7 +471,9 @@ export default class Sidebar extends React.Component {
}
let closeButton = null;
const removeTooltip = <Tooltip>{'Remove from list'}</Tooltip>;
const removeTooltip = (
<Tooltip id='remove-dm-tooltip'>{'Remove from list'}</Tooltip>
);
if (handleClose && !badge) {
closeButton = (
<OverlayTrigger
@@ -564,8 +566,12 @@ export default class Sidebar extends React.Component {
showChannelModal = true;
}
const createChannelTootlip = <Tooltip>{'Create new channel'}</Tooltip>;
const createGroupTootlip = <Tooltip>{'Create new group'}</Tooltip>;
const createChannelTootlip = (
<Tooltip id='new-channel-tooltip' >{'Create new channel'}</Tooltip>
);
const createGroupTootlip = (
<Tooltip id='new-group-tooltip'>{'Create new group'}</Tooltip>
);
return (
<div>

Просмотреть файл

@@ -65,19 +65,29 @@ export default class UserProfile extends React.Component {
var dataContent = [];
dataContent.push(
<img className='user-popover__image'
<img
className='user-popover__image'
src={'/api/v1/users/' + this.state.profile.id + '/image?time=' + this.state.profile.update_at}
height='128'
width='128'
key='user-popover-image'
/>
);
if (!global.window.config.ShowEmailAddress === 'true') {
dataContent.push(<div className='text-nowrap'>{'Email not shared'}</div>);
dataContent.push(
<div
className='text-nowrap'
key='user-popover-no-email'
>
{'Email not shared'}
</div>
);
} else {
dataContent.push(
<div
data-toggle='tooltip'
title="' + this.state.profile.email + '"
key='user-popover-email'
>
<a
href="mailto:' + this.state.profile.email + '"
@@ -94,14 +104,21 @@ export default class UserProfile extends React.Component {
trigger='click'
placement='right'
rootClose={true}
overlay={<Popover title={this.state.profile.username}>{dataContent}</Popover>}
overlay={
<Popover
title={this.state.profile.username}
id='user-profile-popover'
>
{dataContent}
</Popover>
}
>
<div
className='user-popover'
id={'profile_' + this.uniqueId}
>
{name}
</div>
<div
className='user-popover'
id={'profile_' + this.uniqueId}
>
{name}
</div>
</OverlayTrigger>
);
}

Просмотреть файл

@@ -152,9 +152,8 @@ export default class UserSettingsAppearance extends React.Component {
<input type='radio'
checked={!displayCustom}
onChange={this.updateType.bind(this, 'premade')}
>
{'Theme Colors'}
</input>
/>
{'Theme Colors'}
</label>
<br/>
</div>
@@ -164,9 +163,8 @@ export default class UserSettingsAppearance extends React.Component {
<input type='radio'
checked={displayCustom}
onChange={this.updateType.bind(this, 'custom')}
>
{'Custom Theme'}
</input>
/>
{'Custom Theme'}
</label>
<br/>
</div>

Просмотреть файл

@@ -1,7 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import { savePreferences } from '../../utils/client.jsx';
import {savePreferences} from '../../utils/client.jsx';
import SettingItemMin from '../setting_item_min.jsx';
import SettingItemMax from '../setting_item_max.jsx';
import Constants from '../../utils/constants.jsx';
@@ -38,7 +38,7 @@ export default class UserSettingsDisplay extends React.Component {
);
}
handleClockRadio(militaryTime) {
this.setState({militaryTime: militaryTime});
this.setState({militaryTime});
}
updateSection(section) {
this.setState(getDisplayStateFromStores());
@@ -57,7 +57,7 @@ export default class UserSettingsDisplay extends React.Component {
const serverError = this.state.serverError || null;
let clockSection;
if (this.props.activeSection === 'clock') {
let clockFormat = [false, false];
const clockFormat = [false, false];
if (this.state.militaryTime === 'true') {
clockFormat[1] = true;
} else {
@@ -77,9 +77,8 @@ export default class UserSettingsDisplay extends React.Component {
type='radio'
checked={clockFormat[0]}
onChange={this.handleClockRadio.bind(this, 'false')}
>
12-hour clock (example: 4:00 PM)
</input>
/>
{'12-hour clock (example: 4:00 PM)'}
</label>
<br/>
</div>
@@ -89,9 +88,8 @@ export default class UserSettingsDisplay extends React.Component {
type='radio'
checked={clockFormat[1]}
onChange={this.handleClockRadio.bind(this, 'true')}
>
24-hour clock (example: 16:00)
</input>
/>
{'24-hour clock (example: 16:00)'}
</label>
<br/>
</div>
@@ -99,7 +97,6 @@ export default class UserSettingsDisplay extends React.Component {
</div>
];
clockSection = (
<SettingItemMax
title='Clock Display'
@@ -138,13 +135,13 @@ export default class UserSettingsDisplay extends React.Component {
className='close'
data-dismiss='modal'
aria-label='Close'
>
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4
className='modal-title'
ref='title'
>
>
<i className='modal-back'></i>
{'Display Settings'}
</h4>

Просмотреть файл

@@ -228,9 +228,8 @@ export default class NotificationsTab extends React.Component {
<input type='radio'
checked={notifyActive[0]}
onChange={this.handleNotifyRadio.bind(this, 'all')}
>
For all activity
</input>
/>
{'For all activity'}
</label>
<br/>
</div>
@@ -240,9 +239,8 @@ export default class NotificationsTab extends React.Component {
type='radio'
checked={notifyActive[1]}
onChange={this.handleNotifyRadio.bind(this, 'mention')}
>
Only for mentions and direct messages
</input>
/>
{'Only for mentions and direct messages'}
</label>
<br/>
</div>
@@ -252,9 +250,8 @@ export default class NotificationsTab extends React.Component {
type='radio'
checked={notifyActive[2]}
onChange={this.handleNotifyRadio.bind(this, 'none')}
>
Never
</input>
/>
{'Never'}
</label>
</div>
</div>
@@ -320,9 +317,8 @@ export default class NotificationsTab extends React.Component {
type='radio'
checked={soundActive[0]}
onChange={this.handleSoundRadio.bind(this, 'true')}
>
On
</input>
/>
{'On'}
</label>
<br/>
</div>
@@ -332,9 +328,8 @@ export default class NotificationsTab extends React.Component {
type='radio'
checked={soundActive[1]}
onChange={this.handleSoundRadio.bind(this, 'false')}
>
Off
</input>
/>
{'Off'}
</label>
<br/>
</div>
@@ -402,9 +397,8 @@ export default class NotificationsTab extends React.Component {
type='radio'
checked={emailActive[0]}
onChange={this.handleEmailRadio.bind(this, 'true')}
>
On
</input>
/>
{'On'}
</label>
<br/>
</div>
@@ -414,9 +408,8 @@ export default class NotificationsTab extends React.Component {
type='radio'
checked={emailActive[1]}
onChange={this.handleEmailRadio.bind(this, 'false')}
>
Off
</input>
/>
{'Off'}
</label>
<br/>
</div>
@@ -482,9 +475,8 @@ export default class NotificationsTab extends React.Component {
type='checkbox'
checked={this.state.firstNameKey}
onChange={handleUpdateFirstNameKey}
>
{'Your case sensitive first name "' + user.first_name + '"'}
</input>
/>
{'Your case sensitive first name "' + user.first_name + '"'}
</label>
</div>
</div>
@@ -502,9 +494,8 @@ export default class NotificationsTab extends React.Component {
type='checkbox'
checked={this.state.usernameKey}
onChange={handleUpdateUsernameKey}
>
{'Your non-case sensitive username "' + user.username + '"'}
</input>
/>
{'Your non-case sensitive username "' + user.username + '"'}
</label>
</div>
</div>
@@ -521,9 +512,8 @@ export default class NotificationsTab extends React.Component {
type='checkbox'
checked={this.state.mentionKey}
onChange={handleUpdateMentionKey}
>
{'Your username mentioned "@' + user.username + '"'}
</input>
/>
{'Your username mentioned "@' + user.username + '"'}
</label>
</div>
</div>
@@ -540,9 +530,8 @@ export default class NotificationsTab extends React.Component {
type='checkbox'
checked={this.state.allKey}
onChange={handleUpdateAllKey}
>
{'Team-wide mentions "@all"'}
</input>
/>
{'Team-wide mentions "@all"'}
</label>
</div>
</div>
@@ -559,9 +548,8 @@ export default class NotificationsTab extends React.Component {
type='checkbox'
checked={this.state.channelKey}
onChange={handleUpdateChannelKey}
>
{'Channel-wide mentions "@channel"'}
</input>
/>
{'Channel-wide mentions "@channel"'}
</label>
</div>
</div>
@@ -576,9 +564,8 @@ export default class NotificationsTab extends React.Component {
type='checkbox'
checked={this.state.customKeysChecked}
onChange={this.updateCustomMentionKeys}
>
{'Other non-case sensitive words, separated by commas:'}
</input>
/>
{'Other non-case sensitive words, separated by commas:'}
</label>
</div>
<input

Двоичные данные
web/static/images/webhook_icon.jpg Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 67 KiB

Просмотреть файл

@@ -971,12 +971,20 @@ func incomingWebhook(c *api.Context, w http.ResponseWriter, r *http.Request) {
post := &model.Post{UserId: hook.UserId, ChannelId: channel.Id, Message: text}
post.AddProp("from_webhook", "true")
if len(overrideUsername) != 0 && utils.Cfg.ServiceSettings.EnablePostUsernameOverride {
post.AddProp("override_username", overrideUsername)
if utils.Cfg.ServiceSettings.EnablePostUsernameOverride {
if len(overrideUsername) != 0 {
post.AddProp("override_username", overrideUsername)
} else {
post.AddProp("override_username", model.DEFAULT_WEBHOOK_USERNAME)
}
}
if len(overrideIconUrl) != 0 && utils.Cfg.ServiceSettings.EnablePostIconOverride {
post.AddProp("override_icon_url", overrideIconUrl)
if utils.Cfg.ServiceSettings.EnablePostIconOverride {
if len(overrideIconUrl) != 0 {
post.AddProp("override_icon_url", overrideIconUrl)
} else {
post.AddProp("override_icon_url", model.DEFAULT_WEBHOOK_ICON)
}
}
if !c.HasPermissionsToChannel(pchan, "createIncomingHook") && channel.Type != model.CHANNEL_OPEN {