summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--api/post.go1
-rw-r--r--api/post_test.go11
-rw-r--r--model/post.go1
-rw-r--r--store/sql_upgrade.go10
-rw-r--r--webapp/components/post_view/components/post_message_container.jsx2
-rw-r--r--webapp/components/post_view/components/post_message_view.jsx38
-rw-r--r--webapp/components/search_results_item.jsx2
-rw-r--r--webapp/i18n/en.json1
-rw-r--r--webapp/sass/layout/_post.scss39
-rw-r--r--webapp/sass/responsive/_mobile.scss3
-rw-r--r--webapp/utils/post_utils.jsx6
12 files changed, 102 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index 173f8dea8..5d5cae1e8 100644
--- a/Makefile
+++ b/Makefile
@@ -218,7 +218,7 @@ ifeq ($(BUILD_ENTERPRISE_READY),true)
tail -n +2 csaml.out >> ecover.out
tail -n +2 ccluster.out >> ecover.out
tail -n +2 cmetrics.out >> ecover.out
- tail -n +2 caccount_migration.out >> ecover.out
+ tail -n +2 caccount_migration.out >> ecover.out
rm -f cldap.out ccompliance.out cmfa.out cemoji.out csaml.out ccluster.out cmetrics.out caccount_migration.out
rm -r ldap.test
rm -r compliance.test
@@ -394,7 +394,7 @@ else
echo stopping mattermost $$PID; \
kill $$PID; \
done
-endif
+endif
stop-client:
@echo Stopping mattermost client
diff --git a/api/post.go b/api/post.go
index 354fe35db..e8aef2f86 100644
--- a/api/post.go
+++ b/api/post.go
@@ -1217,6 +1217,7 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
*newPost = *oldPost
newPost.Message = post.Message
+ newPost.EditAt = model.GetMillis()
newPost.Hashtags, _ = model.ParseHashtags(post.Message)
if result := <-Srv.Store.Post().Update(newPost, oldPost); result.Err != nil {
diff --git a/api/post_test.go b/api/post_test.go
index e48debcae..6101d2c8d 100644
--- a/api/post_test.go
+++ b/api/post_test.go
@@ -47,6 +47,10 @@ func TestCreatePost(t *testing.T) {
t.Fatal("shouldn't have files")
}
+ if rpost1.Data.(*model.Post).EditAt != 0 {
+ t.Fatal("Newly craeted post shouldn't have EditAt set")
+ }
+
post2 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", RootId: rpost1.Data.(*model.Post).Id}
rpost2, err := Client.CreatePost(post2)
if err != nil {
@@ -326,6 +330,10 @@ func TestUpdatePost(t *testing.T) {
t.Fatal(err)
}
+ if rpost2.Data.(*model.Post).EditAt != 0 {
+ t.Fatal("Newly craeted post shouldn't have EditAt set")
+ }
+
msg2 := "a" + model.NewId() + " update post 1"
rpost2.Data.(*model.Post).Message = msg2
if rupost2, err := Client.UpdatePost(rpost2.Data.(*model.Post)); err != nil {
@@ -334,6 +342,9 @@ func TestUpdatePost(t *testing.T) {
if rupost2.Data.(*model.Post).Message != msg2 {
t.Fatal("failed to updates")
}
+ if rupost2.Data.(*model.Post).EditAt == 0 {
+ t.Fatal("EditAt not updated for post")
+ }
}
msg1 := "#hashtag a" + model.NewId() + " update post 2"
diff --git a/model/post.go b/model/post.go
index 7097e031d..766324b4c 100644
--- a/model/post.go
+++ b/model/post.go
@@ -31,6 +31,7 @@ type Post struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`
UpdateAt int64 `json:"update_at"`
+ EditAt int64 `json:"edit_at"`
DeleteAt int64 `json:"delete_at"`
UserId string `json:"user_id"`
ChannelId string `json:"channel_id"`
diff --git a/store/sql_upgrade.go b/store/sql_upgrade.go
index d69404baa..9ee8f08e2 100644
--- a/store/sql_upgrade.go
+++ b/store/sql_upgrade.go
@@ -15,6 +15,7 @@ import (
)
const (
+ VERIONS_3_7_0 = "3.7.0"
VERSION_3_6_0 = "3.6.0"
VERSION_3_5_0 = "3.5.0"
VERSION_3_4_0 = "3.4.0"
@@ -39,6 +40,7 @@ func UpgradeDatabase(sqlStore *SqlStore) {
UpgradeDatabaseToVersion34(sqlStore)
UpgradeDatabaseToVersion35(sqlStore)
UpgradeDatabaseToVersion36(sqlStore)
+ UpgradeDatabaseToVersion37(sqlStore)
// If the SchemaVersion is empty this this is the first time it has ran
// so lets set it to the current version.
@@ -229,3 +231,11 @@ func UpgradeDatabaseToVersion36(sqlStore *SqlStore) {
saveSchemaVersion(sqlStore, VERSION_3_6_0)
}
}
+
+func UpgradeDatabaseToVersion37(sqlStore *SqlStore) {
+ // TODO: Uncomment following condition when version 3.7.0 is released
+ // if shouldPerformUpgrade(sqlStore, VERSION_3_6_0, VERSION_3_7_0) {
+ // Add EditAt column to Posts
+ sqlStore.CreateColumnIfNotExists("Posts", "EditAt", " bigint", " bigint", "0")
+ // }
+}
diff --git a/webapp/components/post_view/components/post_message_container.jsx b/webapp/components/post_view/components/post_message_container.jsx
index 2d17e74c4..4e27cd29a 100644
--- a/webapp/components/post_view/components/post_message_container.jsx
+++ b/webapp/components/post_view/components/post_message_container.jsx
@@ -89,7 +89,7 @@ export default class PostMessageContainer extends React.Component {
return (
<PostMessageView
options={this.props.options}
- message={this.props.post.message}
+ post={this.props.post}
emojis={this.state.emojis}
enableFormatting={this.state.enableFormatting}
mentionKeys={this.state.mentionKeys}
diff --git a/webapp/components/post_view/components/post_message_view.jsx b/webapp/components/post_view/components/post_message_view.jsx
index 24f96a8d9..eff791aec 100644
--- a/webapp/components/post_view/components/post_message_view.jsx
+++ b/webapp/components/post_view/components/post_message_view.jsx
@@ -2,14 +2,16 @@
// See License.txt for license information.
import React from 'react';
+import {FormattedMessage} from 'react-intl';
import * as TextFormatting from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx';
+import * as PostUtils from 'utils/post_utils.jsx';
export default class PostMessageView extends React.Component {
static propTypes = {
options: React.PropTypes.object.isRequired,
- message: React.PropTypes.string.isRequired,
+ post: React.PropTypes.object.isRequired,
emojis: React.PropTypes.object.isRequired,
enableFormatting: React.PropTypes.bool.isRequired,
mentionKeys: React.PropTypes.arrayOf(React.PropTypes.string).isRequired,
@@ -23,7 +25,7 @@ export default class PostMessageView extends React.Component {
return true;
}
- if (nextProps.message !== this.props.message) {
+ if (nextProps.post.message !== this.props.post.message) {
return true;
}
@@ -47,9 +49,28 @@ export default class PostMessageView extends React.Component {
return false;
}
+ editedIndicator() {
+ return (
+ PostUtils.isEdited(this.props.post) ?
+ <span className='edited'>
+ <FormattedMessage
+ id='post_message_view.edited'
+ defaultMessage='(edited)'
+ />
+ </span> :
+ ''
+ );
+ }
+
render() {
if (!this.props.enableFormatting) {
- return <span>{this.props.message}</span>;
+ return (
+ <span>
+ {this.props.post.message}
+ &nbsp;
+ {this.editedIndicator()}
+ </span>
+ );
}
const options = Object.assign({}, this.props.options, {
@@ -62,10 +83,13 @@ export default class PostMessageView extends React.Component {
});
return (
- <span
- onClick={Utils.handleFormattedTextClick}
- dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.message, options)}}
- />
+ <div>
+ <span
+ onClick={Utils.handleFormattedTextClick}
+ dangerouslySetInnerHTML={{__html: TextFormatting.formatText(this.props.post.message, options)}}
+ />
+ {this.editedIndicator()}
+ </div>
);
}
}
diff --git a/webapp/components/search_results_item.jsx b/webapp/components/search_results_item.jsx
index 50e440b04..be62653c0 100644
--- a/webapp/components/search_results_item.jsx
+++ b/webapp/components/search_results_item.jsx
@@ -285,7 +285,7 @@ export default class SearchResultsItem extends React.Component {
</li>
{rhsControls}
</ul>
- <div className='search-item-snippet'>
+ <div className='search-item-snippet post__body'>
{message}
</div>
</div>
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index aae21a8e6..d18ce059a 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -1667,6 +1667,7 @@
"post_info.mobile.unflag": "Unflag",
"post_info.permalink": "Permalink",
"post_info.reply": "Reply",
+ "post_message_view.edited": "(edited)",
"posts_view.loadMore": "Load more messages",
"posts_view.newMsg": "New Messages",
"posts_view.newMsgBelow": "New {count, plural, one {message} other {messages}} below",
diff --git a/webapp/sass/layout/_post.scss b/webapp/sass/layout/_post.scss
index 1e7b45fba..ff2dce422 100644
--- a/webapp/sass/layout/_post.scss
+++ b/webapp/sass/layout/_post.scss
@@ -560,9 +560,9 @@
}
blockquote {
- display: inline-block;
font-size: 1em;
margin-left: 0;
+ margin-top: 1.3em;
padding: 3px 0 0 25px;
vertical-align: top;
@@ -572,6 +572,11 @@
top: 2px;
}
}
+ .search-item-snippet {
+ blockquote {
+ margin-top: 0;
+ }
+ }
.markdown__heading {
clear: both;
@@ -598,7 +603,15 @@
}
p + p {
- margin-top: 1em;
+ margin: 1em 0;
+ &:last-of-type {
+ margin-bottom: 0;
+ }
+ }
+ span {
+ > p:first-child {
+ margin-bottom: 1em;
+ }
}
ol,
@@ -978,12 +991,24 @@
width: 100%;
word-wrap: break-word;
- p {
+ div {
margin: 0 0 .4em;
}
p + p {
- margin-top: 1.4em;
+ margin: 1.4em 0;
+ &:last-of-type {
+ margin-bottom: 0;
+ }
+ }
+
+ span {
+ > p:last-child {
+ display: inline;
+ }
+ > p:first-child {
+ margin-bottom: 1.4em;
+ }
}
li {
@@ -1063,6 +1088,12 @@
color: $white;
}
}
+
+ span.edited {
+ color: #A3A3A3;
+ font-size: 0.87em;
+ opacity: 0.6;
+ }
}
.post__link {
diff --git a/webapp/sass/responsive/_mobile.scss b/webapp/sass/responsive/_mobile.scss
index 63c890007..67f56b8a2 100644
--- a/webapp/sass/responsive/_mobile.scss
+++ b/webapp/sass/responsive/_mobile.scss
@@ -213,6 +213,9 @@
}
}
}
+ blockquote {
+ margin-top: 0;
+ }
}
&.same--root {
diff --git a/webapp/utils/post_utils.jsx b/webapp/utils/post_utils.jsx
index 4bba784cb..88021c2a5 100644
--- a/webapp/utils/post_utils.jsx
+++ b/webapp/utils/post_utils.jsx
@@ -15,6 +15,10 @@ export function isComment(post) {
return false;
}
+export function isEdited(post) {
+ return post.edit_at > 0;
+}
+
export function getProfilePicSrcForPost(post, timestamp) {
let src = Client.getUsersRoute() + '/' + post.user_id + '/image?time=' + timestamp;
if (post.props && post.props.from_webhook && global.window.mm_config.EnablePostIconOverride === 'true') {
@@ -28,4 +32,4 @@ export function getProfilePicSrcForPost(post, timestamp) {
}
return src;
-} \ No newline at end of file
+}