From 33a6608d26f9b762f35653c212fac73027f53a17 Mon Sep 17 00:00:00 2001 From: it33 Date: Thu, 10 Sep 2015 11:20:23 -0700 Subject: Update README.md --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index de0f4b079..3c9d5d408 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Mattermost is an open source, on-prem Slack-alternative. -It modernizes team communication without locking in your data to a single provider. Offer your end users messaging and file sharing across PCs and phones with archiving and instant search--without losing control of your data. +It offers modern communication from behind your firewall, including messaging and file sharing across PCs and phones with archiving and instant search. ## All team communication in one place, searchable and accessible anywhere @@ -26,12 +26,6 @@ Please see the [features pages of the Mattermost website](http://www.mattermost. - Attach sound, video and image files from mobile devices - Define team-specific branding and color themes across your devices -#### Enterprise Compatible - -- Self-host Mattermost entirely within your organization's insfrastructure -- GitLab Mattermost omnibus supports install to over 100,000 organizations using GitLab -- LDAP/Active Directory connectivity to Mattermost enabled via GitLab Single-Sign-On - ## Learn More - [Product Vision and Target Audiences](http://www.mattermost.org/vision/) - What we're solving and for whom are we building @@ -48,9 +42,9 @@ There are multiple ways to install Mattermost depending on your needs. #### Quick Start Install for Product Evaluation -- [Local Machine Install and Upgrade with Docker](doc/install/single-container-install.md) - Explore product functionality using a single-container Docker install on a local machine, including Mac OSX, Ubuntu, or Arch Linux). Optionally set up email and upgrade your instance using DockerHub. +- [Local Machine Install with Docker](doc/install/single-container-install.md) - Explore product functionality using a single-container Docker install on a local machine, including Mac OSX, Ubuntu, or Arch Linux). Optionally set up email and upgrade your instance using DockerHub. -- [AWS EBS Install and Upgrade with Docker](doc/install/aws-ebs-setup.md) - Explore product functionality using a single-container Docker install for Amazon Web Services Elastic Beanstalk. Optionally set up email and upgrade your instance using DockerHub. +- [AWS EBS Install with Docker](doc/install/aws-ebs-setup.md) - Explore product functionality using a single-container Docker install for Amazon Web Services Elastic Beanstalk. Optionally set up email and upgrade your instance using DockerHub. #### Development Install -- cgit v1.2.3-1-g7c22 From ae8e9c3dfd0f8606064f29d56141b0b3fe35cdef Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Fri, 11 Sep 2015 11:41:16 +0500 Subject: Updating UI for modals and notification bar --- web/sass-files/sass/partials/_modal.scss | 3 ++- web/sass-files/sass/partials/_sidebar--left.scss | 2 +- web/templates/channel.html | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/web/sass-files/sass/partials/_modal.scss b/web/sass-files/sass/partials/_modal.scss index d32306cbc..a046cd904 100644 --- a/web/sass-files/sass/partials/_modal.scss +++ b/web/sass-files/sass/partials/_modal.scss @@ -123,6 +123,7 @@ } .more-channel-table { margin: 0; + table-layout: fixed; p { font-size: 0.9em; overflow: hidden; @@ -154,7 +155,7 @@ &.td--action { text-align: right; padding: 8px 15px 8px 8px; - width: 70px; + width: 80px; vertical-align: middle; } } diff --git a/web/sass-files/sass/partials/_sidebar--left.scss b/web/sass-files/sass/partials/_sidebar--left.scss index 0a504b765..63426dae9 100644 --- a/web/sass-files/sass/partials/_sidebar--left.scss +++ b/web/sass-files/sass/partials/_sidebar--left.scss @@ -49,7 +49,7 @@ left: 0; right: 0; width: 72%; - color: #777; + color: #fff; background: #2389D7; @include border-radius(50px); margin: 0 auto; diff --git a/web/templates/channel.html b/web/templates/channel.html index 9bfd1fa35..a732a25ce 100644 --- a/web/templates/channel.html +++ b/web/templates/channel.html @@ -52,6 +52,7 @@ -- cgit v1.2.3-1-g7c22 From 83931da9f2b3eb5e8dc835313992c7ba2ea65f4a Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 11 Sep 2015 08:38:18 -0400 Subject: Fix load more posts bug. --- web/react/components/post.jsx | 2 +- web/react/components/post_list.jsx | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx index 37de4ecc0..d3c6befd0 100644 --- a/web/react/components/post.jsx +++ b/web/react/components/post.jsx @@ -152,7 +152,7 @@ export default class Post extends React.Component { return (
{profilePic} diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index 9d95887d9..e6aa3f8df 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -189,9 +189,15 @@ export default class PostList extends React.Component { this.scrollToBottom(true); // the user clicked 'load more messages' - } else if (this.gotMorePosts) { - var lastPost = oldPosts[oldOrder[prevState.numToDisplay]]; - $('#' + lastPost.id)[0].scrollIntoView(); + } else if (this.gotMorePosts && oldOrder.length > 0) { + let index; + if (prevState.numToDisplay >= oldOrder.length) { + index = oldOrder.length - 1; + } else { + index = prevState.numToDisplay; + } + const lastPost = oldPosts[oldOrder[index]]; + $('#post_' + lastPost.id)[0].scrollIntoView(); this.gotMorePosts = false; } else { this.scrollTo(this.prevScrollTop); -- cgit v1.2.3-1-g7c22 From bda09c0030caf0f271c362e194a9eb998e56539d Mon Sep 17 00:00:00 2001 From: lfbrock Date: Fri, 11 Sep 2015 09:35:05 -0400 Subject: Updated developer install instructions --- doc/install/dev-setup.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/install/dev-setup.md b/doc/install/dev-setup.md index a088bbbc2..6d26cbd33 100644 --- a/doc/install/dev-setup.md +++ b/doc/install/dev-setup.md @@ -10,7 +10,7 @@ Developer Machine Setup 2. Get your Docker IP address with `boot2docker ip` 3. Add a line to your /etc/hosts that goes ` dockerhost` 4. Run `boot2docker shellinit` and copy the export statements to your ~/.bash_profile -2. Download Go from http://golang.org/dl/ +2. Download Go (version 1.4.2) from http://golang.org/dl/ 3. Set up your Go workspace 1. `mkdir ~/go` 2. Add the following to your ~/.bash_profile @@ -28,7 +28,7 @@ Developer Machine Setup `cd ~/go` `mkdir -p src/github.com/mattermost` `cd src/github.com/mattermost` - `git clone github.com/mattermost/platform.git` + `git clone https://github.com/mattermost/platform.git` `cd platform` 7. Run unit tests on Mattermost using `make test` to make sure the installation was successful 8. If tests passed, you can now run Mattermost using `make run` @@ -50,7 +50,7 @@ Any issues? Please let us know on our forums at: http://forum.mattermost.org `127.0.0.1 dockerhost` 3. Install build essentials 1. `apt-get install build-essential` -4. Download Go from http://golang.org/dl/ +4. Download Go (version 1.4.2) from http://golang.org/dl/ 5. Set up your Go workspace and add Go to the PATH 1. `mkdir ~/go` 2. Add the following to your ~/.bashrc @@ -74,7 +74,7 @@ Any issues? Please let us know on our forums at: http://forum.mattermost.org `cd ~/go` `mkdir -p src/github.com/mattermost` `cd src/github.com/mattermost` - `git clone github.com/mattermost/platform.git` + `git clone https://github.com/mattermost/platform.git` `cd platform` 9. Run unit tests on Mattermost using `make test` to make sure the installation was successful 10. If tests passed, you can now run Mattermost using `make run` -- cgit v1.2.3-1-g7c22 From 9b22cf31f1de925ff7905bba5b302c4f5bc08000 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 11 Sep 2015 10:18:08 -0400 Subject: PLT-198 Removes invalid emails from tests that require valid email addresses --- utils/textgeneration.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/utils/textgeneration.go b/utils/textgeneration.go index 043d7bb8a..6d353cc24 100644 --- a/utils/textgeneration.go +++ b/utils/textgeneration.go @@ -141,17 +141,14 @@ var FUZZY_STRINGS_NAMES = []string{ // Strings that should pass as acceptable emails var FUZZY_STRINGS_EMAILS = []string{ "sue@thatmightbe", - "sue@thatmightbe.", "sue@thatmightbe.c", "sue@thatmightbe.co", "su+san@thatmightbe.com", - "a@b.中国", "1@2.am", "a@b.co.uk", "a@b.cancerresearch", "su+s+an@thatmightbe.com", "per.iod@thatmightbe.com", - "per..iods@thatmightbe.com", } // Lovely giberish for all to use -- cgit v1.2.3-1-g7c22 From 3edb4247e96bc4e203200a4cafe42bfcf0661299 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 11 Sep 2015 10:43:33 -0400 Subject: PLT-198 Added a small delay to one of the web tests to allow the server to get fully set up --- web/web_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/web/web_test.go b/web/web_test.go index ff37b74d5..ccd0bba56 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -36,9 +36,14 @@ func TearDown() { func TestStatic(t *testing.T) { Setup() - resp, _ := http.Get(URL + "/static/images/favicon.ico") + // add a short delay to make sure the server is ready to receive requests + time.Sleep(1 * time.Second) - if resp.StatusCode != http.StatusOK { + resp, err := http.Get(URL + "/static/images/favicon.ico") + + if err != nil { + t.Fatalf("got error while trying to get static files %v", err) + } else if resp.StatusCode != http.StatusOK { t.Fatalf("couldn't get static files %v", resp.StatusCode) } } -- cgit v1.2.3-1-g7c22 From 9a9f2808d6c40f6a661e7f75255ae0951e0615e2 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Fri, 11 Sep 2015 09:09:05 -0700 Subject: Fixing help text based on feedback --- mattermost.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mattermost.go b/mattermost.go index 08963f016..499abcd92 100644 --- a/mattermost.go +++ b/mattermost.go @@ -328,9 +328,9 @@ Usage: Example: platform -create_user -team_name="name" -email="user@example.com" -password="mypassword" - -assign_role Assigns role to a user. It requres the -team_name, - -email and -role flag. If you're assigning the - "system_admin" role it must be for a user on the + -assign_role Assigns role to a user. It requres the -role, + -email and -team_name flag. If you're assigning the + role="system_admin" role it must be for a user on the team_name="admin" Example: platform -assign_role -team_name="name" -email="user@example.com" -role="admin" -- cgit v1.2.3-1-g7c22 From ab6196b158786a56f80cf0d2520b63c58a31639a Mon Sep 17 00:00:00 2001 From: lfbrock Date: Fri, 11 Sep 2015 12:38:10 -0400 Subject: Updated developer install instructions --- doc/install/dev-setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/dev-setup.md b/doc/install/dev-setup.md index 6d26cbd33..b90b6a351 100644 --- a/doc/install/dev-setup.md +++ b/doc/install/dev-setup.md @@ -22,8 +22,8 @@ Developer Machine Setup 1. Download Homebrew from http://brew.sh/ 2. `brew install node` 5. Install Compass - 1. Make sure you have the latest verison of Ruby - 2. `gem install compass` + 1. Run `ruby -v` and check the ruby version is 1.8.7 or higher + 2. `sudo gem install compass` 6. Download Mattermost `cd ~/go` `mkdir -p src/github.com/mattermost` -- cgit v1.2.3-1-g7c22 From e5e88d16049f4527eaab6b066c731fbe4247b574 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Fri, 11 Sep 2015 09:39:28 -0700 Subject: Renaming ROLE_ADMIN to ROLE_TEAM_ADMIN --- api/channel.go | 6 +++--- api/context.go | 2 +- api/post.go | 2 +- api/team.go | 6 +++--- api/user.go | 14 +++++++------- api/user_test.go | 2 +- model/user.go | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/api/channel.go b/api/channel.go index b40366719..63acaa8d1 100644 --- a/api/channel.go +++ b/api/channel.go @@ -191,7 +191,7 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !strings.Contains(channelMember.Roles, model.CHANNEL_ROLE_ADMIN) && !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) { + if !strings.Contains(channelMember.Roles, model.CHANNEL_ROLE_ADMIN) && !strings.Contains(c.Session.Roles, model.ROLE_TEAM_ADMIN) { c.Err = model.NewAppError("updateChannel", "You do not have the appropriate permissions", "") c.Err.StatusCode = http.StatusForbidden return @@ -514,7 +514,7 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !strings.Contains(channelMember.Roles, model.CHANNEL_ROLE_ADMIN) && !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) { + if !strings.Contains(channelMember.Roles, model.CHANNEL_ROLE_ADMIN) && !strings.Contains(c.Session.Roles, model.ROLE_TEAM_ADMIN) { c.Err = model.NewAppError("deleteChannel", "You do not have the appropriate permissions", "") c.Err.StatusCode = http.StatusForbidden return @@ -756,7 +756,7 @@ func removeChannelMember(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !strings.Contains(channelMember.Roles, model.CHANNEL_ROLE_ADMIN) && !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) { + if !strings.Contains(channelMember.Roles, model.CHANNEL_ROLE_ADMIN) && !strings.Contains(c.Session.Roles, model.ROLE_TEAM_ADMIN) { c.Err = model.NewAppError("updateChannel", "You do not have the appropriate permissions ", "") c.Err.StatusCode = http.StatusForbidden return diff --git a/api/context.go b/api/context.go index 1852ed4d6..8e5becda7 100644 --- a/api/context.go +++ b/api/context.go @@ -298,7 +298,7 @@ func (c *Context) IsTeamAdmin(userId string) bool { return false } else { user := uresult.Data.(*model.User) - return model.IsInRole(c.Session.Roles, model.ROLE_ADMIN) && user.TeamId == c.Session.TeamId + return model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) && user.TeamId == c.Session.TeamId } } diff --git a/api/post.go b/api/post.go index f969dd031..bd31e0210 100644 --- a/api/post.go +++ b/api/post.go @@ -716,7 +716,7 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) { return } - if post.UserId != c.Session.UserId && !model.IsInRole(c.Session.Roles, model.ROLE_ADMIN) { + if post.UserId != c.Session.UserId && !model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) { c.Err = model.NewAppError("deletePost", "You do not have the appropriate permissions", "") c.Err.StatusCode = http.StatusForbidden return diff --git a/api/team.go b/api/team.go index 9288b86cb..8258fa929 100644 --- a/api/team.go +++ b/api/team.go @@ -477,7 +477,7 @@ func InviteMembers(c *Context, team *model.Team, user *model.User, invites []str sender := user.GetDisplayName() senderRole := "" - if model.IsInRole(user.Roles, model.ROLE_ADMIN) || model.IsInRole(user.Roles, model.ROLE_SYSTEM_ADMIN) { + if model.IsInRole(user.Roles, model.ROLE_TEAM_ADMIN) || model.IsInRole(user.Roles, model.ROLE_SYSTEM_ADMIN) { senderRole = "administrator" } else { senderRole = "member" @@ -536,7 +536,7 @@ func updateTeamDisplayName(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !model.IsInRole(c.Session.Roles, model.ROLE_ADMIN) { + if !model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) { c.Err = model.NewAppError("updateTeamDisplayName", "You do not have the appropriate permissions", "userId="+c.Session.UserId) c.Err.StatusCode = http.StatusForbidden return @@ -576,7 +576,7 @@ func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !model.IsInRole(c.Session.Roles, model.ROLE_ADMIN) { + if !model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) { c.Err = model.NewAppError("updateValetFeature", "You do not have the appropriate permissions", "userId="+c.Session.UserId) c.Err.StatusCode = http.StatusForbidden return diff --git a/api/user.go b/api/user.go index f32bbbe13..c87b89c7a 100644 --- a/api/user.go +++ b/api/user.go @@ -170,7 +170,7 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User { channelRole := "" if team.Email == user.Email { - user.Roles = model.ROLE_ADMIN + user.Roles = model.ROLE_TEAM_ADMIN channelRole = model.CHANNEL_ROLE_ADMIN } else { user.Roles = "" @@ -945,7 +945,7 @@ func updateRoles(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !model.IsInRole(c.Session.Roles, model.ROLE_ADMIN) && !c.IsSystemAdmin() { + if !model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) && !c.IsSystemAdmin() { c.Err = model.NewAppError("updateRoles", "You do not have the appropriate permissions", "userId="+user_id) c.Err.StatusCode = http.StatusForbidden return @@ -984,7 +984,7 @@ func UpdateRoles(c *Context, user *model.User, roles string) *model.User { // make sure there is at least 1 other active admin if !model.IsInRole(roles, model.ROLE_SYSTEM_ADMIN) { - if model.IsInRole(user.Roles, model.ROLE_ADMIN) && !model.IsInRole(roles, model.ROLE_ADMIN) { + if model.IsInRole(user.Roles, model.ROLE_TEAM_ADMIN) && !model.IsInRole(roles, model.ROLE_TEAM_ADMIN) { if result := <-Srv.Store.User().GetProfiles(user.TeamId); result.Err != nil { c.Err = result.Err return nil @@ -992,7 +992,7 @@ func UpdateRoles(c *Context, user *model.User, roles string) *model.User { activeAdmins := -1 profileUsers := result.Data.(map[string]*model.User) for _, profileUser := range profileUsers { - if profileUser.DeleteAt == 0 && model.IsInRole(profileUser.Roles, model.ROLE_ADMIN) { + if profileUser.DeleteAt == 0 && model.IsInRole(profileUser.Roles, model.ROLE_TEAM_ADMIN) { activeAdmins = activeAdmins + 1 } } @@ -1042,14 +1042,14 @@ func updateActive(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !model.IsInRole(c.Session.Roles, model.ROLE_ADMIN) && !c.IsSystemAdmin() { + if !model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) && !c.IsSystemAdmin() { c.Err = model.NewAppError("updateActive", "You do not have the appropriate permissions", "userId="+user_id) c.Err.StatusCode = http.StatusForbidden return } // make sure there is at least 1 other active admin - if !active && model.IsInRole(user.Roles, model.ROLE_ADMIN) { + if !active && model.IsInRole(user.Roles, model.ROLE_TEAM_ADMIN) { if result := <-Srv.Store.User().GetProfiles(user.TeamId); result.Err != nil { c.Err = result.Err return @@ -1057,7 +1057,7 @@ func updateActive(c *Context, w http.ResponseWriter, r *http.Request) { activeAdmins := -1 profileUsers := result.Data.(map[string]*model.User) for _, profileUser := range profileUsers { - if profileUser.DeleteAt == 0 && model.IsInRole(profileUser.Roles, model.ROLE_ADMIN) { + if profileUser.DeleteAt == 0 && model.IsInRole(profileUser.Roles, model.ROLE_TEAM_ADMIN) { activeAdmins = activeAdmins + 1 } } diff --git a/api/user_test.go b/api/user_test.go index 8c037fdf3..fe5a4a27f 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -509,7 +509,7 @@ func TestUserUpdate(t *testing.T) { user.TeamId = "12345678901234567890123456" user.LastActivityAt = time2 user.LastPingAt = time2 - user.Roles = model.ROLE_ADMIN + user.Roles = model.ROLE_TEAM_ADMIN user.LastPasswordUpdate = 123 if result, err := Client.UpdateUser(user); err != nil { diff --git a/model/user.go b/model/user.go index 1a169f763..fdc519b99 100644 --- a/model/user.go +++ b/model/user.go @@ -13,7 +13,7 @@ import ( ) const ( - ROLE_ADMIN = "admin" + ROLE_TEAM_ADMIN = "admin" ROLE_SYSTEM_ADMIN = "system_admin" USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute @@ -289,7 +289,7 @@ func isValidRole(role string) bool { return true } - if role == ROLE_ADMIN { + if role == ROLE_TEAM_ADMIN { return true } -- cgit v1.2.3-1-g7c22 From 560805321b85b61b98f064ff6d4fa34195686f18 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Fri, 11 Sep 2015 12:46:18 -0400 Subject: Change versioning to exact versions in package.json --- web/react/package.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/web/react/package.json b/web/react/package.json index da55dc2b8..e55722152 100644 --- a/web/react/package.json +++ b/web/react/package.json @@ -3,22 +3,22 @@ "version": "0.0.1", "private": true, "dependencies": { - "autolinker": "^0.18.1", - "flux": "^2.1.1", - "keymirror": "^0.1.1", - "object-assign": "^3.0.0", - "react": "^0.13.3", - "react-zeroclipboard-mixin": "^0.1.0", - "twemoji": "^1.4.1" + "autolinker": "0.18.1", + "flux": "2.1.1", + "keymirror": "0.1.1", + "object-assign": "3.0.0", + "react": "0.13.3", + "react-zeroclipboard-mixin": "0.1.0", + "twemoji": "1.4.1" }, "devDependencies": { - "browserify": "^11.0.1", - "envify": "^3.4.0", - "babelify": "^6.1.3", - "uglify-js": "^2.4.24", - "watchify": "^3.3.1", - "eslint": "^1.3.1", - "eslint-plugin-react": "^3.3.1" + "browserify": "11.0.1", + "envify": "3.4.0", + "babelify": "6.1.3", + "uglify-js": "2.4.24", + "watchify": "3.3.1", + "eslint": "1.3.1", + "eslint-plugin-react": "3.3.1" }, "scripts": { "start": "watchify --extension=jsx -o ../static/js/bundle.js -v -d ./**/*.jsx", -- cgit v1.2.3-1-g7c22 From efca6fb463f0c9d1f8caf22c9ebb79afaeeb0429 Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 12 Sep 2015 00:14:48 -0700 Subject: Fixed broken links in doc/README.md --- doc/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/README.md b/doc/README.md index 36d16b744..c9262eb9c 100644 --- a/doc/README.md +++ b/doc/README.md @@ -16,9 +16,9 @@ ### Configuration - [GitLab SSO Configuration](integrations/sso/gitlab-sso.md) -- [SMTP Email Setup](smtp-email-setup.md) +- [SMTP Email Setup](config/smtp-email-setup.md) ## Developer Documentation -- [Developer Machine Setup](doc/install/dev-setup.md) +- [Developer Machine Setup](install/dev-setup.md) - [Mattermost Style Guide](developer/style-guide.md) -- cgit v1.2.3-1-g7c22 From 3d597905fb13210e6777f95df92bc147ca156793 Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 12 Sep 2015 00:43:03 -0700 Subject: Create code-contribution.md --- doc/developer/code-contribution.md | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 doc/developer/code-contribution.md diff --git a/doc/developer/code-contribution.md b/doc/developer/code-contribution.md new file mode 100644 index 000000000..1a6537287 --- /dev/null +++ b/doc/developer/code-contribution.md @@ -0,0 +1,44 @@ +# Code Contribution Guidelines + +Thank you for your interest in contributing to Mattermost. This guide provides an overview of important information for contributors to know. + +## Choose a Ticket + +1. Review the list of [Good First Contribution](https://mattermost.atlassian.net/issues/?filter=10206) tickets listed in Jira. + +2. These projects are intended to be a straight forward first pull requests from new contributors. +If you don't find something appropriate for your interests, please see the full list of tickets [Accepting Pull Requests](https://mattermost.atlassian.net/issues/?filter=10101). + +3. If you have any questions at all about a ticket, please post to the [Contributor Discussion section](http://forum.mattermost.org/) of the Mattermost forum, or email the [Mattermost Developer Mailing list](https://groups.google.com/a/mattermost.com/forum/#!forum/developer/join). + +## Install Mattermost and set up a Fork + +1. Follow [developer setup instructions](https://github.com/mattermost/platform/blob/master/doc/install/dev-setup.md) to install Mattermost. + +2. Create a branch with set to the ID of the ticket you're working on, for example ```PLT-394```, using command: + +``` +git checkout -b +``` + +## Programming and Testing + +1. Please review the [Mattermost Style Guide](developer/style-guide.md) prior to making changes. + +2. Please make sure to thoroughly test your change before submitting a pull request. + +## Submitting a Pull Request + +1. Please add yourself to the contributor list prior to submitting by completing the [contributor license agreement](http://www.mattermost.org/mattermost-contributor-agreement/). + +2. When you submit your pull request please include the Ticket ID at the beginning of your pull request comment, followed by a colon. + + For example, for a ticket ID `PLT-394` start your comment with: `PLT-394:`. See [previously closed pull requests](https://github.com/mattermost/platform/pulls?q=is%3Apr+is%3Aclosed) for examples. + +3. Once submitted, your pull request will be checked via an automated build process and will be reviewed by the Mattermost core team, who may either accept the PR or follow-up with feedback. + +4. If you've included your mailing address in Step 1, you'll be receiving a [Limited Edition Mattermost Mug](http://forum.mattermost.org/t/limited-edition-mattermost-mugs/143) as a thank you gift after your first pull request has been accepted. + + + + -- cgit v1.2.3-1-g7c22 From 186bb7d23910c61532f4acac4c3f35dab3246804 Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 12 Sep 2015 00:57:47 -0700 Subject: Update CHANGELOG with info on recent commits --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5876dc894..7aac49ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ Documentation - Updated software and hardware requirements documentation - Re-organized install instructions out of README and into separate files +- Added Code Contribution Guidelines +- Added new hardware sizing recommendations - Consolidated licensing information into LICENSE.txt and NOTICE.txt Performance @@ -33,7 +35,8 @@ Code Quality ### Bug Fixes -- Fixed performance issue with slow typing on iOS +- Fixed performance issue with slow typing on iOS +- Fixed issue so that SSO option automatically set EmailVerified=true (it was false previously) ### Contributors -- cgit v1.2.3-1-g7c22 From 27e59c32f933e6b52a01a73b774e6b0ade0d1d4d Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 11 Sep 2015 12:11:10 -0400 Subject: Set default Content-Type to application/json for all API requests --- api/context.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/context.go b/api/context.go index aaf304e2c..ac5dbc7ec 100644 --- a/api/context.go +++ b/api/context.go @@ -106,6 +106,9 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !h.isApi { w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("Content-Security-Policy", "frame-ancestors none") + } else { + // All api response bodies will be JSON formatted + w.Header().Set("Content-Type", "application/json") } sessionId := "" -- cgit v1.2.3-1-g7c22 From 465aa135047c030e5023e064d805936ee6d8912c Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 12 Sep 2015 09:09:15 -0700 Subject: Adding "Get Involved" section to README --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index 3c9d5d408..8cbddc1c6 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,38 @@ Prior to production installation, please review [Mattermost system requirements] - [GitLab Mattermost Production Installation](https://gitlab.com/gitlab-org/gitlab-mattermost) - Install Mattermost for production environments bundled with GitLab, a leading open source Git repository, using an omnibus package for Ubuntu 12.04, Ubuntu 14.04, Debian 7, Debian 8, and CentOS 6 (and RedHat/Oracle/Scientific Linux 6), CentOS 7 (and RedHat/Oracle/Scientific Linux 7). For technical questions and answers, please visit the [Mattermost forum](http://forum.mattermost.org). + +## Get Involved with Mattermost + +Joining the Mattermost community is a great way to build relationships with other talented and like-minded professionals, increase awareness of the interesting work you are doing, and sharpen your skills. Here are some of the ways that you can make a difference in the Mattermost ecosystem: + +#### Discuss + +- Visit the [Mattermost Forum](http://forum.mattermost.org/) for technical questions and answers. +- [Join](https://groups.google.com/a/mattermost.com/forum/#!forum/general/join) the [Mattermost User Mailing List](https://groups.google.com/a/mattermost.com/forum/#!forum/general) for general, open-ended questions and software announcements. +- [Join](https://groups.google.com/a/mattermost.com/forum/#!forum/developer/join) the [Mattermost Developers Mailing List](https://groups.google.com/a/mattermost.com/forum/#!forum/developer) for discussing contributing code to Mattermost. + +#### Review + +- Share feedback on [Mattermost Design Feedback Requests](http://forum.mattermost.org/c/feature-ideas/specifications), which offer early previews of designs community comments and feedback. +- Visit the [Feature Ideas Forum](http://mattermost.uservoice.com/forums/306457-general) and consider upvoting community feature ideas, which are reviewed for each monthly release. + +#### Share + +- Blog about your Mattermost experiences and use cases, either on your personal blog, the [Mattermost forum](http://forum.mattermost.org), or contribute a guest post to the [Mattermost blog](http://www.mattermost.org/category/blog/). If you write about Mattermost. please contact our community team at info@mattermost.com for help promoting your content. +- Tweet to share with your community and friends why you use Mattermost. Follow [@MattermostHQ](https://twitter.com/mattermosthq) on Twitter and conversations on [#mattermost](https://twitter.com/search?q=%23mattermost&src=typd). + +#### Write + +- As with most open source projects, Mattermost documentation is maintained in a public repository. You can propose changes by [submitting pull requests (no programming skills required)](http://forum.mattermost.org/t/help-improve-mattermost-documentation/194). We highly welcome you to add improvements, write guides and tutorials, and expand on sections. +- Prior to contributing, please review [Mattermost Documentation Guidelines](http://www.mattermost.org/documentation-guidelines/), which include standards on writing Mattermost documentation for a global audience, who might not use English as their first language. + +#### Contribute + +- Share [feature ideas](http://www.mattermost.org/feature-requests/) with the Mattermost community +- Review the [Mattermost Code Contribution Guidelines](doc/developer/code-contribution.md) to submit patches for the core product +- Consider building tools that help developers and IT professionals manage Mattermost more effectively (API documentation coming in Beta2) + +#### Have other ideas or suggestions? + +If there’s some other way you’d like to contribute, please contact us at info@mattermost.com. We’d love to meet you! -- cgit v1.2.3-1-g7c22 From 18858f4c7968f9246bfc90eb2ba72c3079e297a7 Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 12 Sep 2015 09:14:28 -0700 Subject: Link Code Contribution Guidelines from TOC --- doc/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/README.md b/doc/README.md index c9262eb9c..491c75b9b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -20,5 +20,6 @@ ## Developer Documentation +- [Code Contribution Guidelines](developer/code-contribution.md) - [Developer Machine Setup](install/dev-setup.md) - [Mattermost Style Guide](developer/style-guide.md) -- cgit v1.2.3-1-g7c22 From f3798a983d161d25601fd0eb7830355151e2a67f Mon Sep 17 00:00:00 2001 From: it33 Date: Sat, 12 Sep 2015 11:09:29 -0700 Subject: Removing "Alpha" from Docker Hub README --- docker/dev/README.md | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/docker/dev/README.md b/docker/dev/README.md index a4b6fb9bb..f737a1554 100644 --- a/docker/dev/README.md +++ b/docker/dev/README.md @@ -1,28 +1,13 @@ -**Mattermost Alpha** -**Team Communication Service** -**Development Build** +Mattermost +========== - -About Mattermost -================ +http:/mattermost.org Mattermost is an open-source team communication service. It brings team messaging and file sharing into one place, accessible across PCs and phones, with archiving and search. - - Installing Mattermost ===================== -You're installing "Mattermost Alpha", a pre-released version providing an early look at what we're building. While the core team runs this version internally, it's not recommended for production since we can't guarantee API stability or backwards compatibility. - -That said, any issues at all, please let us know on the Mattermost forum. - -Notes: -- For Alpha, Docker is intentionally setup as a single container, since production deployment is not yet recommended. - -Local Machine Setup (Docker) ------------------------------ - To run an instance of the latest version of mattermost on your local machine you can run: `docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform` @@ -35,9 +20,4 @@ To run an instance of the latest code from the master branch on GitHub you can r `docker run --name mattermost-dev -d --publish 8065:80 mattermost/platform:dev` - -License -------- - -Mattermost is licensed under an "Apache-wrapped AGPL" model inspired by MongoDB. Similar to MongoDB, you can run and link to the system using Configuration Files and Admin Tools licensed under Apache, version 2.0, as described in the LICENSE file, as an explicit exception to the terms of the GNU Affero General Public License (AGPL) that applies to most of the remaining source files. See individual files for details. - +Any questions, please visit http://forum.mattermost.org -- cgit v1.2.3-1-g7c22 From 543ce8b4bea6f432ae26846d2f1de8b5f330df83 Mon Sep 17 00:00:00 2001 From: nickago Date: Sat, 12 Sep 2015 18:07:04 -0700 Subject: WIP Added base video player --- web/react/components/view_image.jsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx index b0eaba5d6..8d3495e3b 100644 --- a/web/react/components/view_image.jsx +++ b/web/react/components/view_image.jsx @@ -105,6 +105,14 @@ export default class ViewImageModal extends React.Component { this.loadImage(this.state.imgId); }.bind(this)); + $('#' + this.props.modalId).on('hidden.bs.modal', function onModalHide() { + if (this.refs.video) { + var video = React.findDOMNode(this.refs.video); + video.pause(); + video.currentTime = 0; + } + }.bind(this)); + $(React.findDOMNode(this.refs.modal)).click(function onModalClick(e) { if (e.target === this || e.target === React.findDOMNode(this.refs.imageBody)) { $('.image_modal').modal('hide'); @@ -211,6 +219,16 @@ export default class ViewImageModal extends React.Component { /> ); + } else if (fileType === 'video' || fileType === 'audio') { + content = ( + + ); } else { // non-image files include a section providing details about the file var infoString = 'File type ' + fileInfo.ext.toUpperCase(); -- cgit v1.2.3-1-g7c22 From d707de14d785688cf114f85bd19da9070b1196e2 Mon Sep 17 00:00:00 2001 From: it33 Date: Sun, 13 Sep 2015 07:27:58 -0700 Subject: Updating MaxUsersPerTeam error msg This message is displayed to a person attempting to sign-up for a new team, and "You've reached the limit" phrasing is confusing because it refers to the team, not the person signing up for the team. --- store/sql_user_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/sql_user_store.go b/store/sql_user_store.go index be1d29df0..52d670d56 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -74,7 +74,7 @@ func (us SqlUserStore) Save(user *model.User) StoreChannel { close(storeChannel) return } else if int(count) > utils.Cfg.TeamSettings.MaxUsersPerTeam { - result.Err = model.NewAppError("SqlUserStore.Save", "You've reached the limit of the number of allowed accounts.", "teamId="+user.TeamId) + result.Err = model.NewAppError("SqlUserStore.Save", "This team has reached the maxmium number of allowed accounts. Contact your systems administrator to set a higher limit.", "teamId="+user.TeamId) storeChannel <- result close(storeChannel) return -- cgit v1.2.3-1-g7c22 From 45b859ca7485d84ecb6daf110c7f089be197cf4c Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Mon, 14 Sep 2015 14:19:31 +0500 Subject: PLT-217 - Improving horizontal scrollbar in LHS menu --- web/sass-files/sass/partials/_headers.scss | 2 ++ web/sass-files/sass/partials/_sidebar--left.scss | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index c311941b6..e83981397 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -145,6 +145,8 @@ li a { padding: 3px 20px; color: #555; + text-overflow: ellipsis; + overflow: hidden; } } .dropdown__icon { diff --git a/web/sass-files/sass/partials/_sidebar--left.scss b/web/sass-files/sass/partials/_sidebar--left.scss index 63426dae9..e5faff9f8 100644 --- a/web/sass-files/sass/partials/_sidebar--left.scss +++ b/web/sass-files/sass/partials/_sidebar--left.scss @@ -12,7 +12,10 @@ } .dropdown-menu { max-height: 300px; - overflow: auto; + overflow-x: hidden; + overflow-y: auto; + max-width: 200px; + width: 200px; } .search__form { margin: 0; -- cgit v1.2.3-1-g7c22 From ffbe185d827aaaefb2c5ca9067980eb99b9d53b9 Mon Sep 17 00:00:00 2001 From: Michael Leer Date: Mon, 14 Sep 2015 14:54:36 +0100 Subject: PLT-41 Automatically convert uppercase letters to lowercase in username input box. Validator not changed. --- web/react/components/team_signup_username_page.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/react/components/team_signup_username_page.jsx b/web/react/components/team_signup_username_page.jsx index b5c8b14df..984c7afab 100644 --- a/web/react/components/team_signup_username_page.jsx +++ b/web/react/components/team_signup_username_page.jsx @@ -22,7 +22,7 @@ export default class TeamSignupUsernamePage extends React.Component { submitNext(e) { e.preventDefault(); - var name = React.findDOMNode(this.refs.name).value.trim(); + var name = React.findDOMNode(this.refs.name).value.trim().toLowerCase(); var usernameError = Utils.isValidUsername(name); if (usernameError === 'Cannot use a reserved word as a username.') { -- cgit v1.2.3-1-g7c22 From 5fbd1e98601f2a52c0b72d9559dec7a41db7f84a Mon Sep 17 00:00:00 2001 From: Michael Leer Date: Mon, 14 Sep 2015 15:15:48 +0100 Subject: PLT-41 Removed lowercase from the error wording. Removed additional toLowerCase within validator. --- web/react/utils/utils.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 71cd1d344..879f68689 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -828,11 +828,11 @@ export function isValidUsername(name) { } else if (name.length < 3 || name.length > 15) { error = 'Must be between 3 and 15 characters'; } else if (!(/^[a-z0-9\.\-\_]+$/).test(name)) { - error = "Must contain only lowercase letters, numbers, and the symbols '.', '-', and '_'."; + error = "Must contain only letters, numbers, and the symbols '.', '-', and '_'."; } else if (!(/[a-z]/).test(name.charAt(0))) { error = 'First character must be a letter.'; } else { - var lowerName = name.toLowerCase().trim(); + var lowerName = name; for (var i = 0; i < Constants.RESERVED_USERNAMES.length; i++) { if (lowerName === Constants.RESERVED_USERNAMES[i]) { -- cgit v1.2.3-1-g7c22 From 90ef55b4284e654ecae614b8d3b0c59bfba95b3b Mon Sep 17 00:00:00 2001 From: Michael Leer Date: Mon, 14 Sep 2015 16:10:31 +0100 Subject: replace lowerName with name --- web/react/utils/utils.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 879f68689..54d05f484 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -832,10 +832,8 @@ export function isValidUsername(name) { } else if (!(/[a-z]/).test(name.charAt(0))) { error = 'First character must be a letter.'; } else { - var lowerName = name; - for (var i = 0; i < Constants.RESERVED_USERNAMES.length; i++) { - if (lowerName === Constants.RESERVED_USERNAMES[i]) { + if (name === Constants.RESERVED_USERNAMES[i]) { error = 'Cannot use a reserved word as a username.'; break; } -- cgit v1.2.3-1-g7c22 From 7b3c2d6d85ecee86fbc85b440e7028018b1090b1 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 14 Sep 2015 12:04:57 -0400 Subject: Allowing underscores in channel names. Added conversion of some slack channel names into valid mattermost names. --- api/slackimport.go | 11 ++++++++++- model/team.go | 2 +- model/utils.go | 12 +++++++++--- web/react/components/team_import_tab.jsx | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/api/slackimport.go b/api/slackimport.go index 1d037a934..4e6c01dbb 100644 --- a/api/slackimport.go +++ b/api/slackimport.go @@ -50,6 +50,15 @@ func SlackConvertTimeStamp(ts string) int64 { return timeStamp * 1000 // Convert to milliseconds } +func SlackConvertChannelName(channelName string) string { + newName := strings.Trim(channelName, "_-") + if len(newName) == 1 { + return "slack-channel-" + newName + } + + return newName +} + func SlackParseChannels(data io.Reader) []SlackChannel { decoder := json.NewDecoder(data) @@ -172,7 +181,7 @@ func SlackAddChannels(teamId string, slackchannels []SlackChannel, posts map[str TeamId: teamId, Type: model.CHANNEL_OPEN, DisplayName: sChannel.Name, - Name: sChannel.Name, + Name: SlackConvertChannelName(sChannel.Name), Description: sChannel.Topic["value"], } mChannel := ImportChannel(&newChannel) diff --git a/model/team.go b/model/team.go index 6006f738c..8b4f82830 100644 --- a/model/team.go +++ b/model/team.go @@ -158,7 +158,7 @@ func IsReservedTeamName(s string) bool { func IsValidTeamName(s string) bool { - if !IsValidAlphaNum(s) { + if !IsValidAlphaNum(s, false) { return false } diff --git a/model/utils.go b/model/utils.go index 17d1c6317..d5122e805 100644 --- a/model/utils.go +++ b/model/utils.go @@ -202,7 +202,7 @@ func GetSubDomain(s string) (string, string) { func IsValidChannelIdentifier(s string) bool { - if !IsValidAlphaNum(s) { + if !IsValidAlphaNum(s, true) { return false } @@ -213,10 +213,16 @@ func IsValidChannelIdentifier(s string) bool { return true } +var validAlphaNumUnderscore = regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`) var validAlphaNum = regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`) -func IsValidAlphaNum(s string) bool { - match := validAlphaNum.MatchString(s) +func IsValidAlphaNum(s string, allowUnderscores bool) bool { + var match bool + if allowUnderscores { + match = validAlphaNumUnderscore.MatchString(s) + } else { + match = validAlphaNum.MatchString(s) + } if !match { return false diff --git a/web/react/components/team_import_tab.jsx b/web/react/components/team_import_tab.jsx index 031abc36a..8315430e4 100644 --- a/web/react/components/team_import_tab.jsx +++ b/web/react/components/team_import_tab.jsx @@ -35,7 +35,7 @@ export default class TeamImportTab extends React.Component { var uploadHelpText = (

{'Slack does not allow you to export files, images, private groups or direct messages stored in Slack. Therefore, Slack import to Mattermost only supports importing of text messages in your Slack team\'\s public channels.'}

-

{'The Slack import to Mattermost is in "Preview". Slack bot posts and channels with underscores do not yet import.'}

+

{'The Slack import to Mattermost is in "Preview". Slack bot posts do not yet import.'}

); -- cgit v1.2.3-1-g7c22 From 0ea0233c50dbccc498cb53481b9fdf18d027e5b2 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 14 Sep 2015 13:56:58 -0400 Subject: New add channel modal using react-bootstrap. --- Makefile | 10 +- web/react/.eslintrc | 3 +- web/react/components/change_url_modal.jsx | 177 + web/react/components/file_upload.jsx | 2 +- web/react/components/new_channel.jsx | 211 - web/react/components/new_channel_flow.jsx | 206 + web/react/components/new_channel_modal.jsx | 198 + web/react/components/sidebar.jsx | 24 +- web/react/package.json | 1 - web/react/pages/channel.jsx | 6 - web/react/utils/utils.jsx | 11 + web/sass-files/sass/partials/_forms.scss | 33 + web/sass-files/sass/styles.scss | 1 + web/static/css/bootstrap-3.3.1.css | 6332 ------- web/static/css/bootstrap-3.3.1.min.css | 5 - web/static/css/bootstrap-3.3.5.css | 6800 ++++++++ web/static/css/bootstrap-3.3.5.min.css | 5 + web/static/js/bootstrap-3.3.1.js | 2320 --- web/static/js/bootstrap-3.3.1.min.js | 7 - web/static/js/bootstrap-3.3.5.js | 2363 +++ web/static/js/bootstrap-3.3.5.min.js | 7 + web/static/js/jasny-bootstrap.js | 1024 ++ web/static/js/jasny-bootstrap.min.js | 6 + web/static/js/react-bootstrap-0.25.1.js | 15678 +++++++++++++++++ web/static/js/react-bootstrap-0.25.1.min.js | 14 + web/static/js/react-with-addons-0.13.1.js | 21574 ----------------------- web/static/js/react-with-addons-0.13.1.min.js | 16 - web/static/js/react-with-addons-0.13.3.js | 21642 ++++++++++++++++++++++++ web/static/js/react-with-addons-0.13.3.min.js | 18 + web/templates/head.html | 7 +- 30 files changed, 48212 insertions(+), 30489 deletions(-) create mode 100644 web/react/components/change_url_modal.jsx delete mode 100644 web/react/components/new_channel.jsx create mode 100644 web/react/components/new_channel_flow.jsx create mode 100644 web/react/components/new_channel_modal.jsx create mode 100644 web/sass-files/sass/partials/_forms.scss delete mode 100644 web/static/css/bootstrap-3.3.1.css delete mode 100644 web/static/css/bootstrap-3.3.1.min.css create mode 100644 web/static/css/bootstrap-3.3.5.css create mode 100644 web/static/css/bootstrap-3.3.5.min.css delete mode 100644 web/static/js/bootstrap-3.3.1.js delete mode 100644 web/static/js/bootstrap-3.3.1.min.js create mode 100644 web/static/js/bootstrap-3.3.5.js create mode 100644 web/static/js/bootstrap-3.3.5.min.js create mode 100644 web/static/js/jasny-bootstrap.js create mode 100644 web/static/js/jasny-bootstrap.min.js create mode 100644 web/static/js/react-bootstrap-0.25.1.js create mode 100644 web/static/js/react-bootstrap-0.25.1.min.js delete mode 100644 web/static/js/react-with-addons-0.13.1.js delete mode 100644 web/static/js/react-with-addons-0.13.1.min.js create mode 100644 web/static/js/react-with-addons-0.13.3.js create mode 100644 web/static/js/react-with-addons-0.13.3.min.js diff --git a/Makefile b/Makefile index 305926e5b..ea9fc21d4 100644 --- a/Makefile +++ b/Makefile @@ -78,9 +78,10 @@ travis: mv $(DIST_PATH)/web/static/js/bundle.min.js $(DIST_PATH)/web/static/js/bundle-$(BUILD_NUMBER).min.js - @sed -i'.bak' 's|react-with-addons-0.13.1.js|react-with-addons-0.13.1.min.js|g' $(DIST_PATH)/web/templates/head.html + @sed -i'.bak' 's|react-with-addons-0.13.3.js|react-with-addons-0.13.3.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|jquery-1.11.1.js|jquery-1.11.1.min.js|g' $(DIST_PATH)/web/templates/head.html - @sed -i'.bak' 's|bootstrap-3.3.1.js|bootstrap-3.3.1.min.js|g' $(DIST_PATH)/web/templates/head.html + @sed -i'.bak' 's|bootstrap-3.3.5.js|bootstrap-3.3.5.min.js|g' $(DIST_PATH)/web/templates/head.html + @sed -i'.bak' 's|react-bootstrap-0.25.1.js|react-bootstrap-0.25.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|perfect-scrollbar.js|perfect-scrollbar.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|bundle.js|bundle-$(BUILD_NUMBER).min.js|g' $(DIST_PATH)/web/templates/head.html rm $(DIST_PATH)/web/templates/*.bak @@ -231,9 +232,10 @@ dist: install mv $(DIST_PATH)/web/static/js/bundle.min.js $(DIST_PATH)/web/static/js/bundle-$(BUILD_NUMBER).min.js - @sed -i'.bak' 's|react-with-addons-0.13.1.js|react-with-addons-0.13.1.min.js|g' $(DIST_PATH)/web/templates/head.html + @sed -i'.bak' 's|react-with-addons-0.13.3.js|react-with-addons-0.13.3.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|jquery-1.11.1.js|jquery-1.11.1.min.js|g' $(DIST_PATH)/web/templates/head.html - @sed -i'.bak' 's|bootstrap-3.3.1.js|bootstrap-3.3.1.min.js|g' $(DIST_PATH)/web/templates/head.html + @sed -i'.bak' 's|bootstrap-3.3.5.js|bootstrap-3.3.5.min.js|g' $(DIST_PATH)/web/templates/head.html + @sed -i'.bak' 's|react-bootstrap-0.25.1.js|react-bootstrap-0.25.1.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|perfect-scrollbar.js|perfect-scrollbar.min.js|g' $(DIST_PATH)/web/templates/head.html @sed -i'.bak' 's|bundle.js|bundle-$(BUILD_NUMBER).min.js|g' $(DIST_PATH)/web/templates/head.html rm $(DIST_PATH)/web/templates/*.bak diff --git a/web/react/.eslintrc b/web/react/.eslintrc index 53cc75913..c0d0bb200 100644 --- a/web/react/.eslintrc +++ b/web/react/.eslintrc @@ -18,7 +18,8 @@ "es6": true }, "globals": { - "React": false + "React": false, + "ReactBootstrap": false }, "rules": { "comma-dangle": [2, "never"], diff --git a/web/react/components/change_url_modal.jsx b/web/react/components/change_url_modal.jsx new file mode 100644 index 000000000..28fa70c1f --- /dev/null +++ b/web/react/components/change_url_modal.jsx @@ -0,0 +1,177 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var Modal = ReactBootstrap.Modal; +var Utils = require('../utils/utils.jsx'); + +export default class ChangeUrlModal extends React.Component { + constructor(props) { + super(props); + + this.onURLChanged = this.onURLChanged.bind(this); + this.doSubmit = this.doSubmit.bind(this); + this.doCancel = this.doCancel.bind(this); + + this.state = { + currentURL: props.currentURL, + urlError: '', + userEdit: false + }; + } + componentWillReceiveProps(nextProps) { + // This check prevents the url being deleted when we re-render + // because of user status check + if (!this.state.userEdit) { + this.setState({ + currentURL: nextProps.currentURL + }); + } + } + componentDidUpdate(prevProps) { + if (this.props.show === true && prevProps.show === false) { + React.findDOMNode(this.refs.urlinput).select(); + } + } + onURLChanged(e) { + const url = e.target.value.trim(); + this.setState({currentURL: url.replace(/[^A-Za-z0-9-_]/g, '').toLowerCase(), userEdit: true}); + } + getURLError(url) { + let error = []; //eslint-disable-line prefer-const + if (url.length < 2) { + error.push({'Must be longer than two characters'}
); + } + if (url.charAt(0) === '-' || url.charAt(0) === '_') { + error.push({'Must start with a letter or number'}
); + } + if (url.length > 1 && (url.charAt(url.length - 1) === '-' || url.charAt(url.length - 1) === '_')) { + error.push({'Must end with a letter or number'}
); + } + if (url.indexOf('__') > -1) { + error.push({'Can not contain two underscores in a row.'}
); + } + + // In case of error we don't detect + if (error.length === 0) { + error.push({'Invalid URL'}
); + } + return error; + } + doSubmit(e) { + e.preventDefault(); + + const url = React.findDOMNode(this.refs.urlinput).value; + const cleanedURL = Utils.cleanUpUrlable(url); + if (cleanedURL !== url || url.length < 2 || url.indexOf('__') > -1) { + this.setState({urlError: this.getURLError(url)}); + return; + } + this.setState({urlError: '', userEdit: false}); + this.props.onModalSubmit(url); + } + doCancel() { + this.setState({urlError: '', userEdit: false}); + this.props.onModalDismissed(); + } + render() { + let urlClass = 'input-group input-group--limit'; + let urlError = null; + let serverError = null; + + if (this.state.urlError) { + urlClass += ' has-error'; + urlError = (

{this.state.urlError}

); + } + + if (this.props.serverError) { + serverError =

{this.props.serverError}

; + } + + const fullTeamUrl = Utils.getTeamURLFromAddressBar(); + const teamURL = Utils.getShortenedTeamURL(); + + return ( + + + {this.props.title} + +
+ +
{this.props.description}
+
+ +
+
+ + {teamURL} + + +
+ {urlError} + {serverError} +
+
+
+ + + + +
+
+ ); + } +} + +ChangeUrlModal.defaultProps = { + show: false, + title: 'Change URL', + desciption: '', + urlLabel: 'URL', + submitButtonText: 'Submit', + currentURL: '', + serverError: '' +}; + +ChangeUrlModal.propTypes = { + show: React.PropTypes.bool.isRequired, + title: React.PropTypes.string, + description: React.PropTypes.string, + urlLabel: React.PropTypes.string, + submitButtonText: React.PropTypes.string, + currentURL: React.PropTypes.string, + serverError: React.PropTypes.string, + onModalSubmit: React.PropTypes.func.isRequired, + onModalDismissed: React.PropTypes.func.isRequired +}; diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx index 534f0136e..d7b6f08b0 100644 --- a/web/react/components/file_upload.jsx +++ b/web/react/components/file_upload.jsx @@ -53,7 +53,7 @@ export default class FileUpload extends React.Component { } // generate a unique id that can be used by other components to refer back to this upload - var clientId = utils.generateId(); + let clientId = utils.generateId(); // prepare data to be uploaded var formData = new FormData(); diff --git a/web/react/components/new_channel.jsx b/web/react/components/new_channel.jsx deleted file mode 100644 index 1a11fc652..000000000 --- a/web/react/components/new_channel.jsx +++ /dev/null @@ -1,211 +0,0 @@ -// 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'); - -export default class NewChannelModal extends React.Component { - constructor() { - super(); - - this.handleSubmit = this.handleSubmit.bind(this); - this.displayNameKeyUp = this.displayNameKeyUp.bind(this); - this.handleClose = this.handleClose.bind(this); - - this.state = {channelType: ''}; - } - handleSubmit(e) { - e.preventDefault(); - - var channel = {}; - var state = {serverError: ''}; - - channel.display_name = React.findDOMNode(this.refs.display_name).value.trim(); - if (!channel.display_name) { - state.displayNameError = 'This field is required'; - state.inValid = true; - } else if (channel.display_name.length > 22) { - state.displayNameError = 'This field must be less than 22 characters'; - state.inValid = true; - } else { - state.displayNameError = ''; - } - - channel.name = React.findDOMNode(this.refs.channel_name).value.trim(); - if (!channel.name) { - state.nameError = 'This field is required'; - state.inValid = true; - } else if (channel.name.length > 22) { - state.nameError = 'This field must be less than 22 characters'; - state.inValid = true; - } else { - var cleanedName = utils.cleanUpUrlable(channel.name); - if (cleanedName !== channel.name) { - state.nameError = "Must be lowercase alphanumeric characters, allowing '-' but not starting or ending with '-'"; - state.inValid = true; - } else { - state.nameError = ''; - } - } - - this.setState(state); - - if (state.inValid) { - return; - } - - var cu = UserStore.getCurrentUser(); - channel.team_id = cu.team_id; - - channel.description = React.findDOMNode(this.refs.channel_desc).value.trim(); - channel.type = this.state.channelType; - - client.createChannel(channel, - function success(data) { - $(React.findDOMNode(this.refs.modal)).modal('hide'); - - asyncClient.getChannel(data.id); - utils.switchChannel(data); - - React.findDOMNode(this.refs.display_name).value = ''; - React.findDOMNode(this.refs.channel_name).value = ''; - React.findDOMNode(this.refs.channel_desc).value = ''; - }.bind(this), - function error(err) { - state.serverError = err.message; - state.inValid = true; - this.setState(state); - }.bind(this) - ); - } - displayNameKeyUp() { - var displayName = React.findDOMNode(this.refs.display_name).value.trim(); - var channelName = utils.cleanUpUrlable(displayName); - React.findDOMNode(this.refs.channel_name).value = channelName; - } - componentDidMount() { - var self = this; - $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function onModalShow(e) { - var button = e.relatedTarget; - self.setState({channelType: $(button).attr('data-channeltype')}); - }); - $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose); - } - componentWillUnmount() { - $(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose); - } - handleClose() { - $(React.findDOMNode(this)).find('.form-control').each(function clearForms() { - this.value = ''; - }); - - this.setState({channelType: '', displayNameError: '', nameError: '', serverError: '', inValid: false}); - } - render() { - var displayNameError = null; - var nameError = null; - var serverError = null; - var displayNameClass = 'form-group'; - var nameClass = 'form-group'; - - if (this.state.displayNameError) { - displayNameError = ; - displayNameClass += ' has-error'; - } - if (this.state.nameError) { - nameError = ; - nameClass += ' has-error'; - } - if (this.state.serverError) { - serverError =
; - } - - var channelTerm = 'Channel'; - if (this.state.channelType === 'P') { - channelTerm = 'Group'; - } - - return ( -