diff --git a/api/context.go b/api/context.go
index a5d4169cbb..a6f9bc1e17 100644
--- a/api/context.go
+++ b/api/context.go
@@ -37,6 +37,8 @@ type Page struct {
ClientCfg map[string]string
User *model.User
Team *model.Team
+ Channel *model.Channel
+ PostID string
SessionTokenIndex int64
}
diff --git a/api/post.go b/api/post.go
index 0860fd2999..ca99eb15b7 100644
--- a/api/post.go
+++ b/api/post.go
@@ -23,6 +23,7 @@ func InitPost(r *mux.Router) {
l4g.Debug("Initializing post api routes")
r.Handle("/posts/search", ApiUserRequired(searchPosts)).Methods("GET")
+ r.Handle("/posts/{post_id}", ApiUserRequired(getPostById)).Methods("GET")
sr := r.PathPrefix("/channels/{id:[A-Za-z0-9]+}").Subrouter()
sr.Handle("/create", ApiUserRequired(createPost)).Methods("POST")
@@ -767,6 +768,41 @@ func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
+func getPostById(c *Context, w http.ResponseWriter, r *http.Request) {
+ params := mux.Vars(r)
+
+ postId := params["post_id"]
+ if len(postId) != 26 {
+ c.SetInvalidParam("getPostById", "postId")
+ return
+ }
+
+ if result := <-Srv.Store.Post().Get(postId); result.Err != nil {
+ c.Err = result.Err
+ return
+ } else {
+ list := result.Data.(*model.PostList)
+
+ if len(list.Order) != 1 {
+ c.Err = model.NewAppError("getPostById", "Unable to get post", "")
+ return
+ }
+ post := list.Posts[list.Order[0]]
+
+ cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, post.ChannelId, c.Session.UserId)
+ if !c.HasPermissionsToChannel(cchan, "getPostById") {
+ return
+ }
+
+ if HandleEtag(list.Etag(), w, r) {
+ return
+ }
+
+ w.Header().Set(model.HEADER_ETAG_SERVER, list.Etag())
+ w.Write([]byte(list.ToJson()))
+ }
+}
+
func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
diff --git a/web/react/components/center_panel.jsx b/web/react/components/center_panel.jsx
index c2ecf4fa20..3c6a36ad47 100644
--- a/web/react/components/center_panel.jsx
+++ b/web/react/components/center_panel.jsx
@@ -4,11 +4,13 @@
import TutorialIntroScreens from './tutorial/tutorial_intro_screens.jsx';
import CreatePost from './create_post.jsx';
import PostsViewContainer from './posts_view_container.jsx';
+import PostFocusView from './post_focus_view.jsx';
import ChannelHeader from './channel_header.jsx';
import Navbar from './navbar.jsx';
import FileUploadOverlay from './file_upload_overlay.jsx';
import PreferenceStore from '../stores/preference_store.jsx';
+import ChannelStore from '../stores/channel_store.jsx';
import UserStore from '../stores/user_store.jsx';
import Constants from '../utils/constants.jsx';
@@ -20,26 +22,48 @@ export default class CenterPanel extends React.Component {
super(props);
this.onPreferenceChange = this.onPreferenceChange.bind(this);
+ this.onChannelChange = this.onChannelChange.bind(this);
const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '999'});
- this.state = {showTutorialScreens: parseInt(tutorialPref.value, 10) === TutorialSteps.INTRO_SCREENS};
+ this.state = {
+ showTutorialScreens: parseInt(tutorialPref.value, 10) === TutorialSteps.INTRO_SCREENS,
+ showPostFocus: ChannelStore.getPostMode() === ChannelStore.POST_MODE_FOCUS
+ };
}
componentDidMount() {
PreferenceStore.addChangeListener(this.onPreferenceChange);
+ ChannelStore.addChangeListener(this.onChannelChange);
}
componentWillUnmount() {
PreferenceStore.removeChangeListener(this.onPreferenceChange);
+ ChannelStore.removeChangeListener(this.onChannelChange);
}
onPreferenceChange() {
const tutorialPref = PreferenceStore.getPreference(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), {value: '999'});
this.setState({showTutorialScreens: parseInt(tutorialPref.value, 10) <= TutorialSteps.INTRO_SCREENS});
}
+ onChannelChange() {
+ this.setState({showPostFocus: ChannelStore.getPostMode() === ChannelStore.POST_MODE_FOCUS});
+ }
render() {
let postsContainer;
+ let createPost;
if (this.state.showTutorialScreens) {
postsContainer =