Merge branch 'master' of github.com:mattermost/mattermost-server into MM-50966-in-product-expansion

Этот коммит содержится в:
Conor Macpherson
2023-04-10 15:44:47 -04:00
родитель 9e41644c5b 6e7759b314
Коммит cd82eede4d
755 изменённых файлов: 10576 добавлений и 6549 удалений

Просмотреть файл

@@ -1,3 +1,3 @@
save-exact=true
legacy-peer-deps=true
global-style=true
global-style=true

Просмотреть файл

@@ -17,7 +17,7 @@ stop: ## Stops webpack
ifeq ($(OS),Windows_NT)
wmic process where "Caption='node.exe' and CommandLine like '%webpack%'" call terminate
else
@pkill -f webpack || true
-@pkill -f webpack || true
endif
.PHONY: restart

Просмотреть файл

@@ -112,7 +112,6 @@
"Categories.CreateCategoryDialog.UpdateText": "تحديث",
"CenterPanel.Login": "تسجيل الدخول",
"CenterPanel.Share": "مشاركة",
"CloudMessage.cloud-server": "احصل علي خادم سحابي خاص بك مجاني.",
"ColorOption.selectColor": "اختر {color} اللون",
"Comment.delete": "حذف",
"CommentsList.send": "إرسال",

Просмотреть файл

@@ -1,4 +1,6 @@
{
"AdminBadge.SystemAdmin": "Administrator",
"AdminBadge.TeamAdmin": "Teamadministrator",
"AppBar.Tooltip": "Verknüpfte Boards umschalten",
"Attachment.Attachment-title": "Anhang",
"AttachmentBlock.DeleteAction": "Löschen",
@@ -22,7 +24,7 @@
"BoardMember.schemeCommenter": "Kommentator",
"BoardMember.schemeEditor": "Bearbeiter",
"BoardMember.schemeNone": "Keine",
"BoardMember.schemeViewer": "Viewer",
"BoardMember.schemeViewer": "Leser",
"BoardMember.unlinkChannel": "Verknüpfung aufheben",
"BoardPage.newVersion": "Eine neue Version von Boards ist verfügbar, klicke hier, um neu zu laden.",
"BoardPage.syncFailed": "Das Board kann gelöscht oder der Zugang entzogen werden.",
@@ -115,7 +117,6 @@
"CenterPanel.Login": "Anmeldung",
"CenterPanel.Share": "Teilen",
"ChannelIntro.CreateBoard": "Erstelle ein Board",
"CloudMessage.cloud-server": "Hole deine eigenen freien Cloud Server.",
"ColorOption.selectColor": "Wähle Farbe {color}",
"Comment.delete": "Löschen",
"CommentsList.send": "Abschicken",
@@ -138,6 +139,7 @@
"ContentBlock.moveDown": "Nach unten bewegen",
"ContentBlock.moveUp": "Nach oben bewegen",
"ContentBlock.text": "Text",
"DateFilter.empty": "Leer",
"DateRange.clear": "Leeren",
"DateRange.empty": "Leer",
"DateRange.endDate": "Enddatum",
@@ -156,10 +158,14 @@
"Filter.ends-with": "endet mit",
"Filter.includes": "beinhaltet",
"Filter.is": "ist",
"Filter.is-after": "ist nach",
"Filter.is-before": "ist vor",
"Filter.is-empty": "ist leer",
"Filter.is-not-empty": "ist nicht leer",
"Filter.is-not-set": "ist nicht gesetzt",
"Filter.is-set": "ist gesetzt",
"Filter.isafter": "ist nach",
"Filter.isbefore": "ist vor",
"Filter.not-contains": "enthält nicht",
"Filter.not-ends-with": "endet nicht mit",
"Filter.not-includes": "beinhaltet nicht",
@@ -306,6 +312,7 @@
"ValueSelector.valueSelector": "Werteselektor",
"ValueSelectorLabel.openMenu": "Menü öffnen",
"VersionMessage.help": "Finde raus, was es Neues in dieser Version gibt.",
"VersionMessage.learn-more": "Erfahre mehr",
"View.AddView": "Ansicht hinzufügen",
"View.Board": "Board",
"View.DeleteView": "Ansicht löschen",
@@ -360,6 +367,9 @@
"WelcomePage.StartUsingIt.Text": "Verwende es",
"Workspace.editing-board-template": "Du bearbeitest eine Board Vorlage.",
"badge.guest": "Gast",
"boardPage.confirm-join-button": "Teilnehmen",
"boardPage.confirm-join-text": "Du bist dabei einem privaten Board zu betreten, ohne dass du explizit durch den Board-Administrator hinzugefügt wurdest. Bist du sicher, dass du diesem privaten Board beitreten willst?",
"boardPage.confirm-join-title": "Privatem Board beitreten",
"boardSelector.confirm-link-board": "Verknüpfe Board mit Kanal",
"boardSelector.confirm-link-board-button": "Ja, verknüpfe Board",
"boardSelector.confirm-link-board-subtext": "Wenn du \"{boardName}\" mit diesem Kanal verknüpfst, werden alle Mitglieder des Kanals (aktuelle und neue) das Board bearbeiten können. Dies schließt Mitglieder aus, die Gast sind. Du kannst die Verknüpfung eine Boards mit einem Kanal jederzeit entfernen.",

Просмотреть файл

@@ -1,7 +1,7 @@
{
"AdminBadge.SystemAdmin": "Admin",
"AdminBadge.TeamAdmin": "Team Admin",
"AppBar.Tooltip": "Toggle Linked Boards",
"AppBar.Tooltip": "Toggle linked boards",
"Attachment.Attachment-title": "Attachment",
"AttachmentBlock.DeleteAction": "delete",
"AttachmentBlock.addElement": "add {type}",
@@ -453,4 +453,4 @@
"tutorial_tip.ok": "Next",
"tutorial_tip.out": "Opt out of these tips.",
"tutorial_tip.seen": "Seen this before?"
}
}

Просмотреть файл

@@ -1,5 +1,7 @@
{
"AppBar.Tooltip": "Toggle linked boards",
"AdminBadge.SystemAdmin": "Admin",
"AdminBadge.TeamAdmin": "Team Admin",
"AppBar.Tooltip": "Toggle Linked Boards",
"Attachment.Attachment-title": "Attachment",
"AttachmentBlock.DeleteAction": "delete",
"AttachmentBlock.addElement": "add {type}",
@@ -115,7 +117,6 @@
"CenterPanel.Login": "Login",
"CenterPanel.Share": "Share",
"ChannelIntro.CreateBoard": "Create a board",
"CloudMessage.cloud-server": "Get your own free cloud server.",
"ColorOption.selectColor": "Select {color} Colour",
"Comment.delete": "Delete",
"CommentsList.send": "Send",
@@ -138,6 +139,7 @@
"ContentBlock.moveDown": "Move down",
"ContentBlock.moveUp": "Move up",
"ContentBlock.text": "text",
"DateFilter.empty": "Empty",
"DateRange.clear": "Clear",
"DateRange.empty": "Empty",
"DateRange.endDate": "End date",
@@ -156,10 +158,14 @@
"Filter.ends-with": "ends with",
"Filter.includes": "includes",
"Filter.is": "is",
"Filter.is-after": "is after",
"Filter.is-before": "is before",
"Filter.is-empty": "is empty",
"Filter.is-not-empty": "is not empty",
"Filter.is-not-set": "is not set",
"Filter.is-set": "is set",
"Filter.isafter": "is after",
"Filter.isbefore": "is before",
"Filter.not-contains": "does not contain",
"Filter.not-ends-with": "does not end with",
"Filter.not-includes": "doesn't include",
@@ -306,6 +312,7 @@
"ValueSelector.valueSelector": "Value selector",
"ValueSelectorLabel.openMenu": "Open menu",
"VersionMessage.help": "Check out what's new in this version.",
"VersionMessage.learn-more": "Learn more",
"View.AddView": "Add view",
"View.Board": "Board",
"View.DeleteView": "Delete view",
@@ -360,6 +367,9 @@
"WelcomePage.StartUsingIt.Text": "Start using it",
"Workspace.editing-board-template": "You're editing a board template.",
"badge.guest": "Guest",
"boardPage.confirm-join-button": "Join",
"boardPage.confirm-join-text": "You are about to join a private board without explicitly being added by the board admin. Are you sure you wish to join this private board?",
"boardPage.confirm-join-title": "Join private board",
"boardSelector.confirm-link-board": "Link board to channel",
"boardSelector.confirm-link-board-button": "Link board",
"boardSelector.confirm-link-board-subtext": "When you link '\\{boardName}'\\ to the channel, all members of the channel (existing and new) will be able to edit it. This excludes members who are guests. You can unlink a board from a channel at any time.",

Просмотреть файл

@@ -102,7 +102,6 @@
"Categories.CreateCategoryDialog.UpdateText": "Mettre à jour",
"CenterPanel.Login": "Connexion",
"CenterPanel.Share": "Partager",
"CloudMessage.cloud-server": "Obtenez votre propre serveur cloud gratuitement.",
"ColorOption.selectColor": "Choisir la couleur {color}",
"Comment.delete": "Supprimer",
"CommentsList.send": "Envoyer",

Просмотреть файл

@@ -101,7 +101,6 @@
"Categories.CreateCategoryDialog.UpdateText": "עדכון",
"CenterPanel.Login": "כניסה",
"CenterPanel.Share": "שיתוף",
"CloudMessage.cloud-server": "קבל שרת ענן בחינם.",
"ColorOption.selectColor": "בחירת צבע {color}",
"Comment.delete": "מחיקה",
"CommentsList.send": "שליחה",

Просмотреть файл

@@ -1,4 +1,6 @@
{
"AdminBadge.SystemAdmin": "Administrator",
"AdminBadge.TeamAdmin": "Tim administratora",
"AppBar.Tooltip": "Uklj./Isklj. povezane ploče",
"Attachment.Attachment-title": "Prilog",
"AttachmentBlock.DeleteAction": "izbriši",
@@ -115,7 +117,6 @@
"CenterPanel.Login": "Prijava",
"CenterPanel.Share": "Dijeli",
"ChannelIntro.CreateBoard": "Stvori ploču",
"CloudMessage.cloud-server": "Nabavi vlastiti besplatni poslužitelj u oblaku.",
"ColorOption.selectColor": "Odaberi boju {color}",
"Comment.delete": "Izbriši",
"CommentsList.send": "Pošalji",
@@ -138,6 +139,7 @@
"ContentBlock.moveDown": "Pomakni dolje",
"ContentBlock.moveUp": "Pomakni gore",
"ContentBlock.text": "tekst",
"DateFilter.empty": "Prazno",
"DateRange.clear": "Isprazni",
"DateRange.empty": "Prazno",
"DateRange.endDate": "Datum kraja",
@@ -156,10 +158,14 @@
"Filter.ends-with": "završava sa",
"Filter.includes": "uključuje",
"Filter.is": "je",
"Filter.is-after": "je nakon",
"Filter.is-before": "je prije",
"Filter.is-empty": "je prazno",
"Filter.is-not-empty": "nije prazno",
"Filter.is-not-set": "nije postavljeno",
"Filter.is-set": "je postavljeno",
"Filter.isafter": "je nakon",
"Filter.isbefore": "je prije",
"Filter.not-contains": "ne sadrži",
"Filter.not-ends-with": "ne završava sa",
"Filter.not-includes": "ne uključuje",
@@ -306,6 +312,7 @@
"ValueSelector.valueSelector": "Selektor vrijednosti",
"ValueSelectorLabel.openMenu": "Otvori izbornik",
"VersionMessage.help": "Provjeri što je novo u ovoj verziji.",
"VersionMessage.learn-more": "Saznaj više",
"View.AddView": "Dodaj prikaz",
"View.Board": "Ploča",
"View.DeleteView": "Izbriši prikaz",
@@ -360,6 +367,9 @@
"WelcomePage.StartUsingIt.Text": "Počni ga koristiti",
"Workspace.editing-board-template": "Uređuješ predložak ploče.",
"badge.guest": "Gost",
"boardPage.confirm-join-button": "Pridruži se",
"boardPage.confirm-join-text": "Pridružit ćeš se privatnoj ploči bez da te je administrator ploče izričito dodao. Stvarno se želiš pridružiti ovoj privatnoj ploči?",
"boardPage.confirm-join-title": "Pridruži se privatnoj ploči",
"boardSelector.confirm-link-board": "Poveži ploču s kanalom",
"boardSelector.confirm-link-board-button": "Da, poveži ploču",
"boardSelector.confirm-link-board-subtext": "Kad povežeš ploču „{boardName}” s kanalom, svi članovi kanala (postojeći i novi) moći će je uređivati. To ne vrijedi za članove koji su gosti. Vezu između ploče i kanala možeš raskinuti u bilo kojem trenutku.",

Просмотреть файл

@@ -114,7 +114,6 @@
"Categories.CreateCategoryDialog.UpdateText": "Frissítés",
"CenterPanel.Login": "Bejelentkezés",
"CenterPanel.Share": "Megosztás",
"CloudMessage.cloud-server": "Szerezze be saját ingyenes felhőszerverét.",
"ColorOption.selectColor": "{color} szín kiválasztása",
"Comment.delete": "Törlés",
"CommentsList.send": "Küldés",

Просмотреть файл

@@ -100,7 +100,6 @@
"Categories.CreateCategoryDialog.UpdateText": "Aggiorna",
"CenterPanel.Login": "Login",
"CenterPanel.Share": "Condividi",
"CloudMessage.cloud-server": "Ottieni il tuo server cloud gratuito.",
"ColorOption.selectColor": "Seleziona{color} Colore",
"Comment.delete": "Elimina",
"CommentsList.send": "Invia",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "ログイン",
"CenterPanel.Share": "共有",
"ChannelIntro.CreateBoard": "Boardを作成する",
"CloudMessage.cloud-server": "専用の無料クラウドサーバーを入手する。",
"ColorOption.selectColor": "{color} 色を選択",
"Comment.delete": "削除",
"CommentsList.send": "送信",

Просмотреть файл

@@ -102,7 +102,6 @@
"Categories.CreateCategoryDialog.UpdateText": "განახლება",
"CenterPanel.Login": "შესვლა",
"CenterPanel.Share": "გაზიარება",
"CloudMessage.cloud-server": "მიიღეთ თქვენი საკუთარი უფასო Cloud სერვერი.",
"ColorOption.selectColor": "აირჩიეთ {color} ფერი",
"Comment.delete": "წაშლა",
"CommentsList.send": "გაგზავნა",

Просмотреть файл

@@ -114,7 +114,6 @@
"Categories.CreateCategoryDialog.UpdateText": "업데이트",
"CenterPanel.Login": "로그인",
"CenterPanel.Share": "공유",
"CloudMessage.cloud-server": "무료 클라우드 서버를 구입하십시오.",
"ColorOption.selectColor": "{color} 색 선택하기",
"Comment.delete": "삭제하기",
"CommentsList.send": "보내기",

1
webapp/boards/i18n/lt.json Обычный файл
Просмотреть файл

@@ -0,0 +1 @@
{}

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "Logg inn",
"CenterPanel.Share": "Del",
"ChannelIntro.CreateBoard": "Opprett tavle",
"CloudMessage.cloud-server": "Få din egen gratis skytjener.",
"ColorOption.selectColor": "Velg {color} farge",
"Comment.delete": "Slett",
"CommentsList.send": "Send",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "Aanmelden",
"CenterPanel.Share": "Delen",
"ChannelIntro.CreateBoard": "Een bord aanmaken",
"CloudMessage.cloud-server": "Krijg jouw eigen gratis cloud server.",
"ColorOption.selectColor": "Selecteer {color} Kleur",
"Comment.delete": "Verwijderen",
"CommentsList.send": "Verzenden",

Просмотреть файл

@@ -1,5 +1,7 @@
{
"AppBar.Tooltip": "Przełączanie podlinkowanych tablic",
"AdminBadge.SystemAdmin": "Administrator",
"AdminBadge.TeamAdmin": "Administrator Zespołu",
"AppBar.Tooltip": "Przełączanie Podlinkowanych Tablic",
"Attachment.Attachment-title": "Załącznik",
"AttachmentBlock.DeleteAction": "usuń",
"AttachmentBlock.addElement": "dodaj {type}",
@@ -115,7 +117,6 @@
"CenterPanel.Login": "Logowanie",
"CenterPanel.Share": "Udostępnij",
"ChannelIntro.CreateBoard": "Utwórz tablicę",
"CloudMessage.cloud-server": "Uzyskaj własny, bezpłatny serwer w chmurze.",
"ColorOption.selectColor": "Wybierz Kolor {color}",
"Comment.delete": "Usuń",
"CommentsList.send": "Wyślij",
@@ -138,6 +139,7 @@
"ContentBlock.moveDown": "Przenieś w dół",
"ContentBlock.moveUp": "Przenieś w górę",
"ContentBlock.text": "tekst",
"DateFilter.empty": "Puste",
"DateRange.clear": "Wyczyść",
"DateRange.empty": "Puste",
"DateRange.endDate": "Data końcowa",
@@ -156,10 +158,14 @@
"Filter.ends-with": "kończy się na",
"Filter.includes": "zawiera",
"Filter.is": "jest",
"Filter.is-after": "jest po",
"Filter.is-before": "jest przed",
"Filter.is-empty": "jest pusty",
"Filter.is-not-empty": "nie jest pusty",
"Filter.is-not-set": "nie jest ustawiony",
"Filter.is-set": "jest ustawiony",
"Filter.isafter": "jest po",
"Filter.isbefore": "jest przed",
"Filter.not-contains": "nie zawiera",
"Filter.not-ends-with": "nie kończy się na",
"Filter.not-includes": "nie zawiera",
@@ -306,6 +312,7 @@
"ValueSelector.valueSelector": "Selektor wartości",
"ValueSelectorLabel.openMenu": "Otwórz menu",
"VersionMessage.help": "Sprawdź co nowego w tej wersji.",
"VersionMessage.learn-more": "Dowiedź się więcej",
"View.AddView": "Dodaj widok",
"View.Board": "Tablica",
"View.DeleteView": "Usuń widok",
@@ -360,6 +367,9 @@
"WelcomePage.StartUsingIt.Text": "Zacznij używać",
"Workspace.editing-board-template": "Edytujesz szablon tablicy.",
"badge.guest": "Gość",
"boardPage.confirm-join-button": "Dołącz",
"boardPage.confirm-join-text": "Zamierzasz dołączyć do prywatnej tablicy bez wyraźnego dodania przez administratora forum. Czy na pewno chcesz dołączyć do tego prywatnego forum?",
"boardPage.confirm-join-title": "Dołącz do prywatnej tablicy",
"boardSelector.confirm-link-board": "Połączenie tablicy z kanałem",
"boardSelector.confirm-link-board-button": "Tak, podlinkuj tablicę",
"boardSelector.confirm-link-board-subtext": "Kiedy połączysz \"{boardName}\" z kanałem, wszyscy członkowie kanału (istniejący i nowi) będą mogli go edytować. Nie dotyczy to członków, którzy są gośćmi. W każdej chwili możesz odłączyć tablicę od kanału.",

Просмотреть файл

@@ -1,12 +1,96 @@
{
"AdminBadge.SystemAdmin": "Administrador",
"AppBar.Tooltip": "Alternar quadros vinculados",
"Attachment.Attachment-title": "Anexo",
"AttachmentBlock.DeleteAction": "Apagar",
"AttachmentBlock.addElement": "Adicionar {tipo}",
"AttachmentBlock.addElement": "Adicionar {type}",
"AttachmentBlock.delete": "Anexo apagado.",
"AttachmentBlock.failed": "Este arquivo não pôde ser carregado pois ultrapassou o tamanho limite.",
"AttachmentBlock.upload": "Carregando anexo.",
"AttachmentBlock.uploadSuccess": "Anexo carregado.",
"AttachmentElement.delete-confirmation-dialog-button-text": "Apagar",
"AttachmentElement.download": "Baixar"
"AttachmentElement.download": "Baixar",
"BoardComponent.add-a-group": "+ Adicionar um grupo",
"BoardComponent.delete": "Apagar",
"BoardComponent.hidden-columns": "Colunas escondidas",
"BoardComponent.hide": "Esconder",
"BoardComponent.new": "+ Novo",
"BoardComponent.no-property": "Não {property}",
"BoardComponent.show": "Mostrar",
"BoardMember.schemeAdmin": "Admin",
"BoardMember.schemeCommenter": "Comentador",
"BoardMember.schemeEditor": "Editor",
"BoardMember.schemeNone": "Nenhum",
"BoardMember.unlinkChannel": "Desvincular",
"BoardPage.newVersion": "Está disponível uma nova versão do Boards, clique aqui para recarregar.",
"BoardPage.syncFailed": "O Board pode ter sido apagado ou o acesso revogado.",
"BoardTemplateSelector.add-template": "Criar novo modelo",
"BoardTemplateSelector.create-empty-board": "Criar um board vazio",
"BoardTemplateSelector.delete-template": "Apagar",
"BoardTemplateSelector.edit-template": "Editar",
"BoardTemplateSelector.plugin.no-content-title": "Criar um board",
"BoardTemplateSelector.title": "Criar um board",
"BoardTemplateSelector.use-this-template": "Usar este modelo",
"BoardsSwitcher.Title": "Encontrar boards",
"Calculations.Options.average.displayName": "Média",
"Calculations.Options.average.label": "Média",
"Calculations.Options.countUniqueValue.displayName": "Único",
"Calculations.Options.countValue.displayName": "Valores",
"Calculations.Options.dateRange.displayName": "Intervalo",
"Calculations.Options.dateRange.label": "Intervalo",
"Calculations.Options.latest.label": "Mais recente",
"Calculations.Options.max.displayName": "Máx",
"Calculations.Options.max.label": "Máximo",
"Calculations.Options.min.displayName": "Mínimo",
"Calculations.Options.min.label": "Mínimo",
"Calculations.Options.none.label": "Nenhum",
"Calculations.Options.range.displayName": "Intervalo",
"Calculations.Options.range.label": "Intervalo",
"Calculations.Options.sum.displayName": "Soma",
"Calculations.Options.sum.label": "Soma",
"CalendarCard.untitled": "Sem título",
"CardActionsMenu.copiedLink": "Copiado!",
"CardActionsMenu.copyLink": "Copiar link",
"CardActionsMenu.delete": "Apagar",
"CardActionsMenu.duplicate": "Duplicar",
"CardBadges.title-comments": "Comentários",
"CardDetail.Attach": "Anexar",
"CardDetail.Follow": "Seguir",
"CardDetail.Following": "Seguindo",
"CardDetail.add-content": "Adicionar conteúdo",
"CardDetail.add-icon": "Adicionar ícone",
"CardDetail.add-property": "+ Adicionar uma propriedade",
"CardDetail.limited-button": "Atualizar",
"CardDetail.new-comment-placeholder": "Adicionar um comentário...",
"CardDetailProperty.delete-action-button": "Apagar",
"CardDialog.delete-confirmation-dialog-button-text": "Apagar",
"Categories.CreateCategoryDialog.CancelText": "Cancelar",
"Categories.CreateCategoryDialog.CreateText": "Criar",
"Categories.CreateCategoryDialog.UpdateText": "Atualizar",
"CenterPanel.Login": "Entrar",
"CenterPanel.Share": "Compartilhar",
"Comment.delete": "Apagar",
"CommentsList.send": "Enviar",
"ConfirmPerson.empty": "Vazio",
"ConfirmPerson.search": "Procurar...",
"ConfirmationDialog.cancel-action": "Cancelar",
"ConfirmationDialog.confirm-action": "Confirmar",
"ContentBlock.Delete": "Apagar",
"ContentBlock.DeleteAction": "apagar",
"ContentBlock.addElement": "adicionar {type}",
"ContentBlock.editText": "Editar texto...",
"ContentBlock.image": "imagem",
"ContentBlock.moveDown": "Mover pra baixo",
"ContentBlock.moveUp": "Mover pra cima",
"ContentBlock.text": "texto",
"DateFilter.empty": "Vazio",
"DateRange.clear": "Limpar",
"DateRange.empty": "Vazio",
"DateRange.today": "Hoje",
"DeleteBoardDialog.confirm-cancel": "Cancelar",
"DeleteBoardDialog.confirm-delete": "Apagar",
"EditableDayPicker.today": "Hoje",
"shareBoard.members-select-group": "Membros",
"shareBoard.unknown-channel-display-name": "Canal desconhecido",
"tutorial_tip.ok": "Próximo"
}

Просмотреть файл

@@ -1,11 +1,16 @@
{
"AppBar.Tooltip": "Ativar boards vinculados",
"AdminBadge.SystemAdmin": "Administrador",
"AdminBadge.TeamAdmin": "Administrador de equipe",
"AppBar.Tooltip": "Ativar Boards Vinculados",
"Attachment.Attachment-title": "Anexo",
"AttachmentBlock.DeleteAction": "apagar",
"AttachmentBlock.DeleteAction": "excluir",
"AttachmentBlock.addElement": "adicionar {type}",
"AttachmentBlock.delete": "Anexo apagado.",
"AttachmentBlock.failed": "Este arquivo não pôde ser carregado pois ultrapassou o tamanho limite.",
"AttachmentBlock.upload": "Carregando anexo.",
"AttachmentBlock.uploadSuccess": "Anexo enviado.",
"AttachmentElement.delete-confirmation-dialog-button-text": "Apagar",
"AttachmentElement.delete-confirmation-dialog-button-text": "Excluir",
"AttachmentElement.download": "Baixar",
"AttachmentElement.upload-percentage": "Enviando...({uploadPercent}%)",
"BoardComponent.add-a-group": "+ Adicione um grupo",
"BoardComponent.delete": "Excluir",
@@ -13,7 +18,7 @@
"BoardComponent.hide": "Ocultar",
"BoardComponent.new": "Novo",
"BoardComponent.no-property": "Sem {property}",
"BoardComponent.no-property-title": "Itens com um {property} vazio irão aqui. Esta coluna não pode ser removida.",
"BoardComponent.no-property-title": "Itens com um valor {property} vazio aparecerão aqui. Esta coluna não pode ser excluída.",
"BoardComponent.show": "Exibir",
"BoardMember.schemeAdmin": "Administrador",
"BoardMember.schemeCommenter": "Comentarista",
@@ -28,7 +33,7 @@
"BoardTemplateSelector.delete-template": "Excluir",
"BoardTemplateSelector.description": "Adicione um quadro à barra lateral usando qualquer um dos modelos definidos abaixo ou comece do zero.",
"BoardTemplateSelector.edit-template": "Editar",
"BoardTemplateSelector.plugin.no-content-description": "Adicionar um quadro a barra lateral usando qualquer dos templates definidos abaixo ou começar do zero.",
"BoardTemplateSelector.plugin.no-content-description": "Adicione um board à barra lateral usando um dos templates disponíveis abaixo ou comece do zero.",
"BoardTemplateSelector.plugin.no-content-title": "Criar um board",
"BoardTemplateSelector.title": "Criar um board",
"BoardTemplateSelector.use-this-template": "Use este template",
@@ -38,16 +43,16 @@
"BoardsUnfurl.Updated": "Atualizado {time}",
"Calculations.Options.average.displayName": "Média",
"Calculations.Options.average.label": "Média",
"Calculations.Options.count.displayName": "Contagem",
"Calculations.Options.count.label": "Contagem",
"Calculations.Options.countChecked.displayName": "Verificado",
"Calculations.Options.countChecked.label": "Contagem verificada",
"Calculations.Options.countUnchecked.displayName": "Não verificado",
"Calculations.Options.countUnchecked.label": "Contagem não verificada",
"Calculations.Options.count.displayName": "Total",
"Calculations.Options.count.label": "Total",
"Calculations.Options.countChecked.displayName": "Confirmado",
"Calculations.Options.countChecked.label": "Total de itens confirmados",
"Calculations.Options.countUnchecked.displayName": "Não confirmado",
"Calculations.Options.countUnchecked.label": "Total de itens não confirmados",
"Calculations.Options.countUniqueValue.displayName": "Único",
"Calculations.Options.countUniqueValue.label": "Contagem valores únicos",
"Calculations.Options.countUniqueValue.label": "Total de valores únicos",
"Calculations.Options.countValue.displayName": "Valores",
"Calculations.Options.countValue.label": "Contagem de valor",
"Calculations.Options.countValue.label": "Valor total",
"Calculations.Options.dateRange.displayName": "Período",
"Calculations.Options.dateRange.label": "Alcance",
"Calculations.Options.earliest.displayName": "Mais antigo",
@@ -85,7 +90,7 @@
"CardDetail.add-icon": "Adicionar ícone",
"CardDetail.add-property": "+ Adicionar propriedade",
"CardDetail.addCardText": "adicionar texto ao card",
"CardDetail.limited-body": "Atualize para nosso plano Professional ou Enterprise para visualizar cartões arquivados, ter visualizações ilimitadas por quadros, cartões ilimitados e mais.",
"CardDetail.limited-body": "Atualize para nosso plano Professional ou Enterprise.",
"CardDetail.limited-button": "Upgrade",
"CardDetail.limited-title": "Este cartão está oculto",
"CardDetail.moveContent": "Mover conteúdo do cartão",
@@ -100,10 +105,11 @@
"CardDetailProperty.property-deleted": "{propertyName} excluído com êxito!",
"CardDetailProperty.property-name-change-subtext": "digite de \"{oldPropType}\" para \"{newPropType}\"",
"CardDetial.limited-link": "Saiba mais sobre nossos planos.",
"CardDialog.delete-confirmation-dialog-attachment": "Confirmar exclusão de anexo",
"CardDialog.delete-confirmation-dialog-button-text": "Excluir",
"CardDialog.delete-confirmation-dialog-heading": "Confirmar exclusão do card!",
"CardDialog.delete-confirmation-dialog-heading": "Confirmar exclusão do cartão",
"CardDialog.editing-template": "Você está editando um template.",
"CardDialog.nocard": "Esse card não existe ou não está acessível.",
"CardDialog.nocard": "Esse cartão não existe ou não está acessível.",
"Categories.CreateCategoryDialog.CancelText": "Cancelar",
"Categories.CreateCategoryDialog.CreateText": "Criar",
"Categories.CreateCategoryDialog.Placeholder": "Nomeie sua categoria",
@@ -111,7 +117,6 @@
"CenterPanel.Login": "Login",
"CenterPanel.Share": "Compartilhar",
"ChannelIntro.CreateBoard": "Criar um board",
"CloudMessage.cloud-server": "Obtenha seu próprio cloud server de graça.",
"ColorOption.selectColor": "Selecione {color} Cor",
"Comment.delete": "Excluir",
"CommentsList.send": "Enviar",
@@ -125,21 +130,23 @@
"ContentBlock.checkbox": "caixa de seleção",
"ContentBlock.divider": "Divisor",
"ContentBlock.editCardCheckbox": "Caixa de seleção marcada",
"ContentBlock.editCardCheckboxText": "editar texto do card",
"ContentBlock.editCardText": "editar texto do card",
"ContentBlock.editCardCheckboxText": "editar texto do cartão",
"ContentBlock.editCardText": "editar texto do cartão",
"ContentBlock.editText": "Editar texto...",
"ContentBlock.image": "imagem",
"ContentBlock.insertAbove": "Inserir acima",
"ContentBlock.moveBlock": "mover conteúdo do cartão",
"ContentBlock.moveDown": "Mover para baixo",
"ContentBlock.moveUp": "Mover para cima",
"ContentBlock.text": "texto",
"DateFilter.empty": "Vazio",
"DateRange.clear": "Limpar",
"DateRange.empty": "Vazio",
"DateRange.endDate": "data de término",
"DateRange.today": "Hoje",
"DeleteBoardDialog.confirm-cancel": "Cancelar",
"DeleteBoardDialog.confirm-delete": "Excluir",
"DeleteBoardDialog.confirm-info": "Tem certeza que você quer deletar um board \"{boardTitle}\"? Excluir irá apagar todos os cards no board.",
"DeleteBoardDialog.confirm-info": "Tem certeza que quer excluir o quadro \"{boardTitle}\"? Excluí-lo irá apagar todos os cartões no quadro.",
"DeleteBoardDialog.confirm-info-template": "Tem certeza que deseja excluir o board template “{boardTitle}”?",
"DeleteBoardDialog.confirm-tite": "Confirmar exclusão do board",
"DeleteBoardDialog.confirm-tite-template": "Confirmar exclusão do template de board",
@@ -151,10 +158,14 @@
"Filter.ends-with": "termina com",
"Filter.includes": "Inclui",
"Filter.is": "é",
"Filter.is-after": "está depois",
"Filter.is-before": "está antes",
"Filter.is-empty": "está vazio",
"Filter.is-not-empty": "Não está vazio",
"Filter.is-not-set": "não está definido",
"Filter.is-set": "está definido",
"Filter.isafter": "está depois",
"Filter.isbefore": "está antes",
"Filter.not-contains": "não contém",
"Filter.not-ends-with": "não termina com",
"Filter.not-includes": "Não inclui",
@@ -163,6 +174,7 @@
"FilterByText.placeholder": "filtrar texto",
"FilterComponent.add-filter": "+ Adicionar filtro",
"FilterComponent.delete": "Excluir",
"FilterValue.empty": "(vazio)",
"FindBoardsDialog.IntroText": "Procurar por quadros",
"FindBoardsDialog.NoResultsFor": "Sem resultado para \"{searchQuery}\"",
"FindBoardsDialog.NoResultsSubtext": "Verifique a digitação ou tente outra busca.",
@@ -175,20 +187,20 @@
"KanbanCard.untitled": "Sem nome",
"MentionSuggestion.is-not-board-member": "(não membro do board)",
"Mutator.new-board-from-template": "novo board do template",
"Mutator.new-card-from-template": "novo card à partir de um template",
"Mutator.new-template-from-card": "novo template à partir de um card",
"Mutator.new-card-from-template": "novo cartão à partir de um template",
"Mutator.new-template-from-card": "novo template à partir de um cartão",
"OnboardingTour.AddComments.Body": "Você pode comentar questões, e até mesmo @mencionar seus usuários companheiros de Mattermost para conseguir suas atenções.",
"OnboardingTour.AddComments.Title": "Adicionar comentários",
"OnboardingTour.AddDescription.Body": "Adicione uma descrição para que seus companheiros de time saibam sobre o que é o cartão.",
"OnboardingTour.AddDescription.Title": "Adicionar descrição",
"OnboardingTour.AddProperties.Body": "Adicione várias propriedades aos cartões para torna-los mais poderosos!",
"OnboardingTour.AddProperties.Body": "Adicione várias propriedades aos cartões para torná-los mais poderosos.",
"OnboardingTour.AddProperties.Title": "Adicionar propriedades",
"OnboardingTour.AddView.Body": "Crie uma nova view aquei para organizar seu board usando diferentes layouts.",
"OnboardingTour.AddView.Title": "Adicionar nova visualização",
"OnboardingTour.CopyLink.Body": "Você pode compartilhar seus cartões com companheiros de times copiando e colando o link em um canal, mensagem direta, ou mensagem de grupo.",
"OnboardingTour.CopyLink.Title": "Copiar link",
"OnboardingTour.OpenACard.Body": "Abra um cartão para explorar formas poderosas que os Boards podem ajudar a organizar seu trabalho.",
"OnboardingTour.OpenACard.Title": "Abrir um card",
"OnboardingTour.OpenACard.Title": "Abrir um cartão",
"OnboardingTour.ShareBoard.Body": "Você pode compartilhar seu board internament, com seu time, ou public para permitir visibilidade fora da sua organização.",
"OnboardingTour.ShareBoard.Title": "Compartilhar quadro",
"PersonProperty.board-members": "Membros do Board",
@@ -248,6 +260,7 @@
"Sidebar.invite-users": "Convidar usuários",
"Sidebar.logout": "Sair",
"Sidebar.new-category.badge": "Novo",
"Sidebar.new-category.drag-boards-cta": "Solte quadros aqui...",
"Sidebar.no-boards-in-category": "Nenhum board",
"Sidebar.product-tour": "Tour pelo produto",
"Sidebar.random-icons": "Ícones aleatórios",
@@ -271,6 +284,7 @@
"SidebarTour.SidebarCategories.Link": "Saiba mais",
"SidebarTour.SidebarCategories.Title": "Categorias de barra lateral",
"SiteStats.total_boards": "Total de boards",
"SiteStats.total_cards": "Total de cartões",
"TableComponent.add-icon": "Adicionar Ícone",
"TableComponent.name": "Nome",
"TableComponent.plus-new": "+ Novo",
@@ -281,6 +295,7 @@
"TableHeaderMenu.insert-right": "Inserir à direita",
"TableHeaderMenu.sort-ascending": "Ordem ascendente",
"TableHeaderMenu.sort-descending": "Ordem descendente",
"TableRow.DuplicateCard": "duplicar cartão",
"TableRow.MoreOption": "Mais ações",
"TableRow.open": "Abrir",
"TopBar.give-feedback": "Dar feedback",
@@ -297,6 +312,7 @@
"ValueSelector.valueSelector": "Selecionador de valor",
"ValueSelectorLabel.openMenu": "Abrir menu",
"VersionMessage.help": "Verifique o que é novo nesta versão.",
"VersionMessage.learn-more": "Saiba mais",
"View.AddView": "Adicionar visualização",
"View.Board": "Quadro",
"View.DeleteView": "Excluir visualização",
@@ -313,7 +329,7 @@
"ViewHeader.delete-template": "Excluir",
"ViewHeader.display-by": "Exibir por: {property}",
"ViewHeader.edit-template": "Editar",
"ViewHeader.empty-card": "Card vazio",
"ViewHeader.empty-card": "Cartão vazio",
"ViewHeader.export-board-archive": "Exportar arquivo do painel",
"ViewHeader.export-complete": "Exportação completa!",
"ViewHeader.export-csv": "Exportar para CSV",
@@ -323,7 +339,7 @@
"ViewHeader.new": "Novo",
"ViewHeader.properties": "Propriedades",
"ViewHeader.properties-menu": "Menu de propriedades",
"ViewHeader.search-text": "Pesquisar cards",
"ViewHeader.search-text": "Pesquisar cartões",
"ViewHeader.select-a-template": "Selecionar um modelo",
"ViewHeader.set-default-template": "Definir como padrão",
"ViewHeader.sort": "Ordenar",
@@ -333,9 +349,9 @@
"ViewLimitDialog.Heading": "Limite de views por board alcaçado",
"ViewLimitDialog.PrimaryButton.Title.Admin": "Upgrade",
"ViewLimitDialog.PrimaryButton.Title.RegularUser": "Notificar Admin",
"ViewLimitDialog.Subtext.Admin": "Atualize para nosso plano Profissional ou Enterprise para ter visualizações ilimitados por boards, cards ilimitados e mais.",
"ViewLimitDialog.Subtext.Admin": "Atualize para nosso plano Profissional ou Enterprise.",
"ViewLimitDialog.Subtext.Admin.PricingPageLink": "Saiba mais sobre nossos planos.",
"ViewLimitDialog.Subtext.RegularUser": "Nofique seu Admin para atualizar para nosso plano Professional ou Enterprise para ter visualizações ilimitadas, cards ilimitados e mais.",
"ViewLimitDialog.Subtext.RegularUser": "Notifique seu administrador para atualizar para nosso plano Professional ou Enterprise.",
"ViewLimitDialog.UpgradeImg.AltText": "Atualizar imagem",
"ViewLimitDialog.notifyAdmin.Success": "Seu administrador foi notificado",
"ViewTitle.hide-description": "esconder descrição",
@@ -351,6 +367,9 @@
"WelcomePage.StartUsingIt.Text": "Começar a usar",
"Workspace.editing-board-template": "Você está editando um modelo de quadro.",
"badge.guest": "Convidado",
"boardPage.confirm-join-button": "Ingressar",
"boardPage.confirm-join-text": "Você está prestes a ingressar em um board privado sem ter sido explicitamente adicionado pelo administrador do quadro. Você tem certeza de que deseja ingressar neste board privado?",
"boardPage.confirm-join-title": "Ingressar board privado",
"boardSelector.confirm-link-board": "Linkar board para canal",
"boardSelector.confirm-link-board-button": "Sim, linkar board",
"boardSelector.confirm-link-board-subtext": "Quando você vincula \"{boardName}\" a um canal, todos os membros daquele canal (existentes e novos) poderão editá-lo. Isto excluirá os membros que são convidados. Você pode desvincular um board de um canal a qualquer hora.",
@@ -363,12 +382,13 @@
"calendar.month": "Mês",
"calendar.today": "HOJE",
"calendar.week": "Semana",
"centerPanel.undefined": "Sem {propertyName}",
"centerPanel.unknown-user": "Usuário desconhecido",
"cloudMessage.learn-more": "Saiba mais",
"createImageBlock.failed": "Não foi possível enviar o arquivo. Limite de tamanho alcançado.",
"createImageBlock.failed": "Não foi possível enviar o arquivo, pois o tamanho ultrapassou o limite permitido.",
"default-properties.badges": "Comentários e descrição",
"default-properties.title": "Título",
"error.back-to-home": "Volta para Home",
"error.back-to-home": "Volta para o início",
"error.back-to-team": "Volta para o time",
"error.board-not-found": "Quadro não encontrado.",
"error.go-login": "Log in",
@@ -380,31 +400,34 @@
"generic.previous": "Anterior",
"guest-no-board.subtitle": "Você não tem acesso a nenhum board neste time ainda, por favor aguarde até alguém adicionar você a algum board.",
"guest-no-board.title": "Nenhum board ainda",
"imagePaste.upload-failed": "Alguns arquivos não foram enviados. Tamanho limite alcançado",
"limitedCard.title": "Cards ocultos",
"imagePaste.upload-failed": "Alguns arquivos não foram enviados, pois o tamanho ultrapassou o limite permitido.",
"limitedCard.title": "Cartões ocultos",
"login.log-in-button": "Entrar",
"login.log-in-title": "Entrar",
"login.register-button": "ou criar uma conta se você ainda não tiver uma",
"new_channel_modal.create_board.empty_board_description": "Criar um novo quadro vazio",
"new_channel_modal.create_board.empty_board_title": "Quadro vazio",
"new_channel_modal.create_board.select_template_placeholder": "Selecionar um modelo",
"new_channel_modal.create_board.title": "Criar um quadro para este canal",
"notification-box-card-limit-reached.close-tooltip": "Soneca por 10 dias",
"notification-box-card-limit-reached.contact-link": "notificar seu admin",
"notification-box-card-limit-reached.link": "Atualizar para um plano pago",
"notification-box-card-limit-reached.title": "{cards} cards ocultos do board",
"notification-box-cards-hidden.title": "Esta ação ocultou outro card",
"notification-box-card-limit-reached.title": "{cards} cartões ocultos do board",
"notification-box-cards-hidden.title": "Esta ação ocultou outro cartão",
"notification-box.card-limit-reached.not-admin.text": "Para acessar cartões arquivados, você pode {contactLink} para atualizar para um plano pago.",
"notification-box.card-limit-reached.text": "Limite de cartão alcançado, para visualizar cartões mais antigos, {link}",
"person.add-user-to-board": "Adicionar {username} ao board",
"person.add-user-to-board-confirm-button": "Adicionar ao board",
"person.add-user-to-board-permissions": "Permissões",
"person.add-user-to-board-question": "Você quer adicionar {username} ao board?",
"person.add-user-to-board-warning": "{username} não é um membro de um board, e não será notificado.",
"person.add-user-to-board-warning": "{username} não é um membro do quadro e não receberá nenhuma notificação sobre ele.",
"register.login-button": "ou entre se você já tem uma conta",
"register.signup-title": "Registrar uma conta",
"rhs-board-non-admin-msg": "Você não é admin de um board",
"rhs-board-non-admin-msg": "Você não é um adminstrador do quadro",
"rhs-boards.add": "Adicionar",
"rhs-boards.dm": "DM",
"rhs-boards.gm": "GM",
"rhs-boards.header.dm": "esta Direct Message",
"rhs-boards.header.dm": "esta mensagem direta",
"rhs-boards.header.gm": "esta mensagem de grupo",
"rhs-boards.last-update-at": "Última atualização em: {datetime}",
"rhs-boards.link-boards-to-channel": "Vincular boards para {channelName}",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "Логин",
"CenterPanel.Share": "Поделиться",
"ChannelIntro.CreateBoard": "Создать доску",
"CloudMessage.cloud-server": "Получите свой бесплатный облачный сервер.",
"ColorOption.selectColor": "Выберите цвет {color}",
"Comment.delete": "Удалить",
"CommentsList.send": "Отправить",

Просмотреть файл

@@ -113,7 +113,6 @@
"CenterPanel.Login": "Prihlásiť sa",
"CenterPanel.Share": "Zdieľať",
"ChannelIntro.CreateBoard": "Vytvoriť nástenku",
"CloudMessage.cloud-server": "Získajte vlastný cloudový server zadarmo.",
"ColorOption.selectColor": "Vyberte {color} farbu",
"Comment.delete": "Odstrániť",
"CommentsList.send": "Odoslať",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "Logga in",
"CenterPanel.Share": "Dela",
"ChannelIntro.CreateBoard": "Skapa en board",
"CloudMessage.cloud-server": "Skaffa din egen molnserver gratis.",
"ColorOption.selectColor": "Välj {color} färg",
"Comment.delete": "Radera",
"CommentsList.send": "Skicka",

Просмотреть файл

@@ -1,4 +1,6 @@
{
"AdminBadge.SystemAdmin": "Yönetici",
"AdminBadge.TeamAdmin": "Takım yöneticisi",
"AppBar.Tooltip": "Bağlantılı panoları aç/kapat",
"Attachment.Attachment-title": "Ek dosya",
"AttachmentBlock.DeleteAction": "sil",
@@ -115,7 +117,6 @@
"CenterPanel.Login": "Oturum aç",
"CenterPanel.Share": "Paylaş",
"ChannelIntro.CreateBoard": "Bir pano ekle",
"CloudMessage.cloud-server": "Kendi ücretsiz bulut sunucunuzu edinin.",
"ColorOption.selectColor": "{color} rengi seçin",
"Comment.delete": "Sil",
"CommentsList.send": "Gönder",
@@ -138,6 +139,7 @@
"ContentBlock.moveDown": "Alta taşı",
"ContentBlock.moveUp": "Üste taşı",
"ContentBlock.text": "metin",
"DateFilter.empty": "Boş",
"DateRange.clear": "Temizle",
"DateRange.empty": "Boş",
"DateRange.endDate": "Bitiş tarihi",
@@ -156,10 +158,14 @@
"Filter.ends-with": "şununla biten",
"Filter.includes": "şunu içeren",
"Filter.is": "şu olan",
"Filter.is-after": "şundan sonra",
"Filter.is-before": "şundan önce",
"Filter.is-empty": "boş olan",
"Filter.is-not-empty": "boş olmayan",
"Filter.is-not-set": "şuna ayarlanmamış olan",
"Filter.is-set": "şuna ayarlanmış olan",
"Filter.isafter": "şundan sonra",
"Filter.isbefore": "şundan önce",
"Filter.not-contains": "şunu içermeyen",
"Filter.not-ends-with": "şununla bitmeyen",
"Filter.not-includes": "şunu içermeyen",
@@ -221,7 +227,7 @@
"PropertyType.UpdatedTime": "Son güncelleme zamanı",
"PropertyType.Url": "Adres",
"PropertyValueElement.empty": "Boş",
"RegistrationLink.confirmRegenerateToken": "Bu işlem daha önce paylaşılmış bağlantıları geçersiz kılacak. Devam etmek istiyor musunuz?",
"RegistrationLink.confirmRegenerateToken": "Bu işlem daha önce paylaşılmış bağlantıları geçersiz kılacak. İlerlemek istiyor musunuz?",
"RegistrationLink.copiedLink": "Kopyalandı!",
"RegistrationLink.copyLink": "Bağlantıyı kopyala",
"RegistrationLink.description": "Başkalarının hesap ekleyebilmesi için bu bağlantıyı paylaş:",
@@ -232,7 +238,7 @@
"ShareBoard.ShareInternal": "İçeride paylaş",
"ShareBoard.ShareInternalDescription": "İzni olan kullanıcılar bu bağlantıyı kullanabilecek.",
"ShareBoard.Title": "Panoyu paylaş",
"ShareBoard.confirmRegenerateToken": "Bu işlem daha önce paylaşılmış bağlantıları geçersiz kılacak. Devam etmek istiyor musunuz?",
"ShareBoard.confirmRegenerateToken": "Bu işlem daha önce paylaşılmış bağlantıları geçersiz kılacak. İlerlemek istiyor musunuz?",
"ShareBoard.copiedLink": "Kopyalandı!",
"ShareBoard.copyLink": "Bağlantıyı kopyala",
"ShareBoard.regenerate": "Kodu yeniden oluştur",
@@ -306,6 +312,7 @@
"ValueSelector.valueSelector": "Değer seçici",
"ValueSelectorLabel.openMenu": "Menüyü aç",
"VersionMessage.help": "Bu sürümdeki yeniliklere bakın.",
"VersionMessage.learn-more": "Ayrıntılı bilgi alın",
"View.AddView": "Görünüm ekle",
"View.Board": "Pano",
"View.DeleteView": "Görünümü sil",
@@ -360,6 +367,9 @@
"WelcomePage.StartUsingIt.Text": "Kullanmaya başlayın",
"Workspace.editing-board-template": "Bir pano kalıbını düzenliyorsunuz.",
"badge.guest": "Konuk",
"boardPage.confirm-join-button": "Katıl",
"boardPage.confirm-join-text": "Bir özel kanala, pano yöneticisi tarafından açıkça eklenmeden katılmak üzeresiniz. Bu özel kanala katılmak istediğinize emin misiniz?",
"boardPage.confirm-join-title": "Özel kanala katıl",
"boardSelector.confirm-link-board": "Panoyu kanala bağla",
"boardSelector.confirm-link-board-button": "Evet, panoyu bağla",
"boardSelector.confirm-link-board-subtext": "\"{boardName}\" panosunu kanala bağladığınızda, kanalın tüm üyeleri (var olan ve yeni) panoyu düzenleyebilir. Bu işlem konuk üyeleri kaldırır. Bir pano ile bir kanalın bağlantısını istediğiniz zaman kaldırabilirsiniz.",
@@ -395,6 +405,10 @@
"login.log-in-button": "Oturum aç",
"login.log-in-title": "Oturum açın",
"login.register-button": "ya da hesabınız yoksa bir hesap açın",
"new_channel_modal.create_board.empty_board_description": "Yeni boş bir pano oluştur",
"new_channel_modal.create_board.empty_board_title": "Boş pano",
"new_channel_modal.create_board.select_template_placeholder": "Bir kalıp seçin",
"new_channel_modal.create_board.title": "Bu kanal için bir pano oluştur",
"notification-box-card-limit-reached.close-tooltip": "10 gün için sustur",
"notification-box-card-limit-reached.contact-link": "yöneticinizi bilgilendirin",
"notification-box-card-limit-reached.link": "Ücretli bir tarifeye geçin",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "Логін",
"CenterPanel.Share": "Поділитися",
"ChannelIntro.CreateBoard": "Створити дошку",
"CloudMessage.cloud-server": "Отримайте власний безкоштовний хмарний сервер.",
"ColorOption.selectColor": "Виберіть колір {color}",
"Comment.delete": "Видалити",
"CommentsList.send": "Надіслати",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "登录",
"CenterPanel.Share": "分享",
"ChannelIntro.CreateBoard": "创建一个板块",
"CloudMessage.cloud-server": "获得自己的免费云服务器。",
"ColorOption.selectColor": "选择{color}",
"Comment.delete": "删除",
"CommentsList.send": "发送",

Просмотреть файл

@@ -115,7 +115,6 @@
"CenterPanel.Login": "登入",
"CenterPanel.Share": "分享",
"ChannelIntro.CreateBoard": "建立看板",
"CloudMessage.cloud-server": "獲得免費的雲端伺服器.",
"ColorOption.selectColor": "{color} 選擇顏色",
"Comment.delete": "刪除",
"CommentsList.send": "發送",

Просмотреть файл

@@ -102,12 +102,11 @@
"@types/react-router-dom": "^5.3.3",
"@types/react-transition-group": "4.4.4",
"@types/redux-mock-store": "1.0.3",
"@typescript-eslint/eslint-plugin": "5.16.0",
"@typescript-eslint/parser": "5.16.0",
"@typescript-eslint/eslint-plugin": "5.57.1",
"@typescript-eslint/parser": "5.57.1",
"babel-eslint": "10.1.0",
"cross-env": "^7.0.3",
"css-loader": "6.7.1",
"eslint": "^8.11.0",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-formatjs": "4.9.0",

Просмотреть файл

@@ -873,7 +873,7 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
>
<div
class="octo-board-header-cell KanbanColumnHeader"
draggable="true"
draggable="false"
style="opacity: 1;"
>
<span
@@ -901,7 +901,7 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
</div>
<div
class="octo-board-header-cell KanbanColumnHeader"
draggable="true"
draggable="false"
style="opacity: 1;"
>
<span
@@ -1927,7 +1927,7 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
>
<div
class="octo-board-header-cell KanbanColumnHeader"
draggable="true"
draggable="false"
style="opacity: 1;"
>
<span
@@ -1955,7 +1955,7 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
</div>
<div
class="octo-board-header-cell KanbanColumnHeader"
draggable="true"
draggable="false"
style="opacity: 1;"
>
<span

Просмотреть файл

@@ -206,7 +206,7 @@ const BoardTemplateSelector = (props: Props) => {
>
<FormattedMessage
id='BoardTemplateSelector.create-empty-board'
defaultMessage='Create empty board'
defaultMessage='Create an empty board'
/>
</Button>
</div>

Просмотреть файл

@@ -91,7 +91,7 @@ const BoardsSwitcher = (props: Props): JSX.Element => {
<Search/>
<div>
<span>
{intl.formatMessage({id: 'BoardsSwitcher.Title', defaultMessage: 'Find Boards'})}
{intl.formatMessage({id: 'BoardsSwitcher.Title', defaultMessage: 'Find boards'})}
</span>
</div>
</div>

Просмотреть файл

@@ -147,7 +147,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
const confirmDialogProps: ConfirmationDialogBoxProps = useMemo(() => {
return {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {

Просмотреть файл

@@ -255,7 +255,7 @@ const CardDetail = (props: Props): JSX.Element|null => {
<p className='CardDetail__limited-body'>
<FormattedMessage
id='CardDetail.limited-body'
defaultMessage='Upgrade to our Professional or Enterprise plan to view archived cards, have unlimited views per boards, unlimited cards and more.'
defaultMessage='Upgrade to our Professional or Enterprise plan.'
/>
<br/>
<a
@@ -362,7 +362,7 @@ const CardDetail = (props: Props): JSX.Element|null => {
newBlock.title = block.value.value
newBlock.fields = {...newBlock.fields, value: block.value.checked}
}
mutator.updateBlock(card.boardId, newBlock, originalContentBlock, intl.formatMessage({id: 'ContentBlock.editCardText', defaultMessage: 'edit card content'}))
mutator.updateBlock(card.boardId, newBlock, originalContentBlock, intl.formatMessage({id: 'ContentBlock.editCardText', defaultMessage: 'edit card text'}))
return block
}}
onBlockMoved={async (block: BlockData, beforeBlock: BlockData|null, afterBlock: BlockData|null): Promise<void> => {

Просмотреть файл

@@ -43,7 +43,7 @@ export default function useImagePaste(boardId: string, cardId: string, contentOr
}
if (someFilesNotUploaded) {
sendFlashMessage({content: intl.formatMessage({id: 'imagePaste.upload-failed', defaultMessage: 'Some files not uploaded. File size limit reached'}), severity: 'normal'})
sendFlashMessage({content: intl.formatMessage({id: 'imagePaste.upload-failed', defaultMessage: "Some files weren't uploaded because the file size limit has been reached."}), severity: 'normal'})
}
const afterRedo = async (newBlocks: Block[]) => {

Просмотреть файл

@@ -97,7 +97,7 @@ const CardDialog = (props: Props): JSX.Element => {
}
const confirmDialogProps: ConfirmationDialogBoxProps = {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {
@@ -161,7 +161,7 @@ const CardDialog = (props: Props): JSX.Element => {
dispatch(updateAttachments([attachmentBlock]))
if (attachment.size > clientConfig.maxFileSize) {
removeUploadingAttachment(uploadingBlock)
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.failed', defaultMessage: 'Unable to upload the file. Attachment size limit reached.'}), severity: 'normal'})
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.failed', defaultMessage: "This file couldn't be uploaded as the file size limit has been reached."}), severity: 'normal'})
} else {
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.upload', defaultMessage: 'Attachment uploading.'}), severity: 'normal'})
const xhr = await octoClient.uploadAttachment(boardId, attachment)
@@ -183,11 +183,11 @@ const CardDialog = (props: Props): JSX.Element => {
const block = createAttachmentBlock()
block.fields.attachmentId = attachmentId || ''
block.title = attachment.name
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.uploadSuccess', defaultMessage: 'Attachment uploaded successfull.'}), severity: 'normal'})
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.uploadSuccess', defaultMessage: 'Attachment uploaded.'}), severity: 'normal'})
resolve(block)
} else {
removeUploadingAttachment(uploadingBlock)
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.failed', defaultMessage: 'Unable to upload the file. Attachment size limit reached.'}), severity: 'normal'})
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.failed', defaultMessage: "This file couldn't be uploaded as the file size limit has been reached."}), severity: 'normal'})
}
}
}
@@ -217,7 +217,7 @@ const CardDialog = (props: Props): JSX.Element => {
}
const description = intl.formatMessage({id: 'AttachmentBlock.DeleteAction', defaultMessage: 'delete'})
await mutator.deleteBlock(block, description)
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.delete', defaultMessage: 'Attachment Deleted Successfully.'}), severity: 'normal'})
sendFlashMessage({content: intl.formatMessage({id: 'AttachmentBlock.delete', defaultMessage: 'Attachment deleted.'}), severity: 'normal'})
}, [card?.boardId, card?.id, card?.fields.contentOrder])
const attachBtn = (): React.ReactNode => {

Просмотреть файл

@@ -29,7 +29,14 @@ jest.mock('react-router-dom', () => {
return {
...originalModule,
useRouteMatch: jest.fn(() => {
return {url: '/board/view'}
return {
params: {
teamId: 'team1',
boardId: 'boardId1',
viewId: 'viewId1',
cardId: 'cardId1',
},
}
}),
}
})

Просмотреть файл

@@ -76,7 +76,7 @@ const ConfirmAddUserForNotifications = (props: Props): JSX.Element => {
<p>
<FormattedMessage
id='person.add-user-to-board-warning'
defaultMessage='{username} is not a member of the board, and will not receive any notifications about it.'
defaultMessage="{username} isn't a member of the board, and won't receive any notifications about it."
values={{username: props.user.username}}
/>
</p>

Просмотреть файл

@@ -94,7 +94,7 @@ const AttachmentElement = (props: Props): JSX.Element|null => {
}
const confirmDialogProps: ConfirmationDialogBoxProps = {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-attachment', defaultMessage: 'Confirm Attachment delete!'}),
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-attachment', defaultMessage: 'Confirm attachment delete'}),
confirmButtonText: intl.formatMessage({id: 'AttachmentElement.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: deleteAttachment,
onClose: () => {

Просмотреть файл

@@ -70,7 +70,7 @@ contentRegistry.registerContentType({
block.fields.fileId = fileId || ''
resolve(block)
} else {
sendFlashMessage({content: intl.formatMessage({id: 'createImageBlock.failed', defaultMessage: 'Unable to upload the file. File size limit reached.'}), severity: 'normal'})
sendFlashMessage({content: intl.formatMessage({id: 'createImageBlock.failed', defaultMessage: "This file couldn't be uploaded as the file size limit has been reached."}), severity: 'normal'})
}
},
'.jpg,.jpeg,.png,.gif')

Просмотреть файл

@@ -51,7 +51,7 @@ const GalleryCard = (props: Props) => {
const confirmDialogProps: ConfirmationDialogBoxProps = useMemo(() => {
return {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {

Просмотреть файл

@@ -469,7 +469,7 @@ exports[`src/components/kanban/kanbanColumnHeader should match snapshot readonly
<div>
<div
class="octo-board-header-cell KanbanColumnHeader"
draggable="true"
draggable="false"
style="opacity: 1;"
>
<span

Просмотреть файл

@@ -59,7 +59,7 @@ const KanbanCard = (props: Props) => {
const confirmDialogProps: ConfirmationDialogBoxProps = useMemo(() => {
return {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {

Просмотреть файл

@@ -52,8 +52,12 @@ const defaultProperty: IPropertyTemplate = {
export default function KanbanColumnHeader(props: Props): JSX.Element {
const intl = useIntl()
const {board, activeView, group, groupByProperty} = props
let readonly = props.readonly
if(!readonly){
readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
}
const [groupTitle, setGroupTitle] = useState(group.option.value)
const canEditBoardProperties = useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
const canEditOption = groupByProperty?.type !== 'person' && group.option.id
const headerRef = useRef<HTMLDivElement>(null)
@@ -79,7 +83,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
setGroupTitle(group.option.value)
}, [group.option.value])
if (canEditBoardProperties) {
if (!readonly) {
drop(drag(headerRef))
}
@@ -97,13 +101,13 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
ref={headerRef}
style={{opacity: isDragging ? 0.5 : 1}}
className={className}
draggable={!props.readonly && canEditBoardProperties}
draggable={!readonly}
>
{!group.option.id &&
<Label
title={intl.formatMessage({
id: 'BoardComponent.no-property-title',
defaultMessage: 'Items with an empty {property} property will go here. This column cannot be removed.',
defaultMessage: "Items with an empty {property} property will go here. This column can't be removed.",
}, {property: groupByProperty!.name})}
>
<FormattedMessage
@@ -133,7 +137,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
onCancel={() => {
setGroupTitle(group.option.value)
}}
readonly={props.readonly || !canEditBoardProperties}
readonly={readonly}
spellCheck={true}
/>
</Label>}
@@ -145,7 +149,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element {
onMenuClose={props.onCalculationMenuClose}
onMenuOpen={props.onCalculationMenuOpen}
cardProperties={board.cardProperties}
readonly={props.readonly || !canEditBoardProperties}
readonly={readonly}
onChange={(data: {calculation: string, propertyId: string}) => {
if (data.calculation === calculationValue && data.propertyId === calculationProperty.id) {
return

Просмотреть файл

@@ -40,7 +40,7 @@ const AddPropertiesTourStep = (): JSX.Element | null => {
const screen = (
<FormattedMessage
id='OnboardingTour.AddProperties.Body'
defaultMessage='Add various properties to cards to make them more powerful!'
defaultMessage='Add various properties to cards to make them more powerful.'
/>
)

Просмотреть файл

@@ -98,7 +98,7 @@ const RHSChannelBoardItem = (props: Props) => {
onClick={() => {
onUnlinkBoard(props.board)
}}
subText={intl.formatMessage({id: 'rhs-board-non-admin-msg', defaultMessage:'You are not an admin of the board'})}
subText={intl.formatMessage({id: 'rhs-board-non-admin-msg', defaultMessage: "You're not an admin of the board"})}
/>
</BoardPermissionGate>
</Menu>

Просмотреть файл

@@ -92,10 +92,10 @@ const RHSChannelBoards = () => {
if (currentChannel.type === 'D') {
channelName = intl.formatMessage({id: 'rhs-boards.dm', defaultMessage: 'DM'})
headerChannelName = intl.formatMessage({id: 'rhs-boards.header.dm', defaultMessage: 'this Direct Message'})
headerChannelName = intl.formatMessage({id: 'rhs-boards.header.dm', defaultMessage: 'this direct message'})
} else if (currentChannel.type === 'G') {
channelName = intl.formatMessage({id: 'rhs-boards.gm', defaultMessage: 'GM'})
headerChannelName = intl.formatMessage({id: 'rhs-boards.header.gm', defaultMessage: 'this Group Message'})
headerChannelName = intl.formatMessage({id: 'rhs-boards.header.gm', defaultMessage: 'this group message'})
}
if (channelBoards.length === 0) {

Просмотреть файл

@@ -983,11 +983,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Regene
>
<a
class="shareUrl"
href="http://localhost:8065/team/team-id/shared/1/1?r=anotherToken"
href="http://localhost:8065/boards/public/team/team-id/shared/1/1?r=anotherToken"
rel="noreferrer"
target="_blank"
>
http://localhost:8065/team/team-id/shared/1/1?r=anotherToken
http://localhost:8065/boards/public/team/team-id/shared/1/1?r=anotherToken
</a>
<div
class="octo-tooltip tooltip-top"
@@ -3188,11 +3188,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc
>
<a
class="shareUrl"
href="http://localhost:8065/team/team-id/shared/1/1?r=oneToken"
href="http://localhost:8065/boards/public/team/team-id/shared/1/1?r=oneToken"
rel="noreferrer"
target="_blank"
>
http://localhost:8065/team/team-id/shared/1/1?r=oneToken
http://localhost:8065/boards/public/team/team-id/shared/1/1?r=oneToken
</a>
<div
class="octo-tooltip tooltip-top"
@@ -3461,11 +3461,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoardComponent and cli
>
<a
class="shareUrl"
href="http://localhost:8065/team/team-id/shared/1/1?r=aToken"
href="http://localhost:8065/boards/public/team/team-id/shared/1/1?r=aToken"
rel="noreferrer"
target="_blank"
>
http://localhost:8065/team/team-id/shared/1/1?r=aToken
http://localhost:8065/boards/public/team/team-id/shared/1/1?r=aToken
</a>
<div
class="octo-tooltip tooltip-top"

Просмотреть файл

@@ -259,7 +259,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
viewId: match.params.viewId,
teamId: match.params.teamId,
})
shareUrl.pathname = newPath
shareUrl.pathname = `/boards/public${newPath}`
const boardPath = generatePath('/team/:teamId/:boardId/:viewId', {
boardId: match.params.boardId,
@@ -278,7 +278,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
const shareTemplateTitle = (
<FormattedMessage
id={'ShareTemplate.Title'}
defaultMessage={'Share Template'}
defaultMessage={'Share template'}
/>
)

Просмотреть файл

@@ -21,10 +21,12 @@ jest.mock('react-router-dom', () => {
...originalModule,
useRouteMatch: jest.fn(() => {
return {
teamId: 'team1',
boardId: 'boardId1',
viewId: 'viewId1',
cardId: 'cardId1',
params: {
teamId: 'team1',
boardId: 'boardId1',
viewId: 'viewId1',
cardId: 'cardId1',
},
}
}),
}

Просмотреть файл

@@ -3,7 +3,7 @@
import React, {useCallback} from 'react'
import {FormattedMessage} from 'react-intl'
import {generatePath, useRouteMatch, useHistory} from 'react-router-dom'
import {generatePath, useRouteMatch} from 'react-router-dom'
import Button from 'src/widgets/buttons/button'
import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient'
@@ -12,14 +12,17 @@ import './shareBoardLoginButton.scss'
const ShareBoardLoginButton = () => {
const match = useRouteMatch<{teamId: string, boardId: string, viewId?: string, cardId?: string}>()
const history = useHistory()
const redirectQueryParam = 'r=' + encodeURIComponent(generatePath('/:boardId?/:viewId?/:cardId?', match.params))
const loginPath = '/login?' + redirectQueryParam
// Mattermost login doesn't respect the redirect query parameter
// if the user is already logged in, so we send the user to the
// board and if they are not logged in, the webapp will take care
// of the redirection
const baseURL = window.location.href.split('/boards/public')[0]
const loginPath = `${baseURL}/${generatePath('/boards/team/:teamId/:boardId?/:viewId?/:cardId?', match.params)}`
const onLoginClick = useCallback(() => {
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.ShareBoardLogin)
history.push(loginPath)
location.assign(loginPath)
}, [])
return (

Просмотреть файл

@@ -52,19 +52,22 @@ const TeamPermissionsRow = (): JSX.Element => {
}
}
let currentRoleName = intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})
if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Admin) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})
} else if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Editor) {
if (board.isTemplate) {
let currentRoleName = intl.formatMessage({id: 'BoardMember.schemeAdmin', defaultMessage: 'Admin'})
if (board.type === BoardTypeOpen) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
if (board.minimumRole === MemberRole.Editor) {
if (board.isTemplate) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
} else {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
}
} else if (board.minimumRole === MemberRole.Commenter) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})
} else if (board.minimumRole === MemberRole.Viewer) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
} else {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeEditor', defaultMessage: 'Editor'})
}
} else if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Commenter) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeCommenter', defaultMessage: 'Commenter'})
} else if (board.type === BoardTypeOpen && board.minimumRole === MemberRole.Viewer) {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeViewer', defaultMessage: 'Viewer'})
} else {
currentRoleName = intl.formatMessage({id: 'BoardMember.schemeNone', defaultMessage: 'None'})
}
const confirmationDialog = (
@@ -99,7 +102,7 @@ const TeamPermissionsRow = (): JSX.Element => {
icon='mattermost'
className='user-item__img'
/>
<div className='ml-3'><strong>{intl.formatMessage({id: 'ShareBoard.teamPermissionsText', defaultMessage: 'Everyone at {teamName} Team'}, {teamName: team?.title})}</strong></div>
<div className='ml-3'><strong>{intl.formatMessage({id: 'ShareBoard.teamPermissionsText', defaultMessage: 'Everyone at {teamName} team'}, {teamName: team?.title})}</strong></div>
</div>
<div>
<BoardPermissionGate permissions={[Permission.ManageBoardType]}>

Просмотреть файл

@@ -86,7 +86,7 @@ const TableGroupHeaderRow = (props: Props): JSX.Element => {
<Label
title={intl.formatMessage({
id: 'BoardComponent.no-property-title',
defaultMessage: 'Items with an empty {property} property will go here. This column cannot be removed.',
defaultMessage: "Items with an empty {property} property will go here. This column can't be removed.",
}, {property: groupByProperty?.name})}
>
<FormattedMessage

Просмотреть файл

@@ -131,7 +131,7 @@ const TableRow = (props: Props) => {
const confirmDialogProps: ConfirmationDialogBoxProps = useMemo(() => {
return {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {

Просмотреть файл

@@ -59,9 +59,12 @@ const ViewHeader = (props: Props) => {
const [showFilter, setShowFilter] = useState(false)
const [lockFilterOnClose, setLockFilterOnClose] = useState(false)
const intl = useIntl()
const canEditBoardProperties = useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
const {board, activeView, views, groupByProperty, cards, dateDisplayProperty} = props
let readonly = props.readonly
if(!readonly){
readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
}
const withGroupBy = activeView.fields.viewType === 'board' || activeView.fields.viewType === 'table'
const withDisplayBy = activeView.fields.viewType === 'calendar'
@@ -137,7 +140,7 @@ const ViewHeader = (props: Props) => {
}}
onChange={setViewTitle}
saveOnEsc={true}
readonly={props.readonly || !canEditBoardProperties}
readonly={readonly}
spellCheck={true}
autoExpand={false}
/>
@@ -148,7 +151,7 @@ const ViewHeader = (props: Props) => {
board={board}
activeView={activeView}
views={views}
readonly={props.readonly || !canEditBoardProperties}
readonly={readonly}
allowCreateView={allowCreateView}
/>
</MenuWrapper>
@@ -159,7 +162,7 @@ const ViewHeader = (props: Props) => {
<div className='octo-spacer'/>
{!props.readonly && canEditBoardProperties &&
{!readonly &&
<>
{/* Card properties */}

Просмотреть файл

@@ -46,7 +46,7 @@ export const ViewLimitModal = (props: Props): JSX.Element => {
const regularUserSubtext = (
<FormattedMessage
id='ViewLimitDialog.Subtext.RegularUser'
defaultMessage='Notify your Admin to upgrade to our Professional or Enterprise plan to have unlimited views per boards, unlimited cards, and more.'
defaultMessage='Notify your Admin to upgrade to our Professional or Enterprise plan.'
/>
)
@@ -56,7 +56,7 @@ export const ViewLimitModal = (props: Props): JSX.Element => {
<React.Fragment>
<FormattedMessage
id='ViewLimitDialog.Subtext.Admin'
defaultMessage='Upgrade to our Professional or Enterprise plan to have unlimited views per boards, unlimited cards, and more.'
defaultMessage='Upgrade to our Professional or Enterprise plan.'
/>
<a
href='https://mattermost.com/pricing/'

Просмотреть файл

@@ -34,9 +34,11 @@ const ViewTitle = (props: Props) => {
}, [board.id, board.icon])
const onShowDescription = useCallback(() => mutator.showBoardDescription(board.id, Boolean(board.showDescription), true), [board.id, board.showDescription])
const onHideDescription = useCallback(() => mutator.showBoardDescription(board.id, Boolean(board.showDescription), false), [board.id, board.showDescription])
const canEditBoardProperties = useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
const readonly = props.readonly || !canEditBoardProperties
let readonly = props.readonly
if(!readonly){
readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties])
}
const intl = useIntl()

Просмотреть файл

@@ -114,6 +114,7 @@ jest.mock('react-router-dom', () => {
useRouteMatch: jest.fn(() => {
return {
params: {
teamId: board.teamId,
boardId: board.id,
viewId: activeView.id,
},

Просмотреть файл

@@ -49,7 +49,7 @@ function errorDefFromId(id: ErrorId | null): ErrorDef {
case ErrorId.TeamUndefined: {
errDef.title = intl.formatMessage({id: 'error.team-undefined', defaultMessage: 'Not a valid team.'})
errDef.button1Enabled = true
errDef.button1Text = intl.formatMessage({id: 'error.back-to-home', defaultMessage: 'Back to Home'})
errDef.button1Text = intl.formatMessage({id: 'error.back-to-home', defaultMessage: 'Back to home'})
errDef.button1Redirect = (): string => {
UserSettings.setLastTeamID(null)
return window.location.origin
@@ -93,7 +93,7 @@ function errorDefFromId(id: ErrorId | null): ErrorDef {
default: {
errDef.title = intl.formatMessage({id: 'error.unknown', defaultMessage: 'An error occurred.'})
errDef.button1Enabled = true
errDef.button1Text = intl.formatMessage({id: 'error.back-to-home', defaultMessage: 'Back to Home'})
errDef.button1Text = intl.formatMessage({id: 'error.back-to-home', defaultMessage: 'Back to home'})
errDef.button1Redirect = '/'
errDef.button1Fill = true
errDef.button1ClearHistory = true

Просмотреть файл

@@ -12,13 +12,12 @@ export const useHasPermissions = (teamId: string, boardId: string, permissions:
return false
}
const member = useAppSelector(getMyBoardMembership(boardId))
const board = useAppSelector(getBoard(boardId))
if (!board) {
return false
}
const member = useAppSelector(getMyBoardMembership(boardId))
if (!member) {
return false
}

Просмотреть файл

@@ -28,6 +28,7 @@ windowAny.baseURL = '/plugins/boards'
windowAny.frontendBaseURL = '/boards'
import App from 'src/app'
import PublicApp, {publicBaseURL} from 'src/public/app'
import store from 'src/store'
import WithWebSockets from 'src/components/withWebSockets'
@@ -175,10 +176,44 @@ const MainApp = (props: Props) => {
)
}
const PublicMainApp = () => {
useEffect(() => {
document.body.classList.add('focalboard-body')
const root = document.getElementById('root')
if (root) {
while (root.firstElementChild) {
if( root.firstElementChild.id === 'focalboard-app'){
break
}
root.removeChild(root.firstElementChild)
}
root.classList.add('focalboard-plugin-root')
}
return () => {
document.body.classList.remove('focalboard-body')
if (root) {
root.classList.remove('focalboard-plugin-root')
}
}
}, [])
return (
<ErrorBoundary>
<ReduxProvider store={store}>
<div id='focalboard-app'>
<PublicApp />
</div>
<div id='focalboard-root-portal' />
</ReduxProvider>
</ErrorBoundary>
)
}
const HeaderComponent = () => {
return (
<ErrorBoundary>
<GlobalHeader history={browserHistory}/>
<GlobalHeader history={browserHistory} />
</ErrorBoundary>
)
}
@@ -243,8 +278,6 @@ export default class Plugin {
}
})
const initCurrentChannelId = mmStore.getState().entities.channels.currentChannelId
const initCurrentChannel = mmStore.getState().entities.channels.channels[initCurrentChannelId]
let lastViewedChannelId = initCurrentChannelId
@@ -274,7 +307,9 @@ export default class Plugin {
prevTeamId = currentTeamId
store.dispatch(setTeam(currentTeamId))
octoClient.teamId = currentTeamId
store.dispatch(initialLoad())
if(!window.location.pathname.includes(publicBaseURL())){
store.dispatch(initialLoad())
}
}
if (currentTeamId && currentTeamId !== prevTeamId) {
@@ -336,6 +371,9 @@ export default class Plugin {
HeaderComponent,
() => null,
true,
true,
true,
PublicMainApp,
)
const goToFocalboardTemplate = () => {
@@ -350,7 +388,7 @@ export default class Plugin {
}
if (this.registry.registerAppBarComponent) {
this.registry.registerAppBarComponent(appBarIcon, () => mmStore.dispatch(toggleRHSPlugin), intl.formatMessage({id: 'AppBar.Tooltip', defaultMessage: 'Toggle Linked Boards'}))
this.registry.registerAppBarComponent(appBarIcon, () => mmStore.dispatch(toggleRHSPlugin), intl.formatMessage({id: 'AppBar.Tooltip', defaultMessage: 'Toggle linked boards'}))
}
if (this.registry.registerActionAfterChannelCreation) {
@@ -404,13 +442,13 @@ export default class Plugin {
if(siteStats){
return {
boards_count: {
name: intl.formatMessage({id: 'SiteStats.total_boards', defaultMessage: 'Total Boards'}),
name: intl.formatMessage({id: 'SiteStats.total_boards', defaultMessage: 'Total boards'}),
id: 'total_boards',
icon: 'icon-product-boards',
value: siteStats.board_count,
},
cards_count: {
name: intl.formatMessage({id: 'SiteStats.total_cards', defaultMessage: 'Total Cards'}),
name: intl.formatMessage({id: 'SiteStats.total_cards', defaultMessage: 'Total cards'}),
id: 'total_cards',
icon: 'icon-products',
value: siteStats.card_count,

Просмотреть файл

@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`properties/number should match snapshot for number with empty value 1`] = `
<div>
<input
class="Editable octo-propertyvalue"
placeholder=""
style="width: 100%;"
title=""
value=""
/>
</div>
`;

Просмотреть файл

@@ -0,0 +1,70 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {ComponentProps} from 'react'
import {screen} from '@testing-library/react'
import {mocked} from 'jest-mock'
import {setup, wrapIntl} from 'src/testUtils'
import {TestBlockFactory} from 'src/test/testBlockFactory'
import mutator from 'src/mutator'
import {Board, IPropertyTemplate} from 'src/blocks/board'
import {Card} from 'src/blocks/card'
import NumberProperty from './property'
import NumberEditor from './number'
jest.mock('src/components/flashMessages')
jest.mock('src/mutator')
const mockedMutator = mocked(mutator)
describe('properties/number', () => {
let board: Board
let card: Card
let propertyTemplate: IPropertyTemplate
let baseProps: ComponentProps<typeof NumberEditor>
beforeEach(() => {
board = TestBlockFactory.createBoard()
card = TestBlockFactory.createCard()
propertyTemplate = board.cardProperties[0]
baseProps = {
property: new NumberProperty(),
card,
board,
propertyTemplate,
propertyValue: '',
readOnly: false,
showEmptyPlaceholder: false,
}
})
it('should match snapshot for number with empty value', () => {
const {container} = setup(
wrapIntl((
<NumberEditor
{...baseProps}
/>
))
)
expect(container).toMatchSnapshot()
})
it('should fire change event when valid number value is entered', async () => {
const {user} = setup(
wrapIntl(
<NumberEditor
{...baseProps}
/>
)
)
const value = '42'
const input = screen.getByRole('textbox')
await user.type(input, `${value}{Enter}`)
expect(mockedMutator.changePropertyValue).toHaveBeenCalledWith(board.id, card, propertyTemplate.id, `${value}`)
})
})

Просмотреть файл

@@ -10,7 +10,7 @@ const Number = (props: PropertyProps): JSX.Element => {
return (
<BaseTextEditor
{...props}
validator={() => !isNaN(parseInt(props.propertyValue as string, 10))}
validator={() => props.propertyValue === '' || !isNaN(parseInt(props.propertyValue as string, 10))}
/>
)
}

61
webapp/boards/src/public/app.tsx Обычный файл
Просмотреть файл

@@ -0,0 +1,61 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react'
import {Router, Switch} from 'react-router-dom'
import {IntlProvider} from 'react-intl'
import {DndProvider} from 'react-dnd'
import {HTML5Backend} from 'react-dnd-html5-backend'
import {TouchBackend} from 'react-dnd-touch-backend'
import {createBrowserHistory} from 'history'
import BoardPage from 'src/pages/boardPage/boardPage'
import FBRoute from 'src/route'
import {getMessages} from 'src/i18n'
import FlashMessages from 'src/components/flashMessages'
import NewVersionBanner from 'src/components/newVersionBanner'
import {Utils} from 'src/utils'
import {getLanguage} from 'src/store/language'
import {useAppSelector} from 'src/store/hooks'
export const publicBaseURL = () => {
return Utils.getFrontendBaseURL() + '/public'
}
const PublicRouter = () => {
const history = createBrowserHistory({basename: publicBaseURL()})
return (
<Router history={history}>
<Switch>
<FBRoute path={['/team/:teamId/shared/:boardId?/:viewId?/:cardId?', '/shared/:boardId?/:viewId?/:cardId?']}>
<BoardPage readonly={true}/>
</FBRoute>
</Switch>
</Router>
)
}
const PublicApp = (): JSX.Element => {
const language = useAppSelector<string>(getLanguage)
return (
<IntlProvider
locale={language.split(/[_]/)[0]}
messages={getMessages(language)}
>
<DndProvider backend={Utils.isMobile() ? TouchBackend : HTML5Backend}>
<FlashMessages milliseconds={2000}/>
<div id='frame'>
<div id='main'>
<NewVersionBanner/>
<PublicRouter/>
</div>
</div>
</DndProvider>
</IntlProvider>
)
}
export default React.memo(PublicApp)

Просмотреть файл

@@ -14,7 +14,9 @@ export interface PluginRegistry {
registerCustomRoute(route: string, component: ReactResolvable): any
registerProductRoute(route: string, component: ReactResolvable): any
unregisterComponent(componentId: string): any
registerProduct(baseURL: string, switcherIcon: string, switcherText: string, switcherLinkURL: string, mainComponent: ReactResolvable, headerCentreComponent: ReactResolvable, headerRightComponent: ReactResolvable, showTeamSidebar: boolean): any
registerProduct(baseURL: string, switcherIcon: string, switcherText: string, switcherLinkURL: string,
mainComponent: ReactResolvable, headerCentreComponent: ReactResolvable, headerRightComponent: ReactResolvable,
showTeamSidebar: boolean, showAppBar: boolean, wrapped: boolean, publicComponent: ReactResolvable | null): any
registerPostWillRenderEmbedComponent(match: (embed: {type: string, data: any}) => void, component: any, toggleable: boolean): any
registerWebSocketEventHandler(event: string, handler: (e: any) => void): any
unregisterWebSocketEventHandler(event: string): any

Просмотреть файл

@@ -5,7 +5,7 @@
"plugin:react-hooks/recommended"
],
"plugins": [
"@babel/eslint-plugin",
"@babel",
"mattermost",
"import",
"no-only-tests",
@@ -80,11 +80,22 @@
"react/style-prop-object": [2, {
"allow": ["Timestamp"]
}],
"no-restricted-imports": ["error", {
"paths": [
{"name": "react-bootstrap", "importNames": ["OverlayTrigger"], "message": "Please use OverlayTrigger from '/components/overlay_trigger' instead"}
]
}],
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["react-bootstrap"],
"importNames": ["OverlayTrigger"],
"message": "Please use OverlayTrigger from '/components/overlay_trigger' instead."
},
{
"group": ["@mattermost/compass-components/*"],
"message": "compass-components is now archived"
}
]
}
],
"max-lines": ["warn", {"max": 800, "skipBlankLines": true, "skipComments": true}],
"formatjs/no-multiple-whitespaces": ["error"]
},

Просмотреть файл

@@ -5,10 +5,6 @@
},
"version": "7.9.0",
"private": true,
"engines": {
"npm": ">=7.0.0",
"node": ">=16.4.0"
},
"dependencies": {
"@floating-ui/react-dom": "1.0.0",
"@floating-ui/react-dom-interactions": "0.10.3",
@@ -123,14 +119,12 @@
"@types/bootstrap": "4.5.0",
"@types/country-list": "2.1.0",
"@types/enzyme": "3.10.11",
"@types/highlight.js": "10.1.0",
"@types/jest": "26.0.24",
"@types/katex": "0.11.0",
"@types/lodash": "4.14.182",
"@types/luxon": "3.0.2",
"@types/mark.js": "8.11.6",
"@types/marked": "0.7.4",
"@types/moment-timezone": "0.5.30",
"@types/node": "16.3.1",
"@types/react": "17.0.2",
"@types/react-beautiful-dnd": "13.1.2",
@@ -153,8 +147,8 @@
"@types/styled-components": "5.1.24",
"@types/tinycolor2": "1.4.3",
"@types/webpack-env": "1.18.0",
"@typescript-eslint/eslint-plugin": "5.41.0",
"@typescript-eslint/parser": "5.41.0",
"@typescript-eslint/eslint-plugin": "5.57.1",
"@typescript-eslint/parser": "5.57.1",
"babel-loader": "8.2.3",
"babel-plugin-lodash": "3.3.4",
"babel-plugin-styled-components": "1.12.0",
@@ -167,14 +161,13 @@
"enzyme": "3.11.0",
"enzyme-adapter-react-17-updated": "1.0.2",
"enzyme-to-json": "3.6.2",
"eslint": "7.32.0",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-formatjs": "4.3.4",
"eslint-plugin-formatjs": "4.9.1",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#5b0c972eacf19286e4c66221b39113bf8728a99e",
"eslint-plugin-no-only-tests": "2.6.0",
"eslint-plugin-react": "7.31.10",
"eslint-plugin-no-only-tests": "3.1.0",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"external-remotes-plugin": "1.0.0",
"file-loader": "6.2.0",

Просмотреть файл

@@ -14,13 +14,12 @@ import {
searchFilesWithParams,
} from 'mattermost-redux/actions/search';
import * as PostActions from 'mattermost-redux/actions/posts';
import {getCurrentUserId, getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users';
import {getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentChannelId, getCurrentChannelNameForSearchShortcut, getChannel as getChannelSelector} from 'mattermost-redux/selectors/entities/channels';
import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {makeGetUserTimezone} from 'mattermost-redux/selectors/entities/timezone';
import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone';
import {Action, ActionResult, DispatchFunc, GenericAction, GetStateFunc} from 'mattermost-redux/types/actions';
import {Post} from '@mattermost/types/posts';
@@ -174,9 +173,7 @@ export function performSearch(terms: string, isMentionSearch?: boolean) {
}
// timezone offset in seconds
const userId = getCurrentUserId(getState());
const userTimezone = makeGetUserTimezone()(getState(), userId);
const userCurrentTimezone = getUserCurrentTimezone(userTimezone);
const userCurrentTimezone = getCurrentTimezone(getState());
const timezoneOffset = ((userCurrentTimezone && (userCurrentTimezone.length > 0)) ? getUtcOffsetForTimeZone(userCurrentTimezone) : getBrowserUtcOffset()) * 60;
const messagesPromise = dispatch(searchPostsWithParams(isMentionSearch ? '' : teamId, {terms, is_or_search: Boolean(isMentionSearch), include_deleted_channels: viewArchivedChannels, time_zone_offset: timezoneOffset, page: 0, per_page: 20}));
const filesPromise = dispatch(searchFilesWithParams(teamId, {terms: termsWithExtensionsFilters, is_or_search: Boolean(isMentionSearch), include_deleted_channels: viewArchivedChannels, time_zone_offset: timezoneOffset, page: 0, per_page: 20}));

Просмотреть файл

@@ -49,7 +49,7 @@ export default class AboutBuildModal extends React.PureComponent<Props, State> {
doHide = () => {
this.setState({show: false});
}
};
render() {
const config = this.props.config;

Просмотреть файл

@@ -32,11 +32,11 @@ export default class AccessHistoryModal extends React.PureComponent<Props, State
public onShow = () => { // public for testing
this.props.actions.getUserAudits(this.props.currentUserId, 0, 200);
}
};
public onHide = () => { // public for testing
this.setState({show: false});
}
};
public componentDidMount() {
this.onShow();

Просмотреть файл

@@ -23,7 +23,7 @@ export default class Accordion extends React.PureComponent<Props, State> {
setExpanded = (expandedKey: string) => {
this.setState({expandedKey});
}
};
render() {
return (

Просмотреть файл

@@ -39,7 +39,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace disabled
className="post-menu__item post-menu__item--active"
id="center_actions_button_post_id_1"
key="more-actions-button"
onClick={[Function]}
type="button"
>
<i
@@ -107,7 +106,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace enabled a
className="post-menu__item post-menu__item--active"
id="center_actions_button_post_id_1"
key="more-actions-button"
onClick={[Function]}
type="button"
>
<i
@@ -194,7 +192,6 @@ exports[`components/actions_menu/ActionsMenu no actions - sysadmin - menu should
className="post-menu__item post-menu__item--active"
id="center_actions_button_post_id_1"
key="more-actions-button"
onClick={[Function]}
type="button"
>
<i

Просмотреть файл

@@ -38,12 +38,7 @@ describe('components/actions_menu/ActionsMenu', () => {
isSysAdmin: true,
pluginMenuItems: [],
post: TestHelper.getPostMock({id: 'post_id_1', is_pinned: false, type: '' as PostType}),
showTutorialTip: false,
components: {},
handleOpenTip: jest.fn(),
handleNextTip: jest.fn(),
handleDismissTip: jest.fn(),
showPulsatingDot: false,
location: 'center',
canOpenMarketplace: false,
actions: {

Просмотреть файл

@@ -17,7 +17,6 @@ import {AppCallResponseTypes} from 'mattermost-redux/constants/apps';
import {HandleBindingClick, PostEphemeralCallResponseForPost, OpenAppsModal} from 'types/apps';
import {Locations, Constants, ModalIdentifiers} from 'utils/constants';
import Permissions from 'mattermost-redux/constants/permissions';
import {ActionsTutorialTip} from 'components/actions_menu/actions_menu_tutorial_tip';
import {ModalData} from 'types/actions';
import MarketplaceModal, {OpenedFromType} from 'components/plugin_marketplace/marketplace_modal';
import OverlayTrigger from 'components/overlay_trigger';
@@ -44,11 +43,6 @@ export type Props = {
pluginMenuItems?: PluginComponent[];
post: Post;
teamId: string;
handleOpenTip: () => void;
handleNextTip: (e: React.MouseEvent) => void;
handleDismissTip: () => void;
showPulsatingDot?: boolean;
showTutorialTip: boolean;
canOpenMarketplace: boolean;
/**
@@ -98,7 +92,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
appBindings: [],
location: Locations.CENTER,
pluginMenuItems: [],
}
};
private buttonRef: React.RefObject<HTMLButtonElement>;
constructor(props: Props) {
@@ -121,7 +115,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
defaultMessage='Message actions'
/>
</Tooltip>
)
);
componentDidUpdate(prevProps: Props) {
if (this.props.isMenuOpen && !prevProps.isMenuOpen) {
@@ -143,7 +137,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
this.setState({appBindings: data});
});
}
}
};
handleOpenMarketplace = (): void => {
const openedFrom: OpenedFromType = 'actions_menu';
@@ -203,7 +197,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
this.props.actions.postEphemeralCallResponseForPost(callResp, errorMessage, post);
}
}
}
};
visitMarketplaceTip(): React.ReactElement {
return (
@@ -236,14 +230,6 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
);
}
handleActionsIconClick = (e: React.MouseEvent) => {
if (this.props.showPulsatingDot || this.props.showTutorialTip) {
this.props.handleOpenTip();
e.preventDefault();
e.stopPropagation();
}
};
renderDivider = (suffix: string): React.ReactNode => {
return (
<li
@@ -277,7 +263,7 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
this.setState({
openUp: (spaceOnTop > spaceOnBottom),
});
}
};
render(): React.ReactNode {
const isSystemMessage = PostUtils.isSystemMessage(this.props.post);
@@ -413,17 +399,8 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
})}
type='button'
aria-expanded='false'
onClick={this.handleActionsIconClick}
>
<i className={'icon icon-apps'}/>
{this.props.showPulsatingDot &&
<ActionsTutorialTip
showTip={this.props.showTutorialTip}
handleNext={this.props.handleNextTip}
handleOpen={this.props.handleOpenTip}
handleDismiss={this.props.handleDismissTip}
/>
}
</button>
</OverlayTrigger>
<Menu

Просмотреть файл

@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu returning empty ("")', () => {
},
appBindings: [],
pluginMenuItems: [],
handleOpenTip: jest.fn(),
handleNextTip: jest.fn(),
handleDismissTip: jest.fn(),
showPulsatingDot: false,
showTutorialTip: false,
appsEnabled: false,
isSysAdmin: true,
canOpenMarketplace: false,

Просмотреть файл

@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu on mobile view', () => {
},
appBindings: [],
pluginMenuItems: [],
handleOpenTip: jest.fn(),
handleNextTip: jest.fn(),
handleDismissTip: jest.fn(),
showPulsatingDot: false,
showTutorialTip: false,
appsEnabled: false,
isSysAdmin: true,
canOpenMarketplace: false,

Просмотреть файл

@@ -6,7 +6,7 @@ import {Link, useRouteMatch, useLocation, matchPath} from 'react-router-dom';
import {useIntl} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import classNames from 'classnames';
import Icon from '@mattermost/compass-components/foundations/icon';
import Icon from '@mattermost/compass-components/foundations/icon'; // eslint-disable-line no-restricted-imports
import {insightsAreEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getIsRhsOpen, getRhsState} from 'selectors/rhs';

Просмотреть файл

@@ -5,7 +5,7 @@ import React, {memo, useCallback} from 'react';
import ReactSelect, {ValueType} from 'react-select';
import Icon from '@mattermost/compass-components/foundations/icon/Icon';
import Icon from '@mattermost/compass-components/foundations/icon/Icon'; // eslint-disable-line no-restricted-imports
import {trackEvent} from 'actions/telemetry_actions';

Просмотреть файл

@@ -11,14 +11,13 @@ import {TopChannel, TopChannelGraphData} from '@mattermost/types/insights';
import {CircleSkeletonLoader, RectangleSkeletonLoader} from '@mattermost/components';
import {getCurrentRelativeTeamUrl, getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone';
import {getMyTopChannels, getTopChannelsForTeam} from 'mattermost-redux/actions/insights';
import Constants, {InsightsScopes} from 'utils/constants';
import {trackEvent} from 'actions/telemetry_actions';
import {getCurrentUserTimezone} from 'selectors/general';
import OverlayTrigger from 'components/overlay_trigger';
import Tooltip from 'components/tooltip';
@@ -38,7 +37,7 @@ const TopChannels = (props: WidgetHocProps) => {
const currentTeamId = useSelector(getCurrentTeamId);
const currentTeamUrl = useSelector(getCurrentRelativeTeamUrl);
const timeZone = useSelector(getCurrentUserTimezone);
const timeZone = useSelector(getCurrentTimezone);
const getTopTeamChannels = useCallback(async () => {
if (props.filterType === InsightsScopes.TEAM) {

Просмотреть файл

@@ -53,7 +53,7 @@ type State = {
export default class ActivityLogModal extends React.PureComponent<Props, State> {
static propTypes = {
}
};
constructor(props: Props) {
super(props);
@@ -73,15 +73,15 @@ export default class ActivityLogModal extends React.PureComponent<Props, State>
this.props.actions.revokeSession(this.props.currentUserId, altId).then(() => {
this.props.actions.getSessions(this.props.currentUserId);
});
}
};
onShow = () => {
this.props.actions.getSessions(this.props.currentUserId);
}
};
onHide = () => {
this.setState({show: false});
}
};
componentDidMount() {
this.onShow();

Просмотреть файл

@@ -56,11 +56,11 @@ export default class ActivityLog extends React.PureComponent<Props, State> {
handleMoreInfo = (): void => {
this.setState({moreInfo: true});
}
};
submitRevoke = (e: React.MouseEvent): void => {
this.props.submitRevoke(this.props.currentSession.id, e);
}
};
isMobileSession = (session: Session): boolean => {
return Boolean(session.device_id && (session.device_id.includes('apple') || session.device_id.includes('android')));

Просмотреть файл

@@ -110,7 +110,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
handleHide = () => {
this.props.actions.setModalSearchTerm('');
this.setState({show: false});
}
};
handleResponse = (err?: ServerError) => {
let addError = null;
@@ -122,7 +122,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
saving: false,
addError,
});
}
};
handleSubmit = async () => {
const groupIDs = this.state.values.map((v) => v.id);
@@ -147,7 +147,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
this.handleHide();
}
}));
}
};
addValue = (value: GroupValue) => {
const values = Object.assign([], this.state.values);
@@ -157,13 +157,13 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
}
this.setState({values});
}
};
setGroupsLoadingState = (loadingState: boolean) => {
this.setState({
loadingGroups: loadingState,
});
}
};
handlePageChange = (page: number, prevPage: number) => {
if (page > prevPage) {
@@ -172,15 +172,15 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
this.setGroupsLoadingState(false);
});
}
}
};
handleDelete = (values: GroupValue[]) => {
this.setState({values});
}
};
search = (term: string) => {
this.props.actions.setModalSearchTerm(term);
}
};
renderOption = (option: GroupValue, isSelected: boolean, onAdd: (value: GroupValue) => void, onMouseMove?: (value: GroupValue) => void) => {
const rowSelected = isSelected ? 'more-modal__row--selected' : '';
@@ -222,7 +222,7 @@ export default class AddGroupsToChannelModal extends React.PureComponent<Props,
</div>
</div>
);
}
};
renderValue(props: { data: Partial<Value> }) {
return props.data.display_name;

Просмотреть файл

@@ -105,12 +105,12 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
public handleHide = () => {
this.props.actions.setModalSearchTerm('');
this.setState({show: false});
}
};
// public for tests
public handleExit = (): void => {
this.props.onExited();
}
};
// public for tests
public handleResponse = (err?: Error): void => {
@@ -123,7 +123,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
saving: false,
addError,
});
}
};
// public for tests
public handleSubmit = async () => {
@@ -148,7 +148,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
this.handleHide();
}
}));
}
};
// public for tests
public addValue = (value: GroupValue): void => {
@@ -159,13 +159,13 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
}
this.setState({values});
}
};
private setGroupsLoadingState = (loadingState: boolean) => {
this.setState({
loadingGroups: loadingState,
});
}
};
// public for tests
public handlePageChange = (page: number, prevPage: number): void => {
@@ -175,7 +175,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
this.setGroupsLoadingState(false);
});
}
}
};
// public for tests
public handleDelete = (values: GroupValue[]): void => this.setState({values});
@@ -224,7 +224,7 @@ export default class AddGroupsToTeamModal extends React.PureComponent<Props, Sta
</div>
</div>
);
}
};
// public for tests
public renderValue = (props: { data: Value }): string | undefined => props.data.display_name;

Просмотреть файл

@@ -114,7 +114,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
enableChannelProvider = () => {
this.suggestionProviders[0].disableDispatches = false;
}
};
focusTextbox = () => {
if (this.channelSearchBox == null) {
@@ -126,30 +126,30 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
textbox.focus();
placeCaretAtEnd(textbox);
}
}
};
onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
this.setState({text: e.target.value, selectedChannelId: null});
}
};
onHide = () => {
this.setState({show: false});
}
};
onExited = () => {
this.props.onExited();
}
};
setSearchBoxRef = (input: SuggestionBoxComponent) => {
this.channelSearchBox = input;
this.focusTextbox();
}
};
handleSubmitError = (error: {message: string}) => {
if (error) {
this.setState({submitError: error.message, saving: false});
}
}
};
didSelectChannel = (selection: {channel: Channel}) => {
const channel = selection.channel;
@@ -165,7 +165,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
this.props.actions.getChannelMember(channel.id, userId).then(() => {
this.setState({checkingForMembership: false});
});
}
};
handleSubmit = (e: FormEvent) => {
if (e && e.preventDefault) {
@@ -192,7 +192,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
this.onHide();
}
});
}
};
isUserMemberOfChannel = (channelId: string | null) => {
const user = this.props.user;
@@ -207,7 +207,7 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
}
return Boolean(memberships[channelId][user.id]);
}
};
render() {
const user = this.props.user;

Просмотреть файл

@@ -173,7 +173,7 @@ export default class AddUserToGroupMultiSelect extends React.PureComponent<Props
return '';
}
return option.username;
}
};
renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => {
return (
@@ -241,5 +241,5 @@ export default class AddUserToGroupMultiSelect extends React.PureComponent<Props
numRemainingText={numRemainingText}
/>
);
}
};
}

Просмотреть файл

@@ -78,11 +78,11 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
public componentDidMount = async () => {
await this.props.actions.getProfilesNotInTeam(this.props.team.id, false, 0, USERS_PER_PAGE * 2);
this.setUsersLoadingState(false);
}
};
private setUsersLoadingState = (loading: boolean) => {
this.setState({loading});
}
};
public search = async (term: string) => {
this.setUsersLoadingState(true);
@@ -95,17 +95,17 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
await this.props.actions.getProfilesNotInTeam(this.props.team.id, false, 0, USERS_PER_PAGE * 2);
}
this.setState({loading: false, searchResults, search});
}
};
public handleHide = () => {
this.setState({show: false});
}
};
private handleExit = () => {
if (this.props.onExited) {
this.props.onExited();
}
}
};
private renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => {
let rowSelected = '';
@@ -139,15 +139,15 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
</div>
</div>
);
}
};
private renderValue = (value: { data: UserProfileValue }): string => {
return value.data?.username || '';
}
};
private renderAriaLabel = (option: UserProfileValue): string => {
return option?.username || '';
}
};
private handleAdd = (value: UserProfileValue) => {
const values: UserProfileValue[] = [...this.state.values];
@@ -155,11 +155,11 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
values.push(value);
}
this.setState({values});
}
};
private handleDelete = (values: UserProfileValue[]) => {
this.setState({values});
}
};
private handlePageChange = (page: number, prevPage: number) => {
if (page > prevPage) {
@@ -173,7 +173,7 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
private handleSubmit = () => {
this.props.onAddCallback(this.state.values);
this.handleHide();
}
};
public render = (): JSX.Element => {
const numRemainingText = (
@@ -259,5 +259,5 @@ export default class AddUsersToTeamModal extends React.PureComponent<Props, Stat
</Modal.Body>
</Modal>
);
}
};
}

Просмотреть файл

@@ -93,7 +93,7 @@ export default class AdminConsole extends React.PureComponent<Props, State> {
private onFilterChange = (filter: string) => {
this.setState({filter});
}
};
private mainRolesLoaded(roles: Record<string, Role>) {
return (
@@ -186,7 +186,7 @@ export default class AdminConsole extends React.PureComponent<Props, State> {
{<Redirect to={`${this.props.match.url}/${defaultUrl}`}/>}
</Switch>
);
}
};
public render(): JSX.Element | null {
const {

Просмотреть файл

@@ -5746,7 +5746,6 @@ const AdminDefinition = {
sectionTitle: t('admin.sidebar.products'),
sectionTitleDefault: 'Products',
isHidden: it.any(
it.configIsFalse('FeatureFlags', 'BoardsProduct'),
it.not(it.userHasReadPermissionOnSomeResources(RESOURCE_KEYS.PRODUCTS)),
),
boards: {

Просмотреть файл

@@ -69,7 +69,7 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
private closeTooltip = () => {
this.setState({errorTooltip: false});
}
};
private openTooltip = (e: React.MouseEvent) => {
const elm: HTMLElement|null = e.currentTarget.querySelector('.control-label');
@@ -77,7 +77,7 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
const isElipsis = elm.offsetWidth < elm.scrollWidth;
this.setState({errorTooltip: isElipsis});
}
}
};
protected handleChange = (id: string, value: boolean) => {
this.setState((prevState) => ({
@@ -95,7 +95,7 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
e.preventDefault();
this.doSubmit();
}
};
protected doSubmit = async (callback?: () => void) => {
this.setState({

Просмотреть файл

@@ -1072,6 +1072,37 @@ exports[`components/AdminSidebar should match snapshot 1`] = `
title="Plugin 0"
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="products"
icon={
<ProductsIcon
className="category-icon fa"
color="currentColor"
size={16}
/>
}
key="products"
parentLink="/admin_console"
sectionClass=""
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Products"
id="admin.sidebar.products"
/>
}
>
<AdminSidebarSection
definitionKey="products.boards"
key="products.boards"
name="products/boards"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Boards"
id="admin.sidebar.boards"
/>
}
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="integrations"
icon={
@@ -1775,6 +1806,37 @@ exports[`components/AdminSidebar should match snapshot with workspace optimizati
title="Plugin 0"
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="products"
icon={
<ProductsIcon
className="category-icon fa"
color="currentColor"
size={16}
/>
}
key="products"
parentLink="/admin_console"
sectionClass=""
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Products"
id="admin.sidebar.products"
/>
}
>
<AdminSidebarSection
definitionKey="products.boards"
key="products.boards"
name="products/boards"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Boards"
id="admin.sidebar.boards"
/>
}
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="integrations"
icon={
@@ -2533,6 +2595,37 @@ exports[`components/AdminSidebar should match snapshot, not prevent the console
title="Plugin 0"
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="products"
icon={
<ProductsIcon
className="category-icon fa"
color="currentColor"
size={16}
/>
}
key="products"
parentLink="/admin_console"
sectionClass=""
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Products"
id="admin.sidebar.products"
/>
}
>
<AdminSidebarSection
definitionKey="products.boards"
key="products.boards"
name="products/boards"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Boards"
id="admin.sidebar.boards"
/>
}
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="integrations"
icon={
@@ -3236,6 +3329,37 @@ exports[`components/AdminSidebar should match snapshot, render plugins without a
title="Plugin 0"
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="products"
icon={
<ProductsIcon
className="category-icon fa"
color="currentColor"
size={16}
/>
}
key="products"
parentLink="/admin_console"
sectionClass=""
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Products"
id="admin.sidebar.products"
/>
}
>
<AdminSidebarSection
definitionKey="products.boards"
key="products.boards"
name="products/boards"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Boards"
id="admin.sidebar.boards"
/>
}
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="integrations"
icon={
@@ -4038,6 +4162,37 @@ exports[`components/AdminSidebar should match snapshot, with license (with all f
title="Plugin 0"
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="products"
icon={
<ProductsIcon
className="category-icon fa"
color="currentColor"
size={16}
/>
}
key="products"
parentLink="/admin_console"
sectionClass=""
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Products"
id="admin.sidebar.products"
/>
}
>
<AdminSidebarSection
definitionKey="products.boards"
key="products.boards"
name="products/boards"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Boards"
id="admin.sidebar.boards"
/>
}
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="integrations"
icon={
@@ -4973,6 +5128,37 @@ exports[`components/AdminSidebar should match snapshot, with license (without an
title="Plugin 0"
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="products"
icon={
<ProductsIcon
className="category-icon fa"
color="currentColor"
size={16}
/>
}
key="products"
parentLink="/admin_console"
sectionClass=""
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Products"
id="admin.sidebar.products"
/>
}
>
<AdminSidebarSection
definitionKey="products.boards"
key="products.boards"
name="products/boards"
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Boards"
id="admin.sidebar.boards"
/>
}
/>
</AdminSidebarCategory>
<AdminSidebarCategory
definitionKey="integrations"
icon={

Просмотреть файл

@@ -57,11 +57,11 @@ const renderScrollThumbVertical = (props: Props) => (
class AdminSidebar extends React.PureComponent<Props, State> {
searchRef: React.RefObject<HTMLInputElement>;
idx: Index | null
idx: Index | null;
static defaultProps = {
plugins: {},
}
};
constructor(props: Props) {
super(props);
@@ -130,7 +130,7 @@ class AdminSidebar extends React.PureComponent<Props, State> {
}
}
}
}
};
updateTitle = () => {
let currentSiteName = '';
@@ -139,7 +139,7 @@ class AdminSidebar extends React.PureComponent<Props, State> {
}
document.title = localizeMessage('sidebar_right_menu.console', 'System Console') + currentSiteName;
}
};
visibleSections = () => {
const {config, license, buildEnterpriseReady, consoleAccess, adminDefinition, cloud} = this.props;
@@ -166,7 +166,7 @@ class AdminSidebar extends React.PureComponent<Props, State> {
}
}
return result;
}
};
renderRootMenu = (definition: typeof AdminDefinition) => {
const {config, license, buildEnterpriseReady, consoleAccess, cloud, subscriptionProduct} = this.props;
@@ -249,11 +249,11 @@ class AdminSidebar extends React.PureComponent<Props, State> {
return null;
});
return sidebarSections;
}
};
isPluginPresentInSections = (plugin: PluginRedux) => {
return this.state.sections && this.state.sections.indexOf(`plugin_${plugin.id}`) >= 0;
}
};
renderPluginsMenu = () => {
const {config, plugins} = this.props;
@@ -279,12 +279,12 @@ class AdminSidebar extends React.PureComponent<Props, State> {
}
return [];
}
};
handleClearFilter = () => {
this.setState({sections: null, filter: ''});
this.props.onFilterChange('');
}
};
render() {
const {showTaskList} = this.props;

Просмотреть файл

@@ -226,9 +226,9 @@ export const InvoiceInfo = ({invoice, product, fullCharges, partialCharges, hasM
currency='USD'
/>
<FormattedMessage
id='admin.billing.subscriptions.billing_summary.lastInvoice.userCount'
defaultMessage=' x {users} users'
values={{users: charge.quantity}}
id='admin.billing.subscriptions.billing_summary.lastInvoice.seatCount'
defaultMessage=' x {seats} seats'
values={{seats: charge.quantity}}
/>
</>
)}
@@ -309,9 +309,9 @@ export const InvoiceInfo = ({invoice, product, fullCharges, partialCharges, hasM
>
<div className='BillingSummary__lastInvoice-chargeDescription'>
<FormattedMessage
id='admin.billing.subscriptions.billing_summary.lastInvoice.userCountPartial'
defaultMessage='{users} users'
values={{users: charge.quantity}}
id='admin.billing.subscriptions.billing_summary.lastInvoice.seatCountPartial'
defaultMessage='{seats} seats'
values={{seats: charge.quantity}}
/>
</div>
<div className='BillingSummary__lastInvoice-chargeAmount'>

Просмотреть файл

@@ -15,8 +15,6 @@ import {isCloudLicense} from 'utils/license_utils';
import {getCloudSubscription, getSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud';
import ExternalLink from 'components/external_link';
import DeleteWorkspaceModal from './delete_workspace_modal';
export default function DeleteWorkspaceCTA() {
@@ -80,17 +78,15 @@ export default function DeleteWorkspaceCTA() {
}}
/>
</div>
<ExternalLink
href=''
location='delete_workspace_cta'
className='cancelSubscriptionSection__contactUs'
<button
className='btn cancelSubscriptionSection__contactUs'
onClick={handleOnClickDelete}
>
<FormattedMessage
id='admin.billing.subscription.deleteWorkspaceSection.delete'
defaultMessage='Delete Workspace'
/>
</ExternalLink>
</button>
</div>
</div>
);

Просмотреть файл

@@ -51,28 +51,28 @@ describe('InvoiceUserCount', () => {
[1, InvoiceLineItemType.Full],
[1, InvoiceLineItemType.Partial],
),
expected: '1 metered users, 1 users at full rate, 1 users with partial charges',
expected: '1 metered seats, 1 seats at full rate, 1 seats with partial charges',
},
{
name: 'Supports cloud invoices with only metered line items',
invoice: makeInvoice(
[12.34, InvoiceLineItemType.Metered],
),
expected: '12.34 users',
expected: '12.34 seats',
},
{
name: 'Shows minimum decimal necessary',
invoice: makeInvoice(
[12.499, InvoiceLineItemType.Metered],
),
expected: '12.5 users',
expected: '12.5 seats',
},
{
name: 'hides insignificant decimals',
invoice: makeInvoice(
[12.002, InvoiceLineItemType.Metered],
),
expected: '12 users',
expected: '12 seats',
},
{
name: 'Supports cloud invoices with only non-metered line items',
@@ -80,7 +80,7 @@ describe('InvoiceUserCount', () => {
[1, InvoiceLineItemType.Full],
[249, InvoiceLineItemType.Partial],
),
expected: '1 users at full rate, 249 users with partial charges',
expected: '1 seats at full rate, 249 seats with partial charges',
},
{
name: 'Shows default of 0 full users, 0 partial users when there are no users',
@@ -89,19 +89,19 @@ describe('InvoiceUserCount', () => {
[0, InvoiceLineItemType.Full],
[0, InvoiceLineItemType.Partial],
),
expected: '0 users at full rate, 0 users with partial charges',
expected: '0 seats at full rate, 0 seats with partial charges',
},
{
name: 'Shows default of 0 full users, 0 partial users when there are no line items in invoice',
invoice: makeInvoice(),
expected: '0 users at full rate, 0 users with partial charges',
expected: '0 seats at full rate, 0 seats with partial charges',
},
{
name: 'Shows 3 full userswhen there are on prem users',
invoice: makeInvoice(
[3, InvoiceLineItemType.OnPremise],
),
expected: '3 users',
expected: '3 seats',
},
];

Просмотреть файл

@@ -18,8 +18,8 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele
if (onPremUsers) {
return (
<FormattedMessage
id='admin.billing.history.onPremUsers'
defaultMessage='{num} users'
id='admin.billing.history.onPremSeats'
defaultMessage='{num} seats'
values={{
// should always be a whole number, but truncate just in case
@@ -32,12 +32,12 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele
if (fullUsers || partialUsers) {
return (
<FormattedMessage
id='admin.billing.history.fractionalAndRatedUsers'
defaultMessage='{fractionalUsers} metered users, {fullUsers} users at full rate, {partialUsers} users with partial charges'
id='admin.billing.history.fractionalAndRatedSeats'
defaultMessage='{fractionalSeats} metered seats, {fullSeats} seats at full rate, {partialSeats} seats with partial charges'
values={{
fractionalUsers: numberToFixedDynamic(meteredUsers, 2),
fullUsers: fullUsers.toFixed(0),
partialUsers: partialUsers.toFixed(0),
fractionalSeats: numberToFixedDynamic(meteredUsers, 2),
fullSeats: fullUsers.toFixed(0),
partialSeats: partialUsers.toFixed(0),
}}
/>
);
@@ -45,10 +45,10 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele
return (
<FormattedMessage
id='admin.billing.history.fractionalUsers'
defaultMessage='{fractionalUsers} users'
id='admin.billing.history.fractionalSeats'
defaultMessage='{fractionalSeats} seats'
values={{
fractionalUsers: numberToFixedDynamic(meteredUsers, 2),
fractionalSeats: numberToFixedDynamic(meteredUsers, 2),
}}
/>
);
@@ -56,11 +56,11 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele
return (
<FormattedMessage
id='admin.billing.history.usersAndRates'
defaultMessage='{fullUsers} users at full rate, {partialUsers} users with partial charges'
id='admin.billing.history.seatsAndRates'
defaultMessage='{fullSeats} seats at full rate, {partialSeats} seats with partial charges'
values={{
fullUsers: fullUsers.toFixed(0),
partialUsers: partialUsers.toFixed(0),
fullSeats: fullUsers.toFixed(0),
partialSeats: partialUsers.toFixed(0),
}}
/>
);

Просмотреть файл

@@ -25,7 +25,7 @@ export default class BleveSettings extends AdminSettings {
config.BleveSettings.EnableAutocomplete = this.state.enableAutocomplete;
return config;
}
};
getStateFromConfig(config) {
return {
@@ -55,17 +55,17 @@ export default class BleveSettings extends AdminSettings {
}
this.handleChange(id, value);
}
};
handleSaved = () => {
this.setState({
canPurgeAndIndex: this.state.enableIndexing && this.state.indexDir !== '',
});
}
};
canSave = () => {
return this.state.canSave;
}
};
getExtraInfo(job) {
if (job.status === JobStatuses.IN_PROGRESS) {
@@ -246,5 +246,5 @@ export default class BleveSettings extends AdminSettings {
/>
</SettingsGroup>
);
}
};
}

Просмотреть файл

@@ -40,7 +40,7 @@ export default class BooleanSetting extends React.PureComponent<Props> {
private handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.props.onChange(this.props.id, e.target.value === 'true');
}
};
public render() {
let helpText;

Просмотреть файл

@@ -29,7 +29,7 @@ export default class ClusterSettings extends AdminSettings {
config.ClusterSettings.GossipPort = this.parseIntNonZero(this.state.GossipPort, 8074);
config.ClusterSettings.StreamingPort = this.parseIntNonZero(this.state.StreamingPort, 8075);
return config;
}
};
getStateFromConfig(config) {
const settings = config.ClusterSettings;
@@ -62,7 +62,7 @@ export default class ClusterSettings extends AdminSettings {
});
this.handleChange(id, value);
}
};
renderSettings = () => {
const licenseEnabled = this.props.license.IsLicensed === 'true' && this.props.license.Cluster === 'true';
@@ -309,7 +309,7 @@ export default class ClusterSettings extends AdminSettings {
/>
</SettingsGroup>
);
}
};
}
const style = {

Просмотреть файл

@@ -15,7 +15,7 @@ export default class ClusterTable extends React.PureComponent {
static propTypes = {
clusterInfos: PropTypes.array.isRequired,
reload: PropTypes.func.isRequired,
}
};
render() {
var versionMismatch = (

Просмотреть файл

@@ -28,7 +28,7 @@ export default class ClusterTableContainer extends React.PureComponent {
},
null,
);
}
};
componentDidMount() {
this.load();
@@ -53,7 +53,7 @@ export default class ClusterTableContainer extends React.PureComponent {
});
this.load();
}
};
render() {
if (this.state.clusterInfos == null) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше