diff options
-rw-r--r-- | api/channel.go | 53 | ||||
-rw-r--r-- | api/channel_test.go | 62 | ||||
-rw-r--r-- | model/channel_count.go | 63 | ||||
-rw-r--r-- | model/channel_data.go | 43 | ||||
-rw-r--r-- | model/client.go | 18 | ||||
-rw-r--r-- | store/sql_channel_store.go | 35 | ||||
-rw-r--r-- | store/sql_channel_store_test.go | 47 | ||||
-rw-r--r-- | store/store.go | 1 | ||||
-rw-r--r-- | web/react/components/edit_channel_modal.jsx | 2 | ||||
-rw-r--r-- | web/react/components/more_channels.jsx | 123 | ||||
-rw-r--r-- | web/react/components/new_channel.jsx | 12 | ||||
-rw-r--r-- | web/react/components/rename_channel_modal.jsx | 10 | ||||
-rw-r--r-- | web/react/components/sidebar.jsx | 20 | ||||
-rw-r--r-- | web/react/stores/channel_store.jsx | 446 | ||||
-rw-r--r-- | web/react/utils/async_client.jsx | 240 | ||||
-rw-r--r-- | web/react/utils/client.jsx | 37 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 1 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 23 |
18 files changed, 869 insertions, 367 deletions
diff --git a/api/channel.go b/api/channel.go index 803274d32..151627623 100644 --- a/api/channel.go +++ b/api/channel.go @@ -18,11 +18,13 @@ func InitChannel(r *mux.Router) { sr := r.PathPrefix("/channels").Subrouter() sr.Handle("/", ApiUserRequiredActivity(getChannels, false)).Methods("GET") sr.Handle("/more", ApiUserRequired(getMoreChannels)).Methods("GET") + sr.Handle("/counts", ApiUserRequiredActivity(getChannelCounts, false)).Methods("GET") sr.Handle("/create", ApiUserRequired(createChannel)).Methods("POST") sr.Handle("/create_direct", ApiUserRequired(createDirectChannel)).Methods("POST") sr.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST") sr.Handle("/update_desc", ApiUserRequired(updateChannelDesc)).Methods("POST") sr.Handle("/update_notify_level", ApiUserRequired(updateNotifyLevel)).Methods("POST") + sr.Handle("/{id:[A-Za-z0-9]+}/", ApiUserRequiredActivity(getChannel, false)).Methods("GET") sr.Handle("/{id:[A-Za-z0-9]+}/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET") sr.Handle("/{id:[A-Za-z0-9]+}/join", ApiUserRequired(joinChannel)).Methods("POST") sr.Handle("/{id:[A-Za-z0-9]+}/leave", ApiUserRequired(leaveChannel)).Methods("POST") @@ -275,7 +277,7 @@ func updateChannelDesc(c *Context, w http.ResponseWriter, r *http.Request) { func getChannels(c *Context, w http.ResponseWriter, r *http.Request) { - // user is already in the newtork + // user is already in the team if result := <-Srv.Store.Channel().GetChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil { if result.Err.Message == "No channels were found" { @@ -300,7 +302,7 @@ func getChannels(c *Context, w http.ResponseWriter, r *http.Request) { func getMoreChannels(c *Context, w http.ResponseWriter, r *http.Request) { - // user is already in the newtork + // user is already in the team if result := <-Srv.Store.Channel().GetMoreChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil { c.Err = result.Err @@ -314,6 +316,22 @@ func getMoreChannels(c *Context, w http.ResponseWriter, r *http.Request) { } } +func getChannelCounts(c *Context, w http.ResponseWriter, r *http.Request) { + + // user is already in the team + + if result := <-Srv.Store.Channel().GetChannelCounts(c.Session.TeamId, c.Session.UserId); result.Err != nil { + c.Err = model.NewAppError("getChannelCounts", "Unable to get channel counts from the database", result.Err.Message) + return + } else if HandleEtag(result.Data.(*model.ChannelCounts).Etag(), w, r) { + return + } else { + data := result.Data.(*model.ChannelCounts) + w.Header().Set(model.HEADER_ETAG_SERVER, data.Etag()) + w.Write([]byte(data.ToJson())) + } +} + func joinChannel(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) @@ -548,6 +566,37 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(result))) } +func getChannel(c *Context, w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + id := params["id"] + + //pchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId) + cchan := Srv.Store.Channel().Get(id) + cmchan := Srv.Store.Channel().GetMember(id, c.Session.UserId) + + if cresult := <-cchan; cresult.Err != nil { + c.Err = cresult.Err + return + } else if cmresult := <-cmchan; cmresult.Err != nil { + c.Err = cmresult.Err + return + } else { + data := &model.ChannelData{} + data.Channel = cresult.Data.(*model.Channel) + member := cmresult.Data.(model.ChannelMember) + data.Member = &member + + if HandleEtag(data.Etag(), w, r) { + return + } else { + w.Header().Set(model.HEADER_ETAG_SERVER, data.Etag()) + w.Header().Set("Expires", "-1") + w.Write([]byte(data.ToJson())) + } + } + +} + func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) diff --git a/api/channel_test.go b/api/channel_test.go index d4fb11bd8..d65aff66c 100644 --- a/api/channel_test.go +++ b/api/channel_test.go @@ -320,6 +320,27 @@ func TestGetChannel(t *testing.T) { if _, err := Client.UpdateLastViewedAt(channel2.Id); err != nil { t.Fatal(err) } + + if resp, err := Client.GetChannel(channel1.Id, ""); err != nil { + t.Fatal(err) + } else { + data := resp.Data.(*model.ChannelData) + if data.Channel.DisplayName != channel1.DisplayName { + t.Fatal("name didn't match") + } + + // test etag caching + if cache_result, err := Client.GetChannel(channel1.Id, resp.Etag); err != nil { + t.Fatal(err) + } else if cache_result.Data.(*model.ChannelData) != nil { + t.Log(cache_result.Data) + t.Fatal("cache should be empty") + } + } + + if _, err := Client.GetChannel("junk", ""); err == nil { + t.Fatal("should have failed - bad channel id") + } } func TestGetMoreChannel(t *testing.T) { @@ -366,6 +387,47 @@ func TestGetMoreChannel(t *testing.T) { } } +func TestGetChannelCounts(t *testing.T) { + Setup() + + team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} + team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team) + + user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} + user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) + store.Must(Srv.Store.User().VerifyEmail(user.Id)) + + Client.LoginByEmail(team.Name, user.Email, "pwd") + + channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} + channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) + + channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} + channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel) + + if result, err := Client.GetChannelCounts(""); err != nil { + t.Fatal(err) + } else { + counts := result.Data.(*model.ChannelCounts) + + if len(counts.Counts) != 4 { + t.Fatal("wrong number of channel counts") + } + + if len(counts.UpdateTimes) != 4 { + t.Fatal("wrong number of channel update times") + } + + if cache_result, err := Client.GetChannelCounts(result.Etag); err != nil { + t.Fatal(err) + } else if cache_result.Data.(*model.ChannelCounts) != nil { + t.Log(cache_result.Data) + t.Fatal("result data should be empty") + } + } + +} + func TestJoinChannel(t *testing.T) { Setup() diff --git a/model/channel_count.go b/model/channel_count.go new file mode 100644 index 000000000..d5daba14e --- /dev/null +++ b/model/channel_count.go @@ -0,0 +1,63 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "crypto/md5" + "encoding/json" + "fmt" + "io" + "sort" + "strconv" +) + +type ChannelCounts struct { + Counts map[string]int64 `json:"counts"` + UpdateTimes map[string]int64 `json:"update_times"` +} + +func (o *ChannelCounts) Etag() string { + + ids := []string{} + for id, _ := range o.Counts { + ids = append(ids, id) + } + sort.Strings(ids) + + str := "" + for _, id := range ids { + str += id + strconv.FormatInt(o.Counts[id], 10) + } + + md5Counts := fmt.Sprintf("%x", md5.Sum([]byte(str))) + + var update int64 = 0 + for _, u := range o.UpdateTimes { + if u > update { + update = u + } + } + + return Etag(md5Counts, update) +} + +func (o *ChannelCounts) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + +func ChannelCountsFromJson(data io.Reader) *ChannelCounts { + decoder := json.NewDecoder(data) + var o ChannelCounts + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} diff --git a/model/channel_data.go b/model/channel_data.go new file mode 100644 index 000000000..234bdec6e --- /dev/null +++ b/model/channel_data.go @@ -0,0 +1,43 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type ChannelData struct { + Channel *Channel `json:"channel"` + Member *ChannelMember `json:"member"` +} + +func (o *ChannelData) Etag() string { + var mt int64 = 0 + if o.Member != nil { + mt = o.Member.LastUpdateAt + } + + return Etag(o.Channel.Id, o.Channel.UpdateAt, o.Channel.LastPostAt, mt) +} + +func (o *ChannelData) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + +func ChannelDataFromJson(data io.Reader) *ChannelData { + decoder := json.NewDecoder(data) + var o ChannelData + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} diff --git a/model/client.go b/model/client.go index a5016fa2c..6fcfa5043 100644 --- a/model/client.go +++ b/model/client.go @@ -390,6 +390,15 @@ func (c *Client) GetChannels(etag string) (*Result, *AppError) { } } +func (c *Client) GetChannel(id, etag string) (*Result, *AppError) { + if r, err := c.DoGet("/channels/"+id+"/", "", etag); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), ChannelDataFromJson(r.Body)}, nil + } +} + func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) { if r, err := c.DoGet("/channels/more", "", etag); err != nil { return nil, err @@ -399,6 +408,15 @@ func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) { } } +func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) { + if r, err := c.DoGet("/channels/counts", "", etag); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), ChannelCountsFromJson(r.Body)}, nil + } +} + func (c *Client) JoinChannel(id string) (*Result, *AppError) { if r, err := c.DoPost("/channels/"+id+"/join", ""); err != nil { return nil, err diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index cac5c681b..b8bf8b5ac 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -281,6 +281,41 @@ func (s SqlChannelStore) GetMoreChannels(teamId string, userId string) StoreChan return storeChannel } +type channelIdWithCountAndUpdateAt struct { + Id string + TotalMsgCount int64 + UpdateAt int64 +} + +func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) StoreChannel { + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + var data []channelIdWithCountAndUpdateAt + _, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND TeamId = :TeamId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) + + if err != nil { + result.Err = model.NewAppError("SqlChannelStore.GetChannelCounts", "We couldn't get the channel counts", "teamId="+teamId+", userId="+userId+", err="+err.Error()) + } else { + counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)} + for i := range data { + v := data[i] + counts.Counts[v.Id] = v.TotalMsgCount + counts.UpdateTimes[v.Id] = v.UpdateAt + } + + result.Data = counts + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlChannelStore) GetByName(teamId string, name string) StoreChannel { storeChannel := make(StoreChannel) diff --git a/store/sql_channel_store_test.go b/store/sql_channel_store_test.go index b14883843..dabe39904 100644 --- a/store/sql_channel_store_test.go +++ b/store/sql_channel_store_test.go @@ -462,6 +462,53 @@ func TestChannelStoreGetMoreChannels(t *testing.T) { } } +func TestChannelStoreGetChannelCounts(t *testing.T) { + Setup() + + o2 := model.Channel{} + o2.TeamId = model.NewId() + o2.DisplayName = "Channel2" + o2.Name = "a" + model.NewId() + "b" + o2.Type = model.CHANNEL_OPEN + Must(store.Channel().Save(&o2)) + + o1 := model.Channel{} + o1.TeamId = model.NewId() + o1.DisplayName = "Channel1" + o1.Name = "a" + model.NewId() + "b" + o1.Type = model.CHANNEL_OPEN + Must(store.Channel().Save(&o1)) + + m1 := model.ChannelMember{} + m1.ChannelId = o1.Id + m1.UserId = model.NewId() + m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL + Must(store.Channel().SaveMember(&m1)) + + m2 := model.ChannelMember{} + m2.ChannelId = o1.Id + m2.UserId = model.NewId() + m2.NotifyLevel = model.CHANNEL_NOTIFY_ALL + Must(store.Channel().SaveMember(&m2)) + + m3 := model.ChannelMember{} + m3.ChannelId = o2.Id + m3.UserId = model.NewId() + m3.NotifyLevel = model.CHANNEL_NOTIFY_ALL + Must(store.Channel().SaveMember(&m3)) + + cresult := <-store.Channel().GetChannelCounts(o1.TeamId, m1.UserId) + counts := cresult.Data.(*model.ChannelCounts) + + if len(counts.Counts) != 1 { + t.Fatal("wrong number of counts") + } + + if len(counts.UpdateTimes) != 1 { + t.Fatal("wrong number of update times") + } +} + func TestChannelStoreUpdateLastViewedAt(t *testing.T) { Setup() diff --git a/store/store.go b/store/store.go index 0934fe84b..613fe4198 100644 --- a/store/store.go +++ b/store/store.go @@ -50,6 +50,7 @@ type ChannelStore interface { GetByName(team_id string, domain string) StoreChannel GetChannels(teamId string, userId string) StoreChannel GetMoreChannels(teamId string, userId string) StoreChannel + GetChannelCounts(teamId string, userId string) StoreChannel SaveMember(member *model.ChannelMember) StoreChannel GetMembers(channelId string) StoreChannel diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx index 06d7fc3e8..dcff5b89d 100644 --- a/web/react/components/edit_channel_modal.jsx +++ b/web/react/components/edit_channel_modal.jsx @@ -14,7 +14,7 @@ module.exports = React.createClass({ Client.updateChannelDesc(data, function(data) { this.setState({ server_error: "" }); - AsyncClient.getChannels(true); + AsyncClient.getChannel(this.state.channel_id); $(this.refs.modal.getDOMNode()).modal('hide'); }.bind(this), function(err) { diff --git a/web/react/components/more_channels.jsx b/web/react/components/more_channels.jsx index 007476f9b..5261ed6a7 100644 --- a/web/react/components/more_channels.jsx +++ b/web/react/components/more_channels.jsx @@ -1,34 +1,32 @@ // Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. // See License.txt for license information. - var utils = require('../utils/utils.jsx'); var client = require('../utils/client.jsx'); var asyncClient = require('../utils/async_client.jsx'); -var UserStore = require('../stores/user_store.jsx'); var ChannelStore = require('../stores/channel_store.jsx'); var LoadingScreen = require('./loading_screen.jsx'); function getStateFromStores() { - return { - channels: ChannelStore.getMoreAll(), - server_error: null - }; + return { + channels: ChannelStore.getMoreAll(), + serverError: null + }; } module.exports = React.createClass({ - displayName: "MoreChannelsModal", + displayName: 'MoreChannelsModal', componentDidMount: function() { ChannelStore.addMoreChangeListener(this._onChange); - $(this.refs.modal.getDOMNode()).on('shown.bs.modal', function (e) { + $(this.refs.modal.getDOMNode()).on('shown.bs.modal', function shown() { asyncClient.getMoreChannels(true); }); var self = this; - $(this.refs.modal.getDOMNode()).on('show.bs.modal', function(e) { + $(this.refs.modal.getDOMNode()).on('show.bs.modal', function show(e) { var button = e.relatedTarget; - self.setState({ channel_type: $(button).attr('data-channeltype') }); + self.setState({channelType: $(button).attr('data-channeltype')}); }); }, componentWillUnmount: function() { @@ -42,18 +40,17 @@ module.exports = React.createClass({ }, getInitialState: function() { var initState = getStateFromStores(); - initState.channel_type = ""; + initState.channelType = ''; return initState; }, - handleJoin: function(e) { - var self = this; - client.joinChannel(e, - function(data) { - $(self.refs.modal.getDOMNode()).modal('hide'); - asyncClient.getChannels(true); + handleJoin: function(id) { + client.joinChannel(id, + function() { + $(this.refs.modal.getDOMNode()).modal('hide'); + asyncClient.getChannel(id); }.bind(this), function(err) { - this.state.server_error = err.message; + this.state.serverError = err.message; this.setState(this.state); }.bind(this) ); @@ -62,52 +59,66 @@ module.exports = React.createClass({ $(this.refs.modal.getDOMNode()).modal('hide'); }, render: function() { - var server_error = this.state.server_error ? <div className='form-group has-error'><label className='control-label'>{ this.state.server_error }</label></div> : null; + var serverError; + if (this.state.serverError) { + serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>; + } + var outter = this; var moreChannels; - if (this.state.channels != null) - moreChannels = this.state.channels; + if (this.state.channels != null) { + var channels = this.state.channels; + if (!channels.loading) { + if (channels.length) { + moreChannels = ( + <table className='more-channel-table table'> + <tbody> + {channels.map(function cMap(channel) { + return ( + <tr key={channel.id}> + <td> + <p className='more-channel-name'>{channel.display_name}</p> + <p className='more-channel-description'>{channel.description}</p> + </td> + <td className='td--action'><button onClick={outter.handleJoin.bind(outter, channel.id)} className='btn btn-primary'>Join</button></td> + </tr> + ); + })} + </tbody> + </table> + ); + } else { + moreChannels = ( + <div className='no-channel-message'> + <p className='primary-message'>No more channels to join</p> + <p className='secondary-message'>Click 'Create New Channel' to make a new one</p> + </div> + ); + } + } else { + moreChannels = <LoadingScreen />; + } + } return ( - <div className="modal fade" id="more_channels" ref="modal" tabIndex="-1" role="dialog" aria-hidden="true"> - <div className="modal-dialog"> - <div className="modal-content"> - <div className="modal-header"> - <button type="button" className="close" data-dismiss="modal"> - <span aria-hidden="true">×</span> - <span className="sr-only">Close</span> + <div className='modal fade' id='more_channels' ref='modal' tabIndex='-1' role='dialog' aria-hidden='true'> + <div className='modal-dialog'> + <div className='modal-content'> + <div className='modal-header'> + <button type='button' className='close' data-dismiss='modal'> + <span aria-hidden='true'>×</span> + <span className='sr-only'>Close</span> </button> - <h4 className="modal-title">More Channels</h4> - <button data-toggle="modal" data-target="#new_channel" data-channeltype={this.state.channel_type} type="button" className="btn btn-primary channel-create-btn" onClick={this.handleNewChannel}>Create New Channel</button> + <h4 className='modal-title'>More Channels</h4> + <button data-toggle='modal' data-target='#new_channel' data-channeltype={this.state.channelType} type='button' className='btn btn-primary channel-create-btn' onClick={this.handleNewChannel}>Create New Channel</button> </div> - <div className="modal-body"> - {!moreChannels.loading ? - (moreChannels.length ? - <table className="more-channel-table table"> - <tbody> - {moreChannels.map(function(channel) { - return ( - <tr key={channel.id}> - <td> - <p className="more-channel-name">{channel.display_name}</p> - <p className="more-channel-description">{channel.description}</p> - </td> - <td className="td--action"><button onClick={outter.handleJoin.bind(outter, channel.id)} className="btn btn-primary">Join</button></td> - </tr> - ) - })} - </tbody> - </table> - : <div className="no-channel-message"> - <p className="primary-message">No more channels to join</p> - <p className="secondary-message">Click 'Create New Channel' to make a new one</p> - </div>) - : <LoadingScreen /> } - { server_error } + <div className='modal-body'> + {moreChannels} + {serverError} </div> - <div className="modal-footer"> - <button type="button" className="btn btn-default" data-dismiss="modal">Close</button> + <div className='modal-footer'> + <button type='button' className='btn btn-default' data-dismiss='modal'>Close</button> </div> </div> </div> diff --git a/web/react/components/new_channel.jsx b/web/react/components/new_channel.jsx index c22147022..b00376758 100644 --- a/web/react/components/new_channel.jsx +++ b/web/react/components/new_channel.jsx @@ -55,16 +55,16 @@ module.exports = React.createClass({ channel.description = this.refs.channel_desc.getDOMNode().value.trim(); channel.type = this.state.channelType; - var self = this; client.createChannel(channel, - function() { + function(data) { + $(this.refs.modal.getDOMNode()).modal('hide'); + + asyncClient.getChannel(data.id); + utils.switchChannel(data); + this.refs.display_name.getDOMNode().value = ''; this.refs.channel_name.getDOMNode().value = ''; this.refs.channel_desc.getDOMNode().value = ''; - - $(self.refs.modal.getDOMNode()).modal('hide'); - window.location = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name; - asyncClient.getChannels(true); }.bind(this), function(err) { state.serverError = err.message; diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx index 26593b7fa..93cb6ef21 100644 --- a/web/react/components/rename_channel_modal.jsx +++ b/web/react/components/rename_channel_modal.jsx @@ -63,12 +63,14 @@ module.exports = React.createClass({ Client.updateChannel(channel, function(data, text, req) { + $(this.refs.modal.getDOMNode()).modal('hide'); + + AsyncClient.getChannel(channel.id); + utils.updateTabTitle(channel.display_name); + utils.updateAddressBar(channel.name); + this.refs.display_name.getDOMNode().value = ""; this.refs.channel_name.getDOMNode().value = ""; - - $('#' + this.props.modalId).modal('hide'); - window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + this.state.channel_name; - AsyncClient.getChannels(true); }.bind(this), function(err) { state.server_error = err.message; diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index fe73cbcf7..80e3632c7 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -102,7 +102,7 @@ function getStateFromStores() { } readDirectChannels = readDirectChannels.slice(index); - showDirectChannels.sort(function(a, b) { + showDirectChannels.sort(function directSort(a, b) { if (a.display_name < b.display_name) { return -1; } @@ -114,7 +114,7 @@ function getStateFromStores() { } return { - active_id: currentId, + activeId: currentId, channels: ChannelStore.getAll(), members: members, showDirectChannels: showDirectChannels, @@ -157,9 +157,11 @@ module.exports = React.createClass({ onSocketChange: function(msg) { if (msg.action === 'posted') { if (ChannelStore.getCurrentId() === msg.channel_id) { - AsyncClient.getChannels(true, window.isActive); + if (window.isActive) { + AsyncClient.updateLastViewedAt(); + } } else { - AsyncClient.getChannels(true); + AsyncClient.getChannels(); } if (UserStore.getCurrentId() !== msg.user_id) { @@ -214,12 +216,12 @@ module.exports = React.createClass({ } } } else if (msg.action === 'viewed') { - if (ChannelStore.getCurrentId() != msg.channel_id) { - AsyncClient.getChannels(true); + if (ChannelStore.getCurrentId() !== msg.channel_id && UserStore.getCurrentId() === msg.user_id) { + AsyncClient.getChannel(msg.channel_id); } } else if (msg.action === 'user_added') { if (UserStore.getCurrentId() === msg.user_id) { - AsyncClient.getChannels(true); + AsyncClient.getChannel(msg.channel_id); } } else if (msg.action === 'user_removed') { if (msg.user_id === UserStore.getCurrentId()) { @@ -282,7 +284,7 @@ module.exports = React.createClass({ }, render: function() { var members = this.state.members; - var activeId = this.state.active_id; + var activeId = this.state.activeId; var badgesActive = false; // keep track of the first and last unread channels so we can use them to set the unread indicators @@ -294,7 +296,7 @@ module.exports = React.createClass({ var channelMember = members[channel.id]; var linkClass = ''; - if (channel.id === self.state.active_id) { + if (channel.id === activeId) { linkClass = 'active'; } diff --git a/web/react/stores/channel_store.jsx b/web/react/stores/channel_store.jsx index a97f13391..f7c23841c 100644 --- a/web/react/stores/channel_store.jsx +++ b/web/react/stores/channel_store.jsx @@ -10,212 +10,264 @@ var ActionTypes = Constants.ActionTypes; var BrowserStore = require('../stores/browser_store.jsx'); - var CHANGE_EVENT = 'change'; var MORE_CHANGE_EVENT = 'change'; var EXTRA_INFO_EVENT = 'extra_info'; var ChannelStore = assign({}, EventEmitter.prototype, { - _current_id: null, - emitChange: function() { - this.emit(CHANGE_EVENT); - }, - addChangeListener: function(callback) { - this.on(CHANGE_EVENT, callback); - }, - removeChangeListener: function(callback) { - this.removeListener(CHANGE_EVENT, callback); - }, - emitMoreChange: function() { - this.emit(MORE_CHANGE_EVENT); - }, - addMoreChangeListener: function(callback) { - this.on(MORE_CHANGE_EVENT, callback); - }, - removeMoreChangeListener: function(callback) { - this.removeListener(MORE_CHANGE_EVENT, callback); - }, - emitExtraInfoChange: function() { - this.emit(EXTRA_INFO_EVENT); - }, - addExtraInfoChangeListener: function(callback) { - this.on(EXTRA_INFO_EVENT, callback); - }, - removeExtraInfoChangeListener: function(callback) { - this.removeListener(EXTRA_INFO_EVENT, callback); - }, - findFirstBy: function(field, value) { - var channels = this._getChannels(); - for (var i = 0; i < channels.length; i++) { - if (channels[i][field] == value) { - return channels[i]; - } - } + currentId: null, + emitChange: function() { + this.emit(CHANGE_EVENT); + }, + addChangeListener: function(callback) { + this.on(CHANGE_EVENT, callback); + }, + removeChangeListener: function(callback) { + this.removeListener(CHANGE_EVENT, callback); + }, + emitMoreChange: function() { + this.emit(MORE_CHANGE_EVENT); + }, + addMoreChangeListener: function(callback) { + this.on(MORE_CHANGE_EVENT, callback); + }, + removeMoreChangeListener: function(callback) { + this.removeListener(MORE_CHANGE_EVENT, callback); + }, + emitExtraInfoChange: function() { + this.emit(EXTRA_INFO_EVENT); + }, + addExtraInfoChangeListener: function(callback) { + this.on(EXTRA_INFO_EVENT, callback); + }, + removeExtraInfoChangeListener: function(callback) { + this.removeListener(EXTRA_INFO_EVENT, callback); + }, + findFirstBy: function(field, value) { + var channels = this.pGetChannels(); + for (var i = 0; i < channels.length; i++) { + if (channels[i][field] === value) { + return channels[i]; + } + } - return null; - }, - get: function(id) { - return this.findFirstBy('id', id); - }, - getMember: function(id) { - return this.getAllMembers()[id]; - }, - getByName: function(name) { - return this.findFirstBy('name', name); - }, - getAll: function() { - return this._getChannels(); - }, - getAllMembers: function() { - return this._getChannelMembers(); - }, - getMoreAll: function() { - return this._getMoreChannels(); - }, - setCurrentId: function(id) { - this._current_id = id; - }, - setLastVisitedName: function(name) { - if (name == null) - BrowserStore.removeItem("last_visited_name"); - else - BrowserStore.setItem("last_visited_name", name); - }, - getLastVisitedName: function() { - return BrowserStore.getItem("last_visited_name"); - }, - resetCounts: function(id) { - var cm = this._getChannelMembers(); - for (var cmid in cm) { - if (cm[cmid].channel_id == id) { - var c = this.get(id); - if (c) { - cm[cmid].msg_count = this.get(id).total_msg_count; - cm[cmid].mention_count = 0; - } - break; - } - } - this._storeChannelMembers(cm); - }, - getCurrentId: function() { - return this._current_id; - }, - getCurrent: function() { - var currentId = this.getCurrentId(); - - if (currentId) - return this.get(currentId); - else - return null; - }, - getCurrentMember: function() { - var currentId = ChannelStore.getCurrentId(); - - if (currentId) - return this.getAllMembers()[currentId]; - else - return null; - }, - setChannelMember: function(member) { - var members = this._getChannelMembers(); - members[member.channel_id] = member; - this._storeChannelMembers(members); - this.emitChange(); - }, - getCurrentExtraInfo: function() { - var currentId = ChannelStore.getCurrentId(); - var extra = null; - - if (currentId) - extra = this._getExtraInfos()[currentId]; - - if (extra == null) - extra = {members: []}; - - return extra; - }, - getExtraInfo: function(channel_id) { - var extra = null; - - if (channel_id) - extra = this._getExtraInfos()[channel_id]; - - if (extra == null) - extra = {members: []}; - - return extra; - }, - _storeChannels: function(channels) { - BrowserStore.setItem("channels", channels); - }, - _getChannels: function() { - return BrowserStore.getItem("channels", []); - }, - _storeChannelMembers: function(channelMembers) { - BrowserStore.setItem("channel_members", channelMembers); - }, - _getChannelMembers: function() { - return BrowserStore.getItem("channel_members", {}); - }, - _storeMoreChannels: function(channels) { - BrowserStore.setItem("more_channels", channels); - }, - _getMoreChannels: function() { - var channels = BrowserStore.getItem("more_channels"); - - if (channels == null) { - channels = {}; - channels.loading = true; - } + return null; + }, + get: function(id) { + return this.findFirstBy('id', id); + }, + getMember: function(id) { + return this.getAllMembers()[id]; + }, + getByName: function(name) { + return this.findFirstBy('name', name); + }, + getAll: function() { + return this.pGetChannels(); + }, + getAllMembers: function() { + return this.pGetChannelMembers(); + }, + getMoreAll: function() { + return this.pGetMoreChannels(); + }, + setCurrentId: function(id) { + this.currentId = id; + }, + setLastVisitedName: function(name) { + if (name == null) { + BrowserStore.removeItem('last_visited_name'); + } else { + BrowserStore.setItem('last_visited_name', name); + } + }, + getLastVisitedName: function() { + return BrowserStore.getItem('last_visited_name'); + }, + resetCounts: function(id) { + var cm = this.pGetChannelMembers(); + for (var cmid in cm) { + if (cm[cmid].channel_id === id) { + var c = this.get(id); + if (c) { + cm[cmid].msg_count = this.get(id).total_msg_count; + cm[cmid].mention_count = 0; + } + break; + } + } + this.pStoreChannelMembers(cm); + }, + getCurrentId: function() { + return this.currentId; + }, + getCurrent: function() { + var currentId = this.getCurrentId(); + + if (currentId) { + return this.get(currentId); + } else { + return null; + } + }, + getCurrentMember: function() { + var currentId = ChannelStore.getCurrentId(); + + if (currentId) { + return this.getAllMembers()[currentId]; + } else { + return null; + } + }, + setChannelMember: function(member) { + var members = this.pGetChannelMembers(); + members[member.channel_id] = member; + this.pStoreChannelMembers(members); + this.emitChange(); + }, + getCurrentExtraInfo: function() { + var currentId = ChannelStore.getCurrentId(); + var extra = null; + + if (currentId) { + extra = this.pGetExtraInfos()[currentId]; + } + + if (extra == null) { + extra = {members: []}; + } + + return extra; + }, + getExtraInfo: function(channelId) { + var extra = null; + + if (channelId) { + extra = this.pGetExtraInfos()[channelId]; + } + + if (extra == null) { + extra = {members: []}; + } + + return extra; + }, + pStoreChannel: function(channel) { + var channels = this.pGetChannels(); + var found; + + for (var i = 0; i < channels.length; i++) { + if (channels[i].id === channel.id) { + channels[i] = channel; + found = true; + break; + } + } + + if (!found) { + channels.push(channel); + } - return channels; - }, - _storeExtraInfos: function(extraInfos) { - BrowserStore.setItem("extra_infos", extraInfos); - }, - _getExtraInfos: function() { - return BrowserStore.getItem("extra_infos", {}); - }, - isDefault: function(channel) { - return channel.name == Constants.DEFAULT_CHANNEL; - } + channels.sort(function chanSort(a, b) { + if (a.display_name.toLowerCase() < b.display_name.toLowerCase()) { + return -1; + } + if (a.display_name.toLowerCase() > b.display_name.toLowerCase()) { + return 1; + } + return 0; + }); + + this.pStoreChannels(channels); + }, + pStoreChannels: function(channels) { + BrowserStore.setItem('channels', channels); + }, + pGetChannels: function() { + return BrowserStore.getItem('channels', []); + }, + pStoreChannelMember: function(channelMember) { + var members = this.pGetChannelMembers(); + members[channelMember.channel_id] = channelMember; + this.pStoreChannelMembers(members); + }, + pStoreChannelMembers: function(channelMembers) { + BrowserStore.setItem('channel_members', channelMembers); + }, + pGetChannelMembers: function() { + return BrowserStore.getItem('channel_members', {}); + }, + pStoreMoreChannels: function(channels) { + BrowserStore.setItem('more_channels', channels); + }, + pGetMoreChannels: function() { + var channels = BrowserStore.getItem('more_channels'); + + if (channels == null) { + channels = {}; + channels.loading = true; + } + + return channels; + }, + pStoreExtraInfos: function(extraInfos) { + BrowserStore.setItem('extra_infos', extraInfos); + }, + pGetExtraInfos: function() { + return BrowserStore.getItem('extra_infos', {}); + }, + isDefault: function(channel) { + return channel.name === Constants.DEFAULT_CHANNEL; + } }); ChannelStore.dispatchToken = AppDispatcher.register(function(payload) { - var action = payload.action; - - switch(action.type) { - - case ActionTypes.CLICK_CHANNEL: - ChannelStore.setCurrentId(action.id); - ChannelStore.setLastVisitedName(action.name); - ChannelStore.resetCounts(action.id); - ChannelStore.emitChange(); - break; - - case ActionTypes.RECIEVED_CHANNELS: - ChannelStore._storeChannels(action.channels); - ChannelStore._storeChannelMembers(action.members); - var currentId = ChannelStore.getCurrentId(); - if (currentId) ChannelStore.resetCounts(currentId); - ChannelStore.emitChange(); - break; - - case ActionTypes.RECIEVED_MORE_CHANNELS: - ChannelStore._storeMoreChannels(action.channels); - ChannelStore.emitMoreChange(); - break; - - case ActionTypes.RECIEVED_CHANNEL_EXTRA_INFO: - var extra_infos = ChannelStore._getExtraInfos(); - extra_infos[action.extra_info.id] = action.extra_info; - ChannelStore._storeExtraInfos(extra_infos); - ChannelStore.emitExtraInfoChange(); - break; - - default: - } + var action = payload.action; + var currentId; + + switch(action.type) { + + case ActionTypes.CLICK_CHANNEL: + ChannelStore.setCurrentId(action.id); + ChannelStore.setLastVisitedName(action.name); + ChannelStore.resetCounts(action.id); + ChannelStore.emitChange(); + break; + + case ActionTypes.RECIEVED_CHANNELS: + ChannelStore.pStoreChannels(action.channels); + ChannelStore.pStoreChannelMembers(action.members); + currentId = ChannelStore.getCurrentId(); + if (currentId) { + ChannelStore.resetCounts(currentId); + } + ChannelStore.emitChange(); + break; + + case ActionTypes.RECIEVED_CHANNEL: + ChannelStore.pStoreChannel(action.channel); + ChannelStore.pStoreChannelMember(action.member); + currentId = ChannelStore.getCurrentId(); + if (currentId) { + ChannelStore.resetCounts(currentId); + } + ChannelStore.emitChange(); + break; + + case ActionTypes.RECIEVED_MORE_CHANNELS: + ChannelStore.pStoreMoreChannels(action.channels); + ChannelStore.emitMoreChange(); + break; + + case ActionTypes.RECIEVED_CHANNEL_EXTRA_INFO: + var extraInfos = ChannelStore.pGetExtraInfos(); + extraInfos[action.extra_info.id] = action.extra_info; + ChannelStore.pStoreExtraInfos(extraInfos); + ChannelStore.emitExtraInfoChange(); + break; + + default: + } }); -module.exports = ChannelStore;
\ No newline at end of file +module.exports = ChannelStore; diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx index f35b0f6cc..7e8a6116c 100644 --- a/web/react/utils/async_client.jsx +++ b/web/react/utils/async_client.jsx @@ -14,100 +14,171 @@ var ActionTypes = Constants.ActionTypes; // Used to track in progress async calls var callTracker = {}; -var dispatchError = function(err, method) { +function dispatchError(err, method) { AppDispatcher.handleServerAction({ type: ActionTypes.RECIEVED_ERROR, err: err, method: method }); -}; +} +module.exports.dispatchError = dispatchError; -var isCallInProgress = function(callName) { - if (!(callName in callTracker)) return false; +function isCallInProgress(callName) { + if (!(callName in callTracker)) { + return false; + } - if (callTracker[callName] === 0) return false; + if (callTracker[callName] === 0) { + return false; + } if (utils.getTimestamp() - callTracker[callName] > 5000) { - console.log("AsyncClient call " + callName + " expired after more than 5 seconds"); + console.log('AsyncClient call ' + callName + ' expired after more than 5 seconds'); return false; } return true; -}; +} -module.exports.dispatchError = dispatchError; +function getChannels(force, updateLastViewed, checkVersion) { + var channels = ChannelStore.getAll(); + + if (channels.length === 0 || force) { + if (isCallInProgress('getChannels')) { + return; + } -module.exports.getChannels = function(force, updateLastViewed, checkVersion) { - if (isCallInProgress("getChannels")) return; + callTracker.getChannels = utils.getTimestamp(); - if (ChannelStore.getAll().length == 0 || force) { - callTracker["getChannels"] = utils.getTimestamp(); client.getChannels( function(data, textStatus, xhr) { - callTracker["getChannels"] = 0; - - if (updateLastViewed && ChannelStore.getCurrentId() != null) { - module.exports.updateLastViewedAt(); - } + callTracker.getChannels = 0; if (checkVersion) { - var serverVersion = xhr.getResponseHeader("X-Version-ID"); + var serverVersion = xhr.getResponseHeader('X-Version-ID'); if (!UserStore.getLastVersion()) { UserStore.setLastVersion(serverVersion); } - if (serverVersion != UserStore.getLastVersion()) { + if (serverVersion !== UserStore.getLastVersion()) { UserStore.setLastVersion(serverVersion); window.location.href = window.location.href; - console.log("Detected version update refreshing the page"); + console.log('Detected version update refreshing the page'); } } - if (xhr.status === 304 || !data) return; + if (xhr.status === 304 || !data) { + return; + } AppDispatcher.handleServerAction({ type: ActionTypes.RECIEVED_CHANNELS, channels: data.channels, members: data.members }); + }, + function(err) { + callTracker.getChannels = 0; + dispatchError(err, 'getChannels'); + } + ); + } else { + if (isCallInProgress('getChannelCounts')) { + return; + } + + callTracker.getChannelCounts = utils.getTimestamp(); + client.getChannelCounts( + function(data, textStatus, xhr) { + callTracker.getChannelCounts = 0; + + if (xhr.status === 304 || !data) { + return; + } + + var countMap = data.counts; + var updateAtMap = data.update_times; + + for (var id in countMap) { + var c = ChannelStore.get(id); + var count = countMap[id]; + var updateAt = updateAtMap[id]; + if (!c || c.total_msg_count !== count || updateAt > c.update_at) { + getChannel(id); + } + } }, function(err) { - callTracker["getChannels"] = 0; - dispatchError(err, "getChannels"); + callTracker.getChannelCounts = 0; + dispatchError(err, 'getChannelCounts'); } ); } + + if (updateLastViewed && ChannelStore.getCurrentId() != null) { + module.exports.updateLastViewedAt(); + } +} +module.exports.getChannels = getChannels; + +function getChannel(id) { + if (isCallInProgress('getChannel' + id)) { + return; + } + + callTracker['getChannel' + id] = utils.getTimestamp(); + + client.getChannel(id, + function(data, textStatus, xhr) { + callTracker['getChannel' + id] = 0; + + if (xhr.status === 304 || !data) { + return; + } + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECIEVED_CHANNEL, + channel: data.channel, + member: data.member + }); + }, + function(err) { + callTracker['getChannel' + id] = 0; + dispatchError(err, 'getChannel'); + } + ); } +module.exports.getChannel = getChannel; module.exports.updateLastViewedAt = function() { - if (isCallInProgress("updateLastViewed")) return; + if (isCallInProgress('updateLastViewed')) return; if (ChannelStore.getCurrentId() == null) return; - callTracker["updateLastViewed"] = utils.getTimestamp(); + callTracker['updateLastViewed'] = utils.getTimestamp(); client.updateLastViewedAt( ChannelStore.getCurrentId(), function(data) { - callTracker["updateLastViewed"] = 0; + callTracker['updateLastViewed'] = 0; }, function(err) { - callTracker["updateLastViewed"] = 0; - dispatchError(err, "updateLastViewedAt"); + callTracker['updateLastViewed'] = 0; + dispatchError(err, 'updateLastViewedAt'); } ); } module.exports.getMoreChannels = function(force) { - if (isCallInProgress("getMoreChannels")) return; + if (isCallInProgress('getMoreChannels')) return; if (ChannelStore.getMoreAll().loading || force) { - callTracker["getMoreChannels"] = utils.getTimestamp(); + callTracker['getMoreChannels'] = utils.getTimestamp(); client.getMoreChannels( function(data, textStatus, xhr) { - callTracker["getMoreChannels"] = 0; + callTracker['getMoreChannels'] = 0; if (xhr.status === 304 || !data) return; @@ -118,8 +189,8 @@ module.exports.getMoreChannels = function(force) { }); }, function(err) { - callTracker["getMoreChannels"] = 0; - dispatchError(err, "getMoreChannels"); + callTracker['getMoreChannels'] = 0; + dispatchError(err, 'getMoreChannels'); } ); } @@ -129,15 +200,15 @@ module.exports.getChannelExtraInfo = function(force) { var channelId = ChannelStore.getCurrentId(); if (channelId != null) { - if (isCallInProgress("getChannelExtraInfo_"+channelId)) return; + if (isCallInProgress('getChannelExtraInfo_'+channelId)) return; var minMembers = ChannelStore.getCurrent() && ChannelStore.getCurrent().type === 'D' ? 1 : 0; if (ChannelStore.getCurrentExtraInfo().members.length <= minMembers || force) { - callTracker["getChannelExtraInfo_"+channelId] = utils.getTimestamp(); + callTracker['getChannelExtraInfo_'+channelId] = utils.getTimestamp(); client.getChannelExtraInfo( channelId, function(data, textStatus, xhr) { - callTracker["getChannelExtraInfo_"+channelId] = 0; + callTracker['getChannelExtraInfo_'+channelId] = 0; if (xhr.status === 304 || !data) return; @@ -147,8 +218,8 @@ module.exports.getChannelExtraInfo = function(force) { }); }, function(err) { - callTracker["getChannelExtraInfo_"+channelId] = 0; - dispatchError(err, "getChannelExtraInfo"); + callTracker['getChannelExtraInfo_'+channelId] = 0; + dispatchError(err, 'getChannelExtraInfo'); } ); } @@ -156,12 +227,12 @@ module.exports.getChannelExtraInfo = function(force) { } module.exports.getProfiles = function() { - if (isCallInProgress("getProfiles")) return; + if (isCallInProgress('getProfiles')) return; - callTracker["getProfiles"] = utils.getTimestamp(); + callTracker['getProfiles'] = utils.getTimestamp(); client.getProfiles( function(data, textStatus, xhr) { - callTracker["getProfiles"] = 0; + callTracker['getProfiles'] = 0; if (xhr.status === 304 || !data) return; @@ -171,20 +242,20 @@ module.exports.getProfiles = function() { }); }, function(err) { - callTracker["getProfiles"] = 0; - dispatchError(err, "getProfiles"); + callTracker['getProfiles'] = 0; + dispatchError(err, 'getProfiles'); } ); } module.exports.getSessions = function() { - if (isCallInProgress("getSessions")) return; + if (isCallInProgress('getSessions')) return; - callTracker["getSessions"] = utils.getTimestamp(); + callTracker['getSessions'] = utils.getTimestamp(); client.getSessions( UserStore.getCurrentId(), function(data, textStatus, xhr) { - callTracker["getSessions"] = 0; + callTracker['getSessions'] = 0; if (xhr.status === 304 || !data) return; @@ -194,20 +265,20 @@ module.exports.getSessions = function() { }); }, function(err) { - callTracker["getSessions"] = 0; - dispatchError(err, "getSessions"); + callTracker['getSessions'] = 0; + dispatchError(err, 'getSessions'); } ); } module.exports.getAudits = function() { - if (isCallInProgress("getAudits")) return; + if (isCallInProgress('getAudits')) return; - callTracker["getAudits"] = utils.getTimestamp(); + callTracker['getAudits'] = utils.getTimestamp(); client.getAudits( UserStore.getCurrentId(), function(data, textStatus, xhr) { - callTracker["getAudits"] = 0; + callTracker['getAudits'] = 0; if (xhr.status === 304 || !data) return; @@ -217,22 +288,22 @@ module.exports.getAudits = function() { }); }, function(err) { - callTracker["getAudits"] = 0; - dispatchError(err, "getAudits"); + callTracker['getAudits'] = 0; + dispatchError(err, 'getAudits'); } ); } module.exports.findTeams = function(email) { - if (isCallInProgress("findTeams_"+email)) return; + if (isCallInProgress('findTeams_'+email)) return; var user = UserStore.getCurrentUser(); if (user) { - callTracker["findTeams_"+email] = utils.getTimestamp(); + callTracker['findTeams_'+email] = utils.getTimestamp(); client.findTeams( user.email, function(data, textStatus, xhr) { - callTracker["findTeams_"+email] = 0; + callTracker['findTeams_'+email] = 0; if (xhr.status === 304 || !data) return; @@ -242,21 +313,21 @@ module.exports.findTeams = function(email) { }); }, function(err) { - callTracker["findTeams_"+email] = 0; - dispatchError(err, "findTeams"); + callTracker['findTeams_'+email] = 0; + dispatchError(err, 'findTeams'); } ); } } module.exports.search = function(terms) { - if (isCallInProgress("search_"+String(terms))) return; + if (isCallInProgress('search_'+String(terms))) return; - callTracker["search_"+String(terms)] = utils.getTimestamp(); + callTracker['search_'+String(terms)] = utils.getTimestamp(); client.search( terms, function(data, textStatus, xhr) { - callTracker["search_"+String(terms)] = 0; + callTracker['search_'+String(terms)] = 0; if (xhr.status === 304 || !data) return; @@ -266,8 +337,8 @@ module.exports.search = function(terms) { }); }, function(err) { - callTracker["search_"+String(terms)] = 0; - dispatchError(err, "search"); + callTracker['search_'+String(terms)] = 0; + dispatchError(err, 'search'); } ); } @@ -276,7 +347,7 @@ module.exports.getPosts = function(force, id, maxPosts) { if (PostStore.getCurrentPosts() == null || force) { var channelId = id ? id : ChannelStore.getCurrentId(); - if (isCallInProgress("getPosts_"+channelId)) return; + if (isCallInProgress('getPosts_'+channelId)) return; var post_list = PostStore.getCurrentPosts(); @@ -291,7 +362,7 @@ module.exports.getPosts = function(force, id, maxPosts) { } if (channelId != null) { - callTracker["getPosts_"+channelId] = utils.getTimestamp(); + callTracker['getPosts_'+channelId] = utils.getTimestamp(); client.getPosts( channelId, 0, @@ -308,23 +379,25 @@ module.exports.getPosts = function(force, id, maxPosts) { module.exports.getProfiles(); }, function(err) { - dispatchError(err, "getPosts"); + dispatchError(err, 'getPosts'); }, function() { - callTracker["getPosts_"+channelId] = 0; + callTracker['getPosts_'+channelId] = 0; } ); } } } -module.exports.getMe = function() { - if (isCallInProgress("getMe")) return; +function getMe() { + if (isCallInProgress('getMe')) { + return; + } - callTracker["getMe"] = utils.getTimestamp(); + callTracker.getMe = utils.getTimestamp(); client.getMe( function(data, textStatus, xhr) { - callTracker["getMe"] = 0; + callTracker.getMe = 0; if (xhr.status === 304 || !data) return; @@ -334,19 +407,20 @@ module.exports.getMe = function() { }); }, function(err) { - callTracker["getMe"] = 0; - dispatchError(err, "getMe"); + callTracker.getMe = 0; + dispatchError(err, 'getMe'); } ); } +module.exports.getMe = getMe; module.exports.getStatuses = function() { - if (isCallInProgress("getStatuses")) return; + if (isCallInProgress('getStatuses')) return; - callTracker["getStatuses"] = utils.getTimestamp(); + callTracker['getStatuses'] = utils.getTimestamp(); client.getStatuses( function(data, textStatus, xhr) { - callTracker["getStatuses"] = 0; + callTracker['getStatuses'] = 0; if (xhr.status === 304 || !data) return; @@ -356,19 +430,19 @@ module.exports.getStatuses = function() { }); }, function(err) { - callTracker["getStatuses"] = 0; - dispatchError(err, "getStatuses"); + callTracker['getStatuses'] = 0; + dispatchError(err, 'getStatuses'); } ); } module.exports.getMyTeam = function() { - if (isCallInProgress("getMyTeam")) return; + if (isCallInProgress('getMyTeam')) return; - callTracker["getMyTeam"] = utils.getTimestamp(); + callTracker['getMyTeam'] = utils.getTimestamp(); client.getMyTeam( function(data, textStatus, xhr) { - callTracker["getMyTeam"] = 0; + callTracker['getMyTeam'] = 0; if (xhr.status === 304 || !data) return; @@ -378,8 +452,8 @@ module.exports.getMyTeam = function() { }); }, function(err) { - callTracker["getMyTeam"] = 0; - dispatchError(err, "getMyTeam"); + callTracker['getMyTeam'] = 0; + dispatchError(err, 'getMyTeam'); } ); } diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index 6a1f7c820..f2b6619a5 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -540,18 +540,34 @@ module.exports.updateLastViewedAt = function(channelId, success, error) { }); }; -module.exports.getChannels = function(success, error) { +function getChannels(success, error) { $.ajax({ - url: "/api/v1/channels/", + url: '/api/v1/channels/', dataType: 'json', type: 'GET', success: success, ifModified: true, error: function(xhr, status, err) { - e = handleError("getChannels", xhr, status, err); + var e = handleError('getChannels', xhr, status, err); error(e); } }); +} +module.exports.getChannels = getChannels; + +module.exports.getChannel = function(id, success, error) { + $.ajax({ + url: "/api/v1/channels/" + id + "/", + dataType: 'json', + type: 'GET', + success: success, + error: function(xhr, status, err) { + e = handleError("getChannel", xhr, status, err); + error(e); + } + }); + + module.exports.track('api', 'api_channel_get'); }; module.exports.getMoreChannels = function(success, error) { @@ -568,6 +584,21 @@ module.exports.getMoreChannels = function(success, error) { }); }; +function getChannelCounts(success, error) { + $.ajax({ + url: '/api/v1/channels/counts', + dataType: 'json', + type: 'GET', + success: success, + ifModified: true, + error: function(xhr, status, err) { + var e = handleError('getChannelCounts', xhr, status, err); + error(e); + } + }); +} +module.exports.getChannelCounts = getChannelCounts; + module.exports.getChannelExtraInfo = function(id, success, error) { $.ajax({ url: "/api/v1/channels/" + id + "/extra_info", diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 505f7fa17..0c714567a 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -10,6 +10,7 @@ module.exports = { CLICK_CHANNEL: null, CREATE_CHANNEL: null, RECIEVED_CHANNELS: null, + RECIEVED_CHANNEL: null, RECIEVED_MORE_CHANNELS: null, RECIEVED_CHANNEL_EXTRA_INFO: null, diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 2214b6239..7591c138f 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -732,20 +732,19 @@ module.exports.isValidUsername = function (name) { return error; } -module.exports.switchChannel = function(channel, teammate_name) { +function switchChannel(channel, teammateName) { AppDispatcher.handleViewAction({ type: ActionTypes.CLICK_CHANNEL, name: channel.name, id: channel.id }); - var teamURL = window.location.href.split('/channels')[0]; - history.replaceState('data', '', teamURL + '/channels/' + channel.name); + updateAddressBar(channel.name); - if (channel.type === 'D' && teammate_name) { - document.title = teammate_name + " " + document.title.substring(document.title.lastIndexOf("-")); + if (channel.type === 'D' && teammateName) { + updateTabTitle(teammateName); } else { - document.title = channel.display_name + " " + document.title.substring(document.title.lastIndexOf("-")); + updateTabTitle(channel.display_name); } AsyncClient.getChannels(true, true, true); @@ -759,6 +758,18 @@ module.exports.switchChannel = function(channel, teammate_name) { return false; } +module.exports.switchChannel = switchChannel; + +function updateTabTitle(name) { + document.title = name + ' ' + document.title.substring(document.title.lastIndexOf('-')); +} +module.exports.updateTabTitle = updateTabTitle; + +function updateAddressBar(channelName) { + var teamURL = window.location.href.split('/channels')[0]; + history.replaceState('data', '', teamURL + '/channels/' + channelName); +} +module.exports.updateAddressBar = updateAddressBar; module.exports.isMobile = function() { return screen.width <= 768; |