summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/context.go4
-rw-r--r--api/webhook.go26
-rw-r--r--config/config.json3
-rw-r--r--i18n/en.json8
-rw-r--r--i18n/fr.json16
-rw-r--r--i18n/ja.json16
-rw-r--r--i18n/pt-BR.json30
-rw-r--r--mattermost.go34
-rw-r--r--model/config.go13
-rw-r--r--tests/test-markdown-lists.md4
-rw-r--r--utils/config.go1
-rw-r--r--utils/log.go33
-rw-r--r--webapp/actions/global_actions.jsx18
-rw-r--r--webapp/components/about_build_modal.jsx7
-rw-r--r--webapp/components/admin_console/log_settings.jsx21
-rw-r--r--webapp/components/create_comment.jsx21
-rw-r--r--webapp/components/filtered_user_list.jsx4
-rw-r--r--webapp/components/password_reset_form.jsx4
-rw-r--r--webapp/components/post_view/components/post_list.jsx15
-rw-r--r--webapp/components/post_view/post_focus_view_controller.jsx1
-rw-r--r--webapp/components/sidebar_right.jsx6
-rw-r--r--webapp/components/suggestion/suggestion_box.jsx9
-rw-r--r--webapp/components/suggestion/suggestion_list.jsx1
-rw-r--r--webapp/components/user_settings/user_settings.jsx11
-rw-r--r--webapp/components/user_settings/user_settings_display.jsx9
-rw-r--r--webapp/components/user_settings/user_settings_general.jsx2
-rw-r--r--webapp/components/user_settings/user_settings_modal.jsx14
-rw-r--r--webapp/i18n/en.json4
-rw-r--r--webapp/i18n/es.json1
-rw-r--r--webapp/i18n/fr.json7
-rw-r--r--webapp/i18n/ja.json27
-rw-r--r--webapp/i18n/pt-BR.json77
-rw-r--r--webapp/sass/layout/_post.scss4
-rw-r--r--webapp/sass/responsive/_mobile.scss8
-rw-r--r--webapp/stores/post_store.jsx13
-rw-r--r--webapp/utils/constants.jsx1
36 files changed, 289 insertions, 184 deletions
diff --git a/api/context.go b/api/context.go
index 5aa35ad89..798f4dc87 100644
--- a/api/context.go
+++ b/api/context.go
@@ -139,7 +139,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
protocol := GetProtocol(r)
- c.setSiteURL(protocol + "://" + r.Host)
+ c.SetSiteURL(protocol + "://" + r.Host)
w.Header().Set(model.HEADER_REQUEST_ID, c.RequestId)
w.Header().Set(model.HEADER_VERSION_ID, fmt.Sprintf("%v.%v", model.CurrentVersion, utils.CfgLastModified))
@@ -417,7 +417,7 @@ func (c *Context) SetTeamURLFromSession() {
}
}
-func (c *Context) setSiteURL(url string) {
+func (c *Context) SetSiteURL(url string) {
c.siteURL = url
}
diff --git a/api/webhook.go b/api/webhook.go
index 676fd2cbc..6297133da 100644
--- a/api/webhook.go
+++ b/api/webhook.go
@@ -4,6 +4,7 @@
package api
import (
+ "io"
"net/http"
"strings"
@@ -373,14 +374,33 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
r.ParseForm()
- var parsedRequest *model.IncomingWebhookRequest
+ var payload io.Reader
contentType := r.Header.Get("Content-Type")
if strings.Split(contentType, "; ")[0] == "application/x-www-form-urlencoded" {
- parsedRequest = model.IncomingWebhookRequestFromJson(strings.NewReader(r.FormValue("payload")))
+ payload = strings.NewReader(r.FormValue("payload"))
} else {
- parsedRequest = model.IncomingWebhookRequestFromJson(r.Body)
+ payload = r.Body
+ }
+
+ if utils.Cfg.LogSettings.EnableWebhookDebugging {
+ var err error
+ payload, err = utils.DebugReader(
+ payload,
+ utils.T("api.webhook.incoming.debug"),
+ )
+ if err != nil {
+ c.Err = model.NewLocAppError(
+ "incomingWebhook",
+ "api.webhook.incoming.debug.error",
+ nil,
+ err.Error(),
+ )
+ return
+ }
}
+ parsedRequest := model.IncomingWebhookRequestFromJson(payload)
+
if parsedRequest == nil {
c.Err = model.NewLocAppError("incomingWebhook", "web.incoming_webhook.parse.app_error", nil, "")
return
diff --git a/config/config.json b/config/config.json
index 726cb0d8c..db62b0bac 100644
--- a/config/config.json
+++ b/config/config.json
@@ -52,7 +52,8 @@
"EnableFile": true,
"FileLevel": "INFO",
"FileFormat": "",
- "FileLocation": ""
+ "FileLocation": "",
+ "EnableWebhookDebugging": true
},
"FileSettings": {
"MaxFileSize": 52428800,
diff --git a/i18n/en.json b/i18n/en.json
index f88e00d29..1589dd4ac 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1956,6 +1956,14 @@
"translation": "Outgoing webhooks have been disabled by the system admin."
},
{
+ "id": "api.webhook.incoming.debug",
+ "translation": "Incoming webhook received. Content="
+ },
+ {
+ "id": "api.webhook.incoming.debug.error",
+ "translation": "Could not read payload of incoming webhook."
+ },
+ {
"id": "api.webhook.init.debug",
"translation": "Initializing webhook api routes"
},
diff --git a/i18n/fr.json b/i18n/fr.json
index 4d1051752..56374ad77 100644
--- a/i18n/fr.json
+++ b/i18n/fr.json
@@ -305,7 +305,7 @@
},
{
"id": "api.command.duplicate_trigger.app_error",
- "translation": "This trigger word is already in use. Please choose another word."
+ "translation": "Ce mot déclencheur est déjà utilisé. Veuillez choisir un autre mot."
},
{
"id": "api.command.execute_command.debug",
@@ -341,11 +341,11 @@
},
{
"id": "api.command.invite_people.desc",
- "translation": "Send an email invite to your Mattermost team"
+ "translation": "Envoyer un courriel d'invitation à votre équipe"
},
{
"id": "api.command.invite_people.email_off",
- "translation": "Email has not been configured, no invite(s) sent"
+ "translation": "La messagerie n'est pas configurée, aucun courriel envoyé."
},
{
"id": "api.command.invite_people.fail",
@@ -365,7 +365,7 @@
},
{
"id": "api.command.invite_people.sent",
- "translation": "Email invite(s) sent"
+ "translation": "Mail d'invitation envoyé"
},
{
"id": "api.command.regen.app_error",
@@ -409,7 +409,7 @@
},
{
"id": "api.command_expand.name",
- "translation": "expand"
+ "translation": "étendre"
},
{
"id": "api.command_expand_collapse.fail.app_error",
@@ -1257,7 +1257,7 @@
},
{
"id": "api.team.is_team_creation_allowed.disabled.app_error",
- "translation": "La création d'équipes est désactivé. Veuillez demander les détails à votre administrateur système."
+ "translation": "La création d'équipes est désactivée. Veuillez demander les détails à votre administrateur système."
},
{
"id": "api.team.is_team_creation_allowed.domain.app_error",
@@ -3517,7 +3517,7 @@
},
{
"id": "store.sql_team.get_member.missing.app_error",
- "translation": "Aucun élément de canal trouvé pour cet id d'utilisateur et cet id de canal"
+ "translation": "Aucun membre d'équipe trouvé pour cet id d'utilisateur et cet id d'équipe"
},
{
"id": "store.sql_team.get_members.app_error",
@@ -3805,7 +3805,7 @@
},
{
"id": "system.message.name",
- "translation": "System"
+ "translation": "Système"
},
{
"id": "utils.config.load_config.decoding.panic",
diff --git a/i18n/ja.json b/i18n/ja.json
index ebe9926f6..43cc5ca1d 100644
--- a/i18n/ja.json
+++ b/i18n/ja.json
@@ -185,7 +185,7 @@
},
{
"id": "api.channel.delete_channel.failed_send.app_error",
- "translation": "アーカイブマッサージを送信できませんでした"
+ "translation": "アーカイブメッサージを送信できませんでした"
},
{
"id": "api.channel.delete_channel.incoming_webhook.error",
@@ -373,11 +373,11 @@
},
{
"id": "api.command_collapse.desc",
- "translation": "Turn on auto-collapsing of image previews"
+ "translation": "画像プレビューの自動折りたたみをオンにします"
},
{
"id": "api.command_collapse.name",
- "translation": "collapse"
+ "translation": "折りたたみ"
},
{
"id": "api.command_echo.create.app_error",
@@ -405,15 +405,15 @@
},
{
"id": "api.command_expand.desc",
- "translation": "Turn off auto-collapsing of image previews"
+ "translation": "画像プレビューの自動折りたたみをオフにします。"
},
{
"id": "api.command_expand.name",
- "translation": "expand"
+ "translation": "展開"
},
{
"id": "api.command_expand_collapse.fail.app_error",
- "translation": "An error occured while expanding previews"
+ "translation": "プレビューの展開中にエラーが発生しました"
},
{
"id": "api.command_join.desc",
@@ -509,7 +509,7 @@
},
{
"id": "api.command_shortcuts.list",
- "translation": "### キーボードショートカット\n\n#### 移動\n\nALT+UP: 左側のサイドバーの前のチャンネルまたはダイレクトメッセージ\nALT+DOWN: 左側のサイドバーの次のチャンネルまたはダイレクトメッセージ\nALT+SHIFT+UP: 未読のメッセージのある左側のサイドバーの前のチャンネルまたはダイレクトメッセージ\nALT+SHIFT+DOWN: 未読のメッセージのある左側のサイドバーの次のチャンネルまたはダイレクトメッセージ\nCTRL/CMD+SHIFT+A: アカウント設定を開く\nCTRL/CMD+SHIFT+K: 簡易チャンネル変更ダイアログボックスを開く\nCTRL/CMD+SHIFT+M: 最近のあなたについての投稿を開く\nESC: 右側のサイドバーを閉じる\n\n#### ファイル\n\nCTRL/CMD+U: ファイルをアップロードする\n\n#### メッセージ\n\nCTRL/CMD+UP (空の入力欄で): 前のメッセージまたはスラッシュコマンドを表示する\nCTRL/CMD+DOWN (空の入力欄で): 次のメッセージまたはスラッシュコマンドを表示する\nUP (空の入力欄で): 現在のチャンネルの最新のメッセージを編集する\n@[文字]+TAB: [文字]で始まる@usernameを補完する\n:[文字]+TAB: [文字]で始まる絵文字を補完する\n\n#### ブラウザー内蔵のコマンド\n\nALT+LEFT/CMD+[: 履歴の前のチャンネル\nALT+RIGHT/CMD+]: 履歴の次のチャンネル\nCTRL/CMD+PLUS: フォントサイズを大きくする (ズームイン)\nCTRL/CMD+MINUS: フォントサイズを小さくする (ズームアウト)\nSHIFT+UP (入力欄で): 前の行を反転させる\nSHIFT+DOWN (入力欄で): 次の行を反転させる\nSHIFT+ENTER (入力欄で): 改行する\n"
+ "translation": "### キーボードショートカット\n\n#### 移動\n\nALT+UP: 左側のサイドバーの前のチャンネルまたはダイレクトメッセージ\nALT+DOWN: 左側のサイドバーの次のチャンネルまたはダイレクトメッセージ\nALT+SHIFT+UP: 未読のメッセージのある左側のサイドバーの前のチャンネルまたはダイレクトメッセージ\nALT+SHIFT+DOWN: 未読のメッセージのある左側のサイドバーの次のチャンネルまたはダイレクトメッセージ\nCTRL/CMD+SHIFT+K: 簡易チャンネル変更ダイアログボックスを開く\nCTRL/CMD+SHIFT+A: アカウント設定を開く\nCTRL/CMD+SHIFT+M: 最近のあなたについての投稿を開く\n\n#### ファイル\n\nCTRL/CMD+U: ファイルをアップロードする\n\n#### メッセージ\n\nCTRL/CMD+UP (空の入力欄で): 前のメッセージまたはスラッシュコマンドを表示する\nCTRL/CMD+DOWN (空の入力欄で): 次のメッセージまたはスラッシュコマンドを表示する\nUP (空の入力欄で): 現在のチャンネルの最新のメッセージを編集する\n@[文字]+TAB: [文字]で始まる@usernameを補完する\n:[文字]+TAB: [文字]で始まる絵文字を補完する\n\n#### ブラウザー内蔵のコマンド\n\nALT+LEFT/CMD+[: 履歴の前のチャンネル\nALT+RIGHT/CMD+]: 履歴の次のチャンネル\nCTRL/CMD+PLUS: フォントサイズを大きくする (ズームイン)\nCTRL/CMD+MINUS: フォントサイズを小さくする (ズームアウト)\nSHIFT+UP (入力欄で): 前の行を反転させる\nSHIFT+DOWN (入力欄で): 次の行を反転させる\nSHIFT+ENTER (入力欄で): 改行する\n"
},
{
"id": "api.command_shortcuts.name",
@@ -3805,7 +3805,7 @@
},
{
"id": "system.message.name",
- "translation": "System"
+ "translation": "システム"
},
{
"id": "utils.config.load_config.decoding.panic",
diff --git a/i18n/pt-BR.json b/i18n/pt-BR.json
index 9d6c73576..4aa2a83f7 100644
--- a/i18n/pt-BR.json
+++ b/i18n/pt-BR.json
@@ -373,11 +373,11 @@
},
{
"id": "api.command_collapse.desc",
- "translation": "Turn on auto-collapsing of image previews"
+ "translation": "Ativar auto-recolher preview de imagens"
},
{
"id": "api.command_collapse.name",
- "translation": "collapse"
+ "translation": "recolher"
},
{
"id": "api.command_echo.create.app_error",
@@ -405,15 +405,15 @@
},
{
"id": "api.command_expand.desc",
- "translation": "Turn off auto-collapsing of image previews"
+ "translation": "Desativar auto-recolher preview de imagens"
},
{
"id": "api.command_expand.name",
- "translation": "expand"
+ "translation": "expandir"
},
{
"id": "api.command_expand_collapse.fail.app_error",
- "translation": "An error occured while expanding previews"
+ "translation": "Um erro ocorreu ao expandir o preview"
},
{
"id": "api.command_join.desc",
@@ -509,7 +509,7 @@
},
{
"id": "api.command_shortcuts.list",
- "translation": "### Keyboard Shortcuts\n\n#### Navigation\n\nALT+UP: Previous channel or direct message in left hand sidebar\nALT+DOWN: Next channel or direct message in left hand sidebar\nALT+SHIFT+UP: Previous channel or direct message in left hand sidebar with unread messages\nALT+SHIFT+DOWN: Next channel or direct message in left hand sidebar with unread messages\nCTRL/CMD+K: Open a quick channel switcher dialog\nCTRL/CMD+SHIFT+A: Open account settings\nCTRL/CMD+SHIFT+M: Open recent mentions\n\n#### Files\n\nCTRL/CMD+U: Upload file(s)\n\n#### Messages\n\nCTRL/CMD+UP (in empty input field): Reprint the previous message or slash command you entered\nCTRL/CMD+DOWN (in empty input field): Reprint the next message or slash command you entered\nUP (in empty input field): Edit your last message in the current channel\n@[character]+TAB: Autocomplete @username beginning with [character]\n:[character]+TAB: Autocomplete emoji beginning with [character]\n\n#### Built-in Browser Commands\n\nALT+LEFT/CMD+[: Previous channel in your history\nALT+RIGHT/CMD+]: Next channel in your history\nCTRL/CMD+PLUS: Increase font size (zoom in)\nCTRL/CMD+MINUS: Decrease font size (zoom out)\nSHIFT+UP (in input field): Highlight text to the previous line\nSHIFT+DOWN (in input field): Highlight text to the next line\nSHIFT+ENTER (in input field): Create a new line\n"
+ "translation": "### Atalhos do Teclado\n\n#### Navegação\n\nALT+UP: Canal anterior ou mensagem direta na barra lateral esquerda\nALT+DOWN: Próximo canal ou mensagem direta na barra lateral esquerda\nALT+SHIFT+UP: Canal anterior ou mensagem direta na barra lateral esquerda com mensagens não lidas\nALT+SHIFT+DOWN: Próximo canal ou mensagem direta na barra lateral esquerda com mensagens não lidas\nCTRL/CMD+K: Abre uma janela de troca rápida de canal\nCTRL/CMD+SHIFT+A: Abre as configurações de conta\nCTRL/CMD+SHIFT+M: Abre as menções recentes\n\n#### Arquivos\n\nCTRL/CMD+U: Enviar arquivo(s)\n\n#### Mensagens\n\nCTRL/CMD+UP (campo de mensagem vazio): Reimprimir a mensagem anterior ou comando slash digitado\nCTRL/CMD+DOWN (campo de mensagem vazio): Reimprimir a próxima mensagem ou comando slash digitado\nUP (campo de mensagem vazio): Edita sua última mensagem no canal atual\n@[caracter]+TAB: Autocompleta o @usuário começando com [caracter]\n:[caracter]+TAB: Autocompleta o emoji começando com [caracter]\n\n#### Comandos do Navegador\n\nALT+LEFT/CMD+[: Canal anterior no seu histórico\nALT+RIGHT/CMD+]: Próximo canal no seu histórico\nCTRL/CMD+PLUS: Aumentar o tamanho da fonte (zoom in)\nCTRL/CMD+MINUS: Reduzir o tamanho da fonte (zoom out)\nSHIFT+UP (no campo de mensagem): Selecionar texto da linha anterior\nSHIFT+DOWN (no campo de mensagem): Selecionar texto da próxima linha\nSHIFT+ENTER (no campo de mensagem): Criar uma nova linha\n"
},
{
"id": "api.command_shortcuts.name",
@@ -1989,7 +1989,7 @@
},
{
"id": "ent.compliance.licence_disable.app_error",
- "translation": "Funcionalidade Compliance desabilitada pela licença atual. Entre em contato com o administrador do sistema sobre como atualizar sua licença de empresa."
+ "translation": "Funcionalidade Compliance desabilitada pela licença atual. Entre em contato com o administrador do sistema sobre como atualizar sua licença enterprise."
},
{
"id": "ent.compliance.run_failed.error",
@@ -2017,7 +2017,7 @@
},
{
"id": "ent.ldap.do_login.licence_disable.app_error",
- "translation": "Funcionalidade LDAP desabilitada pela licença atual. Entre em contato com o administrador do sistema sobre como atualizar sua licença de empresa."
+ "translation": "Funcionalidade LDAP desabilitada pela licença atual. Entre em contato com o administrador do sistema sobre como atualizar sua licença enterprise."
},
{
"id": "ent.ldap.do_login.matched_to_many_users.app_error",
@@ -2045,11 +2045,11 @@
},
{
"id": "ent.ldap.syncdone.info",
- "translation": "LDAP Synchronization completed"
+ "translation": "Sincronização LDAP completada"
},
{
"id": "ent.ldap.syncronize.get_all.app_error",
- "translation": "Unable to get all users using LDAP"
+ "translation": "Não foi possível obter todos os usuários usando LDAP"
},
{
"id": "ent.ldap.validate_filter.app_error",
@@ -2441,7 +2441,7 @@
},
{
"id": "model.config.is_valid.ldap_sync_interval.app_error",
- "translation": "Invalid sync interval time. Must be at least one minute."
+ "translation": "Intervalo de tempo de sincronização inválido. Deve ser pelo menos um minuto."
},
{
"id": "model.config.is_valid.listen_address.app_error",
@@ -2893,7 +2893,7 @@
},
{
"id": "store.sql.read_replicas_not_licensed.critical",
- "translation": "A funcionalidade de mais de uma réplica está desabilitada pela licença atual. Entre em contato com o administrador do sistema sobre como atualizar sua licença de empresa."
+ "translation": "A funcionalidade de mais de uma réplica está desabilitada pela licença atual. Entre em contato com o administrador do sistema sobre como atualizar sua licença enterprise."
},
{
"id": "store.sql.remove_index.critical",
@@ -3517,7 +3517,7 @@
},
{
"id": "store.sql_team.get_member.missing.app_error",
- "translation": "Nenhum membro canal encontrado para esse id de usuário e id de canal"
+ "translation": "Nenhum membro encontrado para esse id de usuário e id de equipe"
},
{
"id": "store.sql_team.get_members.app_error",
@@ -3585,7 +3585,7 @@
},
{
"id": "store.sql_user.get_all_using_auth_service.other.app_error",
- "translation": "Foi encontrado um erro ao tentar encontrar a conta pelo tipo de autenticação."
+ "translation": "Foi encontrado um erro ao tentar encontrar todas as contas usando um específico tipo de autenticação."
},
{
"id": "store.sql_user.get_by_auth.missing_account.app_error",
@@ -3805,7 +3805,7 @@
},
{
"id": "system.message.name",
- "translation": "System"
+ "translation": "Sistema"
},
{
"id": "utils.config.load_config.decoding.panic",
diff --git a/mattermost.go b/mattermost.go
index 712faf83b..67428275a 100644
--- a/mattermost.go
+++ b/mattermost.go
@@ -63,6 +63,7 @@ var flagLicenseFile string
var flagEmail string
var flagPassword string
var flagTeamName string
+var flagSiteURL string
var flagConfirmBackup string
var flagRole string
var flagRunCmds bool
@@ -262,6 +263,7 @@ func parseCmds() {
flag.StringVar(&flagEmail, "email", "", "")
flag.StringVar(&flagPassword, "password", "", "")
flag.StringVar(&flagTeamName, "team_name", "", "")
+ flag.StringVar(&flagSiteURL, "site_url", "", "")
flag.StringVar(&flagConfirmBackup, "confirm_backup", "", "")
flag.StringVar(&flagRole, "role", "", "")
@@ -821,14 +823,25 @@ func cmdInviteUser() {
os.Exit(1)
}
+ if len(flagSiteURL) == 0 {
+ fmt.Fprintln(os.Stderr, "flag needs an argument: -site_url")
+ flag.Usage()
+ os.Exit(1)
+ }
+
+ // basic validation of the URL format
+ if _, err := url.ParseRequestURI(flagSiteURL); err != nil {
+ fmt.Fprintln(os.Stderr, "-site_url flag is invalid. It should look like http://example.com")
+ flag.Usage()
+ os.Exit(1)
+ }
+
var team *model.Team
- if len(flagTeamName) > 0 {
- if result := <-api.Srv.Store.Team().GetByName(flagTeamName); result.Err != nil {
- l4g.Error("%v", result.Err)
- flushLogAndExit(1)
- } else {
- team = result.Data.(*model.Team)
- }
+ if result := <-api.Srv.Store.Team().GetByName(flagTeamName); result.Err != nil {
+ l4g.Error("%v", result.Err)
+ flushLogAndExit(1)
+ } else {
+ team = result.Data.(*model.Team)
}
var user *model.User
@@ -841,6 +854,7 @@ func cmdInviteUser() {
invites := []string{flagEmail}
c := getMockContext()
+ c.SetSiteURL(strings.TrimSuffix(flagSiteURL, "/"))
api.InviteMembers(c, team, user, invites)
os.Exit(0)
@@ -1237,6 +1251,8 @@ FLAGS:
-team_name="name" The team name used in other commands
+ -site_url="url" The site URL used in other commands
+
-role="system_admin" The role used in other commands
valid values are
"" - The empty role is basic user
@@ -1256,9 +1272,9 @@ COMMANDS:
platform -create_user -team_name="name" -email="user@example.com" -password="mypassword" -username="user"
-invite_user Invites a user to a team by email. It requires the -team_name
- and -email flags.
+ , -email and -site_url flags.
Example:
- platform -invite_user -team_name="name" -email="user@example.com"
+ platform -invite_user -team_name="name" -email="user@example.com" -site_url="https://mattermost.example.com"
-join_team Joins a user to the team. It required the -email and
-team_name. You may need to logout of your current session
diff --git a/model/config.go b/model/config.go
index 55606ee8d..08510fc44 100644
--- a/model/config.go
+++ b/model/config.go
@@ -93,12 +93,13 @@ type SqlSettings struct {
}
type LogSettings struct {
- EnableConsole bool
- ConsoleLevel string
- EnableFile bool
- FileLevel string
- FileFormat string
- FileLocation string
+ EnableConsole bool
+ ConsoleLevel string
+ EnableFile bool
+ FileLevel string
+ FileFormat string
+ FileLocation string
+ EnableWebhookDebugging bool
}
type FileSettings struct {
diff --git a/tests/test-markdown-lists.md b/tests/test-markdown-lists.md
index 355cff021..2ec9bc629 100644
--- a/tests/test-markdown-lists.md
+++ b/tests/test-markdown-lists.md
@@ -138,8 +138,8 @@ Verify that all list types render as expected.
• Lima
• Mike
1. November
- 1. Oscar
- 1. Papa
+ 4. Oscar
+ 5. Papa
```
**Actual:**
diff --git a/utils/config.go b/utils/config.go
index 86fe7c062..9700f44e0 100644
--- a/utils/config.go
+++ b/utils/config.go
@@ -249,6 +249,7 @@ func getClientConfig(c *model.Config) map[string]string {
props["DefaultClientLocale"] = *c.LocalizationSettings.DefaultClientLocale
props["AvailableLocales"] = *c.LocalizationSettings.AvailableLocales
+ props["SQLDriverName"] = c.SqlSettings.DriverName
if IsLicensed {
if *License.Features.CustomBrand {
diff --git a/utils/log.go b/utils/log.go
new file mode 100644
index 000000000..360c785d0
--- /dev/null
+++ b/utils/log.go
@@ -0,0 +1,33 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package utils
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+
+ l4g "github.com/alecthomas/log4go"
+)
+
+// DebugReader logs the content of the io.Reader and returns a new io.Reader
+// with the same content as the received io.Reader.
+// If you pass reader by reference, it won't be re-created unless the loglevel
+// includes Debug.
+// If an error is returned, the reader is consumed an cannot be read again.
+func DebugReader(reader io.Reader, message string) (io.Reader, error) {
+ var err error
+ l4g.Debug(func() string {
+ content, err := ioutil.ReadAll(reader)
+ if err != nil {
+ return ""
+ }
+
+ reader = bytes.NewReader(content)
+
+ return message + string(content)
+ })
+
+ return reader, err
+}
diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx
index 165d655e4..0c07173ac 100644
--- a/webapp/actions/global_actions.jsx
+++ b/webapp/actions/global_actions.jsx
@@ -134,6 +134,7 @@ export function doFocusPost(channelId, postId, data) {
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_FOCUSED_POST,
postId,
+ channelId,
post_list: data
});
AsyncClient.getChannels(true);
@@ -208,25 +209,25 @@ export function emitPostFocusRightHandSideFromSearch(post, isMentionSearch) {
export function emitLoadMorePostsEvent() {
const id = ChannelStore.getCurrentId();
- loadMorePostsTop(id);
+ loadMorePostsTop(id, false);
}
export function emitLoadMorePostsFocusedTopEvent() {
const id = PostStore.getFocusedPostId();
- loadMorePostsTop(id);
+ loadMorePostsTop(id, true);
}
-export function loadMorePostsTop(id) {
+export function loadMorePostsTop(id, isFocusPost) {
const earliestPostId = PostStore.getEarliestPost(id).id;
if (PostStore.requestVisibilityIncrease(id, Constants.POST_CHUNK_SIZE)) {
- AsyncClient.getPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE);
+ AsyncClient.getPostsBefore(earliestPostId, 0, Constants.POST_CHUNK_SIZE, isFocusPost);
}
}
export function emitLoadMorePostsFocusedBottomEvent() {
const id = PostStore.getFocusedPostId();
const latestPostId = PostStore.getLatestPost(id).id;
- AsyncClient.getPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE);
+ AsyncClient.getPostsAfter(latestPostId, 0, Constants.POST_CHUNK_SIZE, !!id);
}
export function emitPostRecievedEvent(post, msg) {
@@ -259,6 +260,13 @@ export function emitUserPostedEvent(post) {
});
}
+export function emitUserCommentedEvent(post) {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.CREATE_COMMENT,
+ post
+ });
+}
+
export function emitPostDeletedEvent(post) {
AppDispatcher.handleServerAction({
type: ActionTypes.POST_DELETED,
diff --git a/webapp/components/about_build_modal.jsx b/webapp/components/about_build_modal.jsx
index 2f7b3e781..de0b2d58c 100644
--- a/webapp/components/about_build_modal.jsx
+++ b/webapp/components/about_build_modal.jsx
@@ -137,6 +137,13 @@ export default class AboutBuildModal extends React.Component {
/>
{'\u00a0' + config.Version + '\u00a0' + config.BuildNumber}
</div>
+ <div>
+ <FormattedMessage
+ id='about.database'
+ defaultMessage='Database:'
+ />
+ {'\u00a0' + config.SQLDriverName}
+ </div>
</div>
{licensee}
</div>
diff --git a/webapp/components/admin_console/log_settings.jsx b/webapp/components/admin_console/log_settings.jsx
index 0a69cbc16..238040b71 100644
--- a/webapp/components/admin_console/log_settings.jsx
+++ b/webapp/components/admin_console/log_settings.jsx
@@ -26,7 +26,8 @@ export default class LogSettings extends AdminSettings {
enableFile: props.config.LogSettings.EnableFile,
fileLevel: props.config.LogSettings.FileLevel,
fileLocation: props.config.LogSettings.FileLocation,
- fileFormat: props.config.LogSettings.FileFormat
+ fileFormat: props.config.LogSettings.FileFormat,
+ enableWebhookDebugging: props.config.LogSettings.EnableWebhookDebugging
});
}
@@ -37,6 +38,7 @@ export default class LogSettings extends AdminSettings {
config.LogSettings.FileLevel = this.state.fileLevel;
config.LogSettings.FileLocation = this.state.fileLocation;
config.LogSettings.FileFormat = this.state.fileFormat;
+ config.LogSettings.EnableWebhookDebugging = this.state.enableWebhookDebugging;
return config;
}
@@ -166,6 +168,23 @@ export default class LogSettings extends AdminSettings {
onChange={this.handleChange}
disabled={!this.state.enableFile}
/>
+ <BooleanSetting
+ id='enableWebhookDebugging'
+ label={
+ <FormattedMessage
+ id='admin.log.enableWebhookDebugging'
+ defaultMessage='Enable Webhook Debugging:'
+ />
+ }
+ helpText={
+ <FormattedMessage
+ id='admin.log.enableWebhookDebuggingDescription'
+ defaultMessage='You can set this to false to disable the debug logging of all incoming webhook request bodies.'
+ />
+ }
+ value={this.state.enableWebhookDebugging}
+ onChange={this.handleChange}
+ />
</SettingsGroup>
);
}
diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx
index a9cf68833..85f8ac864 100644
--- a/webapp/components/create_comment.jsx
+++ b/webapp/components/create_comment.jsx
@@ -5,8 +5,6 @@ import $ from 'jquery';
import ReactDOM from 'react-dom';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import Client from 'utils/web_client.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
-import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
import PostDeletedModal from './post_deleted_modal.jsx';
import PostStore from 'stores/post_store.jsx';
@@ -145,24 +143,11 @@ class CreateComment extends React.Component {
post.user_id = userId;
post.create_at = time;
- PostStore.storePendingPost(post);
- PostStore.storeCommentDraft(this.props.rootId, null);
-
+ GlobalActions.emitUserCommentedEvent(post);
Client.createPost(
post,
- (data) => {
- AsyncClient.getPosts(this.props.channelId);
-
- const channel = ChannelStore.get(this.props.channelId);
- const member = ChannelStore.getMember(this.props.channelId);
- member.msg_count = channel.total_msg_count;
- member.last_viewed_at = Date.now();
- ChannelStore.setChannelMember(member);
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POST,
- post: data
- });
+ () => {
+ PostStore.removePendingPost(post.channel_id, post.pending_post_id);
},
(err) => {
if (err.id === 'api.post.create_post.root_id.app_error') {
diff --git a/webapp/components/filtered_user_list.jsx b/webapp/components/filtered_user_list.jsx
index fca68a81a..181a19c74 100644
--- a/webapp/components/filtered_user_list.jsx
+++ b/webapp/components/filtered_user_list.jsx
@@ -52,6 +52,10 @@ class FilteredUserList extends React.Component {
}
}
+ componentDidMount() {
+ ReactDOM.findDOMNode(this.refs.filter).focus();
+ }
+
componentDidUpdate(prevProps, prevState) {
if (prevState.filter !== this.state.filter) {
$(ReactDOM.findDOMNode(this.refs.userList)).scrollTop(0);
diff --git a/webapp/components/password_reset_form.jsx b/webapp/components/password_reset_form.jsx
index 887bc0c8e..eeea265d8 100644
--- a/webapp/components/password_reset_form.jsx
+++ b/webapp/components/password_reset_form.jsx
@@ -29,7 +29,9 @@ class PasswordResetForm extends React.Component {
<FormattedMessage
id='password_form.error'
defaultMessage='Please enter at least {chars} characters.'
- chars={Constants.MIN_PASSWORD_LENGTH}
+ values={{
+ chars: Constants.MIN_PASSWORD_LENGTH
+ }}
/>
)
});
diff --git a/webapp/components/post_view/components/post_list.jsx b/webapp/components/post_view/components/post_list.jsx
index 28be93544..c23f785d9 100644
--- a/webapp/components/post_view/components/post_list.jsx
+++ b/webapp/components/post_view/components/post_list.jsx
@@ -68,7 +68,7 @@ export default class PostList extends React.Component {
const childNodes = this.refs.postlistcontent.childNodes;
for (let i = 0; i < childNodes.length; i++) {
// If the node is 1/3 down the page
- if (childNodes[i].offsetTop > (this.refs.postlist.scrollTop + (this.refs.postlist.offsetHeight / Constants.SCROLL_PAGE_FRACTION))) {
+ if (childNodes[i].offsetTop >= (this.refs.postlist.scrollTop + (this.refs.postlist.offsetHeight / Constants.SCROLL_PAGE_FRACTION))) {
this.jumpToPostNode = childNodes[i];
break;
}
@@ -137,7 +137,10 @@ export default class PostList extends React.Component {
}
loadMorePostsTop() {
- GlobalActions.emitLoadMorePostsEvent();
+ if (this.props.isFocusPost) {
+ return GlobalActions.emitLoadMorePostsFocusedTopEvent();
+ }
+ return GlobalActions.emitLoadMorePostsEvent();
}
loadMorePostsBottom() {
@@ -364,9 +367,8 @@ export default class PostList extends React.Component {
}
} else if (this.refs.postlist.scrollHeight !== this.prevScrollHeight) {
window.requestAnimationFrame(() => {
- // Only need to jump if we added posts to the top.
- if (this.jumpToPostNode && (this.jumpToPostNode.offsetTop !== this.prevOffsetTop)) {
- this.refs.postlist.scrollTop += (this.refs.postlist.scrollHeight - this.prevScrollHeight);
+ if (this.jumpToPostNode) {
+ this.refs.postlist.scrollTop += (this.jumpToPostNode.offsetTop - this.prevOffsetTop);
}
});
}
@@ -522,5 +524,6 @@ PostList.propTypes = {
displayNameType: React.PropTypes.string,
displayPostsInCenter: React.PropTypes.bool,
compactDisplay: React.PropTypes.bool,
- previewsCollapsed: React.PropTypes.string
+ previewsCollapsed: React.PropTypes.string,
+ isFocusPost: React.PropTypes.bool
};
diff --git a/webapp/components/post_view/post_focus_view_controller.jsx b/webapp/components/post_view/post_focus_view_controller.jsx
index 7c1da6566..c70ebb0f5 100644
--- a/webapp/components/post_view/post_focus_view_controller.jsx
+++ b/webapp/components/post_view/post_focus_view_controller.jsx
@@ -115,6 +115,7 @@ export default class PostFocusView extends React.Component {
showMoreMessagesTop={!this.state.atTop}
showMoreMessagesBottom={!this.state.atBottom}
postsToHighlight={postsToHighlight}
+ isFocusPost={true}
/>
);
}
diff --git a/webapp/components/sidebar_right.jsx b/webapp/components/sidebar_right.jsx
index 22ddfc205..9e2fc32dd 100644
--- a/webapp/components/sidebar_right.jsx
+++ b/webapp/components/sidebar_right.jsx
@@ -10,8 +10,6 @@ import PostStore from 'stores/post_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as Utils from 'utils/utils.jsx';
-const SIDEBAR_SCROLL_DELAY = 500;
-
import React from 'react';
export default class SidebarRight extends React.Component {
@@ -55,8 +53,8 @@ export default class SidebarRight extends React.Component {
const isOpen = this.state.searchVisible || this.state.postRightVisible;
const willOpen = nextState.searchVisible || nextState.postRightVisible;
- if (!isOpen && willOpen) {
- setTimeout(() => PostStore.jumpPostsViewSidebarOpen(), SIDEBAR_SCROLL_DELAY);
+ if (isOpen !== willOpen) {
+ PostStore.jumpPostsViewSidebarOpen();
}
}
doStrangeThings() {
diff --git a/webapp/components/suggestion/suggestion_box.jsx b/webapp/components/suggestion/suggestion_box.jsx
index 6260e179c..2184b9fab 100644
--- a/webapp/components/suggestion/suggestion_box.jsx
+++ b/webapp/components/suggestion/suggestion_box.jsx
@@ -31,7 +31,7 @@ export default class SuggestionBox extends React.Component {
}
componentDidMount() {
- $(document).on('click', this.handleDocumentClick);
+ $(document).on('click touchstart', this.handleDocumentClick);
SuggestionStore.addCompleteWordListener(this.suggestionId, this.handleCompleteWord);
SuggestionStore.addPretextChangedListener(this.suggestionId, this.handlePretextChanged);
@@ -42,7 +42,7 @@ export default class SuggestionBox extends React.Component {
SuggestionStore.removePretextChangedListener(this.suggestionId, this.handlePretextChanged);
SuggestionStore.unregisterSuggestionBox(this.suggestionId);
- $(document).off('click', this.handleDocumentClick);
+ $(document).off('click touchstart', this.handleDocumentClick);
}
getTextbox() {
@@ -58,6 +58,11 @@ export default class SuggestionBox extends React.Component {
handleDocumentClick(e) {
const container = $(ReactDOM.findDOMNode(this));
+ if ($('.suggestion-list__content').length) {
+ if (!($(e.target).hasClass('suggestion-list__content') || $(e.target).parents().hasClass('suggestion-list__content'))) {
+ $('body').removeClass('modal-open');
+ }
+ }
if (!(container.is(e.target) || container.has(e.target).length > 0)) {
// we can't just use blur for this because it fires and hides the children before
// their click handlers can be called
diff --git a/webapp/components/suggestion/suggestion_list.jsx b/webapp/components/suggestion/suggestion_list.jsx
index 134e7a8d4..f1cccf8aa 100644
--- a/webapp/components/suggestion/suggestion_list.jsx
+++ b/webapp/components/suggestion/suggestion_list.jsx
@@ -51,6 +51,7 @@ export default class SuggestionList extends React.Component {
}
getContent() {
+ $('body').addClass('modal-open');
return $(ReactDOM.findDOMNode(this.refs.content));
}
diff --git a/webapp/components/user_settings/user_settings.jsx b/webapp/components/user_settings/user_settings.jsx
index d89298cfb..cf69a564f 100644
--- a/webapp/components/user_settings/user_settings.jsx
+++ b/webapp/components/user_settings/user_settings.jsx
@@ -16,7 +16,6 @@ export default class UserSettings extends React.Component {
constructor(props) {
super(props);
- this.getActiveTab = this.getActiveTab.bind(this);
this.onListenerChange = this.onListenerChange.bind(this);
this.state = {user: UserStore.getCurrentUser()};
@@ -30,10 +29,6 @@ export default class UserSettings extends React.Component {
UserStore.removeChangeListener(this.onListenerChange);
}
- getActiveTab() {
- return this.refs.activeTab;
- }
-
onListenerChange() {
var user = UserStore.getCurrentUser();
if (!utils.areObjectsEqual(this.state.user, user)) {
@@ -46,7 +41,6 @@ export default class UserSettings extends React.Component {
return (
<div>
<GeneralTab
- ref='activeTab'
user={this.state.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
@@ -60,7 +54,6 @@ export default class UserSettings extends React.Component {
return (
<div>
<SecurityTab
- ref='activeTab'
user={this.state.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
@@ -75,7 +68,6 @@ export default class UserSettings extends React.Component {
return (
<div>
<NotificationsTab
- ref='activeTab'
user={this.state.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
@@ -89,7 +81,6 @@ export default class UserSettings extends React.Component {
return (
<div>
<DeveloperTab
- ref='activeTab'
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
@@ -101,7 +92,6 @@ export default class UserSettings extends React.Component {
return (
<div>
<DisplayTab
- ref='activeTab'
user={this.state.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
@@ -117,7 +107,6 @@ export default class UserSettings extends React.Component {
return (
<div>
<AdvancedTab
- ref='activeTab'
user={this.state.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
diff --git a/webapp/components/user_settings/user_settings_display.jsx b/webapp/components/user_settings/user_settings_display.jsx
index f7a030e52..1b6ce3343 100644
--- a/webapp/components/user_settings/user_settings_display.jsx
+++ b/webapp/components/user_settings/user_settings_display.jsx
@@ -41,12 +41,15 @@ export default class UserSettingsDisplay extends React.Component {
this.handleFont = this.handleFont.bind(this);
this.updateSection = this.updateSection.bind(this);
this.updateState = this.updateState.bind(this);
- this.deactivate = this.deactivate.bind(this);
this.createCollapseSection = this.createCollapseSection.bind(this);
this.state = getDisplayStateFromStores();
}
+ componentWillUnmount() {
+ Utils.applyFont(PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT));
+ }
+
handleSubmit() {
const userId = UserStore.getCurrentId();
@@ -136,10 +139,6 @@ export default class UserSettingsDisplay extends React.Component {
}
}
- deactivate() {
- this.updateState();
- }
-
createCollapseSection() {
if (this.props.activeSection === 'collapse') {
const collapseFormat = [false, false];
diff --git a/webapp/components/user_settings/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general.jsx
index bd1e2829d..e586c9290 100644
--- a/webapp/components/user_settings/user_settings_general.jsx
+++ b/webapp/components/user_settings/user_settings_general.jsx
@@ -596,7 +596,7 @@ class UserSettingsGeneralTab extends React.Component {
<span>
<FormattedMessage
id='user.settings.general.field_handled_externally'
- defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
+ defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so through your login provider.'
/>
</span>
);
diff --git a/webapp/components/user_settings/user_settings_modal.jsx b/webapp/components/user_settings/user_settings_modal.jsx
index 43fb728bd..4ceb85bb8 100644
--- a/webapp/components/user_settings/user_settings_modal.jsx
+++ b/webapp/components/user_settings/user_settings_modal.jsx
@@ -65,7 +65,6 @@ class UserSettingsModal extends React.Component {
this.handleConfirm = this.handleConfirm.bind(this);
this.handleCancelConfirmation = this.handleCancelConfirmation.bind(this);
- this.deactivateTab = this.deactivateTab.bind(this);
this.closeModal = this.closeModal.bind(this);
this.collapseModal = this.collapseModal.bind(this);
@@ -108,7 +107,6 @@ class UserSettingsModal extends React.Component {
return;
}
- this.deactivateTab();
this.props.onModalDismissed();
return;
}
@@ -125,8 +123,6 @@ class UserSettingsModal extends React.Component {
handleCollapse() {
$(ReactDOM.findDOMNode(this.refs.modalBody)).closest('.modal-dialog').removeClass('display--content');
- this.deactivateTab();
-
this.setState({
active_tab: '',
active_section: ''
@@ -167,14 +163,6 @@ class UserSettingsModal extends React.Component {
}
}
- // Called to let settings tab perform cleanup before being closed
- deactivateTab() {
- const activeTab = this.refs.userSettings.getActiveTab();
- if (activeTab && activeTab.deactivate) {
- activeTab.deactivate();
- }
- }
-
// Called by settings tabs when their close button is pressed
closeModal() {
if (this.requireConfirm) {
@@ -197,8 +185,6 @@ class UserSettingsModal extends React.Component {
if (!skipConfirm && this.requireConfirm) {
this.showConfirmModal(() => this.updateTab(tab, true));
} else {
- this.deactivateTab();
-
this.setState({
active_tab: tab,
active_section: ''
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index a858e9b94..85f221c7c 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -1,6 +1,7 @@
{
"about.close": "Close",
"about.copyright": "Copyright 2016 Mattermost, Inc. All rights reserved",
+ "about.database": "Database:",
"about.date": "Build Date:",
"about.enterpriseEditionLearn": "Learn more about Enterprise Edition at ",
"about.enterpriseEditionSt": "Modern enterprise communication from behind your firewall.",
@@ -326,6 +327,8 @@
"admin.log.logSettings": "Log Settings",
"admin.logs.reload": "Reload",
"admin.logs.title": "Server Logs",
+ "admin.log.enableWebhookDebugging": "Enable Webhook Debugging:",
+ "admin.log.enableWebhookDebuggingDescription": "You can set this to false to disable the debug logging of all incoming webhook request bodies.",
"admin.nav.help": "Help",
"admin.nav.logout": "Logout",
"admin.nav.report": "Report a Problem",
@@ -1342,6 +1345,7 @@
"user.settings.general.emailMatch": "The new emails you entered do not match.",
"user.settings.general.emptyName": "Click 'Edit' to add your full name",
"user.settings.general.emptyNickname": "Click 'Edit' to add a nickname",
+ "user.settings.general.field_handled_externally": "This field is handled through your login provider. If you want to change it, you need to do so through your login provider.",
"user.settings.general.firstName": "First Name",
"user.settings.general.fullName": "Full Name",
"user.settings.general.imageTooLarge": "Unable to upload profile image. File is too large.",
diff --git a/webapp/i18n/es.json b/webapp/i18n/es.json
index 95ef986db..6ce2e77c3 100644
--- a/webapp/i18n/es.json
+++ b/webapp/i18n/es.json
@@ -1,6 +1,7 @@
{
"about.close": "Cerrar",
"about.copyright": "Derechos de autor 2016 Mattermost, Inc. Todos los derechos reservados",
+ "about.database": "Base de Datos",
"about.date": "Fecha de compilación:",
"about.enterpriseEditionLearn": "Conoce más acerca de la edición Enterprise en ",
"about.enterpriseEditionSt": "Comunicaciones empresariales modernas protegidas por tu cortafuegos.",
diff --git a/webapp/i18n/fr.json b/webapp/i18n/fr.json
index 9021288fa..a3ab8375d 100644
--- a/webapp/i18n/fr.json
+++ b/webapp/i18n/fr.json
@@ -1,6 +1,7 @@
{
"about.close": "Quitter",
"about.copyright": "Copyright 2016 Mattermost, Inc. Tout droits réservés",
+ "about.database": "Base de données",
"about.date": "Date de compilation :",
"about.enterpriseEditionLearn": "Apprenez-en plus sur l’édition entreprise à : ",
"about.enterpriseEditionSt": "Communication d’entreprise moderne derrière votre pare-feu.",
@@ -719,7 +720,7 @@
"channel_notifications.sendDesktop": "Envoyer des notifications sur le bureau",
"channel_notifications.unreadInfo": "Le nom du canal est en gras dans la barre latérale lorsqu'il y a des messages non-plus. Choisir \"Seulement pour les mentions\" mettra en gras le canal seulement si vous être mentionné.",
"channel_select.placeholder": "--- Sélectionnez un canal ---",
- "channel_switch_modal.dm": "(Direct Message)",
+ "channel_switch_modal.dm": "Messages privés",
"channel_switch_modal.help": "Type channel name. Use ↑↓ to browse, TAB to select, ↵ to confirm, ESC to dismiss",
"channel_switch_modal.not_found": "No matches found.",
"channel_switch_modal.submit": "Switch",
@@ -1300,8 +1301,8 @@
"user.settings.display.clockDisplay": "Affichage de l'horloge",
"user.settings.display.collapseDesc": "Toggle whether to automatically collapse all image previews.",
"user.settings.display.collapseDisplay": "Auto Collapse Previews",
- "user.settings.display.collapseOff": "Off",
- "user.settings.display.collapseOn": "On",
+ "user.settings.display.collapseOff": "Désactivé",
+ "user.settings.display.collapseOn": "Activé",
"user.settings.display.fixedWidthCentered": "Largeur fixe, centrée",
"user.settings.display.fontDesc": "Choisissez la police de caractères utilisée pour l'interface de Mattermost.",
"user.settings.display.fontTitle": "Police d'affichage",
diff --git a/webapp/i18n/ja.json b/webapp/i18n/ja.json
index 60950afee..80ffd3bf7 100644
--- a/webapp/i18n/ja.json
+++ b/webapp/i18n/ja.json
@@ -1,6 +1,7 @@
{
"about.close": "閉じる",
"about.copyright": "Copyright 2016 Mattermost, Inc. All rights reserved",
+ "about.database": "データベース:",
"about.date": "ビルド日時:",
"about.enterpriseEditionLearn": "Enterprise Editionについて詳しく知る: ",
"about.enterpriseEditionSt": "ファイアウォールの内側で、現代的なエンタープライズコミュニケーションを実現します。",
@@ -283,7 +284,7 @@
"admin.ldap.skipCertificateVerification": "証明書の検証をしない",
"admin.ldap.skipCertificateVerificationDesc": "TLSまたはSTARTTLSの証明書の検証ステップをスキップします。TLSが必要な本番環境では設定することは推奨されません。テスト用の設定です。",
"admin.ldap.syncIntervalHelpText": "LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour.",
- "admin.ldap.syncIntervalTitle": "Synchronization Interval (In Minutes)",
+ "admin.ldap.syncIntervalTitle": "同期間隔(分)",
"admin.ldap.uernameAttrDesc": "Mattermostのユーザー名を設定するために使用されるLDAPサーバーの属性値です。ID属性値と同じである場合があります。",
"admin.ldap.userFilterDisc": "ユーザーオブジェクトを検索する再のLDAPフィルターを入力できます。任意項目です。これを適用したクエリーで選ばれるユーザーのみがMattermostにアクセスできます。Active Directoryでは、無効化されているユーザーを排除するには、(&(objectCategory=Person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))を設定してください。",
"admin.ldap.userFilterEx": "例: \"(objectClass=user)\"",
@@ -719,7 +720,7 @@
"channel_notifications.sendDesktop": "デスクトップ通知を送ります",
"channel_notifications.unreadInfo": "チャンネル名は未読のメッセージがある場合、サイドバーで太字で表示されます。「あなたについての投稿のみ」を選択することで、あなたについての投稿がある場合のみ太字で表示されます。",
"channel_select.placeholder": "--- チャンネルを選択してください ---",
- "channel_switch_modal.dm": "ダイレクトメッセージ",
+ "channel_switch_modal.dm": "(ダイレクトメッセージ)",
"channel_switch_modal.help": "Type channel name. Use ↑↓ to browse, TAB to select, ↵ to confirm, ESC to dismiss",
"channel_switch_modal.not_found": "一致するものは見つかりませんでした。",
"channel_switch_modal.submit": "切り替える",
@@ -840,11 +841,11 @@
"email_verify.verified": "{siteName}電子メールが確認されました",
"email_verify.verifiedBody": "<p>あなたの電子メールアドレスは確認されました! <a href={url}>here</a>をクロックしてログインしてください。</p>",
"email_verify.verifyFailed": "電子メールアドレスが確認できませんでした。",
- "error.not_found.link_message": "Back to Mattermost",
+ "error.not_found.link_message": "Mattermostに戻る",
"error.not_found.message": "The page you were trying to reach does not exist",
- "error.not_found.title": "Page not found",
- "error.not_supported.message": "Private browsing is not supported",
- "error.not_supported.title": "Browser not supported",
+ "error.not_found.title": "ページが見つかりません",
+ "error.not_supported.message": "プライベートブラウジングはサポートされていません",
+ "error.not_supported.title": "ブラウザはサポートされていません",
"error_bar.expired": "エンタープライズライセンスは期限が切れました。期限切れの日から15日以内にライセンスを更新してください。問い合わせはcommercial@mattermost.comまでお願いします。",
"error_bar.expiring": "エンタープライズライセンスは{date}に期限が切れます。ライセンスを更新するには、commercial@mattermost.comに問い合わせてください。",
"error_bar.past_grace": "エンタープライズライセンスの期限が切れました。システム管理者に詳細を問い合わせてください。",
@@ -1196,8 +1197,8 @@
"sso_signup.length_error": "名前は3から15文字にしてください",
"sso_signup.teamName": "新しいチーム名を入力してください",
"sso_signup.team_error": "チーム名を入力してください",
- "suggestion.mention.all": "Notifies everyone in the channel, use in {townsquare} to notify the whole team",
- "suggestion.mention.channel": "チャネルの全員に通知する",
+ "suggestion.mention.all": "チャンネルの全員に通知します。{townsquare}で使うとチーム全体に通知します。",
+ "suggestion.mention.channel": "チャネルの全員に通知します。",
"suggestion.search.private": "非公開グループ",
"suggestion.search.public": "公開チャンネル",
"team_export_tab.download": "ダウンロードする",
@@ -1298,8 +1299,8 @@
"user.settings.display.channelDisplayTitle": "チャンネル表示",
"user.settings.display.channeldisplaymode": "中央のチャンネルの幅を選択してください。",
"user.settings.display.clockDisplay": "時計表示",
- "user.settings.display.collapseDesc": "Toggle whether to automatically collapse all image previews.",
- "user.settings.display.collapseDisplay": "Auto Collapse Previews",
+ "user.settings.display.collapseDesc": "画像プレビューの自動折りたたみ機能のオン/オフを切り替えます。",
+ "user.settings.display.collapseDisplay": "プレビューの自動折りたたみ",
"user.settings.display.collapseOff": "オフ",
"user.settings.display.collapseOn": "オン",
"user.settings.display.fixedWidthCentered": "固定幅、中央寄せ",
@@ -1388,7 +1389,7 @@
"user.settings.notification.allActivity": "全てのアクティビティーについて",
"user.settings.notification.push": "モバイルプッシュ通知",
"user.settings.notification.soundConfig": "ブラウザーの設定画面で、通知音について設定してください",
- "user.settings.notifications.channelWide": "チャンネル全体についての「@channel」",
+ "user.settings.notifications.channelWide": "チャンネル全体についての「@channel」、「@all」",
"user.settings.notifications.close": "閉じる",
"user.settings.notifications.desktop": "デスクトップ通知を送る",
"user.settings.notifications.desktopSounds": "デスクトップ通知音",
@@ -1410,8 +1411,8 @@
"user.settings.notifications.usernameMention": "あなたのユーザー名についての「@{username}」",
"user.settings.notifications.wordsTrigger": "誰かについての投稿となる単語",
"user.settings.push_notification.allActivity": "全てのアクティビティーについて",
- "user.settings.push_notification.disabled": "Disabled by system administrator",
- "user.settings.push_notification.disabled_long": "Push notifications for mobile devices have been disabled by your System Administrator.",
+ "user.settings.push_notification.disabled": "管理者によって無効化されています",
+ "user.settings.push_notification.disabled_long": "モバイル端末向けのプッシュ通知は管理者によって無効化されています",
"user.settings.push_notification.info": "Mattermostにアクティビティーがあると、あなたのモバイル端末に通知がプッシュされます。",
"user.settings.push_notification.off": "オフ",
"user.settings.push_notification.onlyMentions": "あなたについての投稿とダイレクトメッセージに関して",
diff --git a/webapp/i18n/pt-BR.json b/webapp/i18n/pt-BR.json
index 82ef497f1..ca0fd2dd7 100644
--- a/webapp/i18n/pt-BR.json
+++ b/webapp/i18n/pt-BR.json
@@ -1,6 +1,7 @@
{
"about.close": "Fechar",
"about.copyright": "Copyright 2016 Mattermost, Inc. Todos os direitos reservados",
+ "about.database": "Banco de dados:",
"about.date": "Data De Criação:",
"about.enterpriseEditionLearn": "Saiba mais sobre Enterprise Edition em ",
"about.enterpriseEditionSt": "Moderna comunicação empresarial atrás do seu firewall.",
@@ -90,7 +91,7 @@
"admin.compliance.enableDesc": "Quando verdadeiro, Mattermost permite relatório compliance",
"admin.compliance.enableTitle": "Ativar Compliance:",
"admin.compliance.false": "falso",
- "admin.compliance.noLicense": "<h4 class=\"banner__heading\">Nota:</h4><p>Compliance é um recurso empresarial. Sua licença atual não suporta Compliance. Clique <a href=\"http://mattermost.com\" target=\"_blank\">aqui</a> para informações e preços da licença empresarial.</p>",
+ "admin.compliance.noLicense": "<h4 class=\"banner__heading\">Nota:</h4><p>Compliance é um recurso enterprise. Sua licença atual não suporta Compliance. Clique <a href=\"http://mattermost.com\" target=\"_blank\">aqui</a> para informações e preços da licença enterprise.</p>",
"admin.compliance.save": "Salvar",
"admin.compliance.saving": "Salvando Config...",
"admin.compliance.title": "Configurações Compliance",
@@ -180,9 +181,9 @@
"admin.email.smtpUsernameTitle": "Usuário SMTP:",
"admin.email.testing": "Testando...",
"admin.false": "falso",
- "admin.general.localization.availableLocalesDescription": "Determines which languages are available for users in Account Settings.",
- "admin.general.localization.clientLocaleDescription": "Default language for newly created users and pages where the user hasn't logged in.",
- "admin.general.localization.serverLocaleDescription": "Default language for system messages and logs. Changing this will require a server restart before taking effect.",
+ "admin.general.localization.availableLocalesDescription": "Determina qual linguagem estará disponível para os usuários em Configurações de Conta.",
+ "admin.general.localization.clientLocaleDescription": "Linguagem padrão para os novos usuários criados e páginas onde o usuário não esteja logado.",
+ "admin.general.localization.serverLocaleDescription": "Linguagem padrão para o sistema de mensagens e logs. Alterando isto será necessário reiniciar o servidor antes que a alteração tenha efeito.",
"admin.gitab.clientSecretDescription": "Obter este valor de acordo com as instruções acima para logar no GitLab.",
"admin.gitlab.EnableHtmlDesc": "<ol><li>Faça login na sua conta do GitLab e vá para Configurações do Perfil -> Aplicativos.</li><li>Digite redirecionamento URIs \"<your-mattermost-url>/login/gitlab/complete\" (exemplo: http://localhost:8065/login/gitlab/complete) e \"<your-mattermost-url>/signup/gitlab/complete\".</li><li>Em seguida use os campos \"Secret\" e \"Id\" do Gitlab para completar as opções abaixo.</li><li>Complete o Endpoint com as URLs abaixo. </li></ol>",
"admin.gitlab.authDescription": "Entre https://<your-gitlab-url>/oauth/authorize (exemplo https://example.com:3000/oauth/authorize). Tenha certeza de usar HTTP ou HTTPS na sua URL dependendo da configuração do seu servidor.",
@@ -270,7 +271,7 @@
"admin.ldap.nicknameAttrDesc": "(Opcional) O atributo no servidor LDAP que será usado para preencher o apelido dos usuários no Mattermost.",
"admin.ldap.nicknameAttrEx": "Ex \"nickname\"",
"admin.ldap.nicknameAttrTitle": "Atributo Apelido:",
- "admin.ldap.noLicense": "<h4 class=\"banner__heading\">Nota:</h4><p>LDAP é um recurso empresarial. Sua licença atual não suporta LDAP. Clique <a href=\"http://mattermost.com\" target=\"_blank\">aqui</a> para informações e preços da licença empresarial.</p>",
+ "admin.ldap.noLicense": "<h4 class=\"banner__heading\">Nota:</h4><p>LDAP é um recurso enterprise. Sua licença atual não suporta LDAP. Clique <a href=\"http://mattermost.com\" target=\"_blank\">aqui</a> para informações e preços da licença enterprise.</p>",
"admin.ldap.portDesc": "A porta que o Mattermost irá usar para conectar ao servidor LDAP. Padrão é 389.",
"admin.ldap.portEx": "Ex \"389\"",
"admin.ldap.portTitle": "Porta LDAP:",
@@ -282,8 +283,8 @@
"admin.ldap.serverTitle": "Servidor LDAP:",
"admin.ldap.skipCertificateVerification": "Pular a Verificação do Certificado",
"admin.ldap.skipCertificateVerificationDesc": "Pula a etapa de verificação do certificado para conexões TLS ou STARTTLS. Não recomentado para ambientes de produção onde TLS é necessário. Apenas para teste.",
- "admin.ldap.syncIntervalHelpText": "LDAP Synchronization is the process by which Mattermost updates its users to reflect any updated data on the LDAP server. For example if a name for a user is updated on the LDAP server, the change will be reflected in Mattermost when the synchronization is performed. Accounts that have been removed from the LDAP server will have their active sessions cleared and no longer be able to login to Mattermost. Mattermost will perform this synchronization regularly according to the interval supplied here. For example, if 60 is supplied, Mattermost will update the users every hour.",
- "admin.ldap.syncIntervalTitle": "Synchronization Interval (In Minutes)",
+ "admin.ldap.syncIntervalHelpText": "Sincronização LDAP é o processo pelo qual Mattermost atualiza seus usuários para refletir quaisquer dados atualizados no servidor LDAP. Por exemplo, se um nome de um usuário é atualizado no servidor LDAP, a alteração será refletida no Mattermost quando a sincronização é executada. As contas que tenham sido removidos do servidor LDAP terão suas sessões ativas apagada e não será mais capaz para acessar Mattermost. Mattermost irá realizar a sincronização regularmente, de acordo com o intervalo fornecido aqui. Por exemplo, se 60 é fornecido, Mattermost irá atualizar os usuários cada hora.",
+ "admin.ldap.syncIntervalTitle": "Intervalo de Sincronização (em Minutos)",
"admin.ldap.uernameAttrDesc": "O atributo no servidor LDAP que será usado para preencher o campo nome de usuário no Mattermost. Este pode ser o mesmo que o Atributo ID.",
"admin.ldap.userFilterDisc": "Opcionalmente, insira um filtro LDAP para usar ao procurar por objetos de usuário. Somente os usuários selecionados pela consulta serão capazes de acessar o Mattermost. Para o Active Directory, a consulta para filtrar os usuários desativados é (&(objectCategory=Person)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))).",
"admin.ldap.userFilterEx": "Ex. \"(objectClass=user)\"",
@@ -396,7 +397,7 @@
"admin.service.overrideTitle": "Ativar Sobrescrever os Nomes de usuário a partir de Webhooks e Comandos Slash: ",
"admin.service.securityDesc": "Quando verdadeiro, os Administradores de Sistema são notificados por e-mail se uma relevante correção de segurança foi anunciado nos últimos 12 horas. Requer o e-mail para ser ativado.",
"admin.service.securityTitle": "Ativar Alertas de Segurança: ",
- "admin.service.segmentDescription": "Segment.com is an online service that can be optionally used to track detailed system statistics. You can obtain a key by signing-up for a free account at Segment.com.",
+ "admin.service.segmentDescription": "Segment.com é um serviço online que pode opcionalmente ser usado para rastrear detalhes das estatísticas do sistema. Você pode obter uma chave criando uma conta gratuita em Segment.com.",
"admin.service.segmentExample": "Ex \"g3fgGOXJAQ43QV7rAh6iwQCkV4cA1Gs\"",
"admin.service.segmentTitle": "Desenvolvedor Segmento Chave:",
"admin.service.sessionCache": "Cache da Sessão em Minutos:",
@@ -473,7 +474,7 @@
"admin.sql.warning": "Aviso: re-gerar este salt pode causar algumas colunas no banco de dados para retornar resultados vazios.",
"admin.support.aboutDesc": "Link para página Sobre para mais informações sobre a implantação do Mattermost, por exemplo a sua finalidade e público dentro de sua organização. Padrão página de informação Mattermost.",
"admin.support.aboutTitle": "Sobre link:",
- "admin.support.emailHelp": "Email address displayed on email notifications and during tutorial for end users to ask support questions.",
+ "admin.support.emailHelp": "Endereço de email mostrado na notificação de email e durante o tutorial para o usuário final pedir suporte.",
"admin.support.emailTitle": "E-mail de suporte:",
"admin.support.helpDesc": "Link para documentação de ajuda para o site da equipe no menu principal. Normalmente não é alterado ao menos se sua empresa escolha criar uma documentação customizada.",
"admin.support.helpTitle": "Link de ajuda:",
@@ -552,8 +553,8 @@
"analytics.chart.meaningful": "Não há dados suficientes para uma representação significativa.",
"analytics.system.activeUsers": "Usuários Ativos Com Posts",
"analytics.system.channelTypes": "Tipos de Canal",
- "analytics.system.expiredBanner": "The Enterprise license expired on {date}. You have 15 days from this date to renew the license, please contact <a href='mailto:commercial@mattermost.com'>commercial@mattermost.com</a>.",
- "analytics.system.expiringBanner": "The Enterprise license is expiring on {date}. To renew your license, please contact <a href='mailto:commercial@mattermost.com'>commercial@mattermost.com</a>.",
+ "analytics.system.expiredBanner": "A licença Enterprise expirou em {date}. Você tem 15 dias a partir desta data para renovar a licença, por favor contate <a href='mailto:commercial@mattermost.com'>commercial@mattermost.com</a>.",
+ "analytics.system.expiringBanner": "A licença Enterprise termina em {date}. Para renovar sua licença, por favor contate <a href='mailto:commercial@mattermost.com'>commercial@mattermost.com</a>.",
"analytics.system.postTypes": "Posts, Arquivos e Hashtags",
"analytics.system.privateGroups": "Grupos Privados",
"analytics.system.publicChannels": "Canais Públicos",
@@ -719,11 +720,11 @@
"channel_notifications.sendDesktop": "Enviar notificações de desktop",
"channel_notifications.unreadInfo": "O nome do canal fica em negrito na barra lateral quando houver mensagens não lidas. Selecionando \"Apenas menções\" o canal vai ficar em negrito apenas quando você for mencionado.",
"channel_select.placeholder": "--- Selecione um canal ---",
- "channel_switch_modal.dm": "Mensagem Direta",
- "channel_switch_modal.help": "Type channel name. Use ↑↓ to browse, TAB to select, ↵ to confirm, ESC to dismiss",
- "channel_switch_modal.not_found": "No matches found.",
- "channel_switch_modal.submit": "Switch",
- "channel_switch_modal.title": "Switch Channels",
+ "channel_switch_modal.dm": "(Mensagem Direta)",
+ "channel_switch_modal.help": "Digite o nome do canal. Use ↑↓ para navegar, TAB para selecionar, ↵ para confirmar, ESC para cancelar",
+ "channel_switch_modal.not_found": "Nenhum resultado encontrado.",
+ "channel_switch_modal.submit": "Alternar",
+ "channel_switch_modal.title": "Alternar Canais",
"choose_auth_page.emailCreate": "Criar uma nova equipe com endereço de email",
"choose_auth_page.find": "Encontrar minhas equipes",
"choose_auth_page.gitlabCreate": "Criar uma equipe com uma conta GitLab",
@@ -840,14 +841,14 @@
"email_verify.verified": "{siteName} Email Verificado",
"email_verify.verifiedBody": "<p>Seu email foi verificado! Clique <a href={url}>aqui</a> para login.</p>",
"email_verify.verifyFailed": "Falha ao verificar seu email.",
- "error.not_found.link_message": "Back to Mattermost",
- "error.not_found.message": "The page you were trying to reach does not exist",
- "error.not_found.title": "Page not found",
- "error.not_supported.message": "Private browsing is not supported",
- "error.not_supported.title": "Browser not supported",
- "error_bar.expired": "Enterprise license has expired; you have 15 days from expiry to renew the license, please contact commercial@mattermost.com for details",
- "error_bar.expiring": "The Enterprise license is expiring on {date}. To renew your license, please contact commercial@mattermost.com",
- "error_bar.past_grace": "Enterprise license has expired, please contact your System Administrator for details",
+ "error.not_found.link_message": "Voltar para Mattermost",
+ "error.not_found.message": "A página que você estava tentando alcançar não existe",
+ "error.not_found.title": "Página não encontrada",
+ "error.not_supported.message": "Navegação privada não é suportado",
+ "error.not_supported.title": "Navegador não suportado",
+ "error_bar.expired": "A licença Enterprise expirou; você tem 15 dias a partir da expiração para renovar a licença, por favor contate commercial@mattermost.com para detalhes",
+ "error_bar.expiring": "A licença Enterprise termina em {date}. Para renovar sua licença, por favor contate commercial@mattermost.com",
+ "error_bar.past_grace": "A licença Enterprise está expirada, por favor contate seu Administrador de Sistema para detalhes",
"error_bar.preview_mode": "Modo de visualização: Notificações por E-mail não foram configuradas",
"file_attachment.download": "Download",
"file_info_preview.size": "Tamanho ",
@@ -880,7 +881,7 @@
"general_tab.includeDirDesc": "Incluindo esta equipe irá exibir o nome da equipe da seção Diretório Equipe da página inicial, e fornecer um link para a página de login.",
"general_tab.includeDirTitle": "Incluir esta equipe no Diretório de Equipe",
"general_tab.no": "Não",
- "general_tab.openInviteDesc": "Quando permitido, um link para esta equipe vai ser incluído na página de destino permitindo que qualquer pessoa com uma conta possa participar desse time.",
+ "general_tab.openInviteDesc": "Quando permitido, um link para esta equipe vai ser incluído na página de destino permitindo que qualquer pessoa com uma conta possa participar desta equipe.",
"general_tab.openInviteTitle": "Permitir que qualquer pessoa possa participar desse time",
"general_tab.regenerate": "Re-Gerar",
"general_tab.required": "Este campo é obrigatório",
@@ -967,14 +968,14 @@
"login.ldapUsername": "Usuário LDAP",
"login.ldapUsernameLower": "Usuário LDAP",
"login.noAccount": "Não tem uma conta? ",
- "login.noEmail": "Please enter your email",
- "login.noEmailLdapUsername": "Please enter your email or {ldapUsername}",
- "login.noEmailUsername": "Please enter your email or username",
- "login.noEmailUsernameLdapUsername": "Please enter your email, username or {ldapUsername}",
- "login.noLdapUsername": "Please enter your {ldapUsername}",
- "login.noPassword": "Por favor digite a sua senha.",
- "login.noUsername": "Please enter your username",
- "login.noUsernameLdapUsername": "Please enter your username or {ldapUsername}",
+ "login.noEmail": "Por favor digite seu email",
+ "login.noEmailLdapUsername": "Por favor digite seu email ou {ldapUsername}",
+ "login.noEmailUsername": "Por favor digite seu email ou usuário",
+ "login.noEmailUsernameLdapUsername": "Por favor digite seu email, usuário ou {ldapUsername}",
+ "login.noLdapUsername": "Por favor digite seu {ldapUsername}",
+ "login.noPassword": "Por favor digite a sua senha",
+ "login.noUsername": "Por favor digite seu usuário",
+ "login.noUsernameLdapUsername": "Por favor digite seu usuário ou {ldapUsername}",
"login.on": "no {siteName}",
"login.or": "ou",
"login.password": "Senha",
@@ -1050,8 +1051,8 @@
"pending_post_actions.cancel": "Cancelar",
"pending_post_actions.retry": "Tentar novamente",
"permalink.error.access": "Permalink pertence a um canal que você não tem acesso",
- "post_attachment.collapse": "Show less...",
- "post_attachment.more": "Show more...",
+ "post_attachment.collapse": "Mostrar menos...",
+ "post_attachment.more": "Mostrar mais...",
"post_body.commentedOn": "Comentado da mensagem {name}{apostrophe}: ",
"post_body.deleted": "(mensagem deletada)",
"post_body.plusMore": " mais {count} outros arquivos",
@@ -1173,7 +1174,7 @@
"signup_user_completed.expired": "Você já concluiu o processo de inscrição para este convite ou este convite expirou.",
"signup_user_completed.gitlab": "com GitLab",
"signup_user_completed.google": "com Google",
- "signup_user_completed.haveAccount": "Already have an account?",
+ "signup_user_completed.haveAccount": "Já tem uma conta?",
"signup_user_completed.invalid_invite": "O link convite era inválido. Por favor fale com seu Administrador para receber um convite.",
"signup_user_completed.lets": "Vamos criar a sua conta",
"signup_user_completed.no_open_server": "Este servidor não permite inscrições abertas. Por favor fale com seu Administrador para receber um convite.",
@@ -1183,7 +1184,7 @@
"signup_user_completed.passwordLength": "Por favor entre no mínimo {min} caracteres",
"signup_user_completed.required": "Este campo é obrigatório",
"signup_user_completed.reserved": "Este nome de usuário é reservado, por favor, escolha um novo.",
- "signup_user_completed.signIn": "Click here to sign in.",
+ "signup_user_completed.signIn": "Clique aqui para fazer login.",
"signup_user_completed.userHelp": "O nome de usuário precisa começar com uma letra, e conter entre {min} e {max} caracteres minúsculos contendo números, letras, e os símbolos '.', '-' e '_'",
"signup_user_completed.usernameLength": "O nome de usuário precisa começar com uma letra, e conter entre {min} e {max} caracteres minúsculos contendo números, letras, e os símbolos '.', '-' e '_'.",
"signup_user_completed.validEmail": "Por favor entre um endereço de e-mail válido",
@@ -1196,7 +1197,7 @@
"sso_signup.length_error": "O nome deve ser de 3 ou mais caracteres até um máximo de 15",
"sso_signup.teamName": "Entre o nome da nova equipe",
"sso_signup.team_error": "Por favor entre o nome da equipe",
- "suggestion.mention.all": "Notifies everyone in the channel, use in {townsquare} to notify the whole team",
+ "suggestion.mention.all": "Notifique a todos no canal, use {townsquare} para notificar toda a equipe",
"suggestion.mention.channel": "Notifica todos no canal",
"suggestion.search.private": "Grupos Privados",
"suggestion.search.public": "Canais Públicos",
diff --git a/webapp/sass/layout/_post.scss b/webapp/sass/layout/_post.scss
index 938f4bde6..db64d739e 100644
--- a/webapp/sass/layout/_post.scss
+++ b/webapp/sass/layout/_post.scss
@@ -258,10 +258,6 @@ body.ios {
position: absolute;
width: 100%;
- .modal-open & {
- @include clearfix;
- }
-
&.active {
display: inline;
}
diff --git a/webapp/sass/responsive/_mobile.scss b/webapp/sass/responsive/_mobile.scss
index d4c7242b4..eec08b1e5 100644
--- a/webapp/sass/responsive/_mobile.scss
+++ b/webapp/sass/responsive/_mobile.scss
@@ -1,6 +1,14 @@
@charset 'UTF-8';
@media screen and (max-width: 768px) {
+ #post-list {
+ .post-list-holder-by-time {
+ .modal-open & {
+ @include clearfix;
+ }
+ }
+ }
+
.post-code__language {
@include opacity(.6);
@include transition(none);
diff --git a/webapp/stores/post_store.jsx b/webapp/stores/post_store.jsx
index b5e73b6b4..b77c7bd3c 100644
--- a/webapp/stores/post_store.jsx
+++ b/webapp/stores/post_store.jsx
@@ -231,13 +231,14 @@ class PostStoreClass extends EventEmitter {
this.postsInfo[post.channel_id].postList = postList;
}
- storeFocusedPost(postId, postList) {
+ storeFocusedPost(postId, channelId, postList) {
const focusedPost = postList.posts[postId];
if (!focusedPost) {
return;
}
this.currentFocusedPostId = postId;
this.storePosts(postId, postList);
+ this.storePosts(channelId, postList);
}
checkBounds(id, numRequested, postList, before) {
@@ -407,11 +408,11 @@ class PostStoreClass extends EventEmitter {
return null;
}
- let posts;
+ const posts = {};
let pendingPosts;
for (const k in this.postsInfo) {
if (this.postsInfo[k].postList && this.postsInfo[k].postList.posts.hasOwnProperty(this.selectedPostId)) {
- posts = this.postsInfo[k].postList.posts;
+ Object.assign(posts, this.postsInfo[k].postList.posts);
if (this.postsInfo[k].pendingPosts != null) {
pendingPosts = this.postsInfo[k].pendingPosts.posts;
}
@@ -559,7 +560,7 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => {
}
case ActionTypes.RECEIVED_FOCUSED_POST:
PostStore.clearChannelVisibility(action.postId, false);
- PostStore.storeFocusedPost(action.postId, makePostListNonNull(action.post_list));
+ PostStore.storeFocusedPost(action.postId, action.channelId, makePostListNonNull(action.post_list));
PostStore.emitChange();
break;
case ActionTypes.RECEIVED_POST:
@@ -579,6 +580,10 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => {
PostStore.storeDraft(action.post.channel_id, null);
PostStore.jumpPostsViewToBottom();
break;
+ case ActionTypes.CREATE_COMMENT:
+ PostStore.storePendingPost(action.post);
+ PostStore.storeCommentDraft(action.post.root_id, null);
+ break;
case ActionTypes.POST_DELETED:
PostStore.deletePost(action.post);
PostStore.emitChange();
diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx
index 3a6098713..c8807ae8d 100644
--- a/webapp/utils/constants.jsx
+++ b/webapp/utils/constants.jsx
@@ -41,6 +41,7 @@ export default {
CREATE_CHANNEL: null,
LEAVE_CHANNEL: null,
CREATE_POST: null,
+ CREATE_COMMENT: null,
POST_DELETED: null,
REMOVE_POST: null,