Merge branch 'release-1.2'
Этот коммит содержится в:
39
CHANGELOG.md
39
CHANGELOG.md
@@ -1,12 +1,32 @@
|
|||||||
# Mattermost Changelog
|
# Mattermost Changelog
|
||||||
|
|
||||||
## UNDER DEVELOPMENT Release v1.2.0
|
## Release v1.2.0
|
||||||
|
|
||||||
The "UNDER DEVELOPMENT" section of the Mattermost changelog appears in the product's `master` branch to note key changes committed to master and are on their way to the next stable release. When a stable release is pushed the "UNDER DEVELOPMENT" heading is removed from the final changelog of the release.
|
|
||||||
|
|
||||||
- **Release candidate anticipated:** 2015-11-10
|
|
||||||
- **Final release anticipated:** 2015-11-16
|
- **Final release anticipated:** 2015-11-16
|
||||||
|
|
||||||
|
### Release Highlights
|
||||||
|
|
||||||
|
#### Outgoing webhooks
|
||||||
|
|
||||||
|
- Mattermost users can now interact with external applications using [outgoing webhooks](https://github.com/mattermost/platform/blob/master/doc/integrations/webhooks/Outgoing-Webhooks.md)
|
||||||
|
- An [application template](https://github.com/mattermost/mattermost-integration-giphy) demonstrating user queries sent to the Giphy search engine via Mattermost webhooks now available
|
||||||
|
- A community application, [Matterbrige](https://github.com/42wim/matterbridge?files=1), shows how to use webhooks to connect Mattermost with IRC
|
||||||
|
|
||||||
|
#### Search Scope Modifiers
|
||||||
|
|
||||||
|
- Adding search term `in:[channel_url_name]` now limits searches within a specific channel
|
||||||
|
- Adding search term `from:[username]` now limits searches to messages from a specific user
|
||||||
|
|
||||||
|
#### Syntax Highlighting
|
||||||
|
|
||||||
|
- Syntax highlight for code blocks now available for `Diff, Apache, Makefile, HTTP, JSON, Markdown, Java, CSS, nginx, ObjectiveC, Python, XML, Perl, Bash, PHP, Coffee, C, SQL, Go, Ruby, Java, and ini`
|
||||||
|
|
||||||
|
#### Usability Improvements
|
||||||
|
|
||||||
|
- Added tutorial to teach new users how to use Mattermost
|
||||||
|
- Various performance improvements to support teams with hundreds of users
|
||||||
|
- Direct Messages "More" menu now lets you search for users by username and real name
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
Onboarding
|
Onboarding
|
||||||
@@ -18,7 +38,7 @@ Messaging and Notifications
|
|||||||
- Users can now search for teammates to add to **Direct Message** list via **More** menu
|
- Users can now search for teammates to add to **Direct Message** list via **More** menu
|
||||||
- Users can now personalize Direct Messages list by removing users listed
|
- Users can now personalize Direct Messages list by removing users listed
|
||||||
- Link previews - Adding URL with .gif file adds image below message
|
- Link previews - Adding URL with .gif file adds image below message
|
||||||
- Added new browser tab alerts to indicate unread messages and mentions
|
- Added new browser tab alerts to indicate unread messages and mentions
|
||||||
|
|
||||||
Search
|
Search
|
||||||
|
|
||||||
@@ -34,8 +54,8 @@ Integrations
|
|||||||
User Interface
|
User Interface
|
||||||
|
|
||||||
- Member list in Channel display now scrollable, and includes Message button to message channel members directly
|
- Member list in Channel display now scrollable, and includes Message button to message channel members directly
|
||||||
- Added ability to edit previous message by hitting UP arrow
|
- Added ability to edit previous message by hitting UP arrow
|
||||||
- Syntax highlighting added for code blocks
|
- Syntax highlighting added for code blocks
|
||||||
- Languages include `Diff, Apache, Makefile, HTTP, JSON, Markdown, Java, CSS, nginx, ObjectiveC, Python, XML, Perl, Bash, PHP, Coffee, C, SQL, Go, Ruby, Java, and ini`.
|
- Languages include `Diff, Apache, Makefile, HTTP, JSON, Markdown, Java, CSS, nginx, ObjectiveC, Python, XML, Perl, Bash, PHP, Coffee, C, SQL, Go, Ruby, Java, and ini`.
|
||||||
- Use by adding the name of the language on the first link of the code block, for example: ```python
|
- Use by adding the name of the language on the first link of the code block, for example: ```python
|
||||||
- Syntax color theme can be defined under **Account Settings** > **Appearance Settings** > **Custom Theme**
|
- Syntax color theme can be defined under **Account Settings** > **Appearance Settings** > **Custom Theme**
|
||||||
@@ -65,7 +85,7 @@ System Console
|
|||||||
- Fixed issue with the centre channel scroll position jumping when right hand side was opened and closed
|
- Fixed issue with the centre channel scroll position jumping when right hand side was opened and closed
|
||||||
- Added support for simultaneous login to different teams in different browser tabs
|
- Added support for simultaneous login to different teams in different browser tabs
|
||||||
- Incoming webhooks no longer disrupted when channel is deleted
|
- Incoming webhooks no longer disrupted when channel is deleted
|
||||||
|
- You can now paste a Mattermost incoming webhook URL into the same field designed for a Slack URL and integrations will work
|
||||||
### Compatibility
|
### Compatibility
|
||||||
|
|
||||||
- IE 11 new minimum version for IE, since IE 10 share fell below 5% on desktop
|
- IE 11 new minimum version for IE, since IE 10 share fell below 5% on desktop
|
||||||
@@ -75,7 +95,7 @@ System Console
|
|||||||
|
|
||||||
Multiple settings were added to [`config.json`](./config/config.json). These options can be modified in the System Console, or manually updated in the existing config.json file. This is a list of changes and their new default values in a fresh install:
|
Multiple settings were added to [`config.json`](./config/config.json). These options can be modified in the System Console, or manually updated in the existing config.json file. This is a list of changes and their new default values in a fresh install:
|
||||||
- Under `TeamSettings` in `config.json`:
|
- Under `TeamSettings` in `config.json`:
|
||||||
- Added: `"RestrictTeamNames": true` to control whether team names are restricted
|
- Added: `"RestrictTeamNames": true` to control whether team names can contain reserved words like www, admin, support, test, etc.
|
||||||
- Added: `"EnableTeamListing": false` to control whether teams can be listed on the root page of the site
|
- Added: `"EnableTeamListing": false` to control whether teams can be listed on the root page of the site
|
||||||
- Under `ServiceSettings` in `config.json`
|
- Under `ServiceSettings` in `config.json`
|
||||||
- Added: `EnableOutgoingWebhooks": true` to turn on outgoing webhooks
|
- Added: `EnableOutgoingWebhooks": true` to turn on outgoing webhooks
|
||||||
@@ -99,6 +119,7 @@ The following is for informational purposes only, no action needed. Mattermost a
|
|||||||
|
|
||||||
#### Known Issues
|
#### Known Issues
|
||||||
|
|
||||||
|
- When navigating to a page with new messages as well as message containing inline images added via markdown, the channel may move up and down while loading the inline images
|
||||||
- Microsoft Edge does not yet support drag and drop
|
- Microsoft Edge does not yet support drag and drop
|
||||||
- After upgrading to v1.2 existing users will see the newly added tutorial tips upon login (this is a special case for v1.2 and will not happen in future upgrades)
|
- After upgrading to v1.2 existing users will see the newly added tutorial tips upon login (this is a special case for v1.2 and will not happen in future upgrades)
|
||||||
- Channel list becomes reordered when there are lowercase channel names in a Postgres database
|
- Channel list becomes reordered when there are lowercase channel names in a Postgres database
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ VOLUME /var/lib/mysql
|
|||||||
WORKDIR /mattermost
|
WORKDIR /mattermost
|
||||||
|
|
||||||
# Copy over files
|
# Copy over files
|
||||||
ADD https://github.com/mattermost/platform/releases/download/v1.2.0-rc1/mattermost.tar.gz /
|
ADD https://github.com/mattermost/platform/releases/download/v1.2.0-rc2/mattermost.tar.gz /
|
||||||
RUN tar -zxvf /mattermost.tar.gz --strip-components=1 && rm /mattermost.tar.gz
|
RUN tar -zxvf /mattermost.tar.gz --strip-components=1 && rm /mattermost.tar.gz
|
||||||
ADD config_docker.json /
|
ADD config_docker.json /
|
||||||
ADD docker-entry.sh /
|
ADD docker-entry.sh /
|
||||||
|
|||||||
@@ -140,7 +140,9 @@ export default class Navbar extends React.Component {
|
|||||||
role='menuitem'
|
role='menuitem'
|
||||||
href='#'
|
href='#'
|
||||||
onClick={() => this.setState({showEditChannelPurposeModal: true})}
|
onClick={() => this.setState({showEditChannelPurposeModal: true})}
|
||||||
/>
|
>
|
||||||
|
{'Set Channel Purpose...'}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export default class PostBody extends React.Component {
|
|||||||
this.receivedYoutubeData = false;
|
this.receivedYoutubeData = false;
|
||||||
this.isGifLoading = false;
|
this.isGifLoading = false;
|
||||||
|
|
||||||
|
this.handleUserChange = this.handleUserChange.bind(this);
|
||||||
this.parseEmojis = this.parseEmojis.bind(this);
|
this.parseEmojis = this.parseEmojis.bind(this);
|
||||||
this.createEmbed = this.createEmbed.bind(this);
|
this.createEmbed = this.createEmbed.bind(this);
|
||||||
this.createGifEmbed = this.createGifEmbed.bind(this);
|
this.createGifEmbed = this.createGifEmbed.bind(this);
|
||||||
@@ -25,7 +26,14 @@ export default class PostBody extends React.Component {
|
|||||||
this.createYoutubeEmbed = this.createYoutubeEmbed.bind(this);
|
this.createYoutubeEmbed = this.createYoutubeEmbed.bind(this);
|
||||||
|
|
||||||
const linkData = Utils.extractLinks(this.props.post.message);
|
const linkData = Utils.extractLinks(this.props.post.message);
|
||||||
this.state = {links: linkData.links, message: linkData.text, post: this.props.post};
|
const profiles = UserStore.getProfiles();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
links: linkData.links,
|
||||||
|
message: linkData.text,
|
||||||
|
post: this.props.post
|
||||||
|
hasUserProfiles: profiles && Object.keys(profiles).length > 1
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllChildNodes(nodeIn) {
|
getAllChildNodes(nodeIn) {
|
||||||
@@ -55,12 +63,26 @@ export default class PostBody extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.parseEmojis();
|
this.parseEmojis();
|
||||||
|
|
||||||
|
UserStore.addChangeListener(this.handleUserChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.parseEmojis();
|
this.parseEmojis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
UserStore.removeChangeListener(this.handleUserChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleUserChange() {
|
||||||
|
if (!this.state.hasProfiles) {
|
||||||
|
const profiles = UserStore.getProfiles();
|
||||||
|
|
||||||
|
this.setState({hasProfiles: profiles && Object.keys(profiles).length > 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const linkData = Utils.extractLinks(nextProps.post.message);
|
const linkData = Utils.extractLinks(nextProps.post.message);
|
||||||
if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) {
|
if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
const PostsView = require('./posts_view.jsx');
|
const PostsView = require('./posts_view.jsx');
|
||||||
const LoadingScreen = require('./loading_screen.jsx');
|
const LoadingScreen = require('./loading_screen.jsx');
|
||||||
|
const ChannelInviteModal = require('./channel_invite_modal.jsx');
|
||||||
|
|
||||||
const ChannelStore = require('../stores/channel_store.jsx');
|
const ChannelStore = require('../stores/channel_store.jsx');
|
||||||
const PostStore = require('../stores/post_store.jsx');
|
const PostStore = require('../stores/post_store.jsx');
|
||||||
@@ -50,6 +51,7 @@ export default class PostsViewContainer extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.showInviteModal = false;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -248,7 +250,7 @@ export default class PostsViewContainer extends React.Component {
|
|||||||
postViewScrolled={this.handlePostsViewScroll}
|
postViewScrolled={this.handlePostsViewScroll}
|
||||||
loadMorePostsTopClicked={this.loadMorePostsTop}
|
loadMorePostsTopClicked={this.loadMorePostsTop}
|
||||||
numPostsToDisplay={this.state.numPostsToDisplay}
|
numPostsToDisplay={this.state.numPostsToDisplay}
|
||||||
introText={channel ? createChannelIntroMessage(channel) : null}
|
introText={channel ? createChannelIntroMessage(channel, () => this.setState({showInviteModal: true})) : null}
|
||||||
messageSeparatorTime={this.state.currentLastViewed}
|
messageSeparatorTime={this.state.currentLastViewed}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -263,7 +265,13 @@ export default class PostsViewContainer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id='post-list'>{postListCtls}</div>
|
<div id='post-list'>
|
||||||
|
{postListCtls}
|
||||||
|
<ChannelInviteModal
|
||||||
|
show={this.state.showInviteModal}
|
||||||
|
onModalDismissed={() => this.setState({showInviteModal: false})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export default class Sidebar extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hiddenDirectChannelCount = UserStore.getActiveOnlyProfileList().length - visibleDirectChannels.length;
|
const hiddenDirectChannelCount = UserStore.getActiveOnlyProfileList(true).length - visibleDirectChannels.length;
|
||||||
|
|
||||||
visibleDirectChannels.sort(this.sortChannelsByDisplayName);
|
visibleDirectChannels.sort(this.sortChannelsByDisplayName);
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ export default class CustomThemeChooser extends React.Component {
|
|||||||
{'Copy and paste to share theme colors:'}
|
{'Copy and paste to share theme colors:'}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
readOnly='true'
|
|
||||||
type='text'
|
type='text'
|
||||||
className='form-control'
|
className='form-control'
|
||||||
value={colors}
|
value={colors}
|
||||||
|
|||||||
@@ -197,13 +197,13 @@ class UserStoreClass extends EventEmitter {
|
|||||||
return BrowserStore.getItem('profiles', {});
|
return BrowserStore.getItem('profiles', {});
|
||||||
}
|
}
|
||||||
|
|
||||||
getActiveOnlyProfiles() {
|
getActiveOnlyProfiles(skipCurrent) {
|
||||||
const active = {};
|
const active = {};
|
||||||
const profiles = this.getProfiles();
|
const profiles = this.getProfiles();
|
||||||
const currentId = this.getCurrentId();
|
const currentId = this.getCurrentId();
|
||||||
|
|
||||||
for (var key in profiles) {
|
for (var key in profiles) {
|
||||||
if (profiles[key].delete_at === 0 && profiles[key].id !== currentId) {
|
if (!(profiles[key].id === currentId && skipCurrent) && profiles[key].delete_at === 0) {
|
||||||
active[key] = profiles[key];
|
active[key] = profiles[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ const ChannelStore = require('../stores/channel_store.jsx');
|
|||||||
const Constants = require('../utils/constants.jsx');
|
const Constants = require('../utils/constants.jsx');
|
||||||
const TeamStore = require('../stores/team_store.jsx');
|
const TeamStore = require('../stores/team_store.jsx');
|
||||||
|
|
||||||
export function createChannelIntroMessage(channel) {
|
export function createChannelIntroMessage(channel, showInviteModal) {
|
||||||
if (channel.type === 'D') {
|
if (channel.type === 'D') {
|
||||||
return createDMIntroMessage(channel);
|
return createDMIntroMessage(channel);
|
||||||
} else if (ChannelStore.isDefault(channel)) {
|
} else if (ChannelStore.isDefault(channel)) {
|
||||||
return createDefaultIntroMessage(channel);
|
return createDefaultIntroMessage(channel);
|
||||||
} else if (channel.name === Constants.OFFTOPIC_CHANNEL) {
|
} else if (channel.name === Constants.OFFTOPIC_CHANNEL) {
|
||||||
return createOffTopicIntroMessage(channel);
|
return createOffTopicIntroMessage(channel, showInviteModal);
|
||||||
} else if (channel.type === 'O' || channel.type === 'P') {
|
} else if (channel.type === 'O' || channel.type === 'P') {
|
||||||
return createStandardIntroMessage(channel);
|
return createStandardIntroMessage(channel, showInviteModal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ export function createDMIntroMessage(channel) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createOffTopicIntroMessage(channel) {
|
export function createOffTopicIntroMessage(channel, showInviteModal) {
|
||||||
return (
|
return (
|
||||||
<div className='channel-intro'>
|
<div className='channel-intro'>
|
||||||
<h4 className='channel-intro__title'>{'Beginning of ' + channel.display_name}</h4>
|
<h4 className='channel-intro__title'>{'Beginning of ' + channel.display_name}</h4>
|
||||||
@@ -91,10 +91,8 @@ export function createOffTopicIntroMessage(channel) {
|
|||||||
<i className='fa fa-pencil'></i>{'Set a header'}
|
<i className='fa fa-pencil'></i>{'Set a header'}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
className='intro-links'
|
|
||||||
href='#'
|
href='#'
|
||||||
data-toggle='modal'
|
onClick={showInviteModal}
|
||||||
data-target='#channel_invite'
|
|
||||||
>
|
>
|
||||||
<i className='fa fa-user-plus'></i>{'Invite others to this channel'}
|
<i className='fa fa-user-plus'></i>{'Invite others to this channel'}
|
||||||
</a>
|
</a>
|
||||||
@@ -155,7 +153,7 @@ export function createDefaultIntroMessage(channel) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createStandardIntroMessage(channel) {
|
export function createStandardIntroMessage(channel, showInviteModal) {
|
||||||
var uiName = channel.display_name;
|
var uiName = channel.display_name;
|
||||||
var creatorName = '';
|
var creatorName = '';
|
||||||
|
|
||||||
@@ -206,14 +204,11 @@ export function createStandardIntroMessage(channel) {
|
|||||||
<i className='fa fa-pencil'></i>{'Set a header'}
|
<i className='fa fa-pencil'></i>{'Set a header'}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
className='intro-links'
|
|
||||||
href='#'
|
href='#'
|
||||||
data-toggle='modal'
|
onClick={showInviteModal}
|
||||||
data-target='#channel_invite'
|
|
||||||
>
|
>
|
||||||
<i className='fa fa-user-plus'></i>{'Invite others to this ' + uiType}
|
<i className='fa fa-user-plus'></i>{'Invite others to this ' + uiType}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ func watchAndParseTemplates() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var browsersNotSupported string = "MSIE/8;MSIE/9;MSIE/10;Internet Explorer/8;Internet Explorer/9;Internet Explorer/10;Safari/7"
|
var browsersNotSupported string = "MSIE/8;MSIE/9;MSIE/10;Internet Explorer/8;Internet Explorer/9;Internet Explorer/10;Safari/7;Safari/8"
|
||||||
|
|
||||||
func CheckBrowserCompatability(c *api.Context, r *http.Request) bool {
|
func CheckBrowserCompatability(c *api.Context, r *http.Request) bool {
|
||||||
ua := user_agent.New(r.UserAgent())
|
ua := user_agent.New(r.UserAgent())
|
||||||
@@ -143,7 +143,7 @@ func CheckBrowserCompatability(c *api.Context, r *http.Request) bool {
|
|||||||
version := strings.Split(browser, "/")
|
version := strings.Split(browser, "/")
|
||||||
|
|
||||||
if strings.HasPrefix(bname, version[0]) && strings.HasPrefix(bversion, version[1]) {
|
if strings.HasPrefix(bname, version[0]) && strings.HasPrefix(bversion, version[1]) {
|
||||||
c.Err = model.NewAppError("CheckBrowserCompatability", "Your current browser is not supported, please upgrade to one of the following browsers: Google Chrome 21 or higher, Internet Explorer 11 or higher, FireFox 14 or higher, Safari 8 or higher", "")
|
c.Err = model.NewAppError("CheckBrowserCompatability", "Your current browser is not supported, please upgrade to one of the following browsers: Google Chrome 21 or higher, Internet Explorer 11 or higher, FireFox 14 or higher, Safari 9 or higher", "")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user