Type here to write a message and press Enter to post it.
Click the Attachment button to upload an image or a file.
", "create_post.write": "Write a message...", "create_team.agreement": "By proceeding to create your account and use {siteName}, you agree to our Terms of Service and Privacy Policy. If you do not agree, you cannot use {siteName}.", @@ -1370,6 +1372,8 @@ "post_delete.someone": "Someone deleted the message on which you tried to post a comment.", "post_focus_view.beginning": "Beginning of Channel Archives", "post_info.del": "Delete", + "post_info.mobile.flag": "Flag", + "post_info.mobile.unflag": "Unflag", "post_info.edit": "Edit", "post_info.permalink": "Permalink", "post_info.reply": "Reply", @@ -1393,14 +1397,19 @@ "rename_channel.title": "Rename Channel", "rhs_comment.comment": "Comment", "rhs_comment.del": "Delete", + "rhs_comment.mobile.flag": "Flag", + "rhs_comment.mobile.unflag": "Unflag", "rhs_comment.edit": "Edit", "rhs_comment.permalink": "Permalink", "rhs_header.backToResultsTooltip": "Back to Search Results", + "rhs_header.backToFlaggedTooltip": "Back to Flagged Posts", "rhs_header.closeSidebarTooltip": "Close Sidebar", "rhs_header.details": "Message Details", "rhs_header.expandSidebarTooltip": "Expand Sidebar", "rhs_header.shrinkSidebarTooltip": "Shrink Sidebar", "rhs_root.del": "Delete", + "rhs_root.mobile.flag": "Flag", + "rhs_root.mobile.unflag": "Unflag", "rhs_root.direct": "Direct Message", "rhs_root.edit": "Edit", "rhs_root.permalink": "Permalink", @@ -1409,6 +1418,7 @@ "search_bar.usage": "The Main Menu is where you can Invite New Members, access your Account Settings and set your Theme Color.
Team administrators can also access their Team Settings from this menu.
System administrators will find a System Console option to administrate the entire system.
", "sidebar_right_menu.accountSettings": "Account Settings", + "sidebar_right_menu.flagged": "Flagged Posts", "sidebar_right_menu.console": "System Console", "sidebar_right_menu.help": "Help", "sidebar_right_menu.inviteNew": "Invite New Member", diff --git a/webapp/sass/components/_search.scss b/webapp/sass/components/_search.scss index d259cfc20b..11bcdb92d9 100644 --- a/webapp/sass/components/_search.scss +++ b/webapp/sass/components/_search.scss @@ -137,23 +137,31 @@ } } -.search-item__jump { - @include opacity(.8); +.col__controls { font-size: 13px; position: absolute; right: 0; top: 0; - &:hover { - @include opacity(1); - } -} + a { + @include opacity(.8); + vertical-align: top; -.search-item__comment { - margin-right: 35px; - position: absolute; - right: 0; - top: 0; + &:hover { + @include opacity(1); + } + } + + + .search-item__jump { + font-size: 13px; + position: relative; + top: 1px; + } + + .search-item__comment { + margin-right: 5px; + } } .search-item-time { diff --git a/webapp/sass/layout/_headers.scss b/webapp/sass/layout/_headers.scss index f2705fc0a2..832bed50ef 100644 --- a/webapp/sass/layout/_headers.scss +++ b/webapp/sass/layout/_headers.scss @@ -43,6 +43,7 @@ } &:last-child { + padding-right: 8px; width: 8.9%; } } @@ -375,8 +376,17 @@ font-size: 22px; height: 30px; line-height: 26px; - margin-right: 9px; - width: 24px; + margin-right: 3px; + text-align: center; + width: 30px; + + th { + &:last-child { + div { + margin-right: 10px; + } + } + } .channel__wrap.move--left & { position: absolute; @@ -384,6 +394,15 @@ top: 14px; } + .icon__flag { + svg { + height: 18px; + position: relative; + top: 2px; + width: 19px; + } + } + > a { @include opacity(.6); @include single-transition(all, .1s, ease-in); diff --git a/webapp/sass/layout/_post.scss b/webapp/sass/layout/_post.scss index 605c036581..8513f779a9 100644 --- a/webapp/sass/layout/_post.scss +++ b/webapp/sass/layout/_post.scss @@ -486,6 +486,7 @@ body.ios { &:hover { .dropdown, .comment-icon__container, + .flag-icon__container, .post__reply, .post__remove { visibility: visible; @@ -561,7 +562,7 @@ body.ios { .img-div { max-height: 150px; max-width: 150px; - } + } p { line-height: inherit; @@ -573,7 +574,7 @@ body.ios { ol, ul { - clear: both; + clear: both; padding-left: 20px; } } @@ -694,6 +695,13 @@ body.ios { } } + .flag-icon__container { + left: 36px; + margin-left: 5px; + position: absolute; + top: 8px; + } + .post__img { img { display: none; @@ -835,7 +843,9 @@ body.ios { } .post__img { - width: 42px; + padding-right: 10px; + text-align: right; + width: 53px; svg { height: 32px; @@ -1076,6 +1086,7 @@ body.ios { display: inline-block; margin-right: 6px; visibility: hidden; + svg { fill: inherit; position: relative; @@ -1115,6 +1126,36 @@ body.ios { } } + .flag-icon__container { + display: inline-block; + font-size: 12px; + margin-left: 7px; + position: relative; + top: 1px; + visibility: hidden; + + &.visible { + visibility: visible; + } + + path { + fill: inherit; + } + + .fa-star-o { + @include opacity(.8); + } + + &:focus { + outline: none; + } + + &.icon--visible { + visibility: visible; + } + + } + .web-embed-data { @include border-radius(2px); @include alpha-property(background, $black, 0.05); diff --git a/webapp/sass/layout/_sidebar-right.scss b/webapp/sass/layout/_sidebar-right.scss index fb57b61468..497cd3cea8 100644 --- a/webapp/sass/layout/_sidebar-right.scss +++ b/webapp/sass/layout/_sidebar-right.scss @@ -161,7 +161,7 @@ .sidebar--right__subheader { font-size: 1em; - padding: 1em 1em 0; + padding: 0.5em 1em 0; h4 { font-size: 1em; @@ -176,6 +176,13 @@ font-size: .95em; padding-bottom: 10px; } + + .usage__icon { + @include opacity(.6); + margin: 0 3px; + position: relative; + top: 1px; + } } .suggestion-list__content { diff --git a/webapp/sass/responsive/_mobile.scss b/webapp/sass/responsive/_mobile.scss index df615aa131..c60233ae89 100644 --- a/webapp/sass/responsive/_mobile.scss +++ b/webapp/sass/responsive/_mobile.scss @@ -94,6 +94,16 @@ } } + &.same--root { + &.same--user { + .flag-icon__container { + left: auto; + position: relative; + top: 1px; + } + } + } + .post__content { padding: 0 10px 0 0; } @@ -182,7 +192,23 @@ } } + .star-icon__container { + left: auto; + position: relative; + top: auto; + + &:not(.visible) { + display: none; + } + } + &.same--root { + .star-icon__container { + left: auto; + position: relative; + top: auto; + } + &.same--user { .post__header { height: auto; diff --git a/webapp/sass/responsive/_tablet.scss b/webapp/sass/responsive/_tablet.scss index e6cb898fd7..bb3d786525 100644 --- a/webapp/sass/responsive/_tablet.scss +++ b/webapp/sass/responsive/_tablet.scss @@ -116,7 +116,15 @@ .channel__wrap & { .post__time { font-size: .85em; - left: -70px; + left: -79px; + position: absolute; + text-align: right; + top: 6px; + width: 60px; + } + + .star-icon__container { + left: -65px; position: absolute; text-align: right; top: 6px; @@ -125,7 +133,7 @@ } &:not(.post--thread) { - padding: 5px .5em 0 70px; + padding: 5px .5em 0 72px; .post__link { margin: 4px 0 7px; @@ -197,11 +205,29 @@ } } + .flag-icon__container { + left: -21px; + position: absolute; + top: 7px; + } + + .sidebar--right & .flag-icon__container { + left: auto; + position: relative; + top: 1px; + } + &.same--root { &.same--user { - padding-left: 70px; + padding-left: 72px; padding-top: 0; + .flag-icon__container { + left: -19px; + position: absolute; + top: 7px; + } + .post__header { .col__reply { top: -1px; @@ -265,12 +291,16 @@ &:not(.post--compact) { .post__time { + display: inline-block; font-size: 11px; - left: -4px; - line-height: 37px; + left: -14px; + line-height: 34px; position: absolute; + text-align: right; text-rendering: auto; top: -2px; + width: 51px; + } } } diff --git a/webapp/stores/post_store.jsx b/webapp/stores/post_store.jsx index 1c9a877cf5..135563866a 100644 --- a/webapp/stores/post_store.jsx +++ b/webapp/stores/post_store.jsx @@ -441,8 +441,8 @@ class PostStoreClass extends EventEmitter { return threadPosts; } - emitSelectedPostChange(fromSearch) { - this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch); + emitSelectedPostChange(fromSearch, fromFlaggedPosts) { + this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch, fromFlaggedPosts); } addSelectedPostChangeListener(callback) { @@ -599,7 +599,7 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => { break; case ActionTypes.RECEIVED_POST_SELECTED: PostStore.storeSelectedPostId(action.postId); - PostStore.emitSelectedPostChange(action.from_search); + PostStore.emitSelectedPostChange(action.from_search, action.from_flagged_posts); break; default: } diff --git a/webapp/stores/search_store.jsx b/webapp/stores/search_store.jsx index dc08ca3a6a..7415908956 100644 --- a/webapp/stores/search_store.jsx +++ b/webapp/stores/search_store.jsx @@ -18,6 +18,7 @@ class SearchStoreClass extends EventEmitter { this.searchResults = null; this.isMentionSearch = false; + this.isFlaggedPosts = false; this.searchTerm = ''; } @@ -77,6 +78,10 @@ class SearchStoreClass extends EventEmitter { return this.isMentionSearch; } + getIsFlaggedPosts() { + return this.isFlaggedPosts; + } + storeSearchTerm(term) { this.searchTerm = term; } @@ -85,9 +90,10 @@ class SearchStoreClass extends EventEmitter { return this.searchTerm; } - storeSearchResults(results, isMentionSearch) { + storeSearchResults(results, isMentionSearch, isFlaggedPosts) { this.searchResults = results; this.isMentionSearch = isMentionSearch; + this.isFlaggedPosts = isFlaggedPosts; } } @@ -98,7 +104,7 @@ SearchStore.dispatchToken = AppDispatcher.register((payload) => { switch (action.type) { case ActionTypes.RECEIVED_SEARCH: - SearchStore.storeSearchResults(action.results, action.is_mention_search); + SearchStore.storeSearchResults(action.results, action.is_mention_search, action.is_flagged_posts); SearchStore.emitSearchChange(); break; case ActionTypes.RECEIVED_SEARCH_TERM: diff --git a/webapp/tests/client_post.test.jsx b/webapp/tests/client_post.test.jsx index 3c6f05c9f3..3b9802fb4c 100644 --- a/webapp/tests/client_post.test.jsx +++ b/webapp/tests/client_post.test.jsx @@ -197,5 +197,38 @@ describe('Client.Posts', function() { ); }); }); + + it('getFlaggedPosts', function(done) { + TestHelper.initBasic(() => { + var pref = {}; + pref.user_id = TestHelper.basicUser().id; + pref.category = 'flagged_post'; + pref.name = TestHelper.basicPost().id; + pref.value = 'true'; + + var prefs = []; + prefs.push(pref); + + TestHelper.basicClient().savePreferences( + prefs, + function() { + TestHelper.basicClient().getFlaggedPosts( + 0, + 2, + function(data) { + assert.equal(data.order[0], TestHelper.basicPost().id); + done(); + }, + function(err) { + done(new Error(err.message)); + } + ); + }, + function(err) { + done(new Error(err.message)); + } + ); + }); + }); }); diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx index 812796ebb7..dbdc3e9f1e 100644 --- a/webapp/utils/constants.jsx +++ b/webapp/utils/constants.jsx @@ -51,7 +51,8 @@ export const Preferences = { COLLAPSE_DISPLAY: 'collapse_previews', COLLAPSE_DISPLAY_DEFAULT: 'false', USE_MILITARY_TIME: 'use_military_time', - CATEGORY_THEME: 'theme' + CATEGORY_THEME: 'theme', + CATEGORY_FLAGGED_POST: 'flagged_post' }; export const ActionTypes = keyMirror({ @@ -326,6 +327,8 @@ export const Constants = { OPEN_TEAM: 'O', MAX_POST_LEN: 4000, EMOJI_SIZE: 16, + FLAG_ICON_OUTLINE_SVG: "", + FLAG_ICON_SVG: "", ATTACHMENT_ICON_SVG: "", MATTERMOST_ICON_SVG: "", ONLINE_ICON_SVG: "", diff --git a/webapp/utils/utils.jsx b/webapp/utils/utils.jsx index 187c7d7f48..9f8b1ef6c9 100644 --- a/webapp/utils/utils.jsx +++ b/webapp/utils/utils.jsx @@ -566,7 +566,8 @@ export function applyTheme(theme) { } if (theme.centerChannelColor) { - changeCss('.app__body .post-list__arrows', 'fill:' + changeOpacity(theme.centerChannelColor, 0.3), 1); + changeCss('.app__body .post-list__arrows, .app__body .post .flag-icon__container', 'fill:' + changeOpacity(theme.centerChannelColor, 0.3), 1); + changeCss('.app__body .channel-header__links .icon', 'stroke:' + theme.centerChannelColor, 1); changeCss('@media(min-width: 768px){.app__body .post:hover .post__header .col__reply, .app__body .post.post--hovered .post__header .col__reply', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 2); changeCss('.app__body .sidebar--left, .app__body .sidebar--right .sidebar--right__header, .app__body .suggestion-list__content .command', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1); changeCss('.app__body .post.post--system .post__body', 'color:' + changeOpacity(theme.centerChannelColor, 0.6), 1); @@ -638,7 +639,8 @@ export function applyTheme(theme) { if (theme.linkColor) { changeCss('.app__body a, .app__body a:focus, .app__body a:hover, .app__body .btn, .app__body .btn:focus, .app__body .btn:hover', 'color:' + theme.linkColor, 1); changeCss('.app__body .attachment .attachment__container', 'border-left-color:' + changeOpacity(theme.linkColor, 0.5), 1); - changeCss('.app__body .post .comment-icon__container, .app__body .post .post__reply', 'fill:' + theme.linkColor, 1); + changeCss('.app__body .channel-header__links .icon:hover, .app__body .post .flag-icon__container.visible, .app__body .post .comment-icon__container, .app__body .post .post__reply', 'fill:' + theme.linkColor, 1); + changeCss('.app__body .channel-header__links .icon:hover', 'stroke:' + theme.linkColor, 1); } if (theme.buttonBg) {