diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 548bb4a16c..c9319580f6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -19,6 +19,18 @@ If this pull request addresses a Help Wanted ticket, please link the relevant Gi Otherwise, link the JIRA ticket. --> +#### Screenshots + + #### Release Note - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
- -
- - - - - - -
- -
- - - - - - -
- - - - - - -
- -
-
-
- -
-
- -
- - - - - - -
- -
- - - - - - - - - - - - - - - - - - -
-
{{.Props.Title}}
-
-
{{.Props.SubTitle}}
-
-
-
    -
  • {{.Props.InfoBullet}}{{.Props.Channels}}
  • -
  • {{.Props.InfoBullet1}}{{.Props.Playbooks}}
  • -
  • {{.Props.InfoBullet2}}{{.Props.Boards}}
  • -
-
-
-
{{.Props.Info}}
-
- - - - -
- - {{.Props.Button}} - -
-
-
- -
-
- -
- - - - - - -
- -
- - - - - - -
- - - - - - -
- -
-
-
- -
-
- -
- - - - - - -
- -
- - - - - - - - - -
-
{{.Props.QuestionTitle}}
-
-
{{.Props.QuestionInfo}} - - {{.Props.SupportEmail}} - -
-
-
- -
-
- -
- - - - - - -
- -
- - - - - - - - - -
-
{{.Props.FooterDisclaimer}}
-
-
{{.Props.Organization}} - {{.Props.FooterV2}} -
-
-
- -
-
- -
-
- -
- - - - -{{end}} diff --git a/server/templates/inactivity_body.mjml b/server/templates/inactivity_body.mjml deleted file mode 100644 index 47b17fe42c..0000000000 --- a/server/templates/inactivity_body.mjml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - {{.Props.Title}} - - - {{.Props.SubTitle}} - - -
    -
  • {{.Props.InfoBullet}}{{.Props.Channels}}
  • -
  • {{.Props.InfoBullet1}}{{.Props.Playbooks}}
  • -
  • {{.Props.InfoBullet2}}{{.Props.Boards}}
  • -
-
- - {{.Props.Info}} - - {{.Props.Button}} -
-
- - - - - - - - - - - {{.Props.QuestionTitle}} - - - {{.Props.QuestionInfo}} - - {{.Props.SupportEmail}} - - - - - - - - - {{.Props.FooterDisclaimer}} - - - {{.Props.Organization}} - {{.Props.FooterV2}} - - - - -
-
-
diff --git a/server/tests/test-config.json b/server/tests/test-config.json index 3604556889..d98cbd98ca 100644 --- a/server/tests/test-config.json +++ b/server/tests/test-config.json @@ -167,7 +167,6 @@ "LoginButtonColor": "", "LoginButtonBorderColor": "", "LoginButtonTextColor": "", - "EnableInactivityEmail": true }, "RateLimitSettings": { "Enable": false, diff --git a/webapp/Makefile b/webapp/Makefile index 7e7fe31f68..b921397be5 100644 --- a/webapp/Makefile +++ b/webapp/Makefile @@ -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 diff --git a/webapp/boards/.eslintrc.json b/webapp/boards/.eslintrc.json index 92293bdae7..38051b75e8 100644 --- a/webapp/boards/.eslintrc.json +++ b/webapp/boards/.eslintrc.json @@ -89,7 +89,7 @@ "unused-imports/no-unused-imports": 2, "no-relative-import-paths/no-relative-import-paths": [ "error", - { "allowSameFolder": true, "rootDir": "webapp/src"} + { "allowSameFolder": true, "rootDir": "webapp/boards"} ], /* "no-restricted-imports": ["error", { "patterns": ["..*"] diff --git a/webapp/boards/NOTICE.txt b/webapp/boards/NOTICE.txt index 1fe6975ff0..acebeb67ec 100644 --- a/webapp/boards/NOTICE.txt +++ b/webapp/boards/NOTICE.txt @@ -2982,32 +2982,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----- -The following software may be included in this product: mini-create-react-context. A copy of the source code may be downloaded from https://github.com/StringEpsilon/mini-create-react-context. This software contains the following license and notice below: - -Copyright (c) 2019-present StringEpsilon - -Copyright (c) 2017-2019 James Kyle - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------ - The following software may be included in this product: mkdirp. A copy of the source code may be downloaded from https://github.com/substack/node-mkdirp.git. This software contains the following license and notice below: Copyright 2010 James Halliday (mail@substack.net) diff --git a/webapp/boards/i18n/ar.json b/webapp/boards/i18n/ar.json index 8eeca566ee..622352141c 100644 --- a/webapp/boards/i18n/ar.json +++ b/webapp/boards/i18n/ar.json @@ -112,7 +112,6 @@ "Categories.CreateCategoryDialog.UpdateText": "تحديث", "CenterPanel.Login": "تسجيل الدخول", "CenterPanel.Share": "مشاركة", - "CloudMessage.cloud-server": "احصل علي خادم سحابي خاص بك مجاني.", "ColorOption.selectColor": "اختر {color} اللون", "Comment.delete": "حذف", "CommentsList.send": "إرسال", diff --git a/webapp/boards/i18n/de.json b/webapp/boards/i18n/de.json index cfcee4b6f9..5a2835d428 100644 --- a/webapp/boards/i18n/de.json +++ b/webapp/boards/i18n/de.json @@ -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.", diff --git a/webapp/boards/i18n/en.json b/webapp/boards/i18n/en.json index b7a90daf5f..a913658a73 100644 --- a/webapp/boards/i18n/en.json +++ b/webapp/boards/i18n/en.json @@ -1,4 +1,6 @@ { + "AdminBadge.SystemAdmin": "Admin", + "AdminBadge.TeamAdmin": "Team Admin", "AppBar.Tooltip": "Toggle linked boards", "Attachment.Attachment-title": "Attachment", "AttachmentBlock.DeleteAction": "delete", @@ -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} Color", "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": "doesn't contain", "Filter.not-ends-with": "doesn't end with", "Filter.not-includes": "doesn't include", @@ -243,16 +249,11 @@ "ShareBoard.userPermissionsYouText": "(You)", "ShareTemplate.Title": "Share template", "ShareTemplate.searchPlaceholder": "Search for people", - "Sidebar.about": "About Focalboard", - "Sidebar.add-board": "+ Add board", - "Sidebar.changePassword": "Change password", "Sidebar.delete-board": "Delete board", "Sidebar.duplicate-board": "Duplicate board", "Sidebar.export-archive": "Export archive", "Sidebar.import": "Import", "Sidebar.import-archive": "Import archive", - "Sidebar.invite-users": "Invite users", - "Sidebar.logout": "Log out", "Sidebar.new-category.badge": "New", "Sidebar.new-category.drag-boards-cta": "Drag boards here...", "Sidebar.no-boards-in-category": "No boards inside", @@ -306,6 +307,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 +362,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": "Yes, 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.", @@ -374,7 +379,6 @@ "calendar.week": "Week", "centerPanel.undefined": "No {propertyName}", "centerPanel.unknown-user": "Unknown user", - "cloudMessage.learn-more": "Learn more", "createImageBlock.failed": "This file couldn't be uploaded as the file size limit has been reached.", "default-properties.badges": "Comments and description", "default-properties.title": "Title", @@ -449,4 +453,4 @@ "tutorial_tip.ok": "Next", "tutorial_tip.out": "Opt out of these tips.", "tutorial_tip.seen": "Seen this before?" -} +} \ No newline at end of file diff --git a/webapp/boards/i18n/en_AU.json b/webapp/boards/i18n/en_AU.json index d3f396fb41..a998a55e66 100644 --- a/webapp/boards/i18n/en_AU.json +++ b/webapp/boards/i18n/en_AU.json @@ -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.", diff --git a/webapp/boards/i18n/fr.json b/webapp/boards/i18n/fr.json index b790d973a6..ad55293a0d 100644 --- a/webapp/boards/i18n/fr.json +++ b/webapp/boards/i18n/fr.json @@ -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", diff --git a/webapp/boards/i18n/he.json b/webapp/boards/i18n/he.json index 3ba1488771..692ec27fb0 100644 --- a/webapp/boards/i18n/he.json +++ b/webapp/boards/i18n/he.json @@ -101,7 +101,6 @@ "Categories.CreateCategoryDialog.UpdateText": "עדכון", "CenterPanel.Login": "כניסה", "CenterPanel.Share": "שיתוף", - "CloudMessage.cloud-server": "קבל שרת ענן בחינם.", "ColorOption.selectColor": "בחירת צבע {color}", "Comment.delete": "מחיקה", "CommentsList.send": "שליחה", diff --git a/webapp/boards/i18n/hr.json b/webapp/boards/i18n/hr.json index fb61549d10..23f7f35791 100644 --- a/webapp/boards/i18n/hr.json +++ b/webapp/boards/i18n/hr.json @@ -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.", diff --git a/webapp/boards/i18n/hu.json b/webapp/boards/i18n/hu.json index d1107c36cd..e835144850 100644 --- a/webapp/boards/i18n/hu.json +++ b/webapp/boards/i18n/hu.json @@ -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", diff --git a/webapp/boards/i18n/it.json b/webapp/boards/i18n/it.json index cb31d20f83..ce133950b4 100644 --- a/webapp/boards/i18n/it.json +++ b/webapp/boards/i18n/it.json @@ -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", diff --git a/webapp/boards/i18n/ja.json b/webapp/boards/i18n/ja.json index 6957933250..a4eae6f694 100644 --- a/webapp/boards/i18n/ja.json +++ b/webapp/boards/i18n/ja.json @@ -115,7 +115,6 @@ "CenterPanel.Login": "ログイン", "CenterPanel.Share": "共有", "ChannelIntro.CreateBoard": "Boardを作成する", - "CloudMessage.cloud-server": "専用の無料クラウドサーバーを入手する。", "ColorOption.selectColor": "{color} 色を選択", "Comment.delete": "削除", "CommentsList.send": "送信", diff --git a/webapp/boards/i18n/ka.json b/webapp/boards/i18n/ka.json index 1741695fef..5623cbd56e 100644 --- a/webapp/boards/i18n/ka.json +++ b/webapp/boards/i18n/ka.json @@ -102,7 +102,6 @@ "Categories.CreateCategoryDialog.UpdateText": "განახლება", "CenterPanel.Login": "შესვლა", "CenterPanel.Share": "გაზიარება", - "CloudMessage.cloud-server": "მიიღეთ თქვენი საკუთარი უფასო Cloud სერვერი.", "ColorOption.selectColor": "აირჩიეთ {color} ფერი", "Comment.delete": "წაშლა", "CommentsList.send": "გაგზავნა", diff --git a/webapp/boards/i18n/ko.json b/webapp/boards/i18n/ko.json index 03577f36cb..3e622dda50 100644 --- a/webapp/boards/i18n/ko.json +++ b/webapp/boards/i18n/ko.json @@ -114,7 +114,6 @@ "Categories.CreateCategoryDialog.UpdateText": "업데이트", "CenterPanel.Login": "로그인", "CenterPanel.Share": "공유", - "CloudMessage.cloud-server": "무료 클라우드 서버를 구입하십시오.", "ColorOption.selectColor": "{color} 색 선택하기", "Comment.delete": "삭제하기", "CommentsList.send": "보내기", diff --git a/webapp/boards/src/test/i18n_mock.json b/webapp/boards/i18n/lt.json similarity index 100% rename from webapp/boards/src/test/i18n_mock.json rename to webapp/boards/i18n/lt.json diff --git a/webapp/boards/i18n/nb_NO.json b/webapp/boards/i18n/nb_NO.json index 604a408853..3dc682e13a 100644 --- a/webapp/boards/i18n/nb_NO.json +++ b/webapp/boards/i18n/nb_NO.json @@ -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", diff --git a/webapp/boards/i18n/nl.json b/webapp/boards/i18n/nl.json index e06b492ac0..d0d735c948 100644 --- a/webapp/boards/i18n/nl.json +++ b/webapp/boards/i18n/nl.json @@ -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", diff --git a/webapp/boards/i18n/pl.json b/webapp/boards/i18n/pl.json index 956f2dca40..893ec70168 100644 --- a/webapp/boards/i18n/pl.json +++ b/webapp/boards/i18n/pl.json @@ -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.", diff --git a/webapp/boards/i18n/pt.json b/webapp/boards/i18n/pt.json index 54ffe071d7..6f70f2608e 100644 --- a/webapp/boards/i18n/pt.json +++ b/webapp/boards/i18n/pt.json @@ -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" } diff --git a/webapp/boards/i18n/pt_BR.json b/webapp/boards/i18n/pt_BR.json index aa755dc2f3..8b52e1675f 100644 --- a/webapp/boards/i18n/pt_BR.json +++ b/webapp/boards/i18n/pt_BR.json @@ -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}", diff --git a/webapp/boards/i18n/ru.json b/webapp/boards/i18n/ru.json index f6b502b65c..bcbcbdf899 100644 --- a/webapp/boards/i18n/ru.json +++ b/webapp/boards/i18n/ru.json @@ -115,7 +115,6 @@ "CenterPanel.Login": "Логин", "CenterPanel.Share": "Поделиться", "ChannelIntro.CreateBoard": "Создать доску", - "CloudMessage.cloud-server": "Получите свой бесплатный облачный сервер.", "ColorOption.selectColor": "Выберите цвет {color}", "Comment.delete": "Удалить", "CommentsList.send": "Отправить", diff --git a/webapp/boards/i18n/sk.json b/webapp/boards/i18n/sk.json index 7d5945f89d..6f3c5f222c 100644 --- a/webapp/boards/i18n/sk.json +++ b/webapp/boards/i18n/sk.json @@ -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ť", diff --git a/webapp/boards/i18n/sv.json b/webapp/boards/i18n/sv.json index dbea552e4b..d776db6a9a 100644 --- a/webapp/boards/i18n/sv.json +++ b/webapp/boards/i18n/sv.json @@ -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", diff --git a/webapp/boards/i18n/tr.json b/webapp/boards/i18n/tr.json index 4067219928..0c9614a803 100644 --- a/webapp/boards/i18n/tr.json +++ b/webapp/boards/i18n/tr.json @@ -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", diff --git a/webapp/boards/i18n/uk.json b/webapp/boards/i18n/uk.json index b27fd6e0cc..3e4f7d7cd1 100644 --- a/webapp/boards/i18n/uk.json +++ b/webapp/boards/i18n/uk.json @@ -115,7 +115,6 @@ "CenterPanel.Login": "Логін", "CenterPanel.Share": "Поділитися", "ChannelIntro.CreateBoard": "Створити дошку", - "CloudMessage.cloud-server": "Отримайте власний безкоштовний хмарний сервер.", "ColorOption.selectColor": "Виберіть колір {color}", "Comment.delete": "Видалити", "CommentsList.send": "Надіслати", diff --git a/webapp/boards/i18n/zh_Hans.json b/webapp/boards/i18n/zh_Hans.json index 5e176cf61d..56dfdd2824 100644 --- a/webapp/boards/i18n/zh_Hans.json +++ b/webapp/boards/i18n/zh_Hans.json @@ -115,7 +115,6 @@ "CenterPanel.Login": "登录", "CenterPanel.Share": "分享", "ChannelIntro.CreateBoard": "创建一个板块", - "CloudMessage.cloud-server": "获得自己的免费云服务器。", "ColorOption.selectColor": "选择{color}", "Comment.delete": "删除", "CommentsList.send": "发送", diff --git a/webapp/boards/i18n/zh_Hant.json b/webapp/boards/i18n/zh_Hant.json index 3d7f7f99c4..f5438884f6 100644 --- a/webapp/boards/i18n/zh_Hant.json +++ b/webapp/boards/i18n/zh_Hant.json @@ -115,7 +115,6 @@ "CenterPanel.Login": "登入", "CenterPanel.Share": "分享", "ChannelIntro.CreateBoard": "建立看板", - "CloudMessage.cloud-server": "獲得免費的雲端伺服器.", "ColorOption.selectColor": "{color} 選擇顏色", "Comment.delete": "刪除", "CommentsList.send": "發送", diff --git a/webapp/boards/jest.config.js b/webapp/boards/jest.config.js new file mode 100644 index 0000000000..05b4cd53e9 --- /dev/null +++ b/webapp/boards/jest.config.js @@ -0,0 +1,68 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +/** @type {import('jest').Config} */ + +const config = { + transform: { + "^.+\\.(t|j)sx?$": ["@swc/jest"] + }, + moduleFileExtensions: [ + "ts", + "tsx", + "js", + "jsx", + "json", + "node" + ], + extensionsToTreatAsEsm: ['.ts', '.tsx'], + transformIgnorePatterns: [ + "/nanoevents/", + "node_modules/(?!react-native|react-router|react-day-picker)" + ], + maxWorkers: "80%", + testEnvironment: "jsdom", + collectCoverage: true, + collectCoverageFrom: [ + "src/**/*.{ts,tsx,js,jsx}", + "!src/test/**" + ], + testPathIgnorePatterns: [ + "/node_modules/", + ], + clearMocks: true, + coverageReporters: [ + "lcov", + "text-summary" + ], + moduleNameMapper: { + "^.+\\.(scss|css)$": "/src/test/style_mock.json", + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js", + "\\.(scss|css)$": "/__mocks__/styleMock.js", + "^bundle-loader\\?lazy\\!(.*)$": "$1", + "^src(.*)$": "/src$1", + "^i18n(.*)$": "/i18n$1", + "^static(.*)$": "/static$1", + "^moment(.*)$": "/../node_modules/moment$1", + }, + moduleDirectories: [ + "src", + "node_modules", + ], + reporters: [ + "default", + "jest-junit" + ], + setupFiles: [ + "jest-canvas-mock" + ], + setupFilesAfterEnv: [ + "/src/test/setup.tsx" + ], + testTimeout: 60000, + testEnvironmentOptions: { + url: "http://localhost:8065" + } +}; + +module.exports = config; diff --git a/webapp/boards/junit.xml b/webapp/boards/junit.xml deleted file mode 100644 index e37cd880a6..0000000000 --- a/webapp/boards/junit.xml +++ /dev/null @@ -1,6650 +0,0 @@ - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/blocksEditor/editor should match snapshot on empty 1` - -- Snapshot - 4 -+ Received + 4 - -@@ -14,23 +14,23 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-4bb158-control" -+ class=" css-1haocjs-control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-2-placeholder" - > - Introduce your text or your slash command - </div> - <div -- class=" css-g5309v-Input" -+ class=" css-26cneq-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-2-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/blocksEditor/editor.test.tsx:80:27) - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard should match snapshot 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-2-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-2-placeholder" -@@ -219,15 +219,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:230:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard should match snapshot with sharing 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-3-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-3-placeholder" -@@ -219,15 +219,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:262:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Copy link 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-4-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-4-placeholder" -@@ -219,15 +219,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:288:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Copy link 2` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-4-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-4-placeholder" -@@ -219,15 +219,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:298:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Regenerate token 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-5-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-5-placeholder" -@@ -228,15 +228,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/team/team-id/shared/1/1?r=anotherToken" -+ href="http://localhost:8065/team/team-id/shared/1/1?r=anotherToken" - rel="noreferrer" - target="_blank" - > -- http://localhost/team/team-id/shared/1/1?r=anotherToken -+ http://localhost:8065/team/team-id/shared/1/1?r=anotherToken - </a> - <div - class="octo-tooltip tooltip-top" - data-tooltip="Regenerate token" - > - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:349:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard, and click switch 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-6-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-6-placeholder" -@@ -228,15 +228,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/team/team-id/shared/1/1?r=oneToken" -+ href="http://localhost:8065/team/team-id/shared/1/1?r=oneToken" - rel="noreferrer" - target="_blank" - > -- http://localhost/team/team-id/shared/1/1?r=oneToken -+ http://localhost:8065/team/team-id/shared/1/1?r=oneToken - </a> - <div - class="octo-tooltip tooltip-top" - data-tooltip="Regenerate token" - > - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:389:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoardComponent and click Switch without sharing 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-7-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-7-placeholder" -@@ -228,15 +228,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/team/team-id/shared/1/1?r=aToken" -+ href="http://localhost:8065/team/team-id/shared/1/1?r=aToken" - rel="noreferrer" - target="_blank" - > -- http://localhost/team/team-id/shared/1/1?r=aToken -+ http://localhost:8065/team/team-id/shared/1/1?r=aToken - </a> - <div - class="octo-tooltip tooltip-top" - data-tooltip="Regenerate token" - > - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:441:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard should match snapshot with sharing and subpath 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-8-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-8-placeholder" -@@ -219,15 +219,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:464:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Select 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-9-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-9-placeholder" -@@ -205,15 +205,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:507:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Select 2` - -- Snapshot - 18 -+ Received + 18 - -@@ -62,27 +62,27 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username_1 focused, 0 of 2. 8 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username_1 focused, 1 of 8. 8 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-9-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-9-listbox" -@@ -107,29 +107,29 @@ - <div - class=" css-1hb7zxy-IndicatorsContainer" - /> - </div> - <div -- class=" css-1rsmi4x-menu" -+ class=" css-45h7mv-menu" - id="react-select-9-listbox" - > - <div -- class=" css-g29tl0-MenuList" -+ class=" css-1d1qzc4-MenuList" - > - <div - class=" css-syji7d-Group" - > - <div -- class=" css-18ng2q5-group" -+ class=" css-jtaw72-group" - id="react-select-9-group-0-heading" - > - Members - </div> - <div> - <div - aria-disabled="false" -- class=" css-erqggd-option" -+ class=" css-8e5kjb-option" - id="react-select-9-option-0-0" - tabindex="-1" - > - <div - class="user-item" -@@ -151,11 +151,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-0-1" - tabindex="-1" - > - <div - class="user-item" -@@ -177,11 +177,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-0-2" - tabindex="-1" - > - <div - class="user-item" -@@ -203,11 +203,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-0-3" - tabindex="-1" - > - <div - class="user-item" -@@ -233,19 +233,19 @@ - </div> - <div - class=" css-syji7d-Group" - > - <div -- class=" css-18ng2q5-group" -+ class=" css-jtaw72-group" - id="react-select-9-group-1-heading" - > - Channels - </div> - <div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-1-0" - tabindex="-1" - > - <div - class="user-item" -@@ -262,11 +262,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-1-1" - tabindex="-1" - > - <div - class="user-item" -@@ -283,11 +283,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-1-2" - tabindex="-1" - > - <div - class="user-item" -@@ -304,11 +304,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-9-option-1-3" - tabindex="-1" - > - <div - class="user-item" -@@ -437,15 +437,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:515:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Select, non-plugin mode 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-10-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-10-placeholder" -@@ -205,15 +205,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:556:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard and click Select, non-plugin mode 2` - -- Snapshot - 18 -+ Received + 18 - -@@ -62,27 +62,27 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username_1 focused, 0 of 2. 8 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username_1 focused, 1 of 8. 8 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-10-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-10-listbox" -@@ -107,29 +107,29 @@ - <div - class=" css-1hb7zxy-IndicatorsContainer" - /> - </div> - <div -- class=" css-1rsmi4x-menu" -+ class=" css-45h7mv-menu" - id="react-select-10-listbox" - > - <div -- class=" css-g29tl0-MenuList" -+ class=" css-1d1qzc4-MenuList" - > - <div - class=" css-syji7d-Group" - > - <div -- class=" css-18ng2q5-group" -+ class=" css-jtaw72-group" - id="react-select-10-group-0-heading" - > - Members - </div> - <div> - <div - aria-disabled="false" -- class=" css-erqggd-option" -+ class=" css-8e5kjb-option" - id="react-select-10-option-0-0" - tabindex="-1" - > - <div - class="user-item" -@@ -160,11 +160,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-0-1" - tabindex="-1" - > - <div - class="user-item" -@@ -195,11 +195,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-0-2" - tabindex="-1" - > - <div - class="user-item" -@@ -221,11 +221,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-0-3" - tabindex="-1" - > - <div - class="user-item" -@@ -251,19 +251,19 @@ - </div> - <div - class=" css-syji7d-Group" - > - <div -- class=" css-18ng2q5-group" -+ class=" css-jtaw72-group" - id="react-select-10-group-1-heading" - > - Channels - </div> - <div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-1-0" - tabindex="-1" - > - <div - class="user-item" -@@ -280,11 +280,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-1-1" - tabindex="-1" - > - <div - class="user-item" -@@ -301,11 +301,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-1-2" - tabindex="-1" - > - <div - class="user-item" -@@ -322,11 +322,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-10-option-1-3" - tabindex="-1" - > - <div - class="user-item" -@@ -455,15 +455,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:564:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard confirm unlinking linked channel 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-11-placeholder" - > - Search for people and channels - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-11-placeholder" -@@ -219,15 +219,15 @@ - <div - class="d-flex input-container" - > - <a - class="shareUrl" -- href="http://localhost/undefined/team/team-id/1/1" -+ href="http://localhost:8065/undefined/team/team-id/1/1" - rel="noreferrer" - target="_blank" - > -- http://localhost/undefined/team/team-id/1/1 -+ http://localhost:8065/undefined/team/team-id/1/1 - </a> - </div> - <button - title="Copy link" - type="button" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:590:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard should match snapshot, with template 1` - -- Snapshot - 3 -+ Received + 3 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-12-placeholder" - > - Search for people - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-12-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:636:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard template and click Select 1` - -- Snapshot - 3 -+ Received + 3 - -@@ -60,20 +60,20 @@ - /> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-13-placeholder" - > - Search for people - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-13-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:684:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `src/components/shareBoard/shareBoard return shareBoard template and click Select 2` - -- Snapshot - 11 -+ Received + 11 - -@@ -62,27 +62,27 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username_1 focused, 0 of 1. 4 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username_1 focused, 1 of 4. 4 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class=" css-1wmrr75-Control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-13-placeholder" - > - Search for people - </div> - <div -- class=" css-ox1y69-Input" -+ class=" css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-13-listbox" -@@ -107,29 +107,29 @@ - <div - class=" css-1hb7zxy-IndicatorsContainer" - /> - </div> - <div -- class=" css-1rsmi4x-menu" -+ class=" css-45h7mv-menu" - id="react-select-13-listbox" - > - <div -- class=" css-g29tl0-MenuList" -+ class=" css-1d1qzc4-MenuList" - > - <div - class=" css-syji7d-Group" - > - <div -- class=" css-18ng2q5-group" -+ class=" css-jtaw72-group" - id="react-select-13-group-0-heading" - > - Members - </div> - <div> - <div - aria-disabled="false" -- class=" css-erqggd-option" -+ class=" css-8e5kjb-option" - id="react-select-13-option-0-0" - tabindex="-1" - > - <div - class="user-item" -@@ -151,11 +151,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-13-option-0-1" - tabindex="-1" - > - <div - class="user-item" -@@ -177,11 +177,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-13-option-0-2" - tabindex="-1" - > - <div - class="user-item" -@@ -203,11 +203,11 @@ - </div> - </div> - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-13-option-0-3" - tabindex="-1" - > - <div - class="user-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/shareBoard/shareBoard.test.tsx:693:27) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly, show username 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -14,23 +14,23 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -52,11 +52,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -68,15 +68,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:101:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly, show firstname 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -14,23 +14,23 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - test user - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -52,11 +52,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -68,15 +68,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:135:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly, show modal 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -14,20 +14,20 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container css-433wy7-ValueContainer" -+ class="react-select__value-container css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__placeholder css-14el2xx-placeholder" -+ class="react-select__placeholder css-1jqq78o-placeholder" - id="react-select-4-placeholder" - > - Empty - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-4-placeholder" -@@ -49,15 +49,15 @@ - </div> - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:162:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly, show modal 2` - -- Snapshot - 10 -+ Received + 10 - -@@ -23,20 +23,20 @@ - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container css-433wy7-ValueContainer" -+ class="react-select__value-container css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__placeholder css-14el2xx-placeholder" -+ class="react-select__placeholder css-1jqq78o-placeholder" - id="react-select-4-placeholder" - > - Empty - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-4-listbox" -@@ -60,15 +60,15 @@ - </div> - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -82,19 +82,19 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-4-listbox" - > - <div -- class="react-select__menu-list css-g29tl0-MenuList" -+ class="react-select__menu-list css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-4-option-0" - tabindex="-1" - > - <div - class="Person-item" -@@ -102,11 +102,11 @@ - username-1 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-4-option-1" - tabindex="-1" - > - <div - class="Person-item" -@@ -114,11 +114,11 @@ - username-2 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-4-option-2" - tabindex="-1" - > - <div - class="Person-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:176:31) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person show multiple 1` - -- Snapshot - 11 -+ Received + 11 - -@@ -14,27 +14,27 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-o7cxt9-ValueContainer" -+ class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-pcwdi-ValueContainer" - > - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-1 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -48,24 +48,24 @@ - /> - </svg> - </div> - </div> - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-2 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -79,11 +79,11 @@ - /> - </svg> - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -105,11 +105,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -121,15 +121,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:242:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person show multiple, display modal 1` - -- Snapshot - 11 -+ Received + 11 - -@@ -14,27 +14,27 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-o7cxt9-ValueContainer" -+ class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-pcwdi-ValueContainer" - > - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-1 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -48,24 +48,24 @@ - /> - </svg> - </div> - </div> - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-2 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -79,11 +79,11 @@ - /> - </svg> - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -105,11 +105,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -121,15 +121,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:268:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person show multiple, display modal 2` - -- Snapshot - 15 -+ Received + 15 - -@@ -16,34 +16,34 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username-3 focused, 3 of 3. 1 result available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username-3 focused, 1 of 1. 1 result available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-o7cxt9-ValueContainer" -+ class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-pcwdi-ValueContainer" - > - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-1 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -57,24 +57,24 @@ - /> - </svg> - </div> - </div> - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-2 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -88,11 +88,11 @@ - /> - </svg> - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-6-listbox" -@@ -116,11 +116,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-13eygzs-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-3pqe01-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -132,15 +132,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -154,19 +154,19 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-6-listbox" - > - <div -- class="react-select__menu-list react-select__menu-list--is-multi css-g29tl0-MenuList" -+ class="react-select__menu-list react-select__menu-list--is-multi css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-6-option-2" - tabindex="-1" - > - <div - class="MultiPerson-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:281:31) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly, show me 1` - -- Snapshot - 11 -+ Received + 11 - -@@ -23,20 +23,20 @@ - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container css-433wy7-ValueContainer" -+ class="react-select__value-container css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__placeholder css-14el2xx-placeholder" -+ class="react-select__placeholder css-1jqq78o-placeholder" - id="react-select-7-placeholder" - > - Empty - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-7-listbox" -@@ -60,15 +60,15 @@ - </div> - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -82,19 +82,19 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-7-listbox" - > - <div -- class="react-select__menu-list css-g29tl0-MenuList" -+ class="react-select__menu-list css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-7-option-0" - tabindex="-1" - > - <div - class="Person-item" -@@ -102,11 +102,11 @@ - Me - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-7-option-1" - tabindex="-1" - > - <div - class="Person-item" -@@ -114,11 +114,11 @@ - username-1 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-7-option-2" - tabindex="-1" - > - <div - class="Person-item" -@@ -126,11 +126,11 @@ - username-2 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-7-option-3" - tabindex="-1" - > - <div - class="Person-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:327:31) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly, show me 2` - -- Snapshot - 11 -+ Received + 11 - -@@ -23,20 +23,20 @@ - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container css-433wy7-ValueContainer" -+ class="react-select__value-container css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__placeholder css-14el2xx-placeholder" -+ class="react-select__placeholder css-1jqq78o-placeholder" - id="react-select-7-placeholder" - > - Empty - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-7-listbox" -@@ -60,15 +60,15 @@ - </div> - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -82,19 +82,19 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-7-listbox" - > - <div -- class="react-select__menu-list css-g29tl0-MenuList" -+ class="react-select__menu-list css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-7-option-0" - tabindex="-1" - > - <div - class="Person-item" -@@ -102,11 +102,11 @@ - Me - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-7-option-1" - tabindex="-1" - > - <div - class="Person-item" -@@ -114,11 +114,11 @@ - username-1 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-7-option-2" - tabindex="-1" - > - <div - class="Person-item" -@@ -126,11 +126,11 @@ - username-2 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-7-option-3" - tabindex="-1" - > - <div - class="Person-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/personSelector.test.tsx:331:27) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/calculations/Options should match snapshot 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -14,14 +14,14 @@ - /> - <div - class="CalculationOptions__control css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Calculate - </div> - <input - aria-autocomplete="list" -@@ -39,11 +39,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -55,15 +55,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/calculations/options.test.tsx:34:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/calculations/Options should match snapshot menu open 1` - -- Snapshot - 9 -+ Received + 9 - -@@ -14,14 +14,14 @@ - /> - <div - class="CalculationOptions__control CalculationOptions__control--menu-is-open css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Calculate - </div> - <input - aria-autocomplete="list" -@@ -41,11 +41,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -57,40 +57,40 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - </div> - </div> - <div -- class="CalculationOptions__menu css-1rsmi4x-menu" -+ class="CalculationOptions__menu css-45h7mv-menu" - id="react-select-3-listbox" - > - <div -- class="CalculationOptions__menu-list css-g29tl0-MenuList" -+ class="CalculationOptions__menu-list css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="CalculationOptions__option css-14xsrqy-option" -+ class="CalculationOptions__option css-x3yilo-option" - id="react-select-3-option-0" - tabindex="-1" - > - Count - </div> - <div - aria-disabled="false" -- class="CalculationOptions__option css-14xsrqy-option" -+ class="CalculationOptions__option css-x3yilo-option" - id="react-select-3-option-1" - tabindex="-1" - > - Max - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/calculations/options.test.tsx:64:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/blocksEditor/blocksEditor should match snapshot on empty 1` - -- Snapshot - 4 -+ Received + 4 - -@@ -17,23 +17,23 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-4bb158-control" -+ class=" css-1haocjs-control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-2-placeholder" - > - Introduce your text or your slash command - </div> - <div -- class=" css-g5309v-Input" -+ class=" css-26cneq-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-2-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/blocksEditor/blocksEditor.test.tsx:74:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/blocksEditor/blocksEditor should match snapshot with blocks 1` - -- Snapshot - 4 -+ Received + 4 - -@@ -331,23 +331,23 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-4bb158-control" -+ class=" css-1haocjs-control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-3-placeholder" - > - Introduce your text or your slash command - </div> - <div -- class=" css-g5309v-Input" -+ class=" css-26cneq-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-3-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/blocksEditor/blocksEditor.test.tsx:93:27) - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/blocksEditor/rootInput should match Display snapshot 1` - -- Snapshot - 3 -+ Received + 3 - -@@ -11,17 +11,17 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-4bb158-control" -+ class=" css-1haocjs-control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-nkozic-Input" -+ class=" css-1qgh1u0-Input" - data-value="test-value" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-2-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/blocksEditor/rootInput.test.tsx:19:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/blocksEditor/rootInput should match Input snapshot 1` - -- Snapshot - 3 -+ Received + 3 - -@@ -11,17 +11,17 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-4bb158-control" -+ class=" css-1haocjs-control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-nkozic-Input" -+ class=" css-1qgh1u0-Input" - data-value="test-value" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-3-placeholder" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/blocksEditor/rootInput.test.tsx:31:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/blocksEditor/rootInput should match Input snapshot with menu open 1` - -- Snapshot - 18 -+ Received + 18 - -@@ -11,23 +11,23 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-4bb158-control" -+ class=" css-1haocjs-control" - > - <div -- class=" css-30zlo3-ValueContainer" -+ class=" css-b2z5qd-ValueContainer" - > - <div -- class=" css-14el2xx-placeholder" -+ class=" css-1jqq78o-placeholder" - id="react-select-4-placeholder" - > - Introduce your text or your slash command - </div> - <div -- class=" css-g5309v-Input" -+ class=" css-26cneq-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-4-listbox" -@@ -52,102 +52,102 @@ - <div - class=" css-1hb7zxy-IndicatorsContainer" - /> - </div> - <div -- class=" css-1aj7brc" -+ class=" css-u0i6pk-MenuPortal" - > - <div -- class=" css-1rsmi4x-menu" -+ class=" css-45h7mv-menu" - id="react-select-4-listbox" - > - <div -- class=" css-g29tl0-MenuList" -+ class=" css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class=" css-erqggd-option" -+ class=" css-8e5kjb-option" - id="react-select-4-option-0" - tabindex="-1" - > - /title Creates a new Title block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-1" - tabindex="-1" - > - /subtitle Creates a new Sub title block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-2" - tabindex="-1" - > - /subsubtitle Creates a new Sub Sub title block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-3" - tabindex="-1" - > - /image Creates a new Image block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-4" - tabindex="-1" - > - /text Creates a new Text block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-5" - tabindex="-1" - > - /divider Creates a new Divider block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-6" - tabindex="-1" - > - /list-item Creates a new List item block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-7" - tabindex="-1" - > - /attachment Creates a new Attachment block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-8" - tabindex="-1" - > - /quote Creates a new Quote block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-9" - tabindex="-1" - > - /video Creates a new Video block. - </div> - <div - aria-disabled="false" -- class=" css-14xsrqy-option" -+ class=" css-x3yilo-option" - id="react-select-4-option-10" - tabindex="-1" - > - /checkbox Creates a new Checkbox block. - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/blocksEditor/rootInput.test.tsx:45:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/kanban/calculations/KanbanCalculationOptions base case 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -14,14 +14,14 @@ - /> - <div - class="CalculationOptions__control css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Count - </div> - <input - aria-autocomplete="list" -@@ -39,11 +39,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -55,15 +55,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/kanban/calculation/calculationOptions.test.tsx:29:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/kanban/calculations/KanbanCalculationOptions with menu open 1` - -- Snapshot - 7 -+ Received + 7 - -@@ -14,14 +14,14 @@ - /> - <div - class="CalculationOptions__control CalculationOptions__control--menu-is-open css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Count - </div> - <input - aria-autocomplete="list" -@@ -41,11 +41,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -57,28 +57,28 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - </div> - </div> - <div -- class="CalculationOptions__menu css-1rsmi4x-menu" -+ class="CalculationOptions__menu css-45h7mv-menu" - id="react-select-3-listbox" - > - <div -- class="CalculationOptions__menu-list css-g29tl0-MenuList" -+ class="CalculationOptions__menu-list css-1d1qzc4-MenuList" - > - <div - class="KanbanCalculationOptions_CustomOption active" - > - <span> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/kanban/calculation/calculationOptions.test.tsx:44:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/kanban/calculations/KanbanCalculationOptions with submenu open 1` - -- Snapshot - 7 -+ Received + 7 - -@@ -14,14 +14,14 @@ - /> - <div - class="CalculationOptions__control CalculationOptions__control--menu-is-open css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Count - </div> - <input - aria-autocomplete="list" -@@ -41,11 +41,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -57,28 +57,28 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - </div> - </div> - <div -- class="CalculationOptions__menu css-1rsmi4x-menu" -+ class="CalculationOptions__menu css-45h7mv-menu" - id="react-select-4-listbox" - > - <div -- class="CalculationOptions__menu-list css-g29tl0-MenuList" -+ class="CalculationOptions__menu-list css-1d1qzc4-MenuList" - > - <div - class="KanbanCalculationOptions_CustomOption active" - > - <span> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/kanban/calculation/calculationOptions.test.tsx:62:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/rhsChannelBoardItem render board 1` - -- Snapshot - 1 -+ Received + 1 - -@@ -30,9 +30,9 @@ - class="description" - /> - <div - class="date" - > -- Last update at: July 08, 2022, 8:10 PM -+ Last update at: July 08, 2022, 3:10 PM - </div> - </div> - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/rhsChannelBoardItem.test.tsx:43:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/rhsChannelBoardItem render board with menu open 1` - -- Snapshot - 1 -+ Received + 1 - -@@ -122,9 +122,9 @@ - </p> - </div> - <div - class="date" - > -- Last update at: July 08, 2022, 8:10 PM -+ Last update at: July 08, 2022, 3:10 PM - </div> - </div> - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/rhsChannelBoardItem.test.tsx:75:27) - - - - - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/calculations/Calculation should match snapshot - option change 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -20,14 +20,14 @@ - /> - <div - class="CalculationOptions__control css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Calculate - </div> - <input - aria-autocomplete="list" -@@ -45,11 +45,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -61,15 +61,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/calculations/calculation.test.tsx:175:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `/components/confirmAddUserForNotifications should match snapshot 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -75,22 +75,22 @@ - aria-live="polite" - aria-relevant="additions text" - class="css-1f43avz-a11yText-A11yText" - /> - <div -- class=" css-1s2u09g-control" -+ class=" css-13cymwt-control" - > - <div -- class=" css-319lph-ValueContainer" -+ class=" css-1fdsijx-ValueContainer" - > - <div -- class=" css-qc6sy-singleValue" -+ class=" css-1dimb5e-singleValue" - > - Editor - </div> - <div -- class=" css-6j8wv5-Input" -+ class=" css-qbdosj-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -111,15 +111,15 @@ - </div> - <div - class=" css-1hb7zxy-IndicatorsContainer" - > - <span -- class=" css-1okebmr-indicatorSeparator" -+ class=" css-1u9des2-indicatorSeparator" - /> - <div - aria-hidden="true" -- class=" css-tlfecz-indicatorContainer" -+ class=" css-1xc3v61-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/confirmAddUserForNotifications.test.tsx:28:34) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/boardsUnfurl/BoardsUnfurl renders normally 1` - -- Snapshot - 1 -+ Received + 1 - -@@ -46,11 +46,11 @@ - class="properties" - /> - <span - class="post-preview__time" - > -- Updated January 01, 1970, 12:00 AM -+ Updated December 31, 1969, 6:00 PM - </span> - </div> - </div> - </a> - </div> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/boardsUnfurl/boardsUnfurl.test.tsx:77:27) - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/kanban/calculation/KanbanCalculation calculations menu open 1` - -- Snapshot - 7 -+ Received + 7 - -@@ -26,14 +26,14 @@ - /> - <div - class="CalculationOptions__control CalculationOptions__control--menu-is-open css-1s59geg-Control" - > - <div -- class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1mxrbau-ValueContainer" -+ class="CalculationOptions__value-container CalculationOptions__value-container--has-value css-1kliayw-ValueContainer" - > - <div -- class="CalculationOptions__single-value css-1qlwihv-singleValue" -+ class="CalculationOptions__single-value css-3hkq9s-singleValue" - > - Count - </div> - <input - aria-autocomplete="list" -@@ -53,11 +53,11 @@ - <div - class="CalculationOptions__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__clear-indicator css-tpaeio-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -69,28 +69,28 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="CalculationOptions__indicator-separator css-43ykx9-indicatorSeparator" -+ class="CalculationOptions__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-wpsttr-indicatorContainer" -+ class="CalculationOptions__indicator CalculationOptions__dropdown-indicator css-y45573-indicatorContainer" - > - <i - class="CompassIcon icon-chevron-up ChevronUpIcon" - /> - </div> - </div> - </div> - <div -- class="CalculationOptions__menu css-1rsmi4x-menu" -+ class="CalculationOptions__menu css-45h7mv-menu" - id="react-select-2-listbox" - > - <div -- class="CalculationOptions__menu-list css-g29tl0-MenuList" -+ class="CalculationOptions__menu-list css-1d1qzc4-MenuList" - > - <div - class="KanbanCalculationOptions_CustomOption active" - > - <span> - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/kanban/calculation/calculation.test.tsx:56:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/sidebar/RegistrationLink renders with signupToken in URL query param 1` - -- Snapshot - 2 -+ Received + 2 - -@@ -27,15 +27,15 @@ - <div - class="row" - > - <a - class="shareUrl" -- href="http://localhost/register?t=abc123" -+ href="http://localhost:8065/register?t=abc123" - rel="noreferrer" - target="_blank" - > -- http://localhost/register?t=abc123 -+ http://localhost:8065/register?t=abc123 - </a> - <button - class="Button filled size--small" - type="button" - > - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/sidebar/registrationLink.test.tsx:37:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - - - Error: expect(jest.fn()).toHaveBeenCalledWith(...expected) - -Expected: "http://localhost/api/v2/files/teams/0/board-id/file-id/info", ObjectContaining {"headers": {"Accept": "application/json", "Authorization": "", "Content-Type": "application/json", "X-Requested-With": "XMLHttpRequest"}} -Received: "http://localhost:8065/api/v2/files/teams/0/board-id/file-id/info", {"headers": {"Accept": "application/json", "Authorization": "", "Content-Type": "application/json", "X-Requested-With": "XMLHttpRequest"}} - -Number of calls: 1 - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/octoClient.test.ts:91:26) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/multiperson not readonly not existing user 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -14,20 +14,20 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--is-multi css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--is-multi css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__placeholder css-14el2xx-placeholder" -+ class="react-select__placeholder css-1jqq78o-placeholder" - id="react-select-2-placeholder" - > - Empty - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-2-placeholder" -@@ -49,15 +49,15 @@ - </div> - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/multiperson/multiperson.test.tsx:93:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/multiperson not readonly 1` - -- Snapshot - 11 -+ Received + 11 - -@@ -14,27 +14,27 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-o7cxt9-ValueContainer" -+ class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-pcwdi-ValueContainer" - > - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-1 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -48,24 +48,24 @@ - /> - </svg> - </div> - </div> - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-2 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -79,11 +79,11 @@ - /> - </svg> - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -105,11 +105,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -121,15 +121,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/multiperson/multiperson.test.tsx:124:27) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/multiperson user dropdown open 1` - -- Snapshot - 15 -+ Received + 15 - -@@ -16,34 +16,34 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username-3 focused, 3 of 3. 1 result available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username-3 focused, 1 of 1. 1 result available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-o7cxt9-ValueContainer" -+ class="react-select__value-container react-select__value-container--is-multi react-select__value-container--has-value css-pcwdi-ValueContainer" - > - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-1 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -57,24 +57,24 @@ - /> - </svg> - </div> - </div> - <div -- class="css-1rhbuit-multiValue react-select__multi-value" -+ class="react-select__multi-value css-1p3m7a8-multiValue" - > - <div -- class="css-12jo7m5 react-select__multi-value__label" -+ class="react-select__multi-value__label css-wsp0cs-MultiValueGeneric" - > - <div - class="MultiPerson-item" - > - username-2 - </div> - </div> - <div - aria-label="Remove [object Object]" -- class="css-xb97g8 react-select__multi-value__remove" -+ class="react-select__multi-value__remove css-12a83d4-MultiValueRemove" - role="button" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" -@@ -88,11 +88,11 @@ - /> - </svg> - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-4-listbox" -@@ -116,11 +116,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-13eygzs-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-3pqe01-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -132,15 +132,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -154,19 +154,19 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-4-listbox" - > - <div -- class="react-select__menu-list react-select__menu-list--is-multi css-g29tl0-MenuList" -+ class="react-select__menu-list react-select__menu-list--is-multi css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-4-option-2" - tabindex="-1" - > - <div - class="MultiPerson-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/multiperson/multiperson.test.tsx:196:31) - - - - - - - - - - - - - - - - - - - - - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person select user - confirm 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -14,23 +14,23 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -52,11 +52,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -68,15 +68,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/confirmPerson.test.tsx:158:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person select user - confirm 2` - -- Snapshot - 12 -+ Received + 12 - -@@ -16,30 +16,30 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username-4 focused, 0 of 2. 2 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username-4 focused, 1 of 2. 2 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-2-listbox" -@@ -63,11 +63,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-13eygzs-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-3pqe01-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -79,15 +79,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -101,29 +101,29 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-2-listbox" - > - <div -- class="react-select__menu-list css-g29tl0-MenuList" -+ class="react-select__menu-list css-1d1qzc4-MenuList" - > - <div - class="react-select__group css-syji7d-Group" - > - <div -- class="react-select__group-heading css-18ng2q5-group" -+ class="react-select__group-heading css-jtaw72-group" - id="react-select-2-group-1-heading" - > - Not board members - </div> - <div> - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-2-option-1-0" - tabindex="-1" - > - <div - class="Person-item" -@@ -131,11 +131,11 @@ - username-4 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-2-option-1-1" - tabindex="-1" - > - <div - class="Person-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/confirmPerson.test.tsx:169:31) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person select user - cancel 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -14,23 +14,23 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -52,11 +52,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -68,15 +68,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/confirmPerson.test.tsx:212:27) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person select user - cancel 2` - -- Snapshot - 12 -+ Received + 12 - -@@ -16,30 +16,30 @@ - id="aria-selection" - /> - <span - id="aria-context" - > -- option username-4 focused, 0 of 2. 2 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. -+ option username-4 focused, 1 of 2. 2 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. - </span> - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-4-listbox" -@@ -63,11 +63,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-13eygzs-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-3pqe01-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -79,15 +79,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -101,29 +101,29 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-4-listbox" - > - <div -- class="react-select__menu-list css-g29tl0-MenuList" -+ class="react-select__menu-list css-1d1qzc4-MenuList" - > - <div - class="react-select__group css-syji7d-Group" - > - <div -- class="react-select__group-heading css-18ng2q5-group" -+ class="react-select__group-heading css-jtaw72-group" - id="react-select-4-group-1-heading" - > - Not board members - </div> - <div> - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused css-1bwtvog-option" -+ class="react-select__option react-select__option--is-focused css-63bi6m-option" - id="react-select-4-option-1-0" - tabindex="-1" - > - <div - class="Person-item" -@@ -131,11 +131,11 @@ - username-4 - </div> - </div> - <div - aria-disabled="false" -- class="react-select__option css-nyiims-option" -+ class="react-select__option css-1uk8033-option" - id="react-select-4-option-1-1" - tabindex="-1" - > - <div - class="Person-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/confirmPerson.test.tsx:223:31) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readOnly not existing user 1` - -- Snapshot - 5 -+ Received + 5 - -@@ -14,20 +14,20 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container css-433wy7-ValueContainer" -+ class="react-select__value-container css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__placeholder css-14el2xx-placeholder" -+ class="react-select__placeholder css-1jqq78o-placeholder" - id="react-select-2-placeholder" - > - Empty - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-describedby="react-select-2-placeholder" -@@ -49,15 +49,15 @@ - </div> - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/person.test.tsx:68:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readonly 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -14,23 +14,23 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -52,11 +52,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -68,15 +68,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/person.test.tsx:94:27) - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person not readonly guest user 1` - -- Snapshot - 6 -+ Received + 6 - -@@ -14,14 +14,14 @@ - /> - <div - class="react-select__control css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 -@@ -35,11 +35,11 @@ - </div> - </div> - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-expanded="false" -@@ -61,11 +61,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-tpaeio-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-31haax-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -77,15 +77,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-19sxey8-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-uycnsi-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/person.test.tsx:120:27) - - - - - Error: expect(received).toMatchSnapshot() - -Snapshot name: `properties/person user dropdown open 1` - -- Snapshot - 9 -+ Received + 9 - -@@ -23,23 +23,23 @@ - </span> - <div - class="react-select__control react-select__control--is-focused react-select__control--menu-is-open css-18140j1-Control" - > - <div -- class="react-select__value-container react-select__value-container--has-value css-433wy7-ValueContainer" -+ class="react-select__value-container react-select__value-container--has-value css-1gbdvdc-ValueContainer" - > - <div -- class="react-select__single-value css-1lixa2z-singleValue" -+ class="react-select__single-value css-qosd1h-singleValue" - > - <div - class="Person-item" - > - username-1 - </div> - </div> - <div -- class="react-select__input-container css-ox1y69-Input" -+ class="react-select__input-container css-1p5v8kp-Input" - data-value="" - > - <input - aria-autocomplete="list" - aria-controls="react-select-5-listbox" -@@ -63,11 +63,11 @@ - <div - class="react-select__indicators css-1hb7zxy-IndicatorsContainer" - > - <div - aria-hidden="true" -- class="react-select__indicator react-select__clear-indicator css-13eygzs-indicatorContainer" -+ class="react-select__indicator react-select__clear-indicator css-3pqe01-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -79,15 +79,15 @@ - d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" - /> - </svg> - </div> - <span -- class="react-select__indicator-separator css-43ykx9-indicatorSeparator" -+ class="react-select__indicator-separator css-1uei4ir-indicatorSeparator" - /> - <div - aria-hidden="true" -- class="react-select__indicator react-select__dropdown-indicator css-hl9mox-indicatorContainer" -+ class="react-select__indicator react-select__dropdown-indicator css-zngtjc-indicatorContainer" - > - <svg - aria-hidden="true" - class="css-tj5bde-Svg" - focusable="false" -@@ -101,19 +101,19 @@ - </svg> - </div> - </div> - </div> - <div -- class="react-select__menu css-10b6da7-menu" -+ class="react-select__menu css-1slvcut-menu" - id="react-select-5-listbox" - > - <div -- class="react-select__menu-list css-g29tl0-MenuList" -+ class="react-select__menu-list css-1d1qzc4-MenuList" - > - <div - aria-disabled="false" -- class="react-select__option react-select__option--is-focused react-select__option--is-selected css-10e3bcm-option" -+ class="react-select__option react-select__option--is-focused react-select__option--is-selected css-ad52of-option" - id="react-select-5-option-0" - tabindex="-1" - > - <div - class="Person-item" - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/person/person.test.tsx:182:31) - - - - - - - - - - - - - - - Error: expect(jest.fn()).toHaveBeenCalledWith(...expected) - -Expected: "bteh8esc37dkxd9e7zcfks6a9no", {"boardId": "", "createAt": 1678455445052, "createdBy": "", "deleteAt": 0, "fields": {"contentOrder": [], "icon": "", "isTemplate": false, "properties": {}}, "id": "76bqwy4ppnp7nwhdpjkco9ou3ta", "limited": false, "modifiedBy": "", "parentId": "", "schema": 1, "title": "", "type": "card", "updateAt": 1678455445052}, "select-template", "option-3" - -Number of calls: 0 - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/select/select.test.tsx:199:51) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:101:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: 15. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:103:21) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:127:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: 15. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:132:23) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:167:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: Clear. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:169:23) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLButtonElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLButtonElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLButtonElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:196:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the display value: June 15. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByDisplayValue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:198:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLButtonElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLButtonElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLButtonElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:235:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the display value: 15 de junio. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByDisplayValue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:237:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLButtonElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLButtonElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLButtonElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:272:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the display value: June 15. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByDisplayValue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:274:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:309:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: Today. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/properties/date/date.test.tsx:311:21) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:133:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: 15. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:135:21) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - Error: expect(received).toMatchSnapshot() - -Snapshot name: `components/viewHeader/dateFilter handles calendar click event 1` - -- Snapshot - 2 -+ Received + 0 - -@@ -1,14 +1,12 @@ - <IntlProvider - defaultFormats={Object {}} - defaultLocale="en" -- fallbackOnEmptyString={true} - formats={Object {}} - locale="en" - messages={Object {}} - onError={[Function]} -- onWarn={[Function]} - textComponent={Symbol(react.fragment)} - > - <DateFilter - filter={ - Object { - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:129:27) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:167:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: Clear. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:169:23) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:197:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the placeholder text of: MM/DD/YYYY - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByPlaceholderText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:199:23) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLSpanElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLSpanElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLSpanElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:235:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an element with the text: Today. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByText (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/dateFilter.test.tsx:237:21) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TypeError: Cannot read properties of undefined (reading 'localeData') - at Object.getFirstDayOfWeek (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/addons/MomentLocaleUtils.js:48:27) - at Object.getFirstDayOfWeekFromProps (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/Helpers.js:72:24) - at DayPicker.renderMonths (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:448:36) - at DayPicker.render (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-day-picker/build/DayPicker.js:531:18) - at finishClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17160:31) - at updateClassComponent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:17110:24) - at beginWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:18620:16) - at HTMLUnknownElement.callCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:188:14) - at HTMLUnknownElement.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLUnknownElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLUnknownElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLUnknownElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at Object.invokeGuardedCallbackDev (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:237:16) - at invokeGuardedCallback (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:292:31) - at beginWork$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:23203:7) - at performUnitOfWork (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22157:12) - at workLoopSync (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:22130:22) - at performSyncWorkOnRoot (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21756:9) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11089:24 - at unstable_runWithPriority (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/scheduler/cjs/scheduler.development.js:653:12) - at runWithPriority$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11039:10) - at flushSyncCallbackQueueImpl (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11084:7) - at flushSyncCallbackQueue (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:11072:3) - at discreteUpdates$1 (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:21893:7) - at discreteUpdates (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:806:12) - at dispatchDiscreteEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/react-dom/cjs/react-dom.development.js:4168:3) - at Document.callTheUserObjectsOperation (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventListener.js:26:30) - at innerInvokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:338:25) - at invokeEventListeners (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:274:3) - at HTMLButtonElementImpl._dispatch (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:221:9) - at HTMLButtonElementImpl.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:94:17) - at HTMLButtonElement.dispatchEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:231:34) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:25:20 - at Object.eventWrapper (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/config.js:27:23) - at fireEvent (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:16:35) - at Function.fireEvent.<computed> [as click] (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/dom/dist/events.js:125:36) - at fireClick (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:150:20) - at clickElement (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:91:5) - at Object.click (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/user-event/dist/click.js:140:5) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/filterValue.test.tsx:165:19) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "Clear" - -There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the `hidden` option to `true`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole - -<body> - <div /> -</body> - at Object.getElementError (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/config.js:37:19) - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:90:38 - at /Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:62:17 - at getByRole (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/@testing-library/react/node_modules/@testing-library/dom/dist/query-helpers.js:111:19) - at Object.<anonymous> (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/src/components/viewHeader/filterValue.test.tsx:168:36) - at Promise.then.completed (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:391:28) - at new Promise (<anonymous>) - at callAsyncCircusFn (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/utils.js:316:10) - at _callCircusTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:218:40) - at _runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:155:3) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:66:9) - at _runTestsForDescribeBlock (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:60:9) - at run (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/run.js:25:3) - at runAndTransformResultsToJestFormat (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:170:21) - at jestAdapter (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:82:19) - at runTestInternal (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:389:16) - at runTest (/Users/calebroseland/Sources/github-mattermost/focalboard/webapp/node_modules/jest-runner/build/runTest.js:475:34) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/webapp/boards/package.json b/webapp/boards/package.json index a66ffcfc34..318e177a43 100644 --- a/webapp/boards/package.json +++ b/webapp/boards/package.json @@ -1,6 +1,6 @@ { "name": "boards", - "version": "7.10.0", + "version": "7.9.1", "private": true, "description": "", "scripts": { @@ -19,10 +19,11 @@ "check-types:fix": "npm run check-types -- --noEmit --fix", "check": "npm run check-lint && npm run check-style", "fix": "npm run check-lint:fix && npm run check-style:fix", - "test": "jest --forceExit --detectOpenHandles --verbose", - "test:watch": "jest --watch", - "test:updatesnapshot": "jest --updateSnapshot", - "test-ci": "jest --ci --forceExit --detectOpenHandles --maxWorkers=100%", + "test": "cross-env TZ=Etc/UTC jest", + "test:watch": "cross-env TZ=Etc/UTC jest --watch", + "test:updatesnapshot": "cross-env TZ=Etc/UTC jest --updateSnapshot", + "test:debug": "cross-env TZ=Etc/UTC jest --forceExit --detectOpenHandles --verbose ", + "test-ci": "cross-env TZ=Etc/UTC jest --ci --maxWorkers=100%", "clean": "rm -rf node_modules .eslintcache" }, "dependencies": { @@ -44,78 +45,25 @@ "fullcalendar": "^5.10.2", "glob-parent": "6.0.2", "lodash": "^4.17.21", - "marked": "^4.0.12", - "mattermost-redux": "5.33.1", - "mini-create-react-context": "^0.4.1", + "marked": "4.0.17", "moment": "^2.29.1", "nanoevents": "^5.1.13", - "react": "^16.13.0", + "react": "17.0.2", "react-beautiful-dnd": "^13.1.1", - "react-day-picker": "^7.4.10", + "react-day-picker": "7.4.10", "react-dnd": "^14.0.2", "react-dnd-html5-backend": "^14.0.0", "react-dnd-scrolling": "^1.2.1", "react-dnd-touch-backend": "^14.0.0", - "react-dom": "^16.13.0", + "react-dom": "17.0.2", "react-hot-keys": "^2.7.1", "react-hotkeys-hook": "^3.4.4", "react-intl": "^5.20.0", "react-redux": "^7.2.1", "react-router-dom": "^5.2.0", - "react-select": "5.7.0", + "react-select": "5.5.9", "trim-newlines": "^4.0.2" }, - "jest": { - "transform": { - "^.+\\.(js|tsx|ts|tsx)$": "@swc/jest" - }, - "transformIgnorePatterns": [ - "/nanoevents/", - "node_modules/(?!react-native|react-router|mattermost-webapp|react-day-picker)" - ], - "maxWorkers": "50%", - "testEnvironment": "jsdom", - "collectCoverage": true, - "collectCoverageFrom": [ - "src/**/*.{ts,tsx,js,jsx}", - "!src/test/**" - ], - "moduleFileExtensions": ["js", "jsx", "ts", "tsx"], - "testPathIgnorePatterns": [ - "/node_modules/", - "/non_npm_dependencies/" - ], - "clearMocks": true, - "coverageReporters": [ - "lcov", - "text-summary" - ], - "moduleNameMapper": { - "^.+\\.(scss|css)$": "/src/test/style_mock.json", - "^.*i18n.*\\.(json)$": "/src/test/i18n_mock.json", - "^bundle-loader\\?lazy\\!(.*)$": "$1", - "^react$": "/node_modules/react", - "^react-redux$": "/node_modules/react-redux", - "^react-intl$": "/node_modules/react-intl", - "^src(.*)$": "/src$1" - }, - "moduleDirectories": [ - "src", - "node_modules", - "non_npm_dependencies" - ], - "reporters": [ - "default", - "jest-junit" - ], - "setupFiles": [ - "jest-canvas-mock" - ], - "setupFilesAfterEnv": [ - "/src/test/setup.tsx" - ], - "testURL": "http://localhost:8065" - }, "devDependencies": { "@babel/cli": "7.17.6", "@babel/core": "7.17.8", @@ -130,33 +78,34 @@ "@babel/runtime": "7.17.8", "@formatjs/cli": "^4.8.2", "@formatjs/ts-transformer": "^3.9.2", - "@swc/jest": "^0.2.24", - "@testing-library/dom": "^8.11.4", - "@testing-library/jest-dom": "^5.16.3", - "@testing-library/react": "^11.2.5", - "@testing-library/user-event": "^13.5.0", + "@swc/core": "1.3.40", + "@swc/jest": "0.2.24", + "@testing-library/dom": "8.20.0", + "@testing-library/jest-dom": "5.16.5", + "@testing-library/react": "12.1.5", + "@testing-library/user-event": "14.4.3", "@types/color": "^3.0.3", "@types/draft-js": "^0.11.9", "@types/emoji-mart": "^3.0.9", "@types/enzyme": "3.10.11", - "@types/jest": "27.4.1", + "@types/jest": "29.4.2", "@types/lodash": "4.14.182", "@types/marked": "^4.0.3", "@types/nanoevents": "^1.0.0", - "@types/node": "17.0.23", - "@types/react": "^17.0.43", + "@types/node": "16.11.7", + "@types/react": "17.0.53", "@types/react-beautiful-dnd": "^13.1.2", - "@types/react-dom": "^17.0.14", + "@types/react-day-picker": "5.3.0", + "@types/react-dom": "17.0.19", "@types/react-redux": "^7.1.23", "@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", - "babel-eslint": "10.1.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", @@ -168,7 +117,7 @@ "eslint-plugin-react": "7.29.4", "eslint-plugin-react-hooks": "4.3.0", "eslint-plugin-unused-imports": "2.0.0", - "fetch-mock-jest": "^1.5.1", + "fetch-mock-jest": "1.5.1", "identity-obj-proxy": "3.0.0", "image-webpack-loader": "8.1.0", "imagemin-gifsicle": "^7.0.0", @@ -178,10 +127,12 @@ "imagemin-svgo": "^10.0.1", "imagemin-webp": "7.0.0", "isomorphic-fetch": "3.0.0", - "jest": "27.5.1", - "jest-canvas-mock": "2.3.1", - "jest-junit": "13.0.0", - "jest-mock": "27.5.1", + "jest": "29.5.0", + "jest-canvas-mock": "2.4.0", + "jest-environment-jsdom": "29.5.0", + "jest-fail-on-console": "3.0.2", + "jest-junit": "15.0.0", + "jest-mock": "29.4.3", "prettier": "^2.6.1", "redux-mock-store": "^1.5.4", "sass": "1.49.9", diff --git a/webapp/boards/src/blocks/__snapshots__/block.test.ts.snap b/webapp/boards/src/blocks/__snapshots__/block.test.ts.snap index 0250dae8d2..ed6cd80e54 100644 --- a/webapp/boards/src/blocks/__snapshots__/block.test.ts.snap +++ b/webapp/boards/src/blocks/__snapshots__/block.test.ts.snap @@ -1,46 +1,46 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`block tests correctly generate patches from two blocks should add fields on the new fields added and remove it in the undo 1`] = ` -Array [ - Object { - "deletedFields": Array [], - "updatedFields": Object { +[ + { + "deletedFields": [], + "updatedFields": { "newField": "new field", }, }, - Object { - "deletedFields": Array [ + { + "deletedFields": [ "newField", ], - "updatedFields": Object {}, + "updatedFields": {}, }, ] `; exports[`block tests correctly generate patches from two blocks should generate two empty patches for the same block 1`] = ` -Array [ - Object { - "deletedFields": Array [], - "updatedFields": Object {}, +[ + { + "deletedFields": [], + "updatedFields": {}, }, - Object { - "deletedFields": Array [], - "updatedFields": Object {}, + { + "deletedFields": [], + "updatedFields": {}, }, ] `; exports[`block tests correctly generate patches from two blocks should remove field on the new block added and add it again in the undo 1`] = ` -Array [ - Object { - "deletedFields": Array [ +[ + { + "deletedFields": [ "test", ], - "updatedFields": Object {}, + "updatedFields": {}, }, - Object { - "deletedFields": Array [], - "updatedFields": Object { + { + "deletedFields": [], + "updatedFields": { "test": "test", }, }, @@ -48,16 +48,16 @@ Array [ `; exports[`block tests correctly generate patches from two blocks should update propertie on the main object and revert it back on the undo 1`] = ` -Array [ - Object { - "deletedFields": Array [], +[ + { + "deletedFields": [], "parentId": "new-parent-id", - "updatedFields": Object {}, + "updatedFields": {}, }, - Object { - "deletedFields": Array [], + { + "deletedFields": [], "parentId": "old-parent-id", - "updatedFields": Object {}, + "updatedFields": {}, }, ] `; diff --git a/webapp/boards/src/blocks/__snapshots__/board.test.ts.snap b/webapp/boards/src/blocks/__snapshots__/board.test.ts.snap index 65c113819a..c5042946da 100644 --- a/webapp/boards/src/blocks/__snapshots__/board.test.ts.snap +++ b/webapp/boards/src/blocks/__snapshots__/board.test.ts.snap @@ -1,52 +1,52 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`board tests correctly generate patches for boards and blocks should add fields on update and remove it in the undo 1`] = ` -Array [ - Object { - "blockIDs": Array [ +[ + { + "blockIDs": [ "test-old-block-id", ], - "blockPatches": Array [ - Object { - "deletedFields": Array [], - "updatedFields": Object { + "blockPatches": [ + { + "deletedFields": [], + "updatedFields": { "newField": "new field", }, }, ], - "boardIDs": Array [ + "boardIDs": [ "test-board-id", ], - "boardPatches": Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + "boardPatches": [ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, ], }, - Object { - "blockIDs": Array [ + { + "blockIDs": [ "test-old-block-id", ], - "blockPatches": Array [ - Object { - "deletedFields": Array [ + "blockPatches": [ + { + "deletedFields": [ "newField", ], - "updatedFields": Object {}, + "updatedFields": {}, }, ], - "boardIDs": Array [ + "boardIDs": [ "test-board-id", ], - "boardPatches": Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + "boardPatches": [ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, ], }, @@ -54,48 +54,48 @@ Array [ `; exports[`board tests correctly generate patches for boards and blocks should generate two empty patches for the same board and block 1`] = ` -Array [ - Object { - "blockIDs": Array [ +[ + { + "blockIDs": [ "test-card-id", ], - "blockPatches": Array [ - Object { - "deletedFields": Array [], - "updatedFields": Object {}, + "blockPatches": [ + { + "deletedFields": [], + "updatedFields": {}, }, ], - "boardIDs": Array [ + "boardIDs": [ "test-board-id", ], - "boardPatches": Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + "boardPatches": [ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, ], }, - Object { - "blockIDs": Array [ + { + "blockIDs": [ "test-card-id", ], - "blockPatches": Array [ - Object { - "deletedFields": Array [], - "updatedFields": Object {}, + "blockPatches": [ + { + "deletedFields": [], + "updatedFields": {}, }, ], - "boardIDs": Array [ + "boardIDs": [ "test-board-id", ], - "boardPatches": Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + "boardPatches": [ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, ], }, @@ -103,16 +103,16 @@ Array [ `; exports[`board tests correctly generate patches from two boards should add card properties on the redo and remove them on the undo 1`] = ` -Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [ - Object { +[ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [ + { "id": "new-property-id", "name": "property-name", - "options": Array [ - Object { + "options": [ + { "color": "propColorYellow", "id": "opt", "value": "val", @@ -121,30 +121,30 @@ Array [ "type": "select", }, ], - "updatedProperties": Object {}, + "updatedProperties": {}, }, - Object { - "deletedCardProperties": Array [ + { + "deletedCardProperties": [ "new-property-id", ], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, ] `; exports[`board tests correctly generate patches from two boards should add card properties on the redo and undo if they exists in both, but differ 1`] = ` -Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [ - Object { +[ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [ + { "id": "new-property-id", "name": "property-name", - "options": Array [ - Object { + "options": [ + { "color": "propColorYellow", "id": "opt", "value": "val", @@ -153,17 +153,17 @@ Array [ "type": "select", }, ], - "updatedProperties": Object {}, + "updatedProperties": {}, }, - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [ - Object { + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [ + { "id": "new-property-id", "name": "a-different-name", - "options": Array [ - Object { + "options": [ + { "color": "propColorYellow", "id": "opt", "value": "val", @@ -172,22 +172,22 @@ Array [ "type": "select", }, ], - "updatedProperties": Object {}, + "updatedProperties": {}, }, ] `; exports[`board tests correctly generate patches from two boards should add card properties on the redo and undo if they exists in both, but their options are different 1`] = ` -Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [ - Object { +[ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [ + { "id": "new-property-id", "name": "property-name", - "options": Array [ - Object { + "options": [ + { "color": "propColorYellow", "id": "opt", "value": "val", @@ -196,17 +196,17 @@ Array [ "type": "select", }, ], - "updatedProperties": Object {}, + "updatedProperties": {}, }, - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [ - Object { + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [ + { "id": "new-property-id", "name": "property-name", - "options": Array [ - Object { + "options": [ + { "color": "propColorBrown", "id": "another-opt", "value": "val", @@ -215,45 +215,45 @@ Array [ "type": "select", }, ], - "updatedProperties": Object {}, + "updatedProperties": {}, }, ] `; exports[`board tests correctly generate patches from two boards should add properties on the update patch and remove them on the undo 1`] = ` -Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object { +[ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": { "prop1": "val1", }, }, - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [ + { + "deletedCardProperties": [], + "deletedProperties": [ "prop1", ], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + "updatedCardProperties": [], + "updatedProperties": {}, }, ] `; exports[`board tests correctly generate patches from two boards should generate two empty patches for the same board 1`] = ` -Array [ - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, +[ + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, - Object { - "deletedCardProperties": Array [], - "deletedProperties": Array [], - "updatedCardProperties": Array [], - "updatedProperties": Object {}, + { + "deletedCardProperties": [], + "deletedProperties": [], + "updatedCardProperties": [], + "updatedProperties": {}, }, ] `; diff --git a/webapp/boards/src/cardFilter.test.ts b/webapp/boards/src/cardFilter.test.ts index 2bb0037982..4a2f89e695 100644 --- a/webapp/boards/src/cardFilter.test.ts +++ b/webapp/boards/src/cardFilter.test.ts @@ -12,7 +12,7 @@ import {Utils} from './utils' import {IPropertyTemplate} from './blocks/board' jest.mock('./utils') -const mockedUtils = mocked(Utils, true) +const mockedUtils = mocked(Utils) const dayMillis = 24 * 60 * 60 * 1000 diff --git a/webapp/boards/src/components/__snapshots__/cardDialog.test.tsx.snap b/webapp/boards/src/components/__snapshots__/cardDialog.test.tsx.snap index defa8ebfd9..a776379da7 100644 --- a/webapp/boards/src/components/__snapshots__/cardDialog.test.tsx.snap +++ b/webapp/boards/src/components/__snapshots__/cardDialog.test.tsx.snap @@ -434,7 +434,7 @@ exports[`components/cardDialog limited card shows hidden view (no toolbar) 1`] =

- Upgrade to our Professional or Enterprise plan to view archived cards, have unlimited views per boards, unlimited cards and more. + Upgrade to our Professional or Enterprise plan.

`; diff --git a/webapp/boards/src/components/__snapshots__/rhsChannelBoardItem.test.tsx.snap b/webapp/boards/src/components/__snapshots__/rhsChannelBoardItem.test.tsx.snap index a66cf4de53..0687d6155e 100644 --- a/webapp/boards/src/components/__snapshots__/rhsChannelBoardItem.test.tsx.snap +++ b/webapp/boards/src/components/__snapshots__/rhsChannelBoardItem.test.tsx.snap @@ -110,7 +110,7 @@ exports[`components/rhsChannelBoardItem render board with menu open 1`] = `
@@ -530,7 +530,7 @@ Object { `; exports[`/components/viewMenu should match snapshot, read only 1`] = ` -Object { +{ "asFragment": [Function], "baseElement":
diff --git a/webapp/boards/src/components/__snapshots__/workspace.test.tsx.snap b/webapp/boards/src/components/__snapshots__/workspace.test.tsx.snap index 7046615718..70c70b823c 100644 --- a/webapp/boards/src/components/__snapshots__/workspace.test.tsx.snap +++ b/webapp/boards/src/components/__snapshots__/workspace.test.tsx.snap @@ -46,7 +46,7 @@ exports[`src/components/workspace return workspace and showcard 1`] = ` />
- Find Boards + Find boards
@@ -73,6 +73,7 @@ exports[`src/components/workspace return workspace and showcard 1`] = ` >
No Property 2 @@ -870,12 +873,12 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = ` >
No Property 2 @@ -898,7 +901,7 @@ exports[`src/components/workspace return workspace readonly and showcard 1`] = `
- Find Boards + Find boards
@@ -1124,6 +1127,7 @@ exports[`src/components/workspace should match snapshot 1`] = ` >
No Property 2 @@ -1921,12 +1927,12 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = ` >
No Property 2 @@ -1949,7 +1955,7 @@ exports[`src/components/workspace should match snapshot with readonly 1`] = `
( ) jest.mock('src/mutator') -const mockedMutator = mocked(mutator, true) +const mockedMutator = mocked(mutator) describe('components/addContentMenuItem', () => { beforeEach(() => { @@ -66,7 +65,7 @@ describe('components/addContentMenuItem', () => { ) expect(container).toMatchSnapshot() const buttonElement = screen.getByRole('button', {name: 'text'}) - userEvent.click(buttonElement) + await userEvent.click(buttonElement) await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled()) }) @@ -82,7 +81,7 @@ describe('components/addContentMenuItem', () => { ) expect(container).toMatchSnapshot() const buttonElement = screen.getByRole('button', {name: 'checkbox'}) - userEvent.click(buttonElement) + await userEvent.click(buttonElement) await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled()) }) @@ -98,11 +97,12 @@ describe('components/addContentMenuItem', () => { ) expect(container).toMatchSnapshot() const buttonElement = screen.getByRole('button', {name: 'divider'}) - userEvent.click(buttonElement) + await userEvent.click(buttonElement) await waitFor(() => expect(mockedMutator.insertBlock).toBeCalled()) }) test('return an error and empty element from unknown type', () => { + jest.spyOn(console, 'error').mockImplementation() const {container} = render( wrap( { />, ), ) + expect(console.error).toBeCalledWith(expect.stringContaining('addContentMenu, unknown content type: unknown')) expect(container).toMatchSnapshot() + }) }) diff --git a/webapp/boards/src/components/blockIconSelector.test.tsx b/webapp/boards/src/components/blockIconSelector.test.tsx index 8b2dcbb013..bcce99f771 100644 --- a/webapp/boards/src/components/blockIconSelector.test.tsx +++ b/webapp/boards/src/components/blockIconSelector.test.tsx @@ -2,16 +2,10 @@ // See LICENSE.txt for license information. import React from 'react' -import { - fireEvent, - render, - screen, - act -} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import userEvent from '@testing-library/user-event' -import '@testing-library/jest-dom' import {mocked} from 'jest-mock' @@ -27,7 +21,7 @@ const card = TestBlockFactory.createCard() const icon = '👍' jest.mock('src/mutator') -const mockedMutator = mocked(mutator, true) +const mockedMutator = mocked(mutator) describe('components/blockIconSelector', () => { beforeEach(() => { @@ -53,14 +47,14 @@ describe('components/blockIconSelector', () => { )) expect(container).toMatchSnapshot() }) - test('return menu on click', () => { + test('return menu on click', async () => { const {container} = render(wrapIntl( , )) - userEvent.click(screen.getByRole('button', {name: 'menuwrapper'})) + await userEvent.click(screen.getByRole('button', {name: 'menuwrapper'})) expect(container).toMatchSnapshot() }) test('return no menu in readonly', () => { @@ -73,54 +67,50 @@ describe('components/blockIconSelector', () => { expect(container).toMatchSnapshot() }) - test('return a new icon after click on random menu', () => { + test('return a new icon after click on random menu', async () => { render(wrapIntl( , )) - userEvent.click(screen.getByRole('button', {name: 'menuwrapper'})) + await userEvent.click(screen.getByRole('button', {name: 'menuwrapper'})) const buttonRandom = screen.queryByRole('button', {name: 'Random'}) expect(buttonRandom).not.toBeNull() - userEvent.click(buttonRandom!) + await userEvent.click(buttonRandom!) expect(mockedMutator.changeBlockIcon).toBeCalledTimes(1) }) - test('return a new icon after click on EmojiPicker', () => { + test('return a new icon after click on EmojiPicker', async () => { const {container, getByRole, getAllByRole} = render(wrapIntl( , )) - act(() => { - userEvent.click(getByRole('button', {name: 'menuwrapper'})) - }) + await userEvent.click(getByRole('button', {name: 'menuwrapper'})) const menuPicker = container.querySelector('div#pick') expect(menuPicker).not.toBeNull() - act(() => { - fireEvent.mouseEnter(menuPicker!) - }) + fireEvent.mouseEnter(menuPicker!) const allButtonThumbUp = getAllByRole('button', {name: /thumbsup/i}) - userEvent.click(allButtonThumbUp[0]) + await userEvent.click(allButtonThumbUp[0]) expect(mockedMutator.changeBlockIcon).toBeCalledTimes(1) expect(mockedMutator.changeBlockIcon).toBeCalledWith(card.boardId, card.id, card.fields.icon, '👍') }) - test('return no icon after click on remove menu', () => { + test('return no icon after click on remove menu', async () => { const {container, rerender} = render(wrapIntl( , )) - userEvent.click(screen.getByRole('button', {name: 'menuwrapper'})) + await userEvent.click(screen.getByRole('button', {name: 'menuwrapper'})) const buttonRemove = screen.queryByRole('button', {name: 'Remove icon'}) expect(buttonRemove).not.toBeNull() - userEvent.click(buttonRemove!) + await userEvent.click(buttonRemove!) expect(mockedMutator.changeBlockIcon).toBeCalledTimes(1) expect(mockedMutator.changeBlockIcon).toBeCalledWith(card.boardId, card.id, card.fields.icon, '', 'remove icon') diff --git a/webapp/boards/src/components/blocksEditor/__snapshots__/blocksEditor.test.tsx.snap b/webapp/boards/src/components/blocksEditor/__snapshots__/blocksEditor.test.tsx.snap index 8f2a9e4c4a..2016758dec 100644 --- a/webapp/boards/src/components/blocksEditor/__snapshots__/blocksEditor.test.tsx.snap +++ b/webapp/boards/src/components/blocksEditor/__snapshots__/blocksEditor.test.tsx.snap @@ -14,7 +14,18 @@ exports[`components/blocksEditor/blocksEditor should match snapshot on empty 1`] + > + + option , selected. + + + Select is focused ,type to refine list, press Down to open the menu, + +
+ > + + option , selected. + + + Select is focused ,type to refine list, press Down to open the menu, + +
+ > + + option , selected. + + + Select is focused ,type to refine list, press Down to open the menu, + +
+ > + + option , selected. + + + Select is focused ,type to refine list, press Down to open the menu, + +
+ > + + option , selected. + + + Select is focused ,type to refine list, press Down to open the menu, + +
+ > + + + option /title Creates a new Title block. focused, 1 of 11. 11 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. + +
{ test('should call onSave on hit enter in the input', async () => { const onSave = jest.fn() - await act(async () => { - render(wrapDNDIntl( - - - , - )) - }) + + const {user} = setup(wrapDNDIntl( + + + , + )) const input = screen.getByDisplayValue('Title') expect(onSave).not.toBeCalled() - fireEvent.change(input, {target: {value: 'test'}}) - fireEvent.keyDown(input, {key: 'Enter'}) + await act(async () => { + await user.clear(input) + await user.type(input, 'test') + await user.keyboard('{Enter}') + }) expect(onSave).toBeCalledWith(expect.objectContaining({value: 'test'})) }) diff --git a/webapp/boards/src/components/blocksEditor/blocks/attachment/attachment.test.tsx b/webapp/boards/src/components/blocksEditor/blocks/attachment/attachment.test.tsx index 40c179d43d..ed4f9ee20f 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/attachment/attachment.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/attachment/attachment.test.tsx @@ -13,7 +13,7 @@ jest.mock('src/octoClient') describe('components/blocksEditor/blocks/attachment', () => { test('should match Display snapshot', async () => { - const mockedOcto = mocked(octoClient, true) + const mockedOcto = mocked(octoClient) mockedOcto.getFileAsDataUrl.mockResolvedValue({url: 'test.jpg'}) const Component = AttachmentBlock.Display const {container} = render( diff --git a/webapp/boards/src/components/blocksEditor/blocks/image/image.test.tsx b/webapp/boards/src/components/blocksEditor/blocks/image/image.test.tsx index 92e5525dfd..ce2b1889d6 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/image/image.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/image/image.test.tsx @@ -13,7 +13,7 @@ jest.mock('src/octoClient') describe('components/blocksEditor/blocks/image', () => { test('should match Display snapshot', async () => { - const mockedOcto = mocked(octoClient, true) + const mockedOcto = mocked(octoClient) mockedOcto.getFileAsDataUrl.mockResolvedValue({url: 'test.jpg'}) const Component = ImageBlock.Display const {container} = render( diff --git a/webapp/boards/src/components/blocksEditor/blocks/video/video.test.tsx b/webapp/boards/src/components/blocksEditor/blocks/video/video.test.tsx index 3fe2fd90cc..c4f980a7bd 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/video/video.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/video/video.test.tsx @@ -13,7 +13,7 @@ jest.mock('src/octoClient') describe('components/blocksEditor/blocks/video', () => { test('should match Display snapshot', async () => { - const mockedOcto = mocked(octoClient, true) + const mockedOcto = mocked(octoClient) mockedOcto.getFileAsDataUrl.mockResolvedValue({url: 'test.jpg'}) const Component = VideoBlock.Display const {container} = render( diff --git a/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx b/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx index 125f6e0ad3..2e713f56de 100644 --- a/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx @@ -10,9 +10,15 @@ import { act } from '@testing-library/react' -import {mockDOM, wrapDNDIntl, mockStateStore} from 'src/testUtils' +import { + mockDOM, + wrapDNDIntl, + mockStateStore, + setup +} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' + import {BlockData} from './blocks/types' import BlocksEditor from './blocksEditor' @@ -95,28 +101,25 @@ describe('components/blocksEditor/blocksEditor', () => { test('should call onBlockCreate after introduce text and hit enter', async () => { const onBlockCreated = jest.fn() + const {user} = setup(wrapDNDIntl( + + + , + )) + expect(onBlockCreated).not.toBeCalled() await act(async () => { - render(wrapDNDIntl( - - - , - )) + await user.type(screen.getByRole('combobox'), '/title') + await user.keyboard('{Enter}') + await user.type(screen.getByRole('textbox'), 'test') + await user.keyboard('{Enter}') }) - let input = screen.getByDisplayValue('') - expect(onBlockCreated).not.toBeCalled() - fireEvent.change(input, {target: {value: '/title'}}) - fireEvent.keyDown(input, {key: 'Enter'}) - - input = screen.getByDisplayValue('') - fireEvent.change(input, {target: {value: 'test'}}) - fireEvent.keyDown(input, {key: 'Enter'}) expect(onBlockCreated).toBeCalledWith(expect.objectContaining({value: 'test'})) }) @@ -138,7 +141,7 @@ describe('components/blocksEditor/blocksEditor', () => { const input = screen.getByTestId('checkbox-check') expect(onBlockModified).not.toBeCalled() fireEvent.click(input) - expect(onBlockModified).toBeCalledWith(expect.objectContaining({value: {checked: false, value: 'Checkbox'}})) }) + expect(onBlockModified).toBeCalledWith(expect.objectContaining({value: {checked: false, value: 'Checkbox'}})) }) }) diff --git a/webapp/boards/src/components/blocksEditor/editor.test.tsx b/webapp/boards/src/components/blocksEditor/editor.test.tsx index 1d583064b3..239e5e466e 100644 --- a/webapp/boards/src/components/blocksEditor/editor.test.tsx +++ b/webapp/boards/src/components/blocksEditor/editor.test.tsx @@ -3,14 +3,14 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' -import { - render, - screen, - fireEvent, - act -} from '@testing-library/react' +import {render, screen, act} from '@testing-library/react' -import {mockDOM, wrapDNDIntl, mockStateStore} from 'src/testUtils' +import { + mockDOM, + wrapDNDIntl, + mockStateStore, + setup +} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' import Editor from './editor' @@ -82,25 +82,20 @@ describe('components/blocksEditor/editor', () => { test('should call onSave after introduce text and hit enter', async () => { const onSave = jest.fn() + const {user} = setup(wrapDNDIntl( + + + , + )) await act(async () => { - render(wrapDNDIntl( - - - , - )) + await user.type(screen.getByRole('combobox'), '/title') + await user.keyboard('{Enter}') + await user.type(screen.getByRole('textbox'), 'test') + await user.keyboard('{Enter}') }) - let input = screen.getByDisplayValue('') - expect(onSave).not.toBeCalled() - fireEvent.change(input, {target: {value: '/title'}}) - fireEvent.keyDown(input, {key: 'Enter'}) - expect(onSave).not.toBeCalled() - - input = screen.getByDisplayValue('') - fireEvent.change(input, {target: {value: 'test'}}) - fireEvent.keyDown(input, {key: 'Enter'}) expect(onSave).toBeCalledWith(expect.objectContaining({value: 'test'})) }) diff --git a/webapp/boards/src/components/blocksEditor/rootInput.tsx b/webapp/boards/src/components/blocksEditor/rootInput.tsx index b29dbcc713..336e44be98 100644 --- a/webapp/boards/src/components/blocksEditor/rootInput.tsx +++ b/webapp/boards/src/components/blocksEditor/rootInput.tsx @@ -1,8 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {useState} from 'react' -import Select from 'react-select' -import {CSSObject} from '@emotion/serialize' +import Select, {StylesConfig} from 'react-select' import {getSelectBaseStyle} from 'src/theme' @@ -16,11 +15,11 @@ type Props = { value: string } -const baseStyles = getSelectBaseStyle() +const baseStyles = getSelectBaseStyle() -const styles = { +const styles: StylesConfig = { ...baseStyles, - control: (provided: CSSObject): CSSObject => ({ + control: (provided) => ({ ...provided, width: '100%', height: '100%', @@ -29,12 +28,12 @@ const styles = { color: 'rgb(var(--center-channel-color-rgb))', flexDirection: 'row', }), - input: (provided: CSSObject): CSSObject => ({ + input: (provided) => ({ ...provided, background: 'rgb(var(--center-channel-bg-rgb))', color: 'rgb(var(--center-channel-color-rgb))', }), - menu: (provided: CSSObject): CSSObject => ({ + menu: (provided) => ({ ...provided, minWidth: '100%', width: 'max-content', @@ -42,7 +41,7 @@ const styles = { left: '0', marginBottom: '0', }), - menuPortal: (provided: CSSObject): CSSObject => ({ + menuPortal: (provided) => ({ ...provided, zIndex: 999, }), @@ -52,7 +51,7 @@ export default function RootInput(props: Props) { const [showMenu, setShowMenu] = useState(false) return ( - styles={styles} value={Options[props.value]} isMulti={false} diff --git a/webapp/boards/src/components/calendar/fullCalendar.test.tsx b/webapp/boards/src/components/calendar/fullCalendar.test.tsx index 9c7736689c..556dcb85d1 100644 --- a/webapp/boards/src/components/calendar/fullCalendar.test.tsx +++ b/webapp/boards/src/components/calendar/fullCalendar.test.tsx @@ -5,7 +5,6 @@ import {render} from '@testing-library/react' import {Provider as ReduxProvider} from 'react-redux' import {TestBlockFactory} from 'src/test/testBlockFactory' -import '@testing-library/jest-dom' import {wrapIntl, mockStateStore} from 'src/testUtils' import {IPropertyTemplate} from 'src/blocks/board' diff --git a/webapp/boards/src/components/calendar/fullCalendar.tsx b/webapp/boards/src/components/calendar/fullCalendar.tsx index 09ad5a0a60..1ba1a2c888 100644 --- a/webapp/boards/src/components/calendar/fullCalendar.tsx +++ b/webapp/boards/src/components/calendar/fullCalendar.tsx @@ -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: () => { diff --git a/webapp/boards/src/components/cardActionsMenu/cardActionsMenu.test.tsx b/webapp/boards/src/components/cardActionsMenu/cardActionsMenu.test.tsx index e56a35f977..15af5ccdd7 100644 --- a/webapp/boards/src/components/cardActionsMenu/cardActionsMenu.test.tsx +++ b/webapp/boards/src/components/cardActionsMenu/cardActionsMenu.test.tsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import '@testing-library/jest-dom' import {act, render} from '@testing-library/react' import React from 'react' import {Provider as ReduxProvider} from 'react-redux' diff --git a/webapp/boards/src/components/cardBadges.test.tsx b/webapp/boards/src/components/cardBadges.test.tsx index 3967681a72..a9f360d0bb 100644 --- a/webapp/boards/src/components/cardBadges.test.tsx +++ b/webapp/boards/src/components/cardBadges.test.tsx @@ -5,7 +5,6 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' import {render, screen} from '@testing-library/react' -import '@testing-library/jest-dom' import {TestBlockFactory} from 'src/test/testBlockFactory' import {blocksById, mockStateStore, wrapDNDIntl} from 'src/testUtils' diff --git a/webapp/boards/src/components/cardDetail/__snapshots__/cardDetail.test.tsx.snap b/webapp/boards/src/components/cardDetail/__snapshots__/cardDetail.test.tsx.snap index 10113eaad4..fa85f855fd 100644 --- a/webapp/boards/src/components/cardDetail/__snapshots__/cardDetail.test.tsx.snap +++ b/webapp/boards/src/components/cardDetail/__snapshots__/cardDetail.test.tsx.snap @@ -171,7 +171,7 @@ exports[`components/cardDetail/CardDetail should render hidden view if limited 1

- Upgrade to our Professional or Enterprise plan to view archived cards, have unlimited views per boards, unlimited cards and more. + Upgrade to our Professional or Enterprise plan.
- Add various properties to cards to make them more powerful! + Add various properties to cards to make them more powerful.

@@ -1701,11 +1701,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select > - http://localhost/undefined/team/team-id/1/1 + http://localhost:8065/undefined/team/team-id/1/1
@@ -1937,11 +1937,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select > - http://localhost/undefined/team/team-id/1/1 + http://localhost:8065/undefined/team/team-id/1/1
@@ -2423,11 +2423,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select > - http://localhost/undefined/team/team-id/1/1 + http://localhost:8065/undefined/team/team-id/1/1
- Everyone at Test Team Team + Everyone at Test Team team
@@ -2656,7 +2656,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoard template and cli

- Share Template + Share template

- option username_1 focused, 0 of 1. 4 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu. + option username_1 focused, 1 of 4. 4 results available. Use Up and Down to choose options, press Enter to select the currently focused option, press Escape to exit the menu, press Tab to select the option and exit the menu.
- Everyone at Test Team Team + Everyone at Test Team team
@@ -3074,7 +3074,7 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc class="ml-3" > - Everyone at Test Team Team + Everyone at Test Team team
@@ -3188,11 +3188,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoard, and click switc > - http://localhost/team/team-id/shared/1/1?r=oneToken + http://localhost:8065/boards/public/team/team-id/shared/1/1?r=oneToken
- Everyone at Test Team Team + Everyone at Test Team team
@@ -3461,11 +3461,11 @@ exports[`src/components/shareBoard/shareBoard return shareBoardComponent and cli > - http://localhost/team/team-id/shared/1/1?r=aToken + http://localhost:8065/boards/public/team/team-id/shared/1/1?r=aToken
- Everyone at Test Team Team + Everyone at Test Team team
@@ -3725,11 +3725,11 @@ exports[`src/components/shareBoard/shareBoard should match snapshot 1`] = ` > - http://localhost/undefined/team/team-id/1/1 + http://localhost:8065/undefined/team/team-id/1/1
@@ -3975,11 +3975,11 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing > - http://localhost/undefined/team/team-id/1/1 + http://localhost:8065/undefined/team/team-id/1/1
@@ -4225,11 +4225,11 @@ exports[`src/components/shareBoard/shareBoard should match snapshot with sharing > - http://localhost/undefined/team/team-id/1/1 + http://localhost:8065/undefined/team/team-id/1/1
- Everyone at Test Team Team + Everyone at Test Team team
diff --git a/webapp/boards/src/components/shareBoard/__snapshots__/teamPermissionsRow.test.tsx.snap b/webapp/boards/src/components/shareBoard/__snapshots__/teamPermissionsRow.test.tsx.snap index 44592e8442..c72be1b7de 100644 --- a/webapp/boards/src/components/shareBoard/__snapshots__/teamPermissionsRow.test.tsx.snap +++ b/webapp/boards/src/components/shareBoard/__snapshots__/teamPermissionsRow.test.tsx.snap @@ -15,7 +15,7 @@ exports[`src/components/shareBoard/teamPermissionsRow should match snapshot in p class="ml-3" > - Everyone at Test Team Team + Everyone at Test Team team
@@ -228,7 +228,7 @@ exports[`src/components/shareBoard/teamPermissionsRow should match snapshot in t class="ml-3" > - Everyone at Test Team Team + Everyone at Test Team team diff --git a/webapp/boards/src/components/shareBoard/channelPermissionsRow.test.tsx b/webapp/boards/src/components/shareBoard/channelPermissionsRow.test.tsx index 645ed36464..9d6e7bf2b7 100644 --- a/webapp/boards/src/components/shareBoard/channelPermissionsRow.test.tsx +++ b/webapp/boards/src/components/shareBoard/channelPermissionsRow.test.tsx @@ -17,13 +17,11 @@ import client from 'src/octoClient' import ChannelPermissionsRow from './channelPermissionsRow' -jest.useFakeTimers() - const boardId = '1' jest.mock('src/octoClient') -const mockedOctoClient = mocked(client, true) +const mockedOctoClient = mocked(client) const board = TestBlockFactory.createBoard() board.id = boardId @@ -126,7 +124,7 @@ describe('src/components/shareBoard/channelPermissionsRow', () => { const buttonElement = container?.querySelector('.user-item__button') expect(buttonElement).toBeDefined() - userEvent.click(buttonElement!) + await userEvent.click(buttonElement!) expect(container).toMatchSnapshot() }) @@ -173,7 +171,7 @@ describe('src/components/shareBoard/channelPermissionsRow', () => { const buttonElement = container?.querySelector('.user-item__button') expect(buttonElement).toBeDefined() - userEvent.click(buttonElement!) + await userEvent.click(buttonElement!) expect(container).toMatchSnapshot() }) @@ -204,7 +202,7 @@ describe('src/components/shareBoard/channelPermissionsRow', () => { const buttonElement = container?.querySelector('.user-item__button') expect(buttonElement).toBeDefined() - userEvent.click(buttonElement!) + await userEvent.click(buttonElement!) expect(container).toMatchSnapshot() }) diff --git a/webapp/boards/src/components/shareBoard/shareBoard.test.tsx b/webapp/boards/src/components/shareBoard/shareBoard.test.tsx index 86c466e115..29fb0a47d3 100644 --- a/webapp/boards/src/components/shareBoard/shareBoard.test.tsx +++ b/webapp/boards/src/components/shareBoard/shareBoard.test.tsx @@ -19,8 +19,6 @@ import {Utils} from 'src/utils' import ShareBoard from './shareBoard' -jest.useFakeTimers() - const boardId = '1' const workspaceId: string|undefined = boardId const viewId = boardId @@ -29,8 +27,8 @@ const teamId = 'team-id' jest.mock('src/octoClient') jest.mock('src/utils') -const mockedOctoClient = mocked(client, true) -const mockedUtils = mocked(Utils, true) +const mockedOctoClient = mocked(client) +const mockedUtils = mocked(Utils) let params = {} jest.mock('react-router', () => { @@ -40,7 +38,7 @@ jest.mock('react-router', () => { ...originalModule, useRouteMatch: jest.fn(() => { return { - url: 'http://localhost/', + url: 'http://localhost:8065/', path: '/', params, isExact: true, @@ -49,145 +47,149 @@ jest.mock('react-router', () => { } }) -const board = TestBlockFactory.createBoard() -board.id = boardId -board.teamId = teamId -board.cardProperties = [ - { - id: 'property1', - name: 'Property 1', - type: 'text', - options: [ - { - id: 'value1', - value: 'value 1', - color: 'propColorBrown', - }, - ], - }, - { - id: 'property2', - name: 'Property 2', - type: 'select', - options: [ - { - id: 'value2', - value: 'value 2', - color: 'propColorBlue', - }, - ], - }, -] -board.channelId = 'channel_1' - -const activeView = TestBlockFactory.createBoardView(board) -activeView.id = 'view1' -activeView.fields.hiddenOptionIds = [] -activeView.fields.visiblePropertyIds = ['property1'] -activeView.fields.visibleOptionIds = ['value1'] - -const fakeBoard = {id: board.id} -activeView.boardId = fakeBoard.id - -const card1 = TestBlockFactory.createCard(board) -card1.id = 'card1' -card1.title = 'card-1' -card1.boardId = fakeBoard.id - -const card2 = TestBlockFactory.createCard(board) -card2.id = 'card2' -card2.title = 'card-2' -card2.boardId = fakeBoard.id - -const card3 = TestBlockFactory.createCard(board) -card3.id = 'card3' -card3.title = 'card-3' -card3.boardId = fakeBoard.id - -const me: IUser = { - id: 'user-id-1', - username: 'username_1', - email: '', - nickname: '', - firstname: '', - lastname: '', - props: {}, - create_at: 0, - update_at: 0, - is_bot: false, - is_guest: false, - roles: 'system_user', -} - -const categoryAttribute1 = TestBlockFactory.createCategoryBoards() -categoryAttribute1.name = 'Category 1' -categoryAttribute1.boardMetadata = [{boardID: board.id, hidden: false}] - describe('src/components/shareBoard/shareBoard', () => { const w = (window as any) const oldBaseURL = w.baseURL - const state = { - teams: { - current: {id: teamId, title: 'Test Team'}, - }, - users: { - me, - boardUsers: {[me.id]: me}, - blockSubscriptions: [], - }, - boards: { - current: board.id, - boards: { - [board.id]: board, - }, - templates: [], - membersInBoards: { - [board.id]: {}, - }, - myBoardMemberships: { - [board.id]: {userId: me.id, schemeAdmin: true}, - }, - }, - globalTemplates: { - value: [], - }, - views: { - views: { - [activeView.id]: activeView, - }, - current: activeView.id, - }, - cards: { - templates: [], - cards: [card1, card2, card3], - }, - searchText: {}, - clientConfig: { - value: { - telemetry: true, - telemetryid: 'telemetry', - enablePublicSharedBoards: true, - teammateNameDisplay: 'username', - featureFlags: {}, - }, - }, - contents: { - contents: {}, - }, - comments: { - comments: {}, - }, - sidebar: { - categoryAttributes: [ - categoryAttribute1, + const board = TestBlockFactory.createBoard() + board.id = boardId + board.teamId = teamId + board.cardProperties = [ + { + id: 'property1', + name: 'Property 1', + type: 'text', + options: [ + { + id: 'value1', + value: 'value 1', + color: 'propColorBrown', + }, ], }, + { + id: 'property2', + name: 'Property 2', + type: 'select', + options: [ + { + id: 'value2', + value: 'value 2', + color: 'propColorBlue', + }, + ], + }, + ] + board.channelId = 'channel_1' + + const activeView = TestBlockFactory.createBoardView(board) + activeView.id = 'view1' + activeView.fields.hiddenOptionIds = [] + activeView.fields.visiblePropertyIds = ['property1'] + activeView.fields.visibleOptionIds = ['value1'] + + const fakeBoard = {id: board.id} + activeView.boardId = fakeBoard.id + + const card1 = TestBlockFactory.createCard(board) + card1.id = 'card1' + card1.title = 'card-1' + card1.boardId = fakeBoard.id + + const card2 = TestBlockFactory.createCard(board) + card2.id = 'card2' + card2.title = 'card-2' + card2.boardId = fakeBoard.id + + const card3 = TestBlockFactory.createCard(board) + card3.id = 'card3' + card3.title = 'card-3' + card3.boardId = fakeBoard.id + + const me: IUser = { + id: 'user-id-1', + username: 'username_1', + email: '', + nickname: '', + firstname: '', + lastname: '', + props: {}, + create_at: 0, + update_at: 0, + is_bot: false, + is_guest: false, + roles: 'system_user', } - const store = mockStateStore([thunk], state) + const categoryAttribute1 = TestBlockFactory.createCategoryBoards() + categoryAttribute1.name = 'Category 1' + categoryAttribute1.boardMetadata = [{boardID: board.id, hidden: false}] + + let state: Parameters[1] + let store: ReturnType + beforeEach(() => { - jest.clearAllMocks() + + state = { + teams: { + current: {id: teamId, title: 'Test Team'}, + }, + users: { + me, + boardUsers: {[me.id]: me}, + blockSubscriptions: [], + }, + boards: { + current: board.id, + boards: { + [board.id]: board, + }, + templates: [], + membersInBoards: { + [board.id]: {}, + }, + myBoardMemberships: { + [board.id]: {userId: me.id, schemeAdmin: true}, + }, + }, + globalTemplates: { + value: [], + }, + views: { + views: { + [activeView.id]: activeView, + }, + current: activeView.id, + }, + cards: { + templates: [], + cards: [card1, card2, card3], + }, + searchText: {}, + clientConfig: { + value: { + telemetry: true, + telemetryid: 'telemetry', + enablePublicSharedBoards: true, + teammateNameDisplay: 'username', + featureFlags: {}, + }, + }, + contents: { + contents: {}, + }, + comments: { + comments: {}, + }, + sidebar: { + categoryAttributes: [ + categoryAttribute1, + ], + }, + } + + + store = mockStateStore([thunk], state) // mockedUtils.buildURL.mockImplementation((path) => (w.baseURL || '') + path) @@ -290,8 +292,8 @@ describe('src/components/shareBoard/shareBoard', () => { const copyLinkElement = screen.getByTitle('Copy link') expect(copyLinkElement).toBeDefined() - act(() => { - userEvent.click(copyLinkElement!) + await act(async () => { + await userEvent.click(copyLinkElement!) }) expect(mockedUtils.copyTextToClipboard).toBeCalledTimes(1) @@ -312,20 +314,14 @@ describe('src/components/shareBoard/shareBoard', () => { } mockedOctoClient.getSharing.mockResolvedValue(sharing) - let container - await act(async () => { - const result = render( - wrapDNDIntl( - - - ), - {wrapper: MemoryRouter}, - ) - container = result.container - }) + const {container} = render(wrapDNDIntl( + + + + ), {wrapper: MemoryRouter}) sharing.token = 'anotherToken' mockedUtils.createGuid.mockReturnValue('anotherToken') @@ -334,17 +330,12 @@ describe('src/components/shareBoard/shareBoard', () => { const publishButton = screen.getByRole('button', {name: 'Publish'}) expect(publishButton).toBeDefined() - userEvent.click(publishButton) - await act(async () => { - jest.runOnlyPendingTimers() - }) + await act(() => userEvent.click(publishButton)) const regenerateTokenElement = screen.getByRole('button', {name: 'Regenerate token'}) expect(regenerateTokenElement).toBeDefined() - userEvent.click(regenerateTokenElement) - await act(async () => { - jest.runOnlyPendingTimers() - }) + await act(() => userEvent.click(regenerateTokenElement)) + expect(mockedOctoClient.setSharing).toBeCalledTimes(1) expect(container).toMatchSnapshot() }) @@ -373,15 +364,12 @@ describe('src/components/shareBoard/shareBoard', () => { const publishButton = screen.getByRole('button', {name: 'Publish'}) expect(publishButton).toBeDefined() - userEvent.click(publishButton) - await act(async () => { - jest.runOnlyPendingTimers() - }) + await userEvent.click(publishButton) const switchElement = container?.querySelector('.Switch') expect(switchElement).toBeDefined() await act(async () => { - userEvent.click(switchElement!) + await userEvent.click(switchElement!) }) expect(mockedOctoClient.setSharing).toBeCalledTimes(1) @@ -397,48 +385,41 @@ describe('src/components/shareBoard/shareBoard', () => { } mockedOctoClient.getSharing.mockResolvedValue(sharing) mockedUtils.createGuid.mockReturnValue('aToken') - let container: Element | undefined - await act(async () => { - const result = render( - wrapDNDIntl( - - - ), - {wrapper: MemoryRouter}, - ) - container = result.container - mockedOctoClient.getSharing.mockResolvedValue({ - id: boardId, - enabled: true, - token: 'aToken', - }) - - const publishButton = screen.getByRole('button', {name: 'Publish'}) - expect(publishButton).toBeDefined() - userEvent.click(publishButton) - jest.runOnlyPendingTimers() - - const switchElement = container?.querySelector('.Switch') - expect(switchElement).toBeDefined() - userEvent.click(switchElement!) - jest.runOnlyPendingTimers() - result.rerender( - wrapDNDIntl( - - - )) + const result = render(wrapDNDIntl( + + + + ),{wrapper: MemoryRouter}) + + mockedOctoClient.getSharing.mockResolvedValue({ + id: boardId, + enabled: true, + token: 'aToken', }) + const publishButton = screen.getByRole('button', {name: 'Publish'}) + expect(publishButton).toBeDefined() + await act(() => userEvent.click(publishButton)) + + const switchElement = result.container?.querySelector('.Switch') + expect(switchElement).toBeDefined() + await act(() => userEvent.click(switchElement!)) + + result.rerender(wrapDNDIntl( + + + + )) + expect(mockedOctoClient.setSharing).toBeCalledTimes(1) expect(mockedOctoClient.getSharing).toBeCalledTimes(2) - expect(mockedUtils.createGuid).toBeCalledTimes(1) - expect(container).toMatchSnapshot() + expect(result.container).toMatchSnapshot() }) test('should match snapshot with sharing and subpath', async () => { @@ -509,7 +490,7 @@ describe('src/components/shareBoard/shareBoard', () => { expect(selectElement).toBeDefined() await act(async () => { - userEvent.click(selectElement!) + await userEvent.click(selectElement!) }) expect(container).toMatchSnapshot() @@ -558,7 +539,7 @@ describe('src/components/shareBoard/shareBoard', () => { expect(selectElement).toBeDefined() await act(async () => { - userEvent.click(selectElement!) + await userEvent.click(selectElement!) }) expect(container).toMatchSnapshot() @@ -591,15 +572,15 @@ describe('src/components/shareBoard/shareBoard', () => { const channelMenuBtn = container!.querySelector('.user-item.channel-item .MenuWrapper') expect(channelMenuBtn).not.toBeNull() - userEvent.click(channelMenuBtn as Element) + await userEvent.click(channelMenuBtn as Element) const unlinkOption = screen.getByText('Unlink') expect(unlinkOption).not.toBeNull() - userEvent.click(unlinkOption) + await userEvent.click(unlinkOption) const unlinkConfirmationBtn = screen.getByText('Unlink channel') expect(unlinkConfirmationBtn).not.toBeNull() - userEvent.click(unlinkConfirmationBtn) + await userEvent.click(unlinkConfirmationBtn) expect(mockedOctoClient.patchBoard).toBeCalled() @@ -685,9 +666,7 @@ describe('src/components/shareBoard/shareBoard', () => { const selectElement = screen.getByText('Search for people') expect(selectElement).toBeDefined() - await act(async () => { - userEvent.click(selectElement!) - }) + await act(() => userEvent.click(selectElement!)) expect(mockedOctoClient.searchUserChannels).not.toBeCalled() expect(container).toMatchSnapshot() diff --git a/webapp/boards/src/components/shareBoard/shareBoard.tsx b/webapp/boards/src/components/shareBoard/shareBoard.tsx index 97ef19215d..c5d040f6f2 100644 --- a/webapp/boards/src/components/shareBoard/shareBoard.tsx +++ b/webapp/boards/src/components/shareBoard/shareBoard.tsx @@ -6,7 +6,7 @@ import React, {useState, useEffect} from 'react' import {useIntl, FormattedMessage} from 'react-intl' import {generatePath, useRouteMatch} from 'react-router-dom' import Select from 'react-select/async' -import {CSSObject} from '@emotion/serialize' +import {StylesConfig} from 'react-select' import {useAppSelector} from 'src/store/hooks' import {getCurrentBoard, getCurrentBoardMembers} from 'src/store/boards' @@ -26,7 +26,7 @@ import {BoardMember, createBoard, MemberRole} from 'src/blocks/board' import client from 'src/octoClient' import Dialog from 'src/components/dialog' import ConfirmationDialog from 'src/components/confirmationDialogBox' -import {IUser} from 'src/user' +import {IUser, isUser} from 'src/user' import Switch from 'src/widgets/switch' import Button from 'src/widgets/buttons/button' import {sendFlashMessage} from 'src/components/flashMessages' @@ -58,11 +58,11 @@ type Props = { enableSharedBoards: boolean } -const baseStyles = getSelectBaseStyle() +const baseStyles = getSelectBaseStyle() -const styles = { +const styles: StylesConfig = { ...baseStyles, - control: (): CSSObject => ({ + control: () => ({ border: 0, width: '100%', height: '100%', @@ -70,7 +70,7 @@ const styles = { display: 'flex', flexDirection: 'row', }), - menu: (provided: CSSObject): CSSObject => ({ + menu: (provided) => ({ ...provided, minWidth: '100%', width: 'max-content', @@ -78,8 +78,8 @@ const styles = { left: '0', marginBottom: '0', }), - singleValue: (provided: CSSObject): CSSObject => ({ - ...baseStyles.singleValue(provided), + singleValue: (...props) => ({ + ...baseStyles.singleValue?.(...props), opacity: '0.8', fontSize: '12px', right: '0', @@ -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 = ( ) @@ -344,7 +344,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element {
-
+
+
+
@@ -801,7 +849,7 @@ exports[`components/table/Table extended should match snapshot with CreatedAt 1`
@@ -815,7 +863,7 @@ exports[`components/table/Table extended should match snapshot with CreatedAt 1` />
@@ -829,7 +877,7 @@ exports[`components/table/Table extended should match snapshot with CreatedAt 1` />
@@ -965,7 +1013,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1` - Status + Created By
@@ -1114,6 +1161,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1` class="action-cell octo-table-cell-btn" > +
+
+ + @@ -2943,7 +3058,7 @@ exports[`components/table/Table should match snapshot with GroupBy 1`] = ` class="CalculationRow octo-table-row" >
@@ -2959,7 +3074,7 @@ exports[`components/table/Table should match snapshot with GroupBy 1`] = `
@@ -2973,7 +3088,7 @@ exports[`components/table/Table should match snapshot with GroupBy 1`] = ` />
@@ -3125,6 +3240,7 @@ exports[`components/table/Table should match snapshot without permissions 1`] = class="open-button" > No Property 1 diff --git a/webapp/boards/src/components/table/calculation/calculationRow.test.tsx b/webapp/boards/src/components/table/calculation/calculationRow.test.tsx index 64cf8074d8..e8081bfaa4 100644 --- a/webapp/boards/src/components/table/calculation/calculationRow.test.tsx +++ b/webapp/boards/src/components/table/calculation/calculationRow.test.tsx @@ -3,7 +3,6 @@ import React from 'react' import {render} from '@testing-library/react' -import '@testing-library/jest-dom' import {TestBlockFactory} from 'src/test/testBlockFactory' import {FetchMock} from 'src/test/fetchMock' diff --git a/webapp/boards/src/components/table/table.test.tsx b/webapp/boards/src/components/table/table.test.tsx index c3d39f5fe2..3f947189ec 100644 --- a/webapp/boards/src/components/table/table.test.tsx +++ b/webapp/boards/src/components/table/table.test.tsx @@ -3,10 +3,8 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' -import {render, screen} from '@testing-library/react' +import {act, render, screen} from '@testing-library/react' import configureStore from 'redux-mock-store' -import '@testing-library/jest-dom' -import userEvents from '@testing-library/user-event' import 'isomorphic-fetch' import {mocked} from 'jest-mock' @@ -19,7 +17,7 @@ import {IUser} from 'src/user' import {Utils, IDType} from 'src/utils' -import {wrapDNDIntl} from 'src/testUtils' +import {setup, wrapDNDIntl} from 'src/testUtils' import Mutator from 'src/mutator' @@ -32,9 +30,8 @@ beforeEach(() => { }) jest.mock('src/mutator') -jest.mock('src/utils') jest.mock('src/telemetry/telemetryClient') -const mockedMutator = mocked(Mutator, true) +const mockedMutator = mocked(Mutator) describe('components/table/Table', () => { const board = TestBlockFactory.createBoard() @@ -320,6 +317,7 @@ describe('components/table/Table extended', () => { const board = TestBlockFactory.createBoard() const dateCreatedId = Utils.createGuid(IDType.User) + expect(dateCreatedId).toEqual(expect.any(String)) board.cardProperties.push({ id: dateCreatedId, name: 'Date Created', @@ -390,6 +388,7 @@ describe('components/table/Table extended', () => { test('should match snapshot with UpdatedAt', async () => { const board = TestBlockFactory.createBoard() const dateUpdatedId = Utils.createGuid(IDType.User) + expect(dateUpdatedId).toEqual(expect.any(String)) board.cardProperties.push({ id: dateUpdatedId, name: 'Date Updated', @@ -470,13 +469,16 @@ describe('components/table/Table extended', () => { , ) const {container} = render(component) + expect(card1.id ) expect(container).toMatchSnapshot() }) test('should match snapshot with CreatedBy', async () => { + jest.spyOn(console, 'error').mockImplementation() const board = TestBlockFactory.createBoard() const createdById = Utils.createGuid(IDType.User) + expect(createdById).toEqual(expect.any(String)) board.cardProperties.push({ id: createdById, name: 'Created By', @@ -531,12 +533,21 @@ describe('components/table/Table extended', () => { const {container} = render(component) expect(container).toMatchSnapshot() + + // TODO fix test — fix personSelector + expect(console.error).toHaveBeenCalledWith( + expect.stringContaining('Each child in a list should have a unique "key" prop'), + expect.stringContaining('Check the render method of `PersonSelector`'), + expect.anything(), + expect.anything() + ) }) test('should match snapshot with UpdatedBy', async () => { const board = TestBlockFactory.createBoard() const modifiedById = Utils.createGuid(IDType.User) + expect(modifiedById).toEqual(expect.any(String)) board.cardProperties.push({ id: modifiedById, name: 'Last Modified By', @@ -629,6 +640,7 @@ describe('components/table/Table extended', () => { const board = TestBlockFactory.createBoard() const modifiedById = Utils.createGuid(IDType.User) + expect(modifiedById).toEqual(expect.any(String)) board.cardProperties.push({ id: modifiedById, name: 'Last Modified By', @@ -654,7 +666,7 @@ describe('components/table/Table extended', () => { }, }) - const component = wrapDNDIntl( + const {user} = setup(wrapDNDIntl( { showHiddenCardCountNotification={jest.fn()} /> , - ) - - const {getByTitle, getByRole, getAllByTitle} = render(component) - const card1Name = getByTitle(card1.title) - userEvents.hover(card1Name) - const menuBtn = getAllByTitle('MenuBtn') - userEvents.click(menuBtn[0]) - const deleteBtn = getByRole('button', {name: 'Delete'}) - userEvents.click(deleteBtn) - const dailogDeleteBtn = screen.getByRole('button', {name: 'Delete'}) - userEvents.click(dailogDeleteBtn) + )) + await act(async () => { + await user.hover(screen.getByTitle(card1.title)) + await user.click(screen.getAllByTitle('MenuBtn')[0]) + await user.click(screen.getByRole('button', {name: 'Delete'})) + await user.click(screen.getByRole('button', {name: 'Delete'})) + }) expect(mockedMutator.deleteBlock).toBeCalledTimes(1) }) @@ -690,6 +698,7 @@ describe('components/table/Table extended', () => { const board = TestBlockFactory.createBoard() const modifiedById = Utils.createGuid(IDType.User) + expect(modifiedById).toEqual(expect.any(String)) board.cardProperties.push({ id: modifiedById, name: 'Last Modified By', @@ -715,7 +724,7 @@ describe('components/table/Table extended', () => { }, }) - const component = wrapDNDIntl( + const {container, user} = setup(wrapDNDIntl(
{ showHiddenCardCountNotification={jest.fn()} /> , - ) + )) - const {getByTitle, getByRole, getAllByTitle, container} = render(component) - const card1Name = getByTitle(card1.title) - userEvents.hover(card1Name) - const menuBtn = getAllByTitle('MenuBtn') - userEvents.click(menuBtn[0]) - const duplicateBtn = getByRole('button', {name: 'Duplicate'}) - expect(duplicateBtn).not.toBe(null) - userEvents.click(duplicateBtn) + await act(async () => { + await user.hover(screen.getByTitle(card1.title)) + await user.click(screen.getAllByTitle('MenuBtn')[0]) + await user.click(screen.getByRole('button', {name: 'Duplicate'})) + }) expect(mockedMutator.duplicateCard).toBeCalledTimes(1) expect(container).toMatchSnapshot() }) diff --git a/webapp/boards/src/components/table/tableGroupHeaderRow.test.tsx b/webapp/boards/src/components/table/tableGroupHeaderRow.test.tsx index a37d7ecf45..d8b6fd0024 100644 --- a/webapp/boards/src/components/table/tableGroupHeaderRow.test.tsx +++ b/webapp/boards/src/components/table/tableGroupHeaderRow.test.tsx @@ -3,7 +3,6 @@ import React from 'react' import {fireEvent, render} from '@testing-library/react' -import '@testing-library/jest-dom' import 'isomorphic-fetch' @@ -189,9 +188,9 @@ test('should match snapshot, edit title', async () => { ) const input = getByTitle(/value 1/) - act(() => { - userEvent.click(input) - userEvent.keyboard('{enter}') + await act(async () => { + await userEvent.click(input) + await userEvent.keyboard('{Enter}') }) expect(container).toMatchSnapshot() diff --git a/webapp/boards/src/components/table/tableGroupHeaderRow.tsx b/webapp/boards/src/components/table/tableGroupHeaderRow.tsx index de657bb69e..a9e29935a8 100644 --- a/webapp/boards/src/components/table/tableGroupHeaderRow.tsx +++ b/webapp/boards/src/components/table/tableGroupHeaderRow.tsx @@ -86,7 +86,7 @@ const TableGroupHeaderRow = (props: Props): JSX.Element => { - - +
+ + {getPaymentStatus(invoice.status)}{getPaymentStatus(invoice.status)} e.stopPropagation()} diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx index 68f5503d66..cf8560ed3b 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cancel_subscription.tsx @@ -5,16 +5,12 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; import {trackEvent} from 'actions/telemetry_actions'; +import {useOpenCloudZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm'; import ExternalLink from 'components/external_link'; -type Props = { - cancelAccountLink: any; -} - -const CancelSubscription = (props: Props) => { - const { - cancelAccountLink, - } = props; +const CancelSubscription = () => { + const description = `I am requesting that workspace "${window.location.host}" be deleted`; + const [, contactSupportURL] = useOpenCloudZendeskSupportForm('Request workspace be deleted', description); return (
@@ -33,7 +29,7 @@ const CancelSubscription = (props: Props) => {
trackEvent('cloud_admin', 'click_contact_us')} > diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx index 204495ce90..a62edc1e54 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/cloud_trial_banner.tsx @@ -24,7 +24,6 @@ import AlertBanner from 'components/alert_banner'; import UpgradeLink from 'components/widgets/links/upgrade_link'; import './cloud_trial_banner.scss'; -import {SalesInquiryIssue} from 'selectors/cloud'; export interface Props { trialEndDate: number; @@ -34,7 +33,7 @@ const CloudTrialBanner = ({trialEndDate}: Props): JSX.Element | null => { const endDate = new Date(trialEndDate); const DISMISSED_DAYS = 10; const {formatMessage} = useIntl(); - const openSalesLink = useOpenSalesLink(SalesInquiryIssue.UpgradeEnterprise); + const [openSalesLink] = useOpenSalesLink(); const dispatch = useDispatch(); const user = useSelector(getCurrentUser); const storedDismissedEndDate = useSelector((state: GlobalState) => getPreference(state, Preferences.CLOUD_TRIAL_BANNER, CloudBanners.UPGRADE_FROM_TRIAL)); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx index 0687b78857..3e5bec63e9 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/contact_sales_card.tsx @@ -10,21 +10,19 @@ import {CloudLinks, CloudProducts} from 'utils/constants'; import PrivateCloudSvg from 'components/common/svg_images_components/private_cloud_svg'; import CloudTrialSvg from 'components/common/svg_images_components/cloud_trial_svg'; import {TelemetryProps} from 'components/common/hooks/useOpenPricingModal'; +import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import ExternalLink from 'components/external_link'; type Props = { - contactSalesLink: any; isFreeTrial: boolean; - trialQuestionsLink: any; subscriptionPlan: string | undefined; onUpgradeMattermostCloud: (telemetryProps?: TelemetryProps | undefined) => void; } const ContactSalesCard = (props: Props) => { + const [openSalesLink, contactSalesLink] = useOpenSalesLink(); const { - contactSalesLink, isFreeTrial, - trialQuestionsLink, subscriptionPlan, onUpgradeMattermostCloud, } = props; @@ -145,7 +143,7 @@ const ContactSalesCard = (props: Props) => { {(isFreeTrial || subscriptionPlan === CloudProducts.ENTERPRISE || isCloudLegacyPlan) && trackEvent('cloud_admin', 'click_contact_sales')} > @@ -163,7 +161,7 @@ const ContactSalesCard = (props: Props) => { if (subscriptionPlan === CloudProducts.STARTER) { onUpgradeMattermostCloud({trackingLocation: 'admin_console_subscription_card_upgrade_now_button'}); } else { - window.open(contactSalesLink, '_blank'); + openSalesLink(); } }} className='PrivateCloudCard__actionButton' diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/index.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/index.tsx index f4f07ab0f9..2f46aeb588 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/index.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/index.tsx @@ -13,7 +13,6 @@ import FormattedAdminHeader from 'components/widgets/admin_console/formatted_adm import CloudTrialBanner from 'components/admin_console/billing/billing_subscriptions/cloud_trial_banner'; import CloudFetchError from 'components/cloud_fetch_error'; -import {getCloudContactUsLink, InquiryType, SalesInquiryIssue} from 'selectors/cloud'; import { getSubscriptionProduct, getCloudSubscription as selectCloudSubscription, @@ -49,6 +48,7 @@ import { import LimitReachedBanner from './limit_reached_banner'; import CancelSubscription from './cancel_subscription'; import {ToYearlyNudgeBanner} from './to_yearly_nudge_banner'; +import {ToPaidNudgeBanner} from './to_paid_plan_nudge_banner'; import './billing_subscriptions.scss'; @@ -63,9 +63,6 @@ const BillingSubscriptions = () => { const isCardExpired = isCustomerCardExpired(useSelector(selectCloudCustomer)); - const contactSalesLink = useSelector(getCloudContactUsLink)(InquiryType.Sales); - const cancelAccountLink = useSelector(getCloudContactUsLink)(InquiryType.Sales, SalesInquiryIssue.CancelAccount); - const trialQuestionsLink = useSelector(getCloudContactUsLink)(InquiryType.Sales, SalesInquiryIssue.TrialQuestions); const trialEndDate = subscription?.trial_end_at || 0; const [showCreditCardBanner, setShowCreditCardBanner] = useState(true); @@ -140,6 +137,7 @@ const BillingSubscriptions = () => { /> {shouldShowPaymentFailedBanner() && paymentFailedBanner()} {} + {} {showCreditCardBanner && isCardExpired && creditCardExpiredBanner(setShowCreditCardBanner)} @@ -159,19 +157,12 @@ const BillingSubscriptions = () => { ) : ( )} - {isAnnualProfessionalOrEnterprise && !isFreeTrial ? - : - - } + {isAnnualProfessionalOrEnterprise && !isFreeTrial ? : } } diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx index 0aa08eddb7..66e4356434 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.test.tsx @@ -177,7 +177,7 @@ describe('limits_reached_banner', () => { const store = mockStore(state); const spies = makeSpies(); const mockOpenSalesLink = jest.fn(); - spies.useOpenSalesLink.mockReturnValue(mockOpenSalesLink); + spies.useOpenSalesLink.mockReturnValue([mockOpenSalesLink, '']); spies.useGetUsageDeltas.mockReturnValue(someLimitReached); renderWithIntl(); screen.getByText(titleFree); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.tsx index d006716bea..666adc3bd0 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limit_reached_banner.tsx @@ -5,8 +5,6 @@ import React from 'react'; import {useIntl, FormattedMessage} from 'react-intl'; import {useSelector} from 'react-redux'; -import {SalesInquiryIssue} from 'selectors/cloud'; - import {CloudProducts} from 'utils/constants'; import {anyUsageDeltaExceededLimit} from 'utils/limits'; @@ -33,7 +31,7 @@ const LimitReachedBanner = (props: Props) => { const hasDismissedBanner = useSelector(getHasDismissedSystemConsoleLimitReached); - const openSalesLink = useOpenSalesLink(props.product?.sku === CloudProducts.PROFESSIONAL ? SalesInquiryIssue.UpgradeEnterprise : undefined); + const [openSalesLink] = useOpenSalesLink(); const openPricingModal = useOpenPricingModal(); const saveBool = useSaveBool(); if (hasDismissedBanner || !someLimitExceeded || !props.product || (props.product.sku !== CloudProducts.STARTER)) { diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.tsx index 2798c1374a..3457fbd201 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/limits.tsx @@ -11,8 +11,6 @@ import { getSubscriptionProduct, } from 'mattermost-redux/selectors/entities/cloud'; -import {SalesInquiryIssue} from 'selectors/cloud'; - import {CloudProducts} from 'utils/constants'; import {asGBString, fallbackStarterLimits, hasSomeLimits} from 'utils/limits'; @@ -32,7 +30,7 @@ const Limits = (): JSX.Element | null => { const subscriptionProduct = useSelector(getSubscriptionProduct); const [cloudLimits, limitsLoaded] = useGetLimits(); const usage = useGetUsage(); - const openSalesLink = useOpenSalesLink(SalesInquiryIssue.UpgradeEnterprise); + const [openSalesLink] = useOpenSalesLink(); const openPricingModal = useOpenPricingModal(); if (!subscriptionProduct || !limitsLoaded || !hasSomeLimits(cloudLimits)) { diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.scss b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.scss new file mode 100644 index 0000000000..f49b2f2ab7 --- /dev/null +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.scss @@ -0,0 +1,28 @@ +@import 'utils/mixins'; + +.ToPaidNudgeBanner { + &__actions { + padding-top: 12px; + } + + &__primary { + font-size: 12px; + + @include primary-button; + + &:hover { + color: var(--button-color); + } + } + + &__secondary { + margin-left: 4px; + font-size: 12px; + + @include tertiary-button; + + &:hover { + color: var(--button-bg); + } + } +} diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx new file mode 100644 index 0000000000..ee783bcaaf --- /dev/null +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.test.tsx @@ -0,0 +1,239 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {screen} from '@testing-library/react'; + +import {renderWithIntlAndStore} from 'tests/react_testing_utils'; +import {CloudProducts} from 'utils/constants'; + +import {ToPaidNudgeBanner, ToPaidPlanBannerDismissable} from './to_paid_plan_nudge_banner'; + +const initialState = { + views: { + announcementBar: { + announcementBarState: { + announcementBarCount: 1, + }, + }, + }, + entities: { + general: { + config: { + CWSURL: '', + FeatureFlagDeprecateCloudFree: 'true', + }, + license: { + IsLicensed: 'true', + Cloud: 'true', + }, + }, + users: { + currentUserId: 'current_user_id', + profiles: { + current_user_id: {roles: 'system_user'}, + }, + }, + preferences: { + myPreferences: {}, + }, + cloud: {}, + }, +}; + +describe('ToPaidPlanBannerDismissable', () => { + test('should only show for admins on cloud free', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.users.profiles = { + current_user_id: {roles: 'system_admin'}, + }; + state.entities.cloud = { + subscription: { + product_id: 'prod_starter', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_starter: { + id: 'prod_starter', + sku: CloudProducts.STARTER, + }, + }, + }; + + renderWithIntlAndStore(, state); + + screen.getByTestId('cloud-free-deprecation-announcement-bar'); + }); + + test('should NOT show for NON admins', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.users.profiles = { + current_user_id: {roles: 'system_user'}, + }; + state.entities.cloud = { + subscription: { + product_id: 'prod_starter', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_starter: { + id: 'prod_starter', + sku: CloudProducts.STARTER, + }, + }, + }; + + renderWithIntlAndStore(, state); + + expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); + }); + + test('should NOT show for admins on cloud pro', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.users.profiles = { + current_user_id: {roles: 'system_admin'}, + }; + state.entities.cloud = { + subscription: { + product_id: 'prod_pro', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_pro: { + id: 'prod_pro', + sku: CloudProducts.PROFESSIONAL, + }, + }, + }; + + renderWithIntlAndStore(, state); + + expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); + }); + + test('should NOT show for admins on cloud enterprise', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.users.profiles = { + current_user_id: {roles: 'system_admin'}, + }; + state.entities.cloud = { + subscription: { + product_id: 'prod_enterprise', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_enterprise: { + id: 'prod_enterprise', + sku: CloudProducts.ENTERPRISE, + }, + }, + }; + + renderWithIntlAndStore(, state); + + expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); + }); + + test('should NOT show for admins when banner was dismissed in preferences', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.users.profiles = { + current_user_id: {roles: 'system_admin'}, + }; + state.entities.preferences = { + myPreferences: { + 'to_paid_plan_nudge--nudge_to_paid_plan_snoozed': { + category: 'to_paid_plan_nudge', + name: 'nudge_to_paid_plan_snoozed', + value: '{"range": 0, "show": false}', + }, + }, + }; + + state.entities.cloud = { + subscription: { + product_id: 'prod_starter', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_starter: { + id: 'prod_starter', + sku: CloudProducts.STARTER, + }, + }, + }; + + renderWithIntlAndStore(, state); + + expect(() => screen.getByTestId('cloud-free-deprecation-announcement-bar')).toThrow(); + }); +}); + +describe('ToPaidNudgeBanner', () => { + test('should show only for cloud free', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.cloud = { + subscription: { + product_id: 'prod_starter', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_starter: { + id: 'prod_starter', + sku: CloudProducts.STARTER, + }, + }, + }; + + renderWithIntlAndStore(, state); + + screen.getByTestId('cloud-free-deprecation-alert-banner'); + }); + + test('should NOT show for cloud professional', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.cloud = { + subscription: { + product_id: 'prod_pro', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_pro: { + id: 'prod_pro', + sku: CloudProducts.PROFESSIONAL, + }, + }, + }; + + renderWithIntlAndStore(, state); + + expect(() => screen.getByTestId('cloud-free-deprecation-alert-banner')).toThrow(); + }); + + test('should NOT show for cloud enterprise', () => { + const state = JSON.parse(JSON.stringify(initialState)); + state.entities.cloud = { + subscription: { + product_id: 'prod_ent', + is_free_trial: 'false', + trial_end_at: 1, + }, + products: { + prod_ent: { + id: 'prod_ent', + sku: CloudProducts.ENTERPRISE, + }, + }, + }; + + renderWithIntlAndStore(, state); + + expect(() => screen.getByTestId('cloud-free-deprecation-alert-banner')).toThrow(); + }); +}); diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.tsx new file mode 100644 index 0000000000..06fda8eb9a --- /dev/null +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner.tsx @@ -0,0 +1,246 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useEffect} from 'react'; +import {useDispatch, useSelector} from 'react-redux'; +import {useIntl, FormattedMessage} from 'react-intl'; +import moment from 'moment'; + +import AlertBanner from 'components/alert_banner'; +import useOpenPricingModal from 'components/common/hooks/useOpenPricingModal'; +import useOpenCloudPurchaseModal from 'components/common/hooks/useOpenCloudPurchaseModal'; +import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; +import AnnouncementBar from 'components/announcement_bar/default_announcement_bar'; + +import {getSubscriptionProduct as selectSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud'; +import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users'; +import {savePreferences} from 'mattermost-redux/actions/preferences'; +import {deprecateCloudFree, get as getPreference} from 'mattermost-redux/selectors/entities/preferences'; + +import {AnnouncementBarTypes, CloudBanners, CloudProducts, Preferences} from 'utils/constants'; +import {t} from 'utils/i18n'; + +import {GlobalState} from '@mattermost/types/store'; + +import './to_paid_plan_nudge_banner.scss'; + +enum DismissShowRange { + GreaterThanEqual90 = '>=90', + BetweenNinetyAnd60 = '89-61', + SixtyTo31 = '60-31', + ThirtyTo11 = '30-11', + TenTo1 = '10-1', + Zero = '0' +} + +const cloudFreeCloseMoment = '20230727'; + +interface ToPaidPlanDismissPreference { + + // range represents the range for the days to the deprecation of cloud free e.g. in 30 to 10 days to deprecate cloud free + // Incase of dismissing the banner, range represents the time (days) period when this banner was dismissed. + // This is important because in case the banner was dismissed for a certain period, it helps us know that we should not show it again for that period. + range: DismissShowRange; + show: boolean; +} + +export const ToPaidPlanBannerDismissable = () => { + const dispatch = useDispatch(); + + const openPricingModal = useOpenPricingModal(); + + const currentUser = useSelector(getCurrentUser); + const isAdmin = useSelector(isCurrentUserSystemAdmin); + const product = useSelector(selectSubscriptionProduct); + const cloudFreeDeprecated = useSelector(deprecateCloudFree); + const currentProductStarter = product?.sku === CloudProducts.STARTER; + + const now = moment(Date.now()); + const cloudFreeEndDate = moment(cloudFreeCloseMoment, 'YYYYMMDD'); + const daysToCloudFreeEnd = cloudFreeEndDate.diff(now, 'days'); + + const snoozePreferenceVal = useSelector((state: GlobalState) => getPreference(state, Preferences.TO_PAID_PLAN_NUDGE, CloudBanners.NUDGE_TO_PAID_PLAN_SNOOZED, '{"range": 0, "show": true}')); + const snoozeInfo = JSON.parse(snoozePreferenceVal) as ToPaidPlanDismissPreference; + const show = snoozeInfo.show; + + const snoozedForRange = (range: DismissShowRange) => { + return snoozeInfo.range === range; + }; + + useEffect(() => { + if (!snoozeInfo.show) { + if (daysToCloudFreeEnd >= 90 && !snoozedForRange(DismissShowRange.GreaterThanEqual90)) { + showBanner(true); + } + + if (daysToCloudFreeEnd < 90 && daysToCloudFreeEnd > 60 && !snoozedForRange(DismissShowRange.BetweenNinetyAnd60)) { + showBanner(true); + } + + if (daysToCloudFreeEnd <= 60 && daysToCloudFreeEnd > 30 && !snoozedForRange(DismissShowRange.SixtyTo31)) { + showBanner(true); + } + + if (daysToCloudFreeEnd <= 30 && daysToCloudFreeEnd > 10 && !snoozedForRange(DismissShowRange.ThirtyTo11)) { + showBanner(true); + } + + if (daysToCloudFreeEnd <= 10) { + showBanner(true); + } + } + }, []); + + const showBanner = (show = false) => { + let dRange = DismissShowRange.Zero; + if (daysToCloudFreeEnd >= 90) { + dRange = DismissShowRange.GreaterThanEqual90; + } + + if (daysToCloudFreeEnd < 90 && daysToCloudFreeEnd > 60) { + dRange = DismissShowRange.BetweenNinetyAnd60; + } + + if (daysToCloudFreeEnd <= 60 && daysToCloudFreeEnd > 30) { + dRange = DismissShowRange.SixtyTo31; + } + + if (daysToCloudFreeEnd <= 30 && daysToCloudFreeEnd > 10) { + dRange = DismissShowRange.ThirtyTo11; + } + + // ideally this case should not happen because snooze button is not shown when TenTo1 days are remaining + if (daysToCloudFreeEnd <= 10 && daysToCloudFreeEnd > 0) { + dRange = DismissShowRange.TenTo1; + } + + const snoozeInfo: ToPaidPlanDismissPreference = { + range: dRange, + show, + }; + + dispatch(savePreferences(currentUser.id, [{ + category: Preferences.TO_PAID_PLAN_NUDGE, + name: CloudBanners.NUDGE_TO_PAID_PLAN_SNOOZED, + user_id: currentUser.id, + value: JSON.stringify(snoozeInfo), + }])); + }; + + if (!cloudFreeDeprecated) { + return null; + } + + if (!show) { + return null; + } + + if (!isAdmin) { + return null; + } + + if (!currentProductStarter) { + return null; + } + + let message = { + id: 'cloud_billing.nudge_to_paid.announcement_bar', + defaultMessage: 'Cloud Free will be deprecated on {date}. To keep your workspace, upgrade to a paid plan', + values: { + date: moment(cloudFreeCloseMoment, 'YYYYMMDD').format('MMMM DD, YYYY'), + }, + }; + + if (daysToCloudFreeEnd < 0) { + message = { + id: 'cloud_billing.nudge_to_paid.announcement_bar_deprecated', + defaultMessage: 'Cloud Free was deprecated. To keep your workspace, upgrade to a paid plan', + } as any; + } + + const announcementType = (daysToCloudFreeEnd <= 10) ? AnnouncementBarTypes.CRITICAL : AnnouncementBarTypes.ANNOUNCEMENT; + + return ( + 10} + onButtonClick={openPricingModal} + modalButtonText={t('cloud_billing.nudge_to_paid.view_plans')} + modalButtonDefaultText='View plans' + message={} + showLinkAsButton={true} + handleClose={showBanner} + /> + ); +}; + +export const ToPaidNudgeBanner = () => { + const {formatMessage} = useIntl(); + + const [openSalesLink] = useOpenSalesLink(); + const openPurchaseModal = useOpenCloudPurchaseModal({}); + + const product = useSelector(selectSubscriptionProduct); + const cloudFreeDeprecated = useSelector(deprecateCloudFree); + const currentProductStarter = product?.sku === CloudProducts.STARTER; + + if (!cloudFreeDeprecated) { + return null; + } + + if (!currentProductStarter) { + return null; + } + + const now = moment(Date.now()); + const cloudFreeEndDate = moment(cloudFreeCloseMoment, 'YYYYMMDD'); + const daysToCloudFreeEnd = cloudFreeEndDate.diff(now, 'days'); + + const title = ( + + ); + + const description = ( + + ); + + const viewPlansAction = ( + + ); + + const contactSalesAction = ( + + ); + + const bannerMode = (daysToCloudFreeEnd <= 10) ? 'danger' : 'info'; + + return ( + + ); +}; diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx index af797c5f92..e9061333a5 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.test.tsx @@ -2,11 +2,9 @@ // See LICENSE.txt for license information. import React from 'react'; +import {screen} from '@testing-library/react'; -import {Provider} from 'react-redux'; - -import {mountWithIntl} from 'tests/helpers/intl-test-helper'; -import mockStore from 'tests/test_store'; +import {renderWithIntlAndStore} from 'tests/react_testing_utils'; import {CloudProducts, RecurringIntervals} from 'utils/constants'; import {ToYearlyNudgeBanner, ToYearlyNudgeBannerDismissable} from './to_yearly_nudge_banner'; @@ -42,7 +40,7 @@ const initialState = { }, }; -describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () => { +describe('ToYearlyNudgeBannerDismissable', () => { test('should show for admins cloud professional monthly', () => { const state = JSON.parse(JSON.stringify(initialState)); state.entities.users.profiles = { @@ -63,14 +61,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }, }; - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); + renderWithIntlAndStore(, state); - expect(wrapper.find('AnnouncementBar').exists()).toBe(true); + screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar'); }); test('should NOT show for NON admins', () => { @@ -93,14 +86,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }, }; - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); + renderWithIntlAndStore(, state); - expect(wrapper.find('AnnouncementBar').exists()).toBe(false); + expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); test('should NOT show for admins on cloud free', () => { @@ -123,14 +111,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }, }; - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); + renderWithIntlAndStore(, state); - expect(wrapper.find('AnnouncementBar').exists()).toBe(false); + expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); test('should NOT show for admins on cloud enterprise', () => { @@ -153,14 +136,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }, }; - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); + renderWithIntlAndStore(, state); - expect(wrapper.find('AnnouncementBar').exists()).toBe(false); + expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); test('should NOT show for admins on cloud pro annual', () => { @@ -182,15 +160,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }, }, }; + renderWithIntlAndStore(, state); - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); - - expect(wrapper.find('AnnouncementBar').exists()).toBe(false); + expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); test('should NOT show for admins when banner was dismissed in preferences', () => { @@ -200,10 +172,10 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }; state.entities.preferences = { myPreferences: { - 'cloud_yearly_nudge_banner--nudge_to_yearly_banner_dismissed': { - category: 'cloud_yearly_nudge_banner', - name: 'nudge_to_yearly_banner_dismissed', - value: 'true', + 'to_cloud_yearly_plan_nudge--nudge_to_cloud_yearly_plan_snoozed': { + category: 'to_cloud_yearly_plan_nudge', + name: 'nudge_to_cloud_yearly_plan_snoozed', + value: '{"range": 0, "show": false}', }, }, }; @@ -221,19 +193,13 @@ describe('components/admin_console/billing/ToYearlyNudgeBannerDismissable', () = }, }, }; + renderWithIntlAndStore(, state); - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); - - expect(wrapper.find('AnnouncementBar').exists()).toBe(false); + expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-announcement-bar')).toThrow(); }); }); -describe('components/admin_console/billing/ToYearlyNudgeBanner', () => { +describe('ToYearlyNudgeBanner', () => { test('should show for cloud professional monthly', () => { const state = JSON.parse(JSON.stringify(initialState)); state.entities.cloud = { @@ -251,14 +217,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBanner', () => { }, }; - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); + renderWithIntlAndStore(, state); - expect(wrapper.find('AlertBanner').exists()).toBe(true); + screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner'); }); test('should NOT show for non cloud professional monthly', () => { @@ -278,13 +239,9 @@ describe('components/admin_console/billing/ToYearlyNudgeBanner', () => { }, }; - const store = mockStore(state); - const wrapper = mountWithIntl( - - - , - ); + renderWithIntlAndStore(, state); - expect(wrapper.find('AlertBanner').exists()).toBe(false); + expect(() => screen.getByTestId('cloud-pro-monthly-deprecation-alert-banner')).toThrow(); }); }); + diff --git a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.tsx b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.tsx index 1bbf9823b3..f2eac86e69 100644 --- a/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.tsx +++ b/webapp/channels/src/components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner.tsx @@ -1,16 +1,16 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {useEffect} from 'react'; import {useDispatch, useSelector} from 'react-redux'; import {useIntl, FormattedMessage} from 'react-intl'; +import moment from 'moment'; import AlertBanner from 'components/alert_banner'; import useOpenCloudPurchaseModal from 'components/common/hooks/useOpenCloudPurchaseModal'; import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import AnnouncementBar from 'components/announcement_bar/default_announcement_bar'; -import {SalesInquiryIssue} from 'selectors/cloud'; import {getSubscriptionProduct as selectSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud'; import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users'; import {savePreferences} from 'mattermost-redux/actions/preferences'; @@ -23,12 +23,35 @@ import {GlobalState} from '@mattermost/types/store'; import './to_yearly_nudge_banner.scss'; +enum DismissShowRange { + GreaterThanEqual90 = '>=90', + BetweenNinetyAnd60 = '89-61', + SixtyTo31 = '60-31', + ThirtyTo11 = '30-11', + TenTo1 = '10-1', + Zero = '0' +} + +const cloudProMonthlyCloseMoment = '20230727'; + +interface ToYearlyPlanDismissPreference { + + // range represents the range for the days to the deprecation of cloud free e.g. in 30 to 10 days to deprecate cloud free + // Incase of dismissing the banner, range represents the time (days) period when this banner was dismissed. + // This is important because in case the banner was dismissed for a certain period, it helps us know that we should not show it again for that period. + range: DismissShowRange; + show: boolean; +} + const ToYearlyNudgeBannerDismissable = () => { const dispatch = useDispatch(); const openPurchaseModal = useOpenCloudPurchaseModal({}); - const nudgeDismissed = useSelector((state: GlobalState) => getPreference(state, Preferences.CLOUD_YEARLY_NUDGE_BANNER, CloudBanners.NUDGE_TO_YEARLY_BANNER_DISMISSED)) === 'true'; + const snoozePreferenceVal = useSelector((state: GlobalState) => getPreference(state, Preferences.TO_CLOUD_YEARLY_PLAN_NUDGE, CloudBanners.NUDGE_TO_CLOUD_YEARLY_PLAN_SNOOZED, '{"range": 0, "show": true}')); + const snoozeInfo = JSON.parse(snoozePreferenceVal) as ToYearlyPlanDismissPreference; + const show = snoozeInfo.show; + const currentUser = useSelector(getCurrentUser); const isAdmin = useSelector(isCurrentUserSystemAdmin); const product = useSelector(selectSubscriptionProduct); @@ -36,16 +59,75 @@ const ToYearlyNudgeBannerDismissable = () => { const currentProductIsMonthly = product?.recurring_interval === RecurringIntervals.MONTH; const currentProductProMonthly = currentProductProfessional && currentProductIsMonthly; - const savedDismissedPref = () => { + const now = moment(Date.now()); + const proMonthlyEndDate = moment(cloudProMonthlyCloseMoment, 'YYYYMMDD'); + const daysToProMonthlyEnd = proMonthlyEndDate.diff(now, 'days'); + + const snoozedForRange = (range: DismissShowRange) => { + return snoozeInfo.range === range; + }; + + useEffect(() => { + if (!snoozeInfo.show) { + if (daysToProMonthlyEnd >= 90 && !snoozedForRange(DismissShowRange.GreaterThanEqual90)) { + showBanner(true); + } + + if (daysToProMonthlyEnd < 90 && daysToProMonthlyEnd > 60 && !snoozedForRange(DismissShowRange.BetweenNinetyAnd60)) { + showBanner(true); + } + + if (daysToProMonthlyEnd <= 60 && daysToProMonthlyEnd > 30 && !snoozedForRange(DismissShowRange.SixtyTo31)) { + showBanner(true); + } + + if (daysToProMonthlyEnd <= 30 && daysToProMonthlyEnd > 10 && !snoozedForRange(DismissShowRange.ThirtyTo11)) { + showBanner(true); + } + + if (daysToProMonthlyEnd <= 10) { + showBanner(true); + } + } + }, []); + + const showBanner = (show = false) => { + let dRange = DismissShowRange.Zero; + if (daysToProMonthlyEnd >= 90) { + dRange = DismissShowRange.GreaterThanEqual90; + } + + if (daysToProMonthlyEnd < 90 && daysToProMonthlyEnd > 60) { + dRange = DismissShowRange.BetweenNinetyAnd60; + } + + if (daysToProMonthlyEnd <= 60 && daysToProMonthlyEnd > 30) { + dRange = DismissShowRange.SixtyTo31; + } + + if (daysToProMonthlyEnd <= 30 && daysToProMonthlyEnd > 10) { + dRange = DismissShowRange.ThirtyTo11; + } + + // ideally this case should not happen because snooze button is not shown when TenTo1 days are remaining + if (daysToProMonthlyEnd <= 10 && daysToProMonthlyEnd > 0) { + dRange = DismissShowRange.TenTo1; + } + + const snoozeInfo: ToYearlyPlanDismissPreference = { + range: dRange, + show, + }; + dispatch(savePreferences(currentUser.id, [{ - category: Preferences.CLOUD_YEARLY_NUDGE_BANNER, - name: CloudBanners.NUDGE_TO_YEARLY_BANNER_DISMISSED, + category: Preferences.TO_CLOUD_YEARLY_PLAN_NUDGE, + name: CloudBanners.NUDGE_TO_CLOUD_YEARLY_PLAN_SNOOZED, user_id: currentUser.id, - value: 'true', + value: JSON.stringify(snoozeInfo), }])); }; - if (nudgeDismissed) { + if (!show) { return null; } @@ -57,21 +139,30 @@ const ToYearlyNudgeBannerDismissable = () => { return null; } - const message = { - id: 'cloud_billing.nudge_to_yearly.announcement_bar', - defaultMessage: 'Simplify your billing and switch to an annual plan today', - }; + const message = ( + + ); + + const announcementType = (daysToProMonthlyEnd <= 10) ? AnnouncementBarTypes.CRITICAL : AnnouncementBarTypes.ANNOUNCEMENT; return ( 10} onButtonClick={() => openPurchaseModal({trackingLocation: 'to_yearly_nudge_annoucement_bar'})} modalButtonText={t('cloud_billing.nudge_to_yearly.learn_more')} modalButtonDefaultText='Learn more' - message={} + message={message} showLinkAsButton={true} - handleClose={savedDismissedPref} + handleClose={showBanner} /> ); }; @@ -79,7 +170,7 @@ const ToYearlyNudgeBannerDismissable = () => { const ToYearlyNudgeBanner = () => { const {formatMessage} = useIntl(); - const openSalesLink = useOpenSalesLink(SalesInquiryIssue.AboutPurchasing); + const [openSalesLink] = useOpenSalesLink(); const openPurchaseModal = useOpenCloudPurchaseModal({}); const product = useSelector(selectSubscriptionProduct); @@ -91,17 +182,22 @@ const ToYearlyNudgeBanner = () => { return null; } + const now = moment(Date.now()); + const proMonthlyEndDate = moment(cloudProMonthlyCloseMoment, 'YYYYMMDD'); + const daysToProMonthlyEnd = proMonthlyEndDate.diff(now, 'days'); + const title = ( ); const description = ( ); @@ -123,9 +219,12 @@ const ToYearlyNudgeBanner = () => { ); + const bannerMode = (daysToProMonthlyEnd <= 10) ? 'danger' : 'info'; + return ( )} @@ -309,9 +309,9 @@ export const InvoiceInfo = ({invoice, product, fullCharges, partialCharges, hasM >
diff --git a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_feedback.tsx b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_feedback.tsx index 4b103160cf..25c73d3b73 100644 --- a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_feedback.tsx +++ b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_feedback.tsx @@ -6,7 +6,7 @@ import React from 'react'; import {injectIntl, WrappedComponentProps} from 'react-intl'; import {Feedback} from '@mattermost/types/cloud'; -import FeedbackModal from 'components/feedback_modal/feedback'; +import FeedbackModal, {FeedbackOption} from 'components/feedback_modal/feedback'; type Props = { onSubmit: (deleteFeedback: Feedback) => void; @@ -28,23 +28,35 @@ const DeleteFeedbackModal = (props: Props) => { defaultMessage: 'Delete Workspace', }); - const deleteFeedbackOptions = [ - props.intl.formatMessage({ - id: 'feedback.deleteWorkspace.feedbackNoValue', - defaultMessage: 'No longer found value', - }), - props.intl.formatMessage({ - id: 'feedback.deleteWorkspace.feedbackMoving', - defaultMessage: 'Moving to a different solution', - }), - props.intl.formatMessage({ - id: 'feedback.deleteWorkspace.feedbackMistake', - defaultMessage: 'Created a workspace by mistake', - }), - props.intl.formatMessage({ - id: 'feedback.deleteWorkspace.feedbackHosting', - defaultMessage: 'Moving to hosting my own Mattermost instance (self-hosted)', - }), + const deleteFeedbackOptions: FeedbackOption[] = [ + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.deleteWorkspace.feedbackNoValue', + defaultMessage: 'No longer found value', + }), + submissionValue: 'No longer found value', + }, + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.deleteWorkspace.feedbackMoving', + defaultMessage: 'Moving to a different solution', + }), + submissionValue: 'Moving to a different solution', + }, + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.deleteWorkspace.feedbackMistake', + defaultMessage: 'Created a workspace by mistake', + }), + submissionValue: 'Created a workspace by mistake', + }, + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.deleteWorkspace.feedbackHosting', + defaultMessage: 'Moving to hosting my own Mattermost instance (self-hosted)', + }), + submissionValue: 'Moving to hosting my own Mattermost instance (self-hosted)', + }, ]; return ( diff --git a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx index ef8ec25dad..ccdf364756 100644 --- a/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx +++ b/webapp/channels/src/components/admin_console/billing/delete_workspace/delete_workspace_cta.tsx @@ -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() { }} />
- - + ); diff --git a/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.scss b/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.scss index 2e5b6800f3..413d71dcdd 100644 --- a/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.scss +++ b/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.scss @@ -3,3 +3,77 @@ transform: translateY(50%); } } + +.ResultModal__small { + .modal-header { + .close { + &:hover, + &:active, + &:focus, + &:active:focus { + background-color: rgba(var(--center-channel-color-rgb), 0.08); + color: rgba(var(--center-channel-color-rgb), 0.72); + opacity: 1; + } + + top: 26px; + right: 26px; + width: 24px; + height: 24px; + border-radius: 4px; + color: rgba(var(--center-channel-color-rgb), 0.56) !important; + font-family: + 'Open Sans', + sans-serif; + font-size: 32px; + font-weight: 400; + } + } + + .modal-dialog { + position: absolute; + top: 50%; + left: 50%; + width: 600px; + height: 360px; + border: 1px solid rgba(var(--center-channel-color-rgb), 0.08); + margin: auto; + border-radius: 8px; + transform: translate(-50%, -50%) !important; + + .modal-header { + border: none; + background: var(--center-channel-bg) !important; + } + + .modal-content { + height: 100%; + border-radius: 8px; + + .IconMessage__svg-wrapper { + margin-left: 0; + } + + .IconMessage-h3 { + margin-top: 0; + } + + .IconMessage-sub { + max-width: 504px; + margin-top: 0; + } + + .IconMessage-buttons { + justify-content: right; + padding-right: 24px; + margin-top: 60px; + + .btn { + font-family: 'Open sans', sans-serif; + font-size: 12px; + font-weight: 600; + } + } + } + } +} diff --git a/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.tsx b/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.tsx index b84c72ee90..6e9948756a 100644 --- a/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.tsx +++ b/webapp/channels/src/components/admin_console/billing/delete_workspace/result_modal.tsx @@ -7,17 +7,17 @@ import {useDispatch, useSelector} from 'react-redux'; import IconMessage from 'components/purchase_modal/icon_message'; import FullScreenModal from 'components/widgets/modals/full_screen_modal'; +import {useOpenCloudZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm'; import {closeModal} from 'actions/views/modals'; import {isModalOpen} from 'selectors/views/modals'; import {GlobalState} from 'types/store'; +import {Modal} from 'react-bootstrap'; import './result_modal.scss'; -import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; -import {InquiryType} from 'selectors/cloud'; - type Props = { + type?: string; onHide?: () => void; icon: JSX.Element; title: JSX.Element; @@ -30,48 +30,77 @@ type Props = { ignoreExit: boolean; }; -export default function ResultModal(props: Props) { +export default function ResultModal({type, icon, title, subtitle, primaryButtonText, primaryButtonHandler, identifier, contactSupportButtonVisible, resultType, ignoreExit, onHide}: Props) { const dispatch = useDispatch(); - const openContactUs = useOpenSalesLink(undefined, InquiryType.Technical); + const [openContactSupport] = useOpenCloudZendeskSupportForm('Delete workspace', ''); const isResultModalOpen = useSelector((state: GlobalState) => - isModalOpen(state, props.identifier), + isModalOpen(state, identifier), ); - const onHide = () => { - dispatch(closeModal(props.identifier)); - if (typeof props.onHide === 'function') { - props.onHide(); - } + const handleHide = () => { + dispatch(closeModal(identifier)); + onHide?.(); }; - const modalType = `delete-workspace-result_modal__${props.resultType}`; + const modalType = `delete-workspace-result_modal__${resultType}`; + if (type === 'small') { + return ( + + +
+ : + undefined + } + tertiaryButtonHandler={contactSupportButtonVisible ? openContactSupport : undefined} + /> +
+
+ ); + } return (
: - undefined + />) : undefined } - tertiaryButtonHandler={props.contactSupportButtonVisible ? openContactUs : undefined} + tertiaryButtonHandler={contactSupportButtonVisible ? openContactSupport : undefined} />
diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx index b65bc918e6..e4f6e098f4 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.test.tsx @@ -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', }, ]; diff --git a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx index 896b7f0b63..c93be8af8e 100644 --- a/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx +++ b/webapp/channels/src/components/admin_console/billing/invoice_user_count.tsx @@ -18,8 +18,8 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele if (onPremUsers) { return ( ); @@ -45,10 +45,10 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele return ( ); @@ -56,11 +56,11 @@ export default function InvoiceUserCount({invoice}: {invoice: Invoice}): JSX.Ele return ( ); diff --git a/webapp/channels/src/components/admin_console/bleve_settings.jsx b/webapp/channels/src/components/admin_console/bleve_settings.jsx index 57b061aa96..8961b34bd6 100644 --- a/webapp/channels/src/components/admin_console/bleve_settings.jsx +++ b/webapp/channels/src/components/admin_console/bleve_settings.jsx @@ -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 { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/boolean_setting.tsx b/webapp/channels/src/components/admin_console/boolean_setting.tsx index 39490c97de..f114962661 100644 --- a/webapp/channels/src/components/admin_console/boolean_setting.tsx +++ b/webapp/channels/src/components/admin_console/boolean_setting.tsx @@ -40,7 +40,7 @@ export default class BooleanSetting extends React.PureComponent { private handleChange = (e: React.ChangeEvent) => { this.props.onChange(this.props.id, e.target.value === 'true'); - } + }; public render() { let helpText; diff --git a/webapp/channels/src/components/admin_console/cluster_settings.jsx b/webapp/channels/src/components/admin_console/cluster_settings.jsx index 0aaa90286e..b53aa7ec9b 100644 --- a/webapp/channels/src/components/admin_console/cluster_settings.jsx +++ b/webapp/channels/src/components/admin_console/cluster_settings.jsx @@ -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 { /> ); - } + }; } const style = { diff --git a/webapp/channels/src/components/admin_console/cluster_table.jsx b/webapp/channels/src/components/admin_console/cluster_table.jsx index 62c7fcf27f..aba8bb7234 100644 --- a/webapp/channels/src/components/admin_console/cluster_table.jsx +++ b/webapp/channels/src/components/admin_console/cluster_table.jsx @@ -15,7 +15,7 @@ export default class ClusterTable extends React.PureComponent { static propTypes = { clusterInfos: PropTypes.array.isRequired, reload: PropTypes.func.isRequired, - } + }; render() { var versionMismatch = ( diff --git a/webapp/channels/src/components/admin_console/cluster_table_container.jsx b/webapp/channels/src/components/admin_console/cluster_table_container.jsx index 99b36e4df1..bacb039ce0 100644 --- a/webapp/channels/src/components/admin_console/cluster_table_container.jsx +++ b/webapp/channels/src/components/admin_console/cluster_table_container.jsx @@ -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) { diff --git a/webapp/channels/src/components/admin_console/color_setting.test.tsx b/webapp/channels/src/components/admin_console/color_setting.test.tsx index c74d0162c4..5b18ceb6de 100644 --- a/webapp/channels/src/components/admin_console/color_setting.test.tsx +++ b/webapp/channels/src/components/admin_console/color_setting.test.tsx @@ -2,15 +2,16 @@ // See LICENSE.txt for license information. import React from 'react'; -import {shallow} from 'enzyme'; import ColorSetting from 'components/admin_console/color_setting'; +import {renderWithIntl} from 'tests/react_testing_utils'; +import {screen} from '@testing-library/react'; describe('components/ColorSetting', () => { test('should match snapshot, all', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const wrapper = shallow( + const {container} = renderWithIntl( { disabled={false} />, ); - expect(wrapper).toMatchSnapshot(); + expect(screen.getByText('helptext')).toBeInTheDocument(); + expect(screen.getByTestId('color-inputColorValue')).not.toBeDisabled(); + + expect(container).toMatchSnapshot(); }); test('should match snapshot, no help text', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const wrapper = shallow( + const {container} = renderWithIntl( { disabled={false} />, ); - expect(wrapper).toMatchSnapshot(); + expect(screen.queryByText('helptext')).not.toBeInTheDocument(); + + expect(container).toMatchSnapshot(); }); test('should match snapshot, disabled', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const wrapper = shallow( + const {container} = renderWithIntl( { disabled={true} />, ); - expect(wrapper).toMatchSnapshot(); + expect(screen.getByTestId('color-inputColorValue')).toBeDisabled(); + expect(screen.queryByText('helptext')).not.toBeInTheDocument(); + + expect(container).toMatchSnapshot(); }); test('should match snapshot, clicked on color setting', () => { function emptyFunction() {} //eslint-disable-line no-empty-function - const wrapper = shallow( + const {container} = renderWithIntl( { disabled={false} />, ); + expect(screen.getByTestId('color-inputColorValue')).not.toBeDisabled(); + expect(screen.queryByText('helptext')).toBeInTheDocument(); - expect(wrapper).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); }); diff --git a/webapp/channels/src/components/admin_console/color_setting.tsx b/webapp/channels/src/components/admin_console/color_setting.tsx index b2fdd92cf0..54af4466d8 100644 --- a/webapp/channels/src/components/admin_console/color_setting.tsx +++ b/webapp/channels/src/components/admin_console/color_setting.tsx @@ -21,7 +21,7 @@ export default class ColorSetting extends React.PureComponent { if (this.props.onChange) { this.props.onChange(this.props.id, color); } - } + }; public render() { return ( diff --git a/webapp/channels/src/components/admin_console/compliance_reports/compliance_reports.tsx b/webapp/channels/src/components/admin_console/compliance_reports/compliance_reports.tsx index e80b9ca06a..e85e387664 100644 --- a/webapp/channels/src/components/admin_console/compliance_reports/compliance_reports.tsx +++ b/webapp/channels/src/components/admin_console/compliance_reports/compliance_reports.tsx @@ -94,7 +94,7 @@ export default class ComplianceReports extends React.PureComponent this.props.actions.getComplianceReports().then( () => this.setState({loadingReports: false}), ); - } + }; runReport = (e: React.MouseEvent) => { e.preventDefault(); @@ -131,7 +131,7 @@ export default class ComplianceReports extends React.PureComponent this.props.actions.getComplianceReports(); }, ); - } + }; getDateTime(millis: number) { const date = new Date(millis); diff --git a/webapp/channels/src/components/admin_console/custom_terms_of_service_settings/custom_terms_of_service_settings.tsx b/webapp/channels/src/components/admin_console/custom_terms_of_service_settings/custom_terms_of_service_settings.tsx index 3b32a05e39..4342b2d7f2 100644 --- a/webapp/channels/src/components/admin_console/custom_terms_of_service_settings/custom_terms_of_service_settings.tsx +++ b/webapp/channels/src/components/admin_console/custom_terms_of_service_settings/custom_terms_of_service_settings.tsx @@ -73,7 +73,7 @@ export default class CustomTermsOfServiceSettings extends AdminSettings ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/data_grid/data_grid.tsx b/webapp/channels/src/components/admin_console/data_grid/data_grid.tsx index f6f696827d..37c4665c05 100644 --- a/webapp/channels/src/components/admin_console/data_grid/data_grid.tsx +++ b/webapp/channels/src/components/admin_console/data_grid/data_grid.tsx @@ -82,7 +82,7 @@ class DataGrid extends React.PureComponent { static defaultProps = { term: '', searchPlaceholder: '', - } + }; public constructor(props: Props) { super(props); @@ -134,7 +134,7 @@ class DataGrid extends React.PureComponent { }); this.setState({visibleColumns}); - } + }; private renderRows(): JSX.Element { const {rows, rowsContainerStyles} = this.props; @@ -219,19 +219,19 @@ class DataGrid extends React.PureComponent { if (!this.props.loading) { this.props.nextPage(); } - } + }; private previousPage = () => { if (!this.props.loading) { this.props.previousPage(); } - } + }; private search = (term: string) => { if (this.props.onSearch) { this.props.onSearch(term); } - } + }; private renderFooter = (): JSX.Element | null => { const {startCount, endCount, total} = this.props; @@ -286,7 +286,7 @@ class DataGrid extends React.PureComponent { } return footer; - } + }; public render() { return ( diff --git a/webapp/channels/src/components/admin_console/data_grid/data_grid_search.tsx b/webapp/channels/src/components/admin_console/data_grid/data_grid_search.tsx index d347a7b2c1..9b514c0a6b 100644 --- a/webapp/channels/src/components/admin_console/data_grid/data_grid_search.tsx +++ b/webapp/channels/src/components/admin_console/data_grid/data_grid_search.tsx @@ -32,7 +32,7 @@ class DataGridSearch extends React.PureComponent { static defaultProps = { placeholder: '', term: '', - } + }; public constructor(props: Props) { super(props); @@ -46,7 +46,7 @@ class DataGridSearch extends React.PureComponent { const term = e.target.value; this.setState({term}); this.props.onSearch(term); - } + }; resetSearch = () => { this.props.onSearch(''); diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/channel_list/channel_list.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/channel_list/channel_list.tsx index 37c996dc17..0e5711134e 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/channel_list/channel_list.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/channel_list/channel_list.tsx @@ -58,14 +58,14 @@ export default class ChannelList extends React.PureComponent { componentDidMount = () => { this.loadPage(0, PAGE_SIZE * 2); - } + }; private setStateLoading = (loading: boolean) => { this.setState({loading}); - } + }; private setStatePage = (page: number) => { this.setState({page}); - } + }; private loadPage = async (page: number, pageSize = PAGE_SIZE) => { if (this.props.policyId) { @@ -73,26 +73,26 @@ export default class ChannelList extends React.PureComponent { await this.props.actions.getDataRetentionCustomPolicyChannels(this.props.policyId, page, pageSize); this.setStateLoading(false); } - } + }; private nextPage = () => { const page = this.state.page + 1; this.loadPage(page + 1); this.setStatePage(page); - } + }; private previousPage = () => { const page = this.state.page - 1; this.loadPage(page + 1); this.setStatePage(page); - } + }; private getVisibleTotalCount = (): number => { const {channelsToAdd, channelsToRemove, totalCount} = this.props; const channelsToAddCount = Object.keys(channelsToAdd).length; const channelsToRemoveCount = Object.keys(channelsToRemove).length; return totalCount + (channelsToAddCount - channelsToRemoveCount); - } + }; public getPaginationProps = (): {startCount: number; endCount: number; total: number} => { const {page} = this.state; @@ -105,7 +105,7 @@ export default class ChannelList extends React.PureComponent { endCount = endCount > total ? total : endCount; return {startCount, endCount, total}; - } + }; private removeChannel = (channel: ChannelWithTeamData) => { const {channelsToRemove} = this.props; @@ -122,7 +122,7 @@ export default class ChannelList extends React.PureComponent { } this.setStatePage(page); - } + }; getColumns = (): Column[] => { const name = ( @@ -157,7 +157,7 @@ export default class ChannelList extends React.PureComponent { fixed: true, }, ]; - } + }; getRows = () => { const {page} = this.state; @@ -235,11 +235,11 @@ export default class ChannelList extends React.PureComponent { }, }; }); - } + }; onSearch = async (searchTerm: string) => { this.props.actions.setChannelListSearch(searchTerm); - } + }; public async componentDidUpdate(prevProps: Props) { const {policyId, searchTerm, filters} = this.props; const filtersModified = !isEqual(prevProps.filters, this.props.filters); @@ -284,7 +284,7 @@ export default class ChannelList extends React.PureComponent { filters.team_ids = teamIds.value as string[]; } this.props.actions.setChannelListFilters(filters); - } + }; render() { const rows: Row[] = this.getRows(); const columns: Column[] = this.getColumns(); diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx index 1c296d540f..96d1f534ce 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/custom_policy_form/custom_policy_form.tsx @@ -93,19 +93,19 @@ export default class CustomPolicyForm extends React.PureComponent openAddChannel = () => { this.setState({addChannelOpen: true}); - } + }; closeAddChannel = () => { this.setState({addChannelOpen: false}); - } + }; openAddTeam = () => { this.setState({addTeamOpen: true}); - } + }; closeAddTeam = () => { this.setState({addTeamOpen: false}); - } + }; getMessageRetentionDefaultInputValue = (): string => { if (!this.props.policy || Object.keys(this.props.policy).length === 0 || (this.props.policy && this.props.policy.post_duration === -1)) { return ''; @@ -114,7 +114,7 @@ export default class CustomPolicyForm extends React.PureComponent return (this.props.policy.post_duration / 365).toString(); } return this.props.policy.post_duration.toString(); - } + }; getMessageRetentionDefaultDropdownValue = () => { if (!this.props.policyId || (this.props.policy && this.props.policy.post_duration === -1)) { return keepForeverOption(); @@ -123,11 +123,11 @@ export default class CustomPolicyForm extends React.PureComponent return yearsOption(); } return daysOption(); - } + }; componentDidMount = async () => { this.loadPage(); - } + }; private loadPage = async () => { if (this.props.policyId) { await this.props.actions.fetchPolicy(this.props.policyId); @@ -137,7 +137,7 @@ export default class CustomPolicyForm extends React.PureComponent messageRetentionDropdownValue: this.getMessageRetentionDefaultDropdownValue(), }); } - } + }; addToNewTeams = (teams: Team[]) => { let {removedTeamsCount} = this.state; @@ -152,7 +152,7 @@ export default class CustomPolicyForm extends React.PureComponent }); this.setState({newTeams: {...newTeams}, removedTeams: {...removedTeams}, removedTeamsCount, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; addToRemovedTeams = (team: Team) => { let {removedTeamsCount} = this.state; @@ -165,7 +165,7 @@ export default class CustomPolicyForm extends React.PureComponent } this.setState({removedTeams: {...removedTeams}, newTeams: {...newTeams}, removedTeamsCount, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; addToNewChannels = (channels: ChannelWithTeamData[]) => { let {removedChannelsCount} = this.state; @@ -180,7 +180,7 @@ export default class CustomPolicyForm extends React.PureComponent }); this.setState({newChannels: {...newChannels}, removedChannels: {...removedChannels}, removedChannelsCount, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; addToRemovedChannels = (channel: ChannelWithTeamData) => { let {removedChannelsCount} = this.state; @@ -193,7 +193,7 @@ export default class CustomPolicyForm extends React.PureComponent } this.setState({removedChannels: {...removedChannels}, newChannels: {...newChannels}, removedChannelsCount, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; getTeamsToExclude = () => { const {teams} = this.props; @@ -210,7 +210,7 @@ export default class CustomPolicyForm extends React.PureComponent teamsToDisplay = [...includeTeamsList, ...teamsToDisplay]; } return teamsToDisplay; - } + }; handleSubmit = async () => { const {policyName, messageRetentionInputValue, messageRetentionDropdownValue, newTeams, removedTeams, newChannels, removedChannels} = this.state; const {policyId, policy} = this.props; @@ -302,7 +302,7 @@ export default class CustomPolicyForm extends React.PureComponent this.props.actions.setNavigationBlocked(false); getHistory().push('/admin_console/compliance/data_retention_settings'); } - } + }; render = () => { const {serverError, formErrorText} = this.state; @@ -531,5 +531,5 @@ export default class CustomPolicyForm extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/data_retention_settings.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/data_retention_settings.tsx index a23b555546..468ea078aa 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/data_retention_settings.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/data_retention_settings.tsx @@ -65,9 +65,9 @@ export default class DataRetentionSettings extends React.PureComponent { await this.props.actions.deleteDataRetentionCustomPolicy(id); this.loadPage(0); - } + }; - includeBoards = this.props.config.PluginSettings?.PluginStates?.focalboard?.Enable && this.props.config.FeatureFlags?.BoardsDataRetention + includeBoards = this.props.config.PluginSettings?.PluginStates?.focalboard?.Enable && this.props.config.FeatureFlags?.BoardsDataRetention; getGlobalPolicyColumns = (): Column[] => { const columns: Column[] = [ { @@ -119,7 +119,7 @@ export default class DataRetentionSettings extends React.PureComponent { const columns: Column[] = [ { @@ -156,7 +156,7 @@ export default class DataRetentionSettings extends React.PureComponent { if (!enabled) { return ( @@ -187,7 +187,7 @@ export default class DataRetentionSettings extends React.PureComponent ); - } + }; getGlobalPolicyRows = (): Row[] => { const {DataRetentionSettings} = this.props.config; return [{ @@ -240,7 +240,7 @@ export default class DataRetentionSettings extends React.PureComponent { if (policy.channel_count === 0 && policy.team_count === 0) { return ( @@ -260,7 +260,7 @@ export default class DataRetentionSettings extends React.PureComponent ); - } + }; getCustomPolicyRows = (startCount: number, endCount: number): Row[] => { let policies = Object.values(this.props.customPolicies); policies = policies.slice(startCount - 1, endCount); @@ -333,18 +333,18 @@ export default class DataRetentionSettings extends React.PureComponent { await this.loadPage(this.state.page); - } + }; private nextPage = () => { this.loadPage(this.state.page + 1); - } + }; private previousPage = () => { this.loadPage(this.state.page - 1); - } + }; public getPaginationProps = (): {startCount: number; endCount: number; total: number} => { const {page} = this.state; @@ -354,17 +354,17 @@ export default class DataRetentionSettings extends React.PureComponent total ? total : endCount; return {startCount, endCount, total}; - } + }; showEditJobTime = (value: boolean) => { this.setState({showEditJobTime: value}); - } + }; componentDidUpdate = (prevProps: Props, prevState: State) => { if (prevState.showEditJobTime !== this.state.showEditJobTime && this.state.showEditJobTime) { this.inputRef.current?.focus(); } - } + }; handleCreateJob = async (e?: React.SyntheticEvent) => { e?.preventDefault(); @@ -382,7 +382,7 @@ export default class DataRetentionSettings extends React.PureComponent { const {DataRetentionSettings} = this.props.config; @@ -417,7 +417,7 @@ export default class DataRetentionSettings extends React.PureComponent ); - } + }; getJobTimeOptions = () => { const options: OptionType[] = []; return () => { @@ -445,7 +445,7 @@ export default class DataRetentionSettings extends React.PureComponent { @@ -653,5 +653,5 @@ export default class DataRetentionSettings extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx index ac10fce6b6..596a9d965c 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/global_policy_form/global_policy_form.tsx @@ -60,7 +60,7 @@ export default class GlobalPolicyForm extends React.PureComponent }; } - includeBoards = this.props.config.PluginSettings?.PluginStates?.focalboard?.Enable && this.props.config.FeatureFlags?.BoardsDataRetention + includeBoards = this.props.config.PluginSettings?.PluginStates?.focalboard?.Enable && this.props.config.FeatureFlags?.BoardsDataRetention; getDefaultInputValue = (isEnabled: boolean | undefined, days: number | undefined): string => { if (!isEnabled || days === undefined) { @@ -70,7 +70,7 @@ export default class GlobalPolicyForm extends React.PureComponent return (days / 365).toString(); } return days.toString(); - } + }; getDefaultDropdownValue = (isEnabled: boolean | undefined, days: number | undefined) => { if (!isEnabled || days === undefined) { return keepForeverOption(); @@ -79,7 +79,7 @@ export default class GlobalPolicyForm extends React.PureComponent return yearsOption(); } return daysOption(); - } + }; handleSubmit = async () => { const {messageRetentionDropdownValue, messageRetentionInputValue, fileRetentionDropdownValue, fileRetentionInputValue, boardsRetentionDropdownValue, boardsRetentionInputValue} = this.state; @@ -128,7 +128,7 @@ export default class GlobalPolicyForm extends React.PureComponent return false; } return true; - } + }; setRetentionDays = (dropdownValue: string, value: string): number => { if (dropdownValue === YEARS) { @@ -140,7 +140,7 @@ export default class GlobalPolicyForm extends React.PureComponent } return 0; - } + }; render = () => { return ( @@ -290,5 +290,5 @@ export default class GlobalPolicyForm extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/data_retention_settings/team_list/team_list.tsx b/webapp/channels/src/components/admin_console/data_retention_settings/team_list/team_list.tsx index 2aa71b7662..da7902860d 100644 --- a/webapp/channels/src/components/admin_console/data_retention_settings/team_list/team_list.tsx +++ b/webapp/channels/src/components/admin_console/data_retention_settings/team_list/team_list.tsx @@ -52,14 +52,14 @@ export default class TeamList extends React.PureComponent { componentDidMount = () => { this.loadPage(0, PAGE_SIZE * 2); - } + }; private setStateLoading = (loading: boolean) => { this.setState({loading}); - } + }; private setStatePage = (page: number) => { this.setState({page}); - } + }; private loadPage = async (page: number, pageSize = PAGE_SIZE) => { if (this.props.policyId) { @@ -67,26 +67,26 @@ export default class TeamList extends React.PureComponent { await this.props.actions.getDataRetentionCustomPolicyTeams(this.props.policyId, page, pageSize); this.setStateLoading(false); } - } + }; private nextPage = () => { const page = this.state.page + 1; this.loadPage(page + 1); this.setStatePage(page); - } + }; private previousPage = () => { const page = this.state.page - 1; this.loadPage(page + 1); this.setStatePage(page); - } + }; private getVisibleTotalCount = (): number => { const {teamsToAdd, teamsToRemove, totalCount} = this.props; const teamsToAddCount = Object.keys(teamsToAdd).length; const teamsToRemoveCount = Object.keys(teamsToRemove).length; return totalCount + (teamsToAddCount - teamsToRemoveCount); - } + }; public getPaginationProps = (): {startCount: number; endCount: number; total: number} => { const {page} = this.state; @@ -98,7 +98,7 @@ export default class TeamList extends React.PureComponent { endCount = endCount > total ? total : endCount; return {startCount, endCount, total}; - } + }; private removeTeam = (team: Team) => { const {teamsToRemove} = this.props; @@ -115,7 +115,7 @@ export default class TeamList extends React.PureComponent { } this.setStatePage(page); - } + }; getColumns = (): Column[] => { const name = ( @@ -139,7 +139,7 @@ export default class TeamList extends React.PureComponent { className: 'TeamList__actionColumn', }, ]; - } + }; getRows = () => { const {page} = this.state; @@ -203,11 +203,11 @@ export default class TeamList extends React.PureComponent { }, }; }); - } + }; onSearch = async (searchTerm: string) => { this.props.actions.setTeamListSearch(searchTerm); - } + }; public async componentDidUpdate(prevProps: Props) { const {searchTerm} = this.props; const searchTermModified = prevProps.searchTerm !== this.props.searchTerm; diff --git a/webapp/channels/src/components/admin_console/database_settings.jsx b/webapp/channels/src/components/admin_console/database_settings.jsx index 0f8433ea35..e75e100c89 100644 --- a/webapp/channels/src/components/admin_console/database_settings.jsx +++ b/webapp/channels/src/components/admin_console/database_settings.jsx @@ -32,7 +32,7 @@ export default class DatabaseSettings extends AdminSettings { config.ServiceSettings.MinimumHashtagLength = this.parseIntNonZero(this.state.minimumHashtagLength, 3, 2); return config; - } + }; getStateFromConfig(config) { return { @@ -370,5 +370,5 @@ export default class DatabaseSettings extends AdminSettings { ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/dropdown_setting.jsx b/webapp/channels/src/components/admin_console/dropdown_setting.jsx index c03595dd02..0f43681563 100644 --- a/webapp/channels/src/components/admin_console/dropdown_setting.jsx +++ b/webapp/channels/src/components/admin_console/dropdown_setting.jsx @@ -16,15 +16,15 @@ export default class DropdownSetting extends React.PureComponent { disabled: PropTypes.bool, setByEnv: PropTypes.bool.isRequired, helpText: PropTypes.node, - } + }; static defaultProps = { isDisabled: false, - } + }; handleChange = (e) => { this.props.onChange(this.props.id, e.target.value); - } + }; render() { const options = []; diff --git a/webapp/channels/src/components/admin_console/elasticsearch_settings.jsx b/webapp/channels/src/components/admin_console/elasticsearch_settings.jsx index 6753aa542b..a898283b52 100644 --- a/webapp/channels/src/components/admin_console/elasticsearch_settings.jsx +++ b/webapp/channels/src/components/admin_console/elasticsearch_settings.jsx @@ -33,7 +33,7 @@ export default class ElasticsearchSettings extends AdminSettings { config.ElasticsearchSettings.EnableAutocomplete = this.state.enableAutocomplete; return config; - } + }; getStateFromConfig(config) { return { @@ -83,17 +83,17 @@ export default class ElasticsearchSettings extends AdminSettings { } this.handleChange(id, value); - } + }; handleSaved = () => { this.setState({ canPurgeAndIndex: this.state.enableIndexing, }); - } + }; canSave = () => { return this.state.canSave; - } + }; doTestConfig = (success, error) => { const config = JSON.parse(JSON.stringify(this.props.config)); @@ -116,7 +116,7 @@ export default class ElasticsearchSettings extends AdminSettings { error(err); }, ); - } + }; getExtraInfo(job) { if (job.status === JobStatuses.IN_PROGRESS) { @@ -470,5 +470,5 @@ export default class ElasticsearchSettings extends AdminSettings { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx b/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx index 2b8e5d19b2..e8589a0c09 100644 --- a/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx +++ b/webapp/channels/src/components/admin_console/feature_discovery/feature_discovery.test.tsx @@ -17,7 +17,6 @@ describe('components/feature_discovery', () => { { { callerCTA: 'feature_discovery_subscribe_button', }, }); - } + }; + + contactSalesFunc = () => { + const {customer, isCloud} = this.props; + const customerEmail = customer?.email || ''; + const firstName = customer?.contact_first_name || ''; + const lastName = customer?.contact_last_name || ''; + const companyName = customer?.name || ''; + const utmMedium = isCloud ? 'in-product-cloud' : 'in-product'; + goToMattermostContactSalesForm(firstName, lastName, companyName, customerEmail, 'mattermost', utmMedium); + }; renderPostTrialCta = () => { const { @@ -110,7 +122,7 @@ export default class FeatureDiscovery extends React.PureComponent data-testid='featureDiscovery_primaryCallToAction' onClick={() => { trackEvent(TELEMETRY_CATEGORIES.SELF_HOSTED_ADMIN, 'click_enterprise_contact_sales_feature_discovery'); - window.open(LicenseLinks.CONTACT_SALES, '_blank'); + this.contactSalesFunc(); }} > ); - } + }; renderStartTrial = (learnMoreURL: string, gettingTrialError: React.ReactNode) => { const { @@ -161,7 +173,6 @@ export default class FeatureDiscovery extends React.PureComponent hadPrevCloudTrial, isPaidSubscription, minimumSKURequiredForFeature, - contactSalesLink, } = this.props; const canRequestCloudFreeTrial = isCloud && !isCloudTrial && !hadPrevCloudTrial && !isPaidSubscription; @@ -217,11 +228,10 @@ export default class FeatureDiscovery extends React.PureComponent onClick={() => { if (isCloud) { trackEvent(TELEMETRY_CATEGORIES.CLOUD_ADMIN, 'click_enterprise_contact_sales_feature_discovery'); - window.open(contactSalesLink, '_blank'); } else { trackEvent(TELEMETRY_CATEGORIES.SELF_HOSTED_ADMIN, 'click_enterprise_contact_sales_feature_discovery'); - window.open(LicenseLinks.CONTACT_SALES, '_blank'); } + this.contactSalesFunc(); }} >

} ); - } + }; render() { const { diff --git a/webapp/channels/src/components/admin_console/feature_discovery/index.tsx b/webapp/channels/src/components/admin_console/feature_discovery/index.tsx index f100306b5a..99ea68e874 100644 --- a/webapp/channels/src/components/admin_console/feature_discovery/index.tsx +++ b/webapp/channels/src/components/admin_console/feature_discovery/index.tsx @@ -7,11 +7,9 @@ import {bindActionCreators, Dispatch, ActionCreatorsMapObject} from 'redux'; import {getPrevTrialLicense} from 'mattermost-redux/actions/admin'; import {getCloudSubscription} from 'mattermost-redux/actions/cloud'; import {Action, GenericAction} from 'mattermost-redux/types/actions'; -import {checkHadPriorTrial} from 'mattermost-redux/selectors/entities/cloud'; +import {checkHadPriorTrial, getCloudCustomer} from 'mattermost-redux/selectors/entities/cloud'; import {getLicense} from 'mattermost-redux/selectors/entities/general'; -import {getCloudContactUsLink, InquiryType} from 'selectors/cloud'; - import {ModalData} from 'types/actions'; import {GlobalState} from 'types/store'; @@ -30,7 +28,7 @@ function mapStateToProps(state: GlobalState) { const isCloud = isCloudLicense(license); const hasPriorTrial = checkHadPriorTrial(state); const isCloudTrial = subscription?.is_free_trial === 'true'; - const contactSalesLink = getCloudContactUsLink(state)(InquiryType.Sales); + const customer = getCloudCustomer(state); return { stats: state.entities.admin.analytics, prevTrialLicense: state.entities.admin.prevTrialLicense, @@ -39,7 +37,7 @@ function mapStateToProps(state: GlobalState) { isSubscriptionLoaded: subscription !== undefined && subscription !== null, hadPrevCloudTrial: hasPriorTrial, isPaidSubscription: isCloud && license?.SkuShortName !== LicenseSkus.Starter && !isCloudTrial, - contactSalesLink, + customer, }; } diff --git a/webapp/channels/src/components/admin_console/file_upload_setting.jsx b/webapp/channels/src/components/admin_console/file_upload_setting.jsx index 118a070bac..b0219545b0 100644 --- a/webapp/channels/src/components/admin_console/file_upload_setting.jsx +++ b/webapp/channels/src/components/admin_console/file_upload_setting.jsx @@ -39,7 +39,7 @@ export default class FileUploadSetting extends Setting { if (files && files.length > 0) { this.setState({fileSelected: true, fileName: files[0].name}); } - } + }; handleSubmit = (e) => { e.preventDefault(); @@ -51,7 +51,7 @@ export default class FileUploadSetting extends Setting { Utils.clearFileInput(this.fileInputRef.current); } }); - } + }; render() { let serverError; diff --git a/webapp/channels/src/components/admin_console/filter/filter.tsx b/webapp/channels/src/components/admin_console/filter/filter.tsx index 70a567b00c..4bfb4b37de 100644 --- a/webapp/channels/src/components/admin_console/filter/filter.tsx +++ b/webapp/channels/src/components/admin_console/filter/filter.tsx @@ -96,23 +96,23 @@ class Filter extends React.PureComponent { componentDidMount = () => { document.addEventListener('mousedown', this.handleClickOutside); - } + }; componentWillUnmount = () => { document.removeEventListener('mousedown', this.handleClickOutside); - } + }; handleClickOutside = (event: MouseEvent) => { if (this.filterRef?.current?.contains(event.target as Node)) { return; } this.hidePopover(); - } + }; hidePopover = () => { this.setState({show: false}); this.buttonRef?.current?.blur(); - } + }; togglePopover = () => { if (this.state.show) { @@ -121,7 +121,7 @@ class Filter extends React.PureComponent { } this.setState({show: true}); - } + }; updateValues = async (values: FilterValues, optionKey: string) => { const options = { @@ -134,12 +134,12 @@ class Filter extends React.PureComponent { }, }; this.setState({options, optionsModified: true}); - } + }; onFilter = () => { this.props.onFilter(this.state.options); this.setState({optionsModified: false, show: false, filterCount: this.calculateFilterCount()}); - } + }; calculateFilterCount = () => { const options = this.state.options; @@ -155,11 +155,11 @@ class Filter extends React.PureComponent { }); }); return filterCount; - } + }; resetFilters = () => { this.setState({options: {...this.props.options}}, this.onFilter); - } + }; renderFilterOptions = () => { const {keys, options} = this.state; @@ -176,7 +176,7 @@ class Filter extends React.PureComponent { /> ); }); - } + }; render() { const filters = this.renderFilterOptions(); diff --git a/webapp/channels/src/components/admin_console/filter/filter_checkbox.tsx b/webapp/channels/src/components/admin_console/filter/filter_checkbox.tsx index 47484f2ab0..32ffef2625 100644 --- a/webapp/channels/src/components/admin_console/filter/filter_checkbox.tsx +++ b/webapp/channels/src/components/admin_console/filter/filter_checkbox.tsx @@ -16,7 +16,7 @@ class FilterCheckbox extends React.PureComponent { e.stopPropagation(); const {checked, name, updateOption} = this.props; updateOption(!checked, name); - } + }; render() { const {name, checked, label} = this.props; diff --git a/webapp/channels/src/components/admin_console/filter/filter_list.tsx b/webapp/channels/src/components/admin_console/filter/filter_list.tsx index f3cbb2d02b..41e0e82b84 100644 --- a/webapp/channels/src/components/admin_console/filter/filter_list.tsx +++ b/webapp/channels/src/components/admin_console/filter/filter_list.tsx @@ -23,7 +23,7 @@ class FilterList extends React.PureComponent { }, }; await this.props.updateValues(values, this.props.optionKey); - } + }; render() { const {option} = this.props; diff --git a/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_checkbox.tsx b/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_checkbox.tsx index 5c86c46ae7..48d3a88a5c 100644 --- a/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_checkbox.tsx +++ b/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_checkbox.tsx @@ -15,7 +15,7 @@ class TeamFilterCheckbox extends React.PureComponent { toggleOption = () => { const {checked, id, updateOption} = this.props; updateOption(!checked, id); - } + }; render() { const { diff --git a/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_dropdown.tsx b/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_dropdown.tsx index b683ae5a6f..0d4121f182 100644 --- a/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_dropdown.tsx +++ b/webapp/channels/src/components/admin_console/filter/team_filter_dropdown/team_filter_dropdown.tsx @@ -100,11 +100,11 @@ class TeamFilterDropdown extends React.PureComponent { componentWillUnmount = () => { document.removeEventListener('mousedown', this.handleClickOutside); - } + }; hidePopover = () => { this.setState({show: false}); - } + }; togglePopover = (event: React.MouseEvent) => { if (this.state.show) { @@ -125,18 +125,18 @@ class TeamFilterDropdown extends React.PureComponent { this.listRef.current.scrollTop = 0; } }); - } + }; handleClickOutside = (event: MouseEvent) => { if (this.ref?.current?.contains(event.target as Node)) { return; } this.hidePopover(); - } + }; setScrollPosition = (event: React.UIEvent) => { this.scrollPosition = (event.target as HTMLDivElement).scrollTop; - } + }; hasMore = (): boolean => { if (this.state.loading) { @@ -145,7 +145,7 @@ class TeamFilterDropdown extends React.PureComponent { return this.state.searchTotal > this.state.searchResults.length; } return this.props.total > (this.state.page + 1) * TEAMS_PER_PAGE; - } + }; loadMore = async () => { const {searchTerm, loading} = this.state; @@ -165,7 +165,7 @@ class TeamFilterDropdown extends React.PureComponent { } this.setState({page, loading: false}); - } + }; searchTeams = async (term: string, page: number) => { let searchResults = []; @@ -180,7 +180,7 @@ class TeamFilterDropdown extends React.PureComponent { } this.searchRetryInterval *= 2; this.searchRetryId = window.setTimeout(this.searchTeams.bind(null, term, page), this.searchRetryInterval); - } + }; searchTeamsDebounced = debounce((page, term) => this.searchTeams(term, page), INITIAL_SEARCH_RETRY_TIMEOUT, false, () => {}); @@ -203,12 +203,12 @@ class TeamFilterDropdown extends React.PureComponent { } this.searchTeamsDebounced(0, searchTerm); - } + }; resetTeams = () => { this.setState({savedSelectedTeams: [], show: false, searchResults: [], searchTotal: 0, page: 0, searchTerm: ''}); this.props.updateValues({team_ids: {name: 'Teams', value: []}}, 'teams'); - } + }; toggleTeam = (checked: boolean, teamId: string) => { const prevSelectedTeamIds = this.props.option.values.team_ids.value as string[]; @@ -220,7 +220,7 @@ class TeamFilterDropdown extends React.PureComponent { } this.props.updateValues({team_ids: {name: 'Teams', value: selectedTeamIds}}, 'teams'); - } + }; generateButtonText = () => { const selectedTeamIds = this.props.option.values.team_ids.value as string[]; @@ -252,7 +252,7 @@ class TeamFilterDropdown extends React.PureComponent { }); return {buttonText, buttonMore}; - } + }; render() { const selectedTeamIds = this.props.option.values.team_ids.value as string[]; diff --git a/webapp/channels/src/components/admin_console/full_log_event_modal/full_log_event_modal.tsx b/webapp/channels/src/components/admin_console/full_log_event_modal/full_log_event_modal.tsx index a960637357..df5ca2f0a9 100644 --- a/webapp/channels/src/components/admin_console/full_log_event_modal/full_log_event_modal.tsx +++ b/webapp/channels/src/components/admin_console/full_log_event_modal/full_log_event_modal.tsx @@ -42,12 +42,12 @@ export default class FullLogEventModal extends React.PureComponent ); - } + }; copyLog = () => { navigator.clipboard.writeText(JSON.stringify(this.props.log, undefined, 2)); this.showCopySuccess(); - } + }; exportToCsv = () => { const file = navigator.clipboard.writeText(JSON.stringify(this.props.log, undefined, 2)); @@ -55,7 +55,7 @@ export default class FullLogEventModal extends React.PureComponent const encodedUri = encodeURI(csvContent); window.open(encodedUri); this.showExportSuccess(); - } + }; showCopySuccess = () => { this.setState({ @@ -67,7 +67,7 @@ export default class FullLogEventModal extends React.PureComponent copySuccess: false, }); }, 3000); - } + }; showExportSuccess = () => { this.setState({ @@ -79,7 +79,7 @@ export default class FullLogEventModal extends React.PureComponent exportSuccess: false, }); }, 3000); - } + }; render() { return ( diff --git a/webapp/channels/src/components/admin_console/generated_setting.tsx b/webapp/channels/src/components/admin_console/generated_setting.tsx index 6871f983c0..8f00f5c862 100644 --- a/webapp/channels/src/components/admin_console/generated_setting.tsx +++ b/webapp/channels/src/components/admin_console/generated_setting.tsx @@ -39,7 +39,7 @@ export default class GeneratedSetting extends React.PureComponent { e.preventDefault(); this.props.onChange(this.props.id, crypto.randomBytes(256).toString('base64').substring(0, 32)); - } + }; public render() { let disabledText = null; diff --git a/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx b/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx index bc3ba40028..b309efa433 100644 --- a/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx +++ b/webapp/channels/src/components/admin_console/group_settings/groups_list/groups_list.tsx @@ -88,7 +88,7 @@ export default class GroupsList extends React.PureComponent { public closeFilters = () => { this.setState({showFilters: false}); - } + }; public componentDidMount() { this.props.actions.getLdapGroups(this.state.page, LDAP_GROUPS_PAGE_SIZE).then(() => { @@ -222,7 +222,7 @@ export default class GroupsList extends React.PureComponent { ); - } + }; public renderRows(): JSX.Element | JSX.Element[] { if (this.state.loading) { @@ -437,7 +437,7 @@ export default class GroupsList extends React.PureComponent { this.props.actions.getLdapGroups(this.state.page, LDAP_GROUPS_PAGE_SIZE, {q: ''}).then(() => { this.setState({loading: false}); }); - } + }; public render(): JSX.Element { const startCount = (this.state.page * LDAP_GROUPS_PAGE_SIZE) + 1; diff --git a/webapp/channels/src/components/admin_console/jobs/table.tsx b/webapp/channels/src/components/admin_console/jobs/table.tsx index f198e1e81e..1cd72a058b 100644 --- a/webapp/channels/src/components/admin_console/jobs/table.tsx +++ b/webapp/channels/src/components/admin_console/jobs/table.tsx @@ -60,7 +60,7 @@ class JobTable extends React.PureComponent { } return ; - } + }; reload = () => { this.props.actions.getJobsByType(this.props.jobType); diff --git a/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap index f5bb34aea6..393b44eff3 100644 --- a/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/license_settings/__snapshots__/license_settings.test.tsx.snap @@ -208,117 +208,6 @@ exports[`components/admin_console/license_settings/LicenseSettings load screen w `; -exports[`components/admin_console/license_settings/LicenseSettings should match snapshot after starting trial and removing license 1`] = ` -
- -
-
-
- -
-
-
-
- - - Current Plan -
- } - fileInputRef={ - Object { - "current": null, - } - } - handleChange={[Function]} - openEELicenseModal={[Function]} - upgradedFromTE={false} - /> -
-
- See also - - Enterprise Edition Terms of Use - - and - - Privacy Policy - -
-
-
-
- -
-
- Curious about upgrading? - - Compare Plans - -
-
-
-
-
- -`; - exports[`components/admin_console/license_settings/LicenseSettings should match snapshot enterprise build with E10 license 1`] = `
- - - ({legend, value}: {legend: LegendValues; value: string | JSX.Element | null}, index: number): React.ReactNode => { if (legend === 'ACTIVE USERS:') { @@ -236,7 +236,7 @@ const renderLicenseContent = ( }> = [ {legend: 'START DATE:', value: startsAt}, {legend: 'EXPIRES:', value: expiresAt}, - {legend: 'USERS:', value: users}, + {legend: 'LICENSED SEATS:', value: users}, {legend: 'ACTIVE USERS:', value: activeUsers}, {legend: 'EDITION:', value: sku}, {legend: 'LICENSE ISSUED:', value: issued}, diff --git a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_right_panel.test.tsx b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_right_panel.test.tsx index 5428243fff..8245dacbbe 100644 --- a/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_right_panel.test.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/enterprise_edition/enterprise_edition_right_panel.test.tsx @@ -2,13 +2,46 @@ // See LICENSE.txt for license information. import React from 'react'; +import {Provider} from 'react-redux'; import {LicenseSkus} from 'utils/constants'; import {mountWithIntl} from 'tests/helpers/intl-test-helper'; +import mockStore from 'tests/test_store'; import EnterpriseEditionRightPanel, {EnterpriseEditionProps} from './enterprise_edition_right_panel'; +const initialState = { + views: { + announcementBar: { + announcementBarState: { + announcementBarCount: 1, + }, + }, + }, + entities: { + general: { + config: { + CWSURL: '', + }, + license: { + IsLicensed: 'true', + Cloud: 'true', + }, + }, + users: { + currentUserId: 'current_user_id', + profiles: { + current_user_id: {roles: 'system_user'}, + }, + }, + preferences: { + myPreferences: {}, + }, + cloud: {}, + }, +}; + describe('components/admin_console/license_settings/enterprise_edition/enterprise_edition_right_panel', () => { const license = { IsLicensed: 'true', @@ -28,8 +61,11 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris } as EnterpriseEditionProps; test('should render for no Gov no Trial no Enterprise', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( - , + + + , ); expect(wrapper.find('.upgrade-title').text()).toEqual('Upgrade to the Enterprise Plan'); @@ -43,11 +79,14 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris }); test('should render for Gov no Trial no Enterprise', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( - , + + + , ); expect(wrapper.find('.upgrade-title').text()).toEqual('Upgrade to the Enterprise Gov Plan'); @@ -61,11 +100,14 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris }); test('should render for Enterprise no Trial', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( - , + + + , ); expect(wrapper.find('.upgrade-title').text()).toEqual('Need to increase your headcount?'); @@ -73,11 +115,14 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris }); test('should render for E20 no Trial', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( - , + + + , ); expect(wrapper.find('.upgrade-title').text()).toEqual('Need to increase your headcount?'); @@ -85,11 +130,14 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris }); test('should render for Trial no Gov', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( - , + + + , ); expect(wrapper.find('.upgrade-title').text()).toEqual('Purchase the Enterprise Plan'); @@ -97,11 +145,14 @@ describe('components/admin_console/license_settings/enterprise_edition/enterpris }); test('should render for Trial Gov', () => { + const store = mockStore(initialState); const wrapper = mountWithIntl( - , + + + , ); expect(wrapper.find('.upgrade-title').text()).toEqual('Purchase the Enterprise Gov Plan'); diff --git a/webapp/channels/src/components/admin_console/license_settings/license_settings.test.tsx b/webapp/channels/src/components/admin_console/license_settings/license_settings.test.tsx index c70f0cd6c4..1273ac3f77 100644 --- a/webapp/channels/src/components/admin_console/license_settings/license_settings.test.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/license_settings.test.tsx @@ -167,34 +167,6 @@ describe('components/admin_console/license_settings/LicenseSettings', () => { expect(wrapper).toMatchSnapshot(); }); - test('should match snapshot after starting trial and removing license', async () => { - const actions = { - ...defaultProps.actions, - getLicenseConfig: jest.fn(), - upgradeToE0: jest.fn(), - upgradeToE0Status: jest.fn().mockImplementation(() => Promise.resolve({percentage: 0, error: null})), - }; - const props = {...defaultProps, license: {IsLicensed: 'false'}, prevTrialLicense: {IsLicensed: 'false'}, actions}; - - const wrapper = shallow(); - - const instance = wrapper.instance(); - - // First start trial - actions.requestTrialLicense = jest.fn().mockImplementation(() => Promise.resolve({percentage: 1, error: null})); - actions.getLicenseConfig = jest.fn().mockImplementation(() => Promise.resolve({})); - await instance.requestLicense({preventDefault: jest.fn()} as unknown as React.MouseEvent); - expect(wrapper.state('gettingTrial')).toBe(false); - - // Then remove license - actions.removeLicense = jest.fn().mockImplementation(() => Promise.resolve({percentage: 1, error: null})); - actions.getPrevTrialLicense = jest.fn().mockImplementation(() => Promise.resolve({})); - await instance.handleRemove({preventDefault: jest.fn()} as unknown as React.MouseEvent); - expect(wrapper.state('removing')).toBe(false); - - expect(wrapper).toMatchSnapshot(); - }); - test('should match snapshot enterprise build with E20 license', () => { const props = {...defaultProps, license: {...defaultProps.license, SkuShortName: LicenseSkus.E20}}; const wrapper = shallow(); diff --git a/webapp/channels/src/components/admin_console/license_settings/license_settings.tsx b/webapp/channels/src/components/admin_console/license_settings/license_settings.tsx index 2d55c9fc76..067292faa6 100644 --- a/webapp/channels/src/components/admin_console/license_settings/license_settings.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/license_settings.tsx @@ -145,14 +145,14 @@ export default class LicenseSettings extends React.PureComponent { this.interval = setInterval(this.reloadPercentage, 2000); } this.setState({upgradingPercentage: percentage || 0, upgradeError: error as string}); - } + }; handleChange = () => { const element = this.fileInputRef.current; if (element?.files?.length) { this.setState({fileSelected: true, file: element.files[0]}); } - } + }; openEELicenseModal = async () => { this.props.actions.openModal({ @@ -183,7 +183,7 @@ export default class LicenseSettings extends React.PureComponent { this.props.actions.getPrevTrialLicense(); await this.props.actions.getLicenseConfig(); this.setState({serverError: null, removing: false}); - } + }; handleUpgrade = async (e?: React.MouseEvent) => { if (e) { @@ -200,24 +200,7 @@ export default class LicenseSettings extends React.PureComponent { trackEvent('api', 'upgrade_to_e0_failed', {error: error.message as string}); this.setState({upgradeError: error.message, upgradingPercentage: 0}); } - } - - requestLicense = async (e?: React.MouseEvent) => { - if (e) { - e.preventDefault(); - } - if (this.state.gettingTrial) { - return; - } - this.setState({gettingTrial: true, gettingTrialError: null}); - const requestedUsers = Math.max(this.props.totalUsers, 30) || 30; - const {error, data} = await this.props.actions.requestTrialLicense(requestedUsers, true, true, 'license'); - if (error) { - this.setState({gettingTrialError: error}); - } - this.setState({gettingTrial: false, gettingTrialResponseCode: data?.status}); - await this.props.actions.getLicenseConfig(); - } + }; checkRestarted = () => { this.props.actions.ping().then(() => { @@ -225,7 +208,7 @@ export default class LicenseSettings extends React.PureComponent { }).catch(() => { setTimeout(this.checkRestarted, 1000); }); - } + }; handleRestart = async (e?: React.MouseEvent) => { if (e) { @@ -238,11 +221,11 @@ export default class LicenseSettings extends React.PureComponent { this.setState({restarting: false, restartError: err as string}); } setTimeout(this.checkRestarted, 1000); - } + }; setClickNormalUpgradeBtn = () => { this.setState({clickNormalUpgradeBtn: true}); - } + }; currentPlan = (
@@ -261,7 +244,7 @@ export default class LicenseSettings extends React.PureComponent { {text} ); - } + }; termsAndPolicy = (
@@ -363,7 +346,6 @@ export default class LicenseSettings extends React.PureComponent { isDisabled={isDisabled} gettingTrialResponseCode={this.state.gettingTrialResponseCode} gettingTrialError={this.state.gettingTrialError} - requestLicense={this.requestLicense} gettingTrial={this.state.gettingTrial} enterpriseReady={this.props.enterpriseReady} upgradingPercentage={this.state.upgradingPercentage} @@ -418,5 +400,5 @@ export default class LicenseSettings extends React.PureComponent { ); } return null; - } + }; } diff --git a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx index 7d16824535..634b030724 100644 --- a/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/modals/upload_license_modal.tsx @@ -260,7 +260,7 @@ const UploadLicenseModal = (props: Props): JSX.Element | null => {
act( () => @@ -47,7 +78,7 @@ describe('components/RenewalLicenseCard', () => { }); }); getRenewalLinkSpy.mockImplementation(() => promise); - const store = mockStore({}); + const store = mockStore(initialState); const wrapper = mountWithIntl(); // wait for the promise to resolve and component to update @@ -64,7 +95,7 @@ describe('components/RenewalLicenseCard', () => { reject(new Error('License cannot be renewed from portal')); }); getRenewalLinkSpy.mockImplementation(() => promise); - const store = mockStore({}); + const store = mockStore(initialState); const wrapper = mountWithIntl(); // wait for the promise to resolve and component to update diff --git a/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx b/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx index 3db6a6e0e2..ba97c6a2f0 100644 --- a/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx +++ b/webapp/channels/src/components/admin_console/license_settings/trial_banner/trial_banner.tsx @@ -13,6 +13,8 @@ import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences'; import AlertBanner from 'components/alert_banner'; import LoadingWrapper from 'components/widgets/loading/loading_wrapper'; import FormattedMarkdownMessage from 'components/formatted_markdown_message'; +import withOpenStartTrialFormModal from 'components/common/hocs/cloud/with_open_start_trial_form_modal'; +import {TelemetryProps} from 'components/common/hooks/useOpenPricingModal'; import {format} from 'utils/markdown'; @@ -26,13 +28,13 @@ interface TrialBannerProps { isDisabled: boolean; gettingTrialError: string | null; gettingTrialResponseCode: number | null; - requestLicense: (e?: React.MouseEvent, reload?: boolean) => Promise; gettingTrial: boolean; enterpriseReady: boolean; upgradingPercentage: number; handleUpgrade: () => Promise; upgradeError: string | null; restartError: string | null; + openTrialForm?: (telemetryProps?: TelemetryProps) => void; handleRestart: () => Promise; @@ -72,7 +74,6 @@ const TrialBanner = ({ isDisabled, gettingTrialError, gettingTrialResponseCode, - requestLicense, gettingTrial, enterpriseReady, upgradingPercentage, @@ -82,6 +83,7 @@ const TrialBanner = ({ handleRestart, restarting, openEEModal, + openTrialForm, }: TrialBannerProps) => { let trialButton; let upgradeTermsMessage; @@ -119,6 +121,12 @@ const TrialBanner = ({ } }; + const handleRequestLicense = () => { + if (openTrialForm) { + openTrialForm({trackingLocation: 'license_settings.trial_banner'}); + } + }; + useEffect(() => { async function savePrefsAndRequestTrial() { await savePrefsRestartedAfterUpgrade(); @@ -150,7 +158,7 @@ const TrialBanner = ({ const clickedBtn = Unique.CLICKED_UPGRADE_AND_TRIAL_BTN; dispatch(savePreferences(userId, [{category, name: reqLicense, user_id: userId, value: ''}, {category, name: clickedBtn, user_id: userId, value: ''}])); - requestLicense(); + handleRequestLicense(); } }, [restartedAfterUpgradePrefs, clickedUpgradeAndTrialBtn]); @@ -213,7 +221,7 @@ const TrialBanner = ({
); - } + }; render() { return ( diff --git a/webapp/channels/src/components/admin_console/manage_tokens_modal/manage_tokens_modal.tsx b/webapp/channels/src/components/admin_console/manage_tokens_modal/manage_tokens_modal.tsx index 4c1649d7be..cbe23d3a23 100644 --- a/webapp/channels/src/components/admin_console/manage_tokens_modal/manage_tokens_modal.tsx +++ b/webapp/channels/src/components/admin_console/manage_tokens_modal/manage_tokens_modal.tsx @@ -69,7 +69,7 @@ export default class ManageTokensModal extends React.PureComponent this.setState({ error, }); - } + }; private renderContents = (): JSX.Element => { const {user, userAccessTokens} = this.props; @@ -181,7 +181,7 @@ export default class ManageTokensModal extends React.PureComponent
); - } + }; public render = (): JSX.Element => { return ( @@ -209,5 +209,5 @@ export default class ManageTokensModal extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/member_list_group/member_list_group.tsx b/webapp/channels/src/components/admin_console/member_list_group/member_list_group.tsx index 059445b1c1..96c8fb06fc 100644 --- a/webapp/channels/src/components/admin_console/member_list_group/member_list_group.tsx +++ b/webapp/channels/src/components/admin_console/member_list_group/member_list_group.tsx @@ -96,7 +96,7 @@ export default class MemberListGroup extends React.PureComponent { loadComplete = () => { this.setState({loading: false}); - } + }; private nextPage = async () => { const {actions, groupID} = this.props; @@ -104,11 +104,11 @@ export default class MemberListGroup extends React.PureComponent { this.setState({loading: true, page}); await actions.getProfilesInGroup(groupID, page, USERS_PER_PAGE * 2); this.setState({loading: false}); - } + }; private previousPage = () => { this.setState({page: this.state.page - 1}); - } + }; private getRows = (): Row[] => { const {users} = this.props; @@ -129,7 +129,7 @@ export default class MemberListGroup extends React.PureComponent { }, }; }); - } + }; private getColumns = (): Column[] => { return [ @@ -143,7 +143,7 @@ export default class MemberListGroup extends React.PureComponent { field: 'name', }, ]; - } + }; private getPaginationProps = () => { let {total} = this.props; @@ -158,7 +158,7 @@ export default class MemberListGroup extends React.PureComponent { endCount = total; } return {startCount, endCount, total}; - } + }; public render = (): JSX.Element => { const rows: Row[] = this.getRows(); @@ -190,5 +190,5 @@ export default class MemberListGroup extends React.PureComponent { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/message_export_settings.jsx b/webapp/channels/src/components/admin_console/message_export_settings.jsx index c58c1102d5..bf5eec4beb 100644 --- a/webapp/channels/src/components/admin_console/message_export_settings.jsx +++ b/webapp/channels/src/components/admin_console/message_export_settings.jsx @@ -36,7 +36,7 @@ export default class MessageExportSettings extends AdminSettings { }; } return config; - } + }; getStateFromConfig(config) { const state = { @@ -321,5 +321,5 @@ export default class MessageExportSettings extends AdminSettings { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/multiselect_settings.jsx b/webapp/channels/src/components/admin_console/multiselect_settings.jsx index 309ef4843f..e1f0df3513 100644 --- a/webapp/channels/src/components/admin_console/multiselect_settings.jsx +++ b/webapp/channels/src/components/admin_console/multiselect_settings.jsx @@ -39,7 +39,7 @@ export default class MultiSelectSetting extends React.PureComponent { this.props.onChange(this.props.id, values); this.setState({error: false}); - } + }; calculateValue = () => { return this.props.selected.reduce((values, item) => { diff --git a/webapp/channels/src/components/admin_console/openid_convert/openid_convert.tsx b/webapp/channels/src/components/admin_console/openid_convert/openid_convert.tsx index a9054ce7a5..3cba4ddb41 100644 --- a/webapp/channels/src/components/admin_console/openid_convert/openid_convert.tsx +++ b/webapp/channels/src/components/admin_console/openid_convert/openid_convert.tsx @@ -73,7 +73,7 @@ export default class OpenIdConvert extends React.PureComponent { } else { getHistory().push('/admin_console/authentication/openid'); } - } + }; render() { return ( diff --git a/webapp/channels/src/components/admin_console/password_settings.jsx b/webapp/channels/src/components/admin_console/password_settings.jsx index bacc4fa60b..7e3a76dc2a 100644 --- a/webapp/channels/src/components/admin_console/password_settings.jsx +++ b/webapp/channels/src/components/admin_console/password_settings.jsx @@ -78,7 +78,7 @@ export default class PasswordSettings extends AdminSettings { config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts, Constants.MAXIMUM_LOGIN_ATTEMPTS_DEFAULT); return config; - } + }; getStateFromConfig(config) { return { @@ -123,17 +123,17 @@ export default class PasswordSettings extends AdminSettings { }} /> ); - } + }; handlePasswordLengthChange = (id, value) => { this.handleChange(id, value); - } + }; handleCheckboxChange = (id) => { return ({target: {checked}}) => { this.handleChange(id, checked); }; - } + }; renderTitle() { return ( @@ -283,5 +283,5 @@ export default class PasswordSettings extends AdminSettings { } ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_group.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_group.tsx index ad8d8d3d37..135ce5c53c 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_group.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_group.tsx @@ -70,21 +70,21 @@ export default class PermissionGroup extends React.PureComponent { toggleExpanded = (e: MouseEvent) => { e.stopPropagation(); this.setState({expanded: !this.state.expanded}); - } + }; toggleSelectRow = (id: string) => { if (this.props.readOnly) { return; } this.props.onChange([id]); - } + }; toggleSelectSubGroup = (ids: string[]) => { if (this.props.readOnly) { return; } this.props.onChange(ids); - } + }; toggleSelectGroup = () => { const {readOnly, permissions, role, onChange} = this.props; @@ -129,7 +129,7 @@ export default class PermissionGroup extends React.PureComponent { this.setState({prevPermissions: role.permissions || [], expanded: false}); onChange(permissionsToToggle); } - } + }; isInScope = (permission: string) => { if (this.props.scope === 'channel_scope' && PermissionsScope[permission] !== 'channel_scope') { @@ -139,7 +139,7 @@ export default class PermissionGroup extends React.PureComponent { return false; } return true; - } + }; renderPermission = (permission: string, additionalValues: AdditionalValues) => { if (!this.isInScope(permission)) { @@ -162,7 +162,7 @@ export default class PermissionGroup extends React.PureComponent { additionalValues={additionalValues} /> ); - } + }; renderGroup = (g: Permission) => { return ( @@ -183,11 +183,11 @@ export default class PermissionGroup extends React.PureComponent { root={false} /> ); - } + }; fromParent = (id: string) => { return this.props.parentRole && this.props.parentRole.permissions?.indexOf(id) !== -1; - } + }; getStatus = (permissions: Permissions) => { let anyChecked = false; @@ -219,11 +219,11 @@ export default class PermissionGroup extends React.PureComponent { return 'checked'; } return ''; - } + }; hasPermissionsOnScope = () => { return getRecursivePermissions(this.props.permissions).some((permission) => this.isInScope(permission)); - } + }; allPermissionsFromParent = (permissions: Permissions) => { for (const permission of permissions) { @@ -238,7 +238,7 @@ export default class PermissionGroup extends React.PureComponent { } } return true; - } + }; render = () => { const {id, uniqId, permissions, readOnly, combined, root, selected, additionalValues} = this.props; diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_schemes_settings.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_schemes_settings.tsx index 78c077a559..2225edd183 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_schemes_settings.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_schemes_settings.tsx @@ -89,7 +89,7 @@ export default class PermissionSchemesSettings extends React.PureComponent this.setState({loadingMore: false, page: this.state.page + 1})); }); - } + }; // |RunJobs && !EnableCluster|(*App).IsPhase2MigrationCompleted|View | // |-------------------------|---------------------------------|-------------------------------------------------------| @@ -127,7 +127,7 @@ export default class PermissionSchemesSettings extends React.PureComponent { return ( @@ -211,7 +211,7 @@ export default class PermissionSchemesSettings extends React.PureComponent { if (this.state.loading) { diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx index 812149275b..5077062d95 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/permission_system_scheme_settings.tsx @@ -127,7 +127,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< return true; } return false; - } + }; selectRow = (permission: string) => { this.setState({selectedPermission: permission}); @@ -139,7 +139,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< setTimeout(() => { this.setState({selectedPermission: undefined}); }, 3000); - } + }; loadRolesIntoState(props: Props) { this.setState({ @@ -195,7 +195,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< permissions: role.permissions?.filter((p) => PermissionsScope[p] === 'run_scope'), }, }; - } + }; deriveRolesFromGuests = (role: Partial): Record> => { return { @@ -212,7 +212,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< permissions: role.permissions?.filter((p) => PermissionsScope[p] === 'channel_scope'), }, }; - } + }; restoreExcludedPermissions = (roles: Record>) => { for (const permission of this.props.roles.system_user.permissions) { @@ -236,7 +236,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< } } return roles; - } + }; restoreGuestPermissions = (roles: Record>) => { for (const permission of this.props.roles.system_guest.permissions) { @@ -255,7 +255,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< } } return roles; - } + }; handleSubmit = async () => { const teamAdminPromise = this.props.actions.editRole(this.state.roles.team_admin); @@ -303,13 +303,13 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< this.setState({serverError, saving: false, saveNeeded}); this.props.actions.setNavigationBlocked(saveNeeded); - } + }; toggleRole = (roleId: string) => { const newOpenRoles = {...this.state.openRoles}; newOpenRoles[roleId] = !newOpenRoles[roleId]; this.setState({openRoles: newOpenRoles}); - } + }; togglePermission = (roleId: string, permissions: Iterable) => { const roles = {...this.state.roles}; @@ -327,7 +327,7 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< this.setState({roles, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; resetDefaults = () => { const newRolesState = JSON.parse(JSON.stringify({...this.state.roles})); @@ -338,11 +338,11 @@ export default class PermissionSystemSchemeSettings extends React.PureComponent< this.setState({roles: newRolesState, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; haveGuestAccountsPermissions = () => { return this.props.license.GuestAccountsPermissions === 'true'; - } + }; render = () => { if (!this.state.loaded) { diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings.tsx index e133d4182c..f30f687406 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/permission_team_scheme_settings.tsx @@ -110,7 +110,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { const selected = document.querySelector('.permission-row.selected,.permission-group-row.selected'); @@ -196,7 +196,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { this.setState({selectedPermission: permission}); @@ -208,7 +208,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { this.setState({selectedPermission: undefined}); }, 3000); - } + }; getStateRoles = () => { if (this.state.roles !== null) { @@ -276,7 +276,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { return { @@ -289,7 +289,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent PermissionsScope[p] === 'channel_scope'), }, }; - } + }; restoreGuestPermissions = (teamGuest: Role, channelGuest: Role, roles: RolesMap) => { for (const permission of teamGuest.permissions) { @@ -303,7 +303,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { return { @@ -324,7 +324,7 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent PermissionsScope[p] === 'run_scope'), }, }; - } + }; restoreExcludedPermissions = (baseTeam: Role, baseChannel: Role, roles: RolesMap) => { for (const permission of baseTeam.permissions) { @@ -338,17 +338,17 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent) => { this.setState({schemeName: e.target.value, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; handleDescriptionChange = (e: React.ChangeEvent) => { this.setState({schemeDescription: e.target.value, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; handleSubmit = async () => { const roles = this.getStateRoles(); @@ -495,13 +495,13 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { const newOpenRoles = {...this.state.openRoles}; newOpenRoles[roleId] = !newOpenRoles[roleId]; this.setState({openRoles: newOpenRoles}); - } + }; togglePermission = (roleId: string, permissions: string[]) => { const roles = {...this.getStateRoles()} as RolesMap; @@ -543,17 +543,17 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { this.setState({addTeamOpen: true}); - } + }; removeTeam = (teamId: string) => { const teams = (this.state.teams || this.props.teams).filter((team) => team.id !== teamId); this.setState({teams, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; addTeams = (teams: Team[]) => { const currentTeams = this.state.teams || this.props.teams || []; @@ -562,15 +562,15 @@ export default class PermissionTeamSchemeSettings extends React.PureComponent { this.setState({addTeamOpen: false}); - } + }; haveGuestAccountsPermissions = () => { return this.props.license.GuestAccountsPermissions === 'true'; - } + }; render = () => { if (!this.isLoaded(this.props)) { diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/team_in_list/team_in_list.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/team_in_list/team_in_list.tsx index 5ace78b29e..729153659d 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/team_in_list/team_in_list.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/team_in_list/team_in_list.tsx @@ -22,7 +22,7 @@ export default class TeamInList extends React.PureComponent { return; } onRemoveTeam(team.id); - } + }; render() { const {team, isDisabled} = this.props; diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_scheme_summary/permissions_scheme_summary.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_scheme_summary/permissions_scheme_summary.tsx index ad639d2232..b09f1fc243 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_scheme_summary/permissions_scheme_summary.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_scheme_summary/permissions_scheme_summary.tsx @@ -96,17 +96,17 @@ export default class PermissionsSchemeSummary extends React.PureComponent ); - } + }; stopPropagation = (e: React.MouseEvent): void => { e.stopPropagation(); - } + }; handleDeleteCanceled = (): void => { this.setState({ showConfirmModal: false, }); - } + }; handleDeleteConfirmed = async (): Promise => { this.setState({deleting: true, serverError: undefined}); @@ -116,7 +116,7 @@ export default class PermissionsSchemeSummary extends React.PureComponent): void => { e.stopPropagation(); @@ -124,11 +124,11 @@ export default class PermissionsSchemeSummary extends React.PureComponent { this.props.history.push('/admin_console/user_management/permissions/team_override_scheme/' + this.props.scheme.id); - } + }; render = () => { const {scheme, isDisabled} = this.props; diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_tree/permissions_tree.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_tree/permissions_tree.tsx index e32c82c42e..32cf4dd1dd 100644 --- a/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_tree/permissions_tree.tsx +++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_tree/permissions_tree.tsx @@ -260,15 +260,15 @@ export default class PermissionsTree extends React.PureComponent { return true; }); - } + }; openPostTimeLimitModal = () => { this.setState({editTimeLimitModalIsVisible: true}); - } + }; closePostTimeLimitModal = () => { this.setState({editTimeLimitModalIsVisible: false}); - } + }; componentDidUpdate(prevProps: Props) { if (this.props.config !== prevProps.config || this.props.license !== prevProps.license) { @@ -281,7 +281,7 @@ export default class PermissionsTree extends React.PureComponent { return; } this.props.onToggle(this.props.role.name!, ids); - } + }; render = () => { return ( diff --git a/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx b/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx index 90e8b472b0..b5f2b35e11 100644 --- a/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx +++ b/webapp/channels/src/components/admin_console/plugin_management/plugin_management.tsx @@ -486,7 +486,7 @@ export default class PluginManagement extends AdminSettings { } return config; - } + }; getStateFromConfig(config: Props['config']) { const state = { @@ -517,7 +517,7 @@ export default class PluginManagement extends AdminSettings { if (element.files && element.files.length > 0) { this.setState({fileSelected: true, file: element.files[0]}); } - } + }; helpSubmitUpload = async (file: File, force: boolean) => { this.setState({uploading: true}); @@ -561,7 +561,7 @@ export default class PluginManagement extends AdminSettings { uploading: false, loading: false, }); - } + }; handleSubmitUpload = (e: React.SyntheticEvent) => { e.preventDefault(); @@ -575,7 +575,7 @@ export default class PluginManagement extends AdminSettings { this.helpSubmitUpload(file, false); } Utils.clearFileInput(element); - } + }; handleOverwriteUploadPluginCancel = () => { this.setState({ @@ -586,20 +586,20 @@ export default class PluginManagement extends AdminSettings { lastMessage: null, uploading: false, }); - } + }; handleOverwriteUploadPlugin = () => { this.setState({confirmOverwriteUploadModal: false}); if (this.state.file) { this.helpSubmitUpload(this.state.file, true); } - } + }; onPluginDownloadUrlChange = (e: React.ChangeEvent) => { this.setState({ pluginDownloadUrl: e.target.value, }); - } + }; installFromUrl = async (force: boolean) => { const {pluginDownloadUrl} = this.state; @@ -644,7 +644,7 @@ export default class PluginManagement extends AdminSettings { installing: false, loading: false, }); - } + }; getMarketplaceURLHelpText = (url: string, enableUploads: boolean) => { return ( @@ -685,16 +685,16 @@ export default class PluginManagement extends AdminSettings { } ); - } + }; canSave = () => { return this.state.marketplaceUrl !== ''; - } + }; handleSubmitInstall = (e: React.SyntheticEvent) => { e.preventDefault(); return this.installFromUrl(false); - } + }; handleOverwriteInstallPluginCancel = () => { this.setState({ @@ -703,12 +703,12 @@ export default class PluginManagement extends AdminSettings { serverError: null, lastMessage: null, }); - } + }; handleOverwriteInstallPlugin = () => { this.setState({confirmOverwriteInstallModal: false}); return this.installFromUrl(true); - } + }; showRemovePluginModal = (e: React.SyntheticEvent) => { if (this.props.isDisabled) { @@ -717,16 +717,16 @@ export default class PluginManagement extends AdminSettings { e.preventDefault(); const pluginId = e.currentTarget.getAttribute('data-plugin-id'); this.setState({showRemoveModal: true, removing: pluginId}); - } + }; handleRemovePluginCancel = () => { this.setState({showRemoveModal: false, removing: null}); - } + }; handleRemovePlugin = () => { this.setState({showRemoveModal: false}); this.handleRemove(); - } + }; handleRemove = async () => { this.setState({lastMessage: null, serverError: null}); @@ -738,7 +738,7 @@ export default class PluginManagement extends AdminSettings { this.setState({serverError: error.message}); } } - } + }; handleEnable = async (e: React.KeyboardEvent) => { e.preventDefault(); @@ -755,7 +755,7 @@ export default class PluginManagement extends AdminSettings { this.setState({serverError: error.message}); } } - } + }; handleDisable = async (e: React.KeyboardEvent) => { this.setState({lastMessage: null, serverError: null}); @@ -772,7 +772,7 @@ export default class PluginManagement extends AdminSettings { this.setState({serverError: error.message}); } } - } + }; renderTitle() { return ( @@ -818,7 +818,7 @@ export default class PluginManagement extends AdminSettings { onCancel={onCancel} /> ); - } + }; renderRemovePluginModal = ( show: boolean, onConfirm: (checked: boolean) => void, onCancel: (checked: boolean) => void) => { @@ -854,7 +854,7 @@ export default class PluginManagement extends AdminSettings { onCancel={onCancel} /> ); - } + }; renderEnablePluginsSetting = () => { const hideEnablePlugins = this.props.config.ExperimentalSettings && this.props.config.ExperimentalSettings.RestrictSystemAdmin; @@ -892,7 +892,7 @@ export default class PluginManagement extends AdminSettings { ); } return null; - } + }; renderSettings = () => { const {enableUploads} = this.state; @@ -1256,5 +1256,5 @@ export default class PluginManagement extends AdminSettings { ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/push_settings.jsx b/webapp/channels/src/components/admin_console/push_settings.jsx index ea550c1d75..cb6e291913 100644 --- a/webapp/channels/src/components/admin_console/push_settings.jsx +++ b/webapp/channels/src/components/admin_console/push_settings.jsx @@ -22,13 +22,13 @@ const PUSH_NOTIFICATIONS_CUSTOM = 'custom'; export default class PushSettings extends AdminSettings { canSave = () => { return this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_MHPNS || this.state.agree; - } + }; handleAgreeChange = (e) => { this.setState({ agree: e.target.checked, }); - } + }; handleDropdownChange = (id, value) => { if (id === 'pushNotificationServerType') { @@ -54,7 +54,7 @@ export default class PushSettings extends AdminSettings { } this.handleChange(id, value); - } + }; getConfigFromState = (config) => { config.EmailSettings.SendPushNotifications = this.state.pushNotificationServerType !== PUSH_NOTIFICATIONS_OFF; @@ -62,7 +62,7 @@ export default class PushSettings extends AdminSettings { config.TeamSettings.MaxNotificationsPerChannel = this.state.maxNotificationsPerChannel; return config; - } + }; getStateFromConfig(config) { let pushNotificationServerType = PUSH_NOTIFICATIONS_CUSTOM; @@ -318,5 +318,5 @@ export default class PushSettings extends AdminSettings { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/remove_file_setting.jsx b/webapp/channels/src/components/admin_console/remove_file_setting.jsx index ba68c3b217..0d145ade83 100644 --- a/webapp/channels/src/components/admin_console/remove_file_setting.jsx +++ b/webapp/channels/src/components/admin_console/remove_file_setting.jsx @@ -35,7 +35,7 @@ export default class RemoveFileSetting extends Setting { this.props.onSubmit(this.props.id, () => { this.setState({removing: false}); }); - } + }; render() { return ( diff --git a/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.tsx b/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.tsx index 5d3915cde9..dde3f723e8 100644 --- a/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.tsx +++ b/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.tsx @@ -59,7 +59,7 @@ export default class ResetEmailModal extends React.PureComponent { isEmailError: false, isCurrentPasswordError: false, }); - } + }; private isEmailValid = (): boolean => { if (!this.emailRef.current || !this.emailRef.current.value || !isEmail(this.emailRef.current.value)) { @@ -75,7 +75,7 @@ export default class ResetEmailModal extends React.PureComponent { this.setState({error: null, isEmailError: false}); return true; - } + }; private isCurrentPasswordValid = (): boolean => { if (!this.currentPasswordRef.current || !this.currentPasswordRef.current.value) { @@ -91,7 +91,7 @@ export default class ResetEmailModal extends React.PureComponent { } this.setState({error: null, isCurrentPasswordError: false}); return true; - } + }; private doSubmit = async (e: React.MouseEvent) => { e.preventDefault(); @@ -126,14 +126,14 @@ export default class ResetEmailModal extends React.PureComponent { } this.props.onModalSubmit(this.props.user); - } + }; private doCancel = (): void => { this.setState({ error: null, }); this.props.onModalDismissed(); - } + }; public render(): JSX.Element { const user = this.props.user; diff --git a/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.tsx b/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.tsx index e84b511de8..566fb1fed5 100644 --- a/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.tsx +++ b/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.tsx @@ -98,7 +98,7 @@ export default class ResetPasswordModal extends React.PureComponent { this.setState({ @@ -106,7 +106,7 @@ export default class ResetPasswordModal extends React.PureComponent { if (!this.props.schema) { @@ -353,7 +353,7 @@ export default class SchemaAdminSettings extends React.PureComponent { textValues={helpTextValues} /> ); - } + }; renderLabel = (setting) => { if (!this.props.schema) { @@ -364,7 +364,7 @@ export default class SchemaAdminSettings extends React.PureComponent { return setting.label; } return Utils.localizeMessage(setting.label, setting.label_default); - } + }; isDisabled = (setting) => { const enterpriseReady = this.props.config.BuildEnterpriseReady === 'true'; @@ -372,14 +372,14 @@ export default class SchemaAdminSettings extends React.PureComponent { return setting.isDisabled(this.props.config, this.state, this.props.license, enterpriseReady, this.props.consoleAccess, this.props.cloud, this.props.isCurrentUserSystemAdmin); } return Boolean(setting.isDisabled); - } + }; isHidden = (setting) => { if (typeof setting.isHidden === 'function') { return setting.isHidden(this.props.config, this.state, this.props.license); } return Boolean(setting.isHidden); - } + }; buildButtonSetting = (setting) => { const handleRequestAction = (success, error) => { @@ -437,7 +437,7 @@ export default class SchemaAdminSettings extends React.PureComponent { }} /> ); - } + }; buildTextSetting = (setting) => { let inputType = 'input'; @@ -479,7 +479,7 @@ export default class SchemaAdminSettings extends React.PureComponent { footer={footer} /> ); - } + }; buildColorSetting = (setting) => { return ( @@ -494,7 +494,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleChange} /> ); - } + }; buildBoolSetting = (setting) => { return ( @@ -509,7 +509,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleChange} /> ); - } + }; buildPermissionSetting = (setting) => { return ( @@ -524,7 +524,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handlePermissionChange} /> ); - } + }; buildDropdownSetting = (setting) => { const enterpriseReady = this.props.config.BuildEnterpriseReady === 'true'; @@ -569,7 +569,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleChange} /> ); - } + }; buildLanguageSetting = (setting) => { const locales = I18n.getAllLanguages(); @@ -613,7 +613,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleChange} /> ); - } + }; buildRadioSetting = (setting) => { const options = setting.options || []; @@ -632,7 +632,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleChange} /> ); - } + }; buildBannerSetting = (setting) => { if (this.isDisabled(setting)) { @@ -651,7 +651,7 @@ export default class SchemaAdminSettings extends React.PureComponent { ); - } + }; buildGeneratedSetting = (setting) => { return ( @@ -668,11 +668,11 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleGeneratedChange} /> ); - } + }; handleGeneratedChange = (id, s) => { this.handleChange(id, s.replace('+', '-').replace('/', '_')); - } + }; handleChange = (id, value, confirm = false, doSubmit = false, warning = false) => { let saveNeeded = this.state.saveNeeded === 'permissions' ? 'both' : 'config'; @@ -702,7 +702,7 @@ export default class SchemaAdminSettings extends React.PureComponent { } this.props.setNavigationBlocked(true); - } + }; handlePermissionChange = (id, value) => { let saveNeeded = 'permissions'; @@ -715,7 +715,7 @@ export default class SchemaAdminSettings extends React.PureComponent { }); this.props.setNavigationBlocked(true); - } + }; buildUsernameSetting = (setting) => { return ( @@ -730,7 +730,7 @@ export default class SchemaAdminSettings extends React.PureComponent { onChange={this.handleChange} /> ); - } + }; buildJobsTableSetting = (setting) => { return ( @@ -753,7 +753,7 @@ export default class SchemaAdminSettings extends React.PureComponent { } /> ); - } + }; buildFileUploadSetting = (setting) => { const setData = (id, data) => { @@ -831,7 +831,7 @@ export default class SchemaAdminSettings extends React.PureComponent { setByEnv={this.isSetByEnv(setting.key)} /> ); - } + }; buildCustomSetting = (setting) => { const CustomComponent = setting.component; @@ -869,21 +869,21 @@ export default class SchemaAdminSettings extends React.PureComponent { ); } return componentInstance; - } + }; unRegisterSaveAction = (saveAction) => { const indexOfSaveAction = this.saveActions.indexOf(saveAction); this.saveActions.splice(indexOfSaveAction, 1); - } + }; registerSaveAction = (saveAction) => { this.saveActions.push(saveAction); - } + }; setSaveNeeded = () => { this.setState({saveNeeded: 'config'}); this.props.setNavigationBlocked(true); - } + }; renderSettings = () => { const schema = this.props.schema; @@ -995,17 +995,17 @@ export default class SchemaAdminSettings extends React.PureComponent { } return null; - } + }; closeTooltip = () => { this.setState({errorTooltip: false}); - } + }; openTooltip = (e) => { const elm = e.currentTarget.querySelector('.control-label'); const isElipsis = elm.offsetWidth < elm.scrollWidth; this.setState({errorTooltip: isElipsis}); - } + }; doSubmit = async (getStateFromConfig) => { // clone config so that we aren't modifying data in the stores @@ -1106,7 +1106,7 @@ export default class SchemaAdminSettings extends React.PureComponent { ); } return null; - } + }; canSave = () => { if (!this.props.schema || !this.props.schema.settings) { @@ -1126,6 +1126,15 @@ export default class SchemaAdminSettings extends React.PureComponent { } if (setting.validate) { + if (setting.isHidden?.(this.props.config)) { + // MM-50952 + // If the setting is hidden, then it is not being set in state so there is + // nothing to validate, and validation would fail anyways and prevent saving + // In practice, this only happens in custom cloud setup environments like RFQA + // where it sets things in the config file directly instead of in the environment + // (like cloud Mattermost does) + continue; + } const result = setting.validate(this.state[setting.key]); if (!result.isValid()) { return false; @@ -1134,7 +1143,7 @@ export default class SchemaAdminSettings extends React.PureComponent { } return true; - } + }; render = () => { const schema = this.props.schema; @@ -1229,5 +1238,5 @@ export default class SchemaAdminSettings extends React.PureComponent { ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/server_logs/log_list.tsx b/webapp/channels/src/components/admin_console/server_logs/log_list.tsx index 2f3338198c..d73d3d4b4e 100644 --- a/webapp/channels/src/components/admin_console/server_logs/log_list.tsx +++ b/webapp/channels/src/components/admin_console/server_logs/log_list.tsx @@ -46,21 +46,21 @@ export default class LogList extends React.PureComponent { isSearching = (term: string, filters: ChannelSearchOpts) => { return term.length > 0 || Object.keys(filters).length > 0; - } + }; onSearch = (term: string) => { this.props.onSearchChange(term); - } + }; nextPage = () => { const page = this.state.page + 1; this.setState({page}); - } + }; previousPage = () => { const page = this.state.page - 1; this.setState({page}); - } + }; getPaginationProps = (): {startCount: number; endCount: number; total: number} => { const {page} = this.state; @@ -73,12 +73,12 @@ export default class LogList extends React.PureComponent { endCount = endCount > total ? total : endCount; return {startCount, endCount, total}; - } + }; handleDateSort = () => { this.setState({dateAsc: !this.state.dateAsc}); this.getColumns(this.state.dateAsc); - } + }; getColumns = (dateAsc: boolean): Column[] => { const timestamp: JSX.Element = ( @@ -155,7 +155,7 @@ export default class LogList extends React.PureComponent { width: 1, }, ]; - } + }; getRows = (): Row[] => { const {startCount, endCount} = this.getPaginationProps(); @@ -219,21 +219,21 @@ export default class LogList extends React.PureComponent { onClick: () => this.showFullLogEvent(log), }; }); - } + }; showFullLogEvent = (log: LogObject) => { this.setState({ modalLog: log, modalOpen: true, }); - } + }; hideModal = () => { this.setState({ modalLog: null, modalOpen: false, }); - } + }; onFilter = (filterOptions: FilterOptions) => { const filters = {} as unknown as LogFilter; @@ -249,17 +249,17 @@ export default class LogList extends React.PureComponent { }, []); } this.props.onFiltersChange(filters); - } + }; showErrors = () => { this.props.onFiltersChange({logLevels: ['error']} as unknown as LogFilter); - } + }; getErrorCount = (): number => { let n = 0; this.props.logs.map((log) => log.level === 'error' && ++n); return n; - } + }; render = (): JSX.Element => { const {search} = this.props; @@ -377,5 +377,5 @@ export default class LogList extends React.PureComponent { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/server_logs/logs.tsx b/webapp/channels/src/components/admin_console/server_logs/logs.tsx index d92b24423e..0edbb270fc 100644 --- a/webapp/channels/src/components/admin_console/server_logs/logs.tsx +++ b/webapp/channels/src/components/admin_console/server_logs/logs.tsx @@ -57,11 +57,11 @@ export default class Logs extends React.PureComponent { dateTo: this.state.dateTo, }); this.setState({loadingLogs: false}); - } + }; onSearchChange = (search: string) => { this.setState({search}, () => this.performSearch()); - } + }; performSearch = debounce(() => { const {search} = this.state; @@ -74,7 +74,7 @@ export default class Logs extends React.PureComponent { onFiltersChange = ({dateFrom, dateTo, logLevels, serverNames}: LogFilter) => { this.setState({dateFrom, dateTo, logLevels, serverNames}, () => this.reload()); - } + }; render() { return ( diff --git a/webapp/channels/src/components/admin_console/session_length_settings.jsx b/webapp/channels/src/components/admin_console/session_length_settings.jsx index caecb90965..16aa21aef4 100644 --- a/webapp/channels/src/components/admin_console/session_length_settings.jsx +++ b/webapp/channels/src/components/admin_console/session_length_settings.jsx @@ -24,7 +24,7 @@ export default class SessionLengthSettings extends AdminSettings { config.ServiceSettings.SessionIdleTimeoutInMinutes = this.parseIntZeroOrMin(this.state.sessionIdleTimeoutInMinutes, MINIMUM_IDLE_TIMEOUT); return config; - } + }; getStateFromConfig(config) { return { @@ -204,5 +204,5 @@ export default class SessionLengthSettings extends AdminSettings { {sessionTimeoutSetting} ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/add_users_to_role_modal/add_users_to_role_modal.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/add_users_to_role_modal/add_users_to_role_modal.tsx index a764e1f759..f285736bf1 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/add_users_to_role_modal/add_users_to_role_modal.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/add_users_to_role_modal/add_users_to_role_modal.tsx @@ -76,11 +76,11 @@ export default class AddUsersToRoleModal extends React.PureComponent { await this.props.actions.getProfiles(0, USERS_PER_PAGE * 2); this.setUsersLoadingState(false); - } + }; setUsersLoadingState = (loading: boolean) => { this.setState({loading}); - } + }; search = async (term: string) => { this.setUsersLoadingState(true); @@ -93,17 +93,17 @@ export default class AddUsersToRoleModal extends React.PureComponent { this.setState({show: false}); - } + }; handleExit = () => { if (this.props.onExited) { this.props.onExited(); } - } + }; renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => { let rowSelected = ''; @@ -137,15 +137,15 @@ export default class AddUsersToRoleModal extends React.PureComponent ); - } + }; renderValue = (value: { data: UserProfileValue }): string => { return value.data?.username || ''; - } + }; renderAriaLabel = (option: UserProfileValue): string => { return option?.username || ''; - } + }; handleAdd = (value: UserProfileValue) => { const values: UserProfileValue[] = [...this.state.values]; @@ -153,11 +153,11 @@ export default class AddUsersToRoleModal extends React.PureComponent { this.setState({values}); - } + }; handlePageChange = (page: number, prevPage: number) => { if (page > prevPage) { @@ -171,7 +171,7 @@ export default class AddUsersToRoleModal extends React.PureComponent { this.props.onAddCallback(this.state.values); this.handleHide(); - } + }; render = (): JSX.Element => { const numRemainingText = ( @@ -265,5 +265,5 @@ export default class AddUsersToRoleModal extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role.tsx index b36f29a2b9..5a897a299f 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role.tsx @@ -74,7 +74,7 @@ export default class SystemRole extends React.PureComponent { saveNeeded = saveNeeded || difference(updatedRolePermissions, role.permissions).length > 0 || difference(role.permissions, updatedRolePermissions).length > 0; } return saveNeeded; - } + }; addUsersToRole = (users: UserProfile[]) => { const {actions: {setNavigationBlocked}} = this.props; @@ -95,7 +95,7 @@ export default class SystemRole extends React.PureComponent { const saveNeeded = this.getSaveStateNeeded({usersToAdd, usersToRemove}); setNavigationBlocked(saveNeeded); this.setState({usersToAdd, usersToRemove, saveNeeded}); - } + }; removeUserFromRole = (user: UserProfile) => { const {actions: {setNavigationBlocked}} = this.props; @@ -114,7 +114,7 @@ export default class SystemRole extends React.PureComponent { const saveNeeded = this.getSaveStateNeeded({usersToAdd, usersToRemove}); setNavigationBlocked(saveNeeded); this.setState({usersToRemove, usersToAdd, saveNeeded}); - } + }; handleSubmit = async () => { this.setState({saving: true, saveNeeded: false}); @@ -189,7 +189,7 @@ export default class SystemRole extends React.PureComponent { usersToRemove: {}, saveKey, }); - } + }; updatePermissions = (permissions: PermissionToUpdate[]) => { const {role, actions: {setNavigationBlocked}} = this.props; @@ -235,7 +235,7 @@ export default class SystemRole extends React.PureComponent { ...nextState, saveNeeded: this.getSaveStateNeeded(nextState), }); - } + }; render() { const {usersToAdd, usersToRemove, saving, saveNeeded, serverError, permissionsToUpdate, saveKey} = this.state; diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission.tsx index 219ba40279..1a47ca4a4b 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission.tsx @@ -28,7 +28,7 @@ export default class SystemRolePermission extends React.PureComponent { return visibleSections[section.name]; } return this.getAccessForSection(section, permissionsMap, permissionsToUpdate) === mixedAccess; - } + }; renderSubsectionToggle = (section: SystemSection, isSectionVisible: boolean) => { if (!section.subsections || section.subsections.length === 0) { @@ -59,7 +59,7 @@ export default class SystemRolePermission extends React.PureComponent { ); - } + }; renderSubsections = (section: SystemSection, permissionsMap: Record, permissionsToUpdate: PermissionsToUpdate, isSectionVisible: boolean) => { if (!section.subsections || section.subsections.length === 0) { @@ -74,7 +74,7 @@ export default class SystemRolePermission extends React.PureComponent { } ); - } + }; renderSectionRow = (section: SystemSection, permissionsMap: Record, permissionsToUpdate: PermissionsToUpdate, isSectionVisible: boolean) => { return ( @@ -111,7 +111,7 @@ export default class SystemRolePermission extends React.PureComponent { ); - } + }; getAccessForSection = (section: SystemSection, permissions: Record, permissionsToUpdate: Record) => { // If we have subsections then use them to determine access to show. @@ -145,7 +145,7 @@ export default class SystemRolePermission extends React.PureComponent { } } return this.getAccessForSectionByName(section.name, permissions, permissionsToUpdate); - } + }; getAccessForSectionByName = (sectionName: string, permissions: Record, permissionsToUpdate: Record) => { // Assume sysadmin has write access for everything, this is a bit of a hack but it should be left in until `user_management_read|write_system_roles` is actually a permission @@ -167,7 +167,7 @@ export default class SystemRolePermission extends React.PureComponent { } return access; - } + }; render() { const {section, permissionsMap, permissionsToUpdate, visibleSections} = this.props; diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission_dropdown.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission_dropdown.tsx index 649a7968a1..614d5d050e 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission_dropdown.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permission_dropdown.tsx @@ -37,7 +37,7 @@ export default class SystemRolePermissionDropdown extends React.PureComponent { return ( @@ -50,7 +50,7 @@ export default class SystemRolePermissionDropdown extends React.PureComponent ); - } + }; render() { const {isDisabled, section} = this.props; diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx index abb784bada..54a3d93c7c 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_permissions.tsx @@ -181,11 +181,11 @@ export default class SystemRolePermissions extends React.PureComponent -1) { sectionsList.splice(sectionIndex, 1); } - } + }; updatePermissions = (permissions: PermissionToUpdate[]) => { this.props.updatePermissions(permissions); - } + }; setSectionVisible = (name: string, visible: boolean) => { const {visibleSections} = this.state; @@ -195,7 +195,7 @@ export default class SystemRolePermissions extends React.PureComponent, permissionsToUpdate: PermissionsToUpdate, visibleSections: Record) => { const {isLicensedForCloud} = this.props; @@ -257,7 +257,7 @@ export default class SystemRolePermissions extends React.PureComponent ); }); - } + }; render() { const {role, permissionsToUpdate} = this.props; diff --git a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_users/system_role_users.tsx b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_users/system_role_users.tsx index 658320e126..64fdcfd20e 100644 --- a/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_users/system_role_users.tsx +++ b/webapp/channels/src/components/admin_console/system_roles/system_role/system_role_users/system_role_users.tsx @@ -106,14 +106,14 @@ export default class SystemRoleUsers extends React.PureComponent { setStateLoading = (loading: boolean) => { this.setState({loading}); - } + }; getVisibleTotalCount = (): number => { const {usersToRemove, usersToAdd, totalCount} = this.props; const usersToAddCount = Object.keys(usersToAdd).length; const usersToRemoveCount = Object.keys(usersToRemove).length; return totalCount + (usersToAddCount - usersToRemoveCount); - } + }; getPaginationProps = (): {startCount: number; endCount: number; total: number} => { const {term, usersToRemove, usersToAdd} = this.props; @@ -138,11 +138,11 @@ export default class SystemRoleUsers extends React.PureComponent { endCount = endCount > total ? total : endCount; return {startCount, endCount, total}; - } + }; onSearch = async (term: string) => { this.props.actions.setUserGridSearch(term); - } + }; nextPage = async () => { if (this.state.loading) { @@ -152,14 +152,14 @@ export default class SystemRoleUsers extends React.PureComponent { this.setState({loading: true}); await this.props.actions.getProfiles(page, USERS_PER_PAGE, {role: this.props.role.name}); this.setState({loading: false, page}); - } + }; previousPage = async () => { if (this.state.loading || this.state.page === 0) { return; } this.setState({page: this.state.page - 1}); - } + }; getRows = () => { const {users, readOnly, usersToAdd, usersToRemove} = this.props; @@ -198,7 +198,7 @@ export default class SystemRoleUsers extends React.PureComponent { }, }; }); - } + }; getColumns = () => { const name: JSX.Element = ( @@ -228,15 +228,15 @@ export default class SystemRoleUsers extends React.PureComponent { fixed: true, }, ]; - } + }; onAddCallback = (users: UserProfile[]) => { this.props.onAddCallback(users); - } + }; onRemoveCallback = (user: UserProfile) => { this.props.onRemoveCallback(user); - } + }; render() { const {page, loading} = this.state; diff --git a/webapp/channels/src/components/admin_console/system_user_detail/system_user_detail.tsx b/webapp/channels/src/components/admin_console/system_user_detail/system_user_detail.tsx index c486c8e9d1..bd2ca80a73 100644 --- a/webapp/channels/src/components/admin_console/system_user_detail/system_user_detail.tsx +++ b/webapp/channels/src/components/admin_console/system_user_detail/system_user_detail.tsx @@ -108,11 +108,11 @@ export default class SystemUserDetail extends React.PureComponent { this.setState({addTeamOpen: true}); - } + }; addTeams = (teams: Team[]): void => { const promises = []; @@ -120,63 +120,63 @@ export default class SystemUserDetail extends React.PureComponent this.setState({refreshTeams: true})); - } + }; closeAddTeam = (): void => { this.setState({addTeamOpen: false}); - } + }; doPasswordReset = (user: UserProfile): void => { this.setState({ showPasswordModal: true, user, }); - } + }; doPasswordResetDismiss = (): void => { this.setState({ showPasswordModal: false, }); - } + }; doPasswordResetSubmit = (): void => { this.setState({ showPasswordModal: false, }); - } + }; handleMakeActive = (e: React.MouseEvent): void => { e.preventDefault(); this.props.actions.updateUserActive(this.props.user.id, true). then((data) => this.onUpdateActiveResult(data.error)); - } + }; handleShowDeactivateMemberModal = (e: React.MouseEvent): void => { e.preventDefault(); this.setState({showDeactivateMemberModal: true}); - } + }; handleDeactivateMember = (): void => { this.props.actions.updateUserActive(this.props.user.id, false). then((data) => this.onUpdateActiveResult(data.error)); this.setState({showDeactivateMemberModal: false}); - } + }; onUpdateActiveResult = (error: ServerError): void => { if (error) { this.setState({error}); } - } + }; handleDeactivateCancel = (): void => { this.setState({showDeactivateMemberModal: false}); - } + }; // TODO: add error handler function handleResetMfa = (e: React.MouseEvent): void => { e.preventDefault(); adminResetMfa(this.props.user.id, null, null); - } + }; handleEmailChange = (e: React.ChangeEvent): void => { const emailChanged = e.target.value !== this.props.user.email; @@ -187,7 +187,7 @@ export default class SystemUserDetail extends React.PureComponent): void => { e.preventDefault(); @@ -220,7 +220,7 @@ export default class SystemUserDetail extends React.PureComponent { const title = ( @@ -279,7 +279,7 @@ export default class SystemUserDetail extends React.PureComponent ); - } + }; renderActivateDeactivate = (): React.ReactNode => { if (this.props.user.delete_at > 0) { @@ -302,7 +302,7 @@ export default class SystemUserDetail extends React.PureComponent ); - } + }; renderRemoveMFA = (): React.ReactNode => { if (this.props.user.mfa_active) { @@ -317,7 +317,7 @@ export default class SystemUserDetail extends React.PureComponent { const page = this.state.page < 1 ? 0 : this.state.page - 1; this.setState({page, loading: true}); this.performSearch(); - } + }; private nextPage = async (e: React.MouseEvent): Promise => { e.preventDefault(); const page = this.state.page + 1; this.setState({page, loading: true}); this.performSearch(); - } + }; private performSearch = (): void => { const userId = this.props.userId; @@ -83,7 +83,7 @@ export default class AbstractList extends React.PureComponent { } this.setState({loading: false}); }); - } + }; private getPaging(): Paging { const startCount = (this.state.page * PAGE_SIZE) + 1; @@ -110,7 +110,7 @@ export default class AbstractList extends React.PureComponent { ); } return null; - } + }; private renderRows = (): JSX.Element | JSX.Element[] => { if (this.state.loading) { @@ -134,7 +134,7 @@ export default class AbstractList extends React.PureComponent { const pageEnd = this.state.page < 1 ? PAGE_SIZE : (this.state.page + 1) * PAGE_SIZE; // ie 10, 20, 30, etc. const pageData = this.props.data.slice(pageStart, pageEnd).map(this.props.renderRow); // ie 0-10, 10-20, etc. return pageData; - } + }; public render = (): JSX.Element => { const {startCount, endCount, total} = this.getPaging(); @@ -179,6 +179,6 @@ export default class AbstractList extends React.PureComponent { } ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_list.tsx b/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_list.tsx index aef1b01dc0..0d3987bd74 100644 --- a/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_list.tsx +++ b/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_list.tsx @@ -71,7 +71,7 @@ export default class TeamList extends React.PureComponent { emptyListTextId: t('admin.team_settings.team_list.no_teams_found'), emptyListTextDefaultMessage: 'No teams found', refreshTeams: false, - } + }; public constructor(props: Props) { super(props); @@ -100,7 +100,7 @@ export default class TeamList extends React.PureComponent { this.setState({teamsWithMemberships}); this.props.userDetailCallback(teamsWithMemberships); }); - } + }; // check this out private mergeTeamsWithMemberships = (data: [{data: Team[]}, {data: TeamMembership[]}]): TeamWithMembership[] => { @@ -113,7 +113,7 @@ export default class TeamList extends React.PureComponent { }); teamsWithMemberships = filterAndSortTeamsByDisplayName(teamsWithMemberships, this.props.locale); return teamsWithMemberships; - } + }; private doRemoveUserFromTeam = async (teamId: string): Promise => { const {error} = await this.props.actions.removeUserFromTeam(teamId, this.props.userId); @@ -122,7 +122,7 @@ export default class TeamList extends React.PureComponent { } else { this.getTeamsAndMemberships(); } - } + }; private doMakeUserTeamAdmin = async (teamId: string) => { const {error} = await this.props.actions.updateTeamMemberSchemeRoles(teamId, this.props.userId, true, true); @@ -131,7 +131,7 @@ export default class TeamList extends React.PureComponent { } else { this.getTeamsAndMemberships(); } - } + }; private doMakeUserTeamMember = async (teamId: string) => { const {error} = await this.props.actions.updateTeamMemberSchemeRoles(teamId, this.props.userId, true, false); @@ -140,7 +140,7 @@ export default class TeamList extends React.PureComponent { } else { this.getTeamsAndMemberships(); } - } + }; public render(): JSX.Element { let serverError = null; @@ -179,5 +179,5 @@ export default class TeamList extends React.PureComponent { readOnly={this.props.readOnly} /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_row.tsx b/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_row.tsx index 77292d03c1..d9915692e4 100644 --- a/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_row.tsx +++ b/webapp/channels/src/components/admin_console/system_user_detail/team_list/team_row.tsx @@ -46,7 +46,7 @@ export default class TeamRow extends React.PureComponent { defaultMessage={'Invite only'} /> ); - } + }; private renderTeamRole = (team: TeamWithMembership) => { if (team.scheme_guest) { return ( @@ -73,7 +73,7 @@ export default class TeamRow extends React.PureComponent { ); } return null; - } + }; public render = (): JSX.Element => { const {team} = this.props; const teamIconUrl = Utils.imageURLForTeam(team); diff --git a/webapp/channels/src/components/admin_console/system_users/list/system_users_list.tsx b/webapp/channels/src/components/admin_console/system_users/list/system_users_list.tsx index 6938e0a353..4bd0fbeb02 100644 --- a/webapp/channels/src/components/admin_console/system_users/list/system_users_list.tsx +++ b/webapp/channels/src/components/admin_console/system_users/list/system_users_list.tsx @@ -103,11 +103,11 @@ export default class SystemUsersList extends React.PureComponent { this.setState({page: this.state.page + 1}); this.props.nextPage(this.state.page + 1); - } + }; previousPage = () => { this.setState({page: this.state.page - 1}); - } + }; search = (term: string) => { this.props.search(term); @@ -115,63 +115,63 @@ export default class SystemUsersList extends React.PureComponent { if (term !== '') { this.setState({page: 0}); } - } + }; doManageTeams = (user: UserProfile) => { this.setState({ showManageTeamsModal: true, user, }); - } + }; doManageRoles = (user: UserProfile) => { this.setState({ showManageRolesModal: true, user, }); - } + }; doManageTokens = (user: UserProfile) => { this.setState({ showManageTokensModal: true, user, }); - } + }; doManageTeamsDismiss = () => { this.setState({ showManageTeamsModal: false, user: undefined, }); - } + }; doManageRolesDismiss = () => { this.setState({ showManageRolesModal: false, user: undefined, }); - } + }; doManageTokensDismiss = () => { this.setState({ showManageTokensModal: false, user: undefined, }); - } + }; doPasswordReset = (user: UserProfile) => { this.setState({ showPasswordModal: true, user, }); - } + }; doPasswordResetDismiss = () => { this.setState({ showPasswordModal: false, user: undefined, }); - } + }; doPasswordResetSubmit = (user?: UserProfile) => { if (user) { @@ -182,21 +182,21 @@ export default class SystemUsersList extends React.PureComponent { showPasswordModal: false, user: undefined, }); - } + }; doEmailReset = (user: UserProfile) => { this.setState({ showEmailModal: true, user, }); - } + }; doEmailResetDismiss = () => { this.setState({ showEmailModal: false, user: undefined, }); - } + }; doEmailResetSubmit = (user?: UserProfile) => { if (user) { @@ -207,7 +207,7 @@ export default class SystemUsersList extends React.PureComponent { showEmailModal: false, user: undefined, }); - } + }; getInfoForUser(user: UserProfile) { const info = []; diff --git a/webapp/channels/src/components/admin_console/system_users/system_users.tsx b/webapp/channels/src/components/admin_console/system_users/system_users.tsx index 0b93372dcf..89c1b56d6f 100644 --- a/webapp/channels/src/components/admin_console/system_users/system_users.tsx +++ b/webapp/channels/src/components/admin_console/system_users/system_users.tsx @@ -164,23 +164,23 @@ export default class SystemUsers extends React.PureComponent { } this.setState({loading: false}); - } + }; handleTeamChange = (e: ChangeEvent) => { const teamId = e.target.value; this.loadDataForTeam(teamId, this.props.filter); this.props.actions.setSystemUsersSearch(this.props.searchTerm, teamId, this.props.filter); - } + }; handleFilterChange = (e: ChangeEvent) => { const filter = e.target.value; this.loadDataForTeam(this.props.teamId, filter); this.props.actions.setSystemUsersSearch(this.props.searchTerm, this.props.teamId, filter); - } + }; handleTermChange = (term: string) => { this.props.actions.setSystemUsersSearch(term, this.props.teamId, this.props.filter); - } + }; handleRevokeAllSessions = async () => { const {data} = await this.props.actions.revokeSessionsForAllUsers(); if (data) { @@ -188,13 +188,13 @@ export default class SystemUsers extends React.PureComponent { } else { this.props.actions.logError({type: 'critical', message: 'Can\'t revoke all sessions'}); } - } + }; handleRevokeAllSessionsCancel = () => { this.setState({showRevokeAllSessionsModal: false}); - } + }; handleShowRevokeAllSessionsModal = () => { this.setState({showRevokeAllSessionsModal: true}); - } + }; nextPage = async (page: number) => { const {teamId, filter} = this.props; @@ -216,7 +216,7 @@ export default class SystemUsers extends React.PureComponent { await loadProfilesAndTeamMembers(page + 1, USERS_PER_PAGE, teamId, options); } this.setState({loading: false}); - } + }; doSearch = debounce(async (term, teamId = this.props.teamId, filter = this.props.filter) => { if (!term) { @@ -250,7 +250,7 @@ export default class SystemUsers extends React.PureComponent { await this.props.actions.getUser(id); this.setState({loading: false}); - } + }; getUserByTokenOrId = async (id: string) => { if (this.props.enableUserAccessTokens) { @@ -264,7 +264,7 @@ export default class SystemUsers extends React.PureComponent { } this.getUserById(id); - } + }; renderRevokeAllUsersModal = () => { const title = ( @@ -302,7 +302,7 @@ export default class SystemUsers extends React.PureComponent { onCancel={this.handleRevokeAllSessionsCancel} /> ); - } + }; renderFilterRow = (doSearch: ((event: React.FormEvent) => void) | undefined) => { const teams = this.props.teams.map((team) => ( @@ -363,7 +363,7 @@ export default class SystemUsers extends React.PureComponent { ); - } + }; render() { const revokeAllUsersModal = this.renderRevokeAllUsersModal(); diff --git a/webapp/channels/src/components/admin_console/system_users/system_users_dropdown/system_users_dropdown.tsx b/webapp/channels/src/components/admin_console/system_users/system_users_dropdown/system_users_dropdown.tsx index 2d5e7af1a6..fabc10f3d3 100644 --- a/webapp/channels/src/components/admin_console/system_users/system_users_dropdown/system_users_dropdown.tsx +++ b/webapp/channels/src/components/admin_console/system_users/system_users_dropdown/system_users_dropdown.tsx @@ -86,40 +86,40 @@ export default class SystemUsersDropdown extends React.PureComponent void}) => { e.preventDefault(); this.props.doManageTeams(this.props.user); - } + }; handleManageRoles = (e: {preventDefault: () => void}) => { e.preventDefault(); this.props.doManageRoles(this.props.user); - } + }; handleManageTokens = (e: {preventDefault: () => void}) => { e.preventDefault(); this.props.doManageTokens(this.props.user); - } + }; handleResetPassword = (e: {preventDefault: () => void}) => { e.preventDefault(); this.props.doPasswordReset(this.props.user); - } + }; handleResetEmail = (e: {preventDefault: () => void}) => { e.preventDefault(); this.props.doEmailReset(this.props.user); - } + }; handleResetMfa = (e: {preventDefault: () => void}) => { e.preventDefault(); adminResetMfa(this.props.user.id, null, this.props.onError); - } + }; handleShowDeactivateMemberModal = async (e: {preventDefault: () => void}) => { e.preventDefault(); @@ -130,23 +130,23 @@ export default class SystemUsersDropdown extends React.PureComponent { this.props.actions.updateUserActive(this.props.user.id, false). then(this.onUpdateActiveResult); this.setState({showDeactivateMemberModal: false}); - } + }; onUpdateActiveResult = ({error}: {error: ServerError}) => { if (error) { this.props.onError({id: error.server_error_id, ...error}); } - } + }; handleDeactivateCancel = () => { this.setState({showDeactivateMemberModal: false}); - } + }; renderDeactivateMemberModal = () => { const user = this.props.user; @@ -273,7 +273,7 @@ export default class SystemUsersDropdown extends React.PureComponent ); - } + }; shouldDisableBotsWhenOwnerIsDeactivated() { return this.props.config && @@ -284,12 +284,12 @@ export default class SystemUsersDropdown extends React.PureComponent void}) => { e.preventDefault(); this.setState({showRevokeSessionsModal: true}); - } + }; handleShowCreateGroupSyncableMembershipsModal = (e: {preventDefault: () => void}) => { e.preventDefault(); this.setState({showCreateGroupMembershipsModal: true}); - } + }; handleCreateGroupSyncableMemberships = async () => { const {error} = await this.props.actions.createGroupTeamsAndChannels(this.props.user.id); @@ -298,11 +298,11 @@ export default class SystemUsersDropdown extends React.PureComponent { this.setState({showCreateGroupMembershipsModal: false}); - } + }; handleRevokeSessions = async () => { const me = this.props.currentUser; @@ -315,15 +315,15 @@ export default class SystemUsersDropdown extends React.PureComponent { this.setState({showRevokeSessionsModal: false}); - } + }; handlePromoteToUser = () => { this.setState({showPromoteToUserModal: true}); - } + }; handlePromoteToUserConfirm = async () => { const {error} = await this.props.actions.promoteGuestToUser(this.props.user.id); @@ -332,15 +332,15 @@ export default class SystemUsersDropdown extends React.PureComponent { this.setState({showPromoteToUserModal: false}); - } + }; handleDemoteToGuest = () => { this.setState({showDemoteToGuestModal: true}); - } + }; handleDemoteToGuestConfirm = async () => { const {error} = await this.props.actions.demoteUserToGuest(this.props.user.id); @@ -348,11 +348,11 @@ export default class SystemUsersDropdown extends React.PureComponent { this.setState({showDemoteToGuestModal: false}); - } + }; renderPromoteToUserModal = () => { const title = ( @@ -393,7 +393,7 @@ export default class SystemUsersDropdown extends React.PureComponent ); - } + }; renderDemoteToGuestModal = () => { const title = ( @@ -434,7 +434,7 @@ export default class SystemUsersDropdown extends React.PureComponent ); - } + }; renderRevokeSessionsModal = () => { const title = ( @@ -475,7 +475,7 @@ export default class SystemUsersDropdown extends React.PureComponent ); - } + }; renderCreateGroupSyncablesMembershipsModal = () => { const title = ( @@ -524,7 +524,7 @@ export default class SystemUsersDropdown extends React.PureComponent ); - } + }; renderAccessToken = () => { const userAccessTokensEnabled = this.props.enableUserAccessTokens; @@ -561,7 +561,7 @@ export default class SystemUsersDropdown extends React.PureComponent ); - } + }; render() { const {currentUser, user, isLicensed, config} = this.props; diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/abstract_list.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/abstract_list.tsx index 5cf79950ed..fb10bb6e43 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/abstract_list.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/abstract_list.tsx @@ -62,21 +62,21 @@ export default class AbstractList extends React.PureComponent { const page = this.state.page < 1 ? 0 : this.state.page - 1; this.setState({page, loading: true}); this.performSearch(page); - } + }; nextPage = async (e: MouseEvent): Promise => { e.preventDefault(); const page = this.state.page + 1; this.setState({page, loading: true}); this.performSearch(page); - } + }; renderHeader = (): JSX.Element | null => { if (this.props.data.length > 0) { return this.props.header; } return null; - } + }; renderRows = (): JSX.Element | JSX.Element[] => { if (this.state.loading) { @@ -98,7 +98,7 @@ export default class AbstractList extends React.PureComponent { } const offset = this.state.page * PAGE_SIZE; return this.props.data.slice(offset, offset + PAGE_SIZE).map(this.props.renderRow); - } + }; performSearch = (page: number): void => { this.setState({loading: true}); @@ -109,7 +109,7 @@ export default class AbstractList extends React.PureComponent { } this.setState({loading: false}); }); - } + }; getPaging(): Paging { const startCount = (this.state.page * PAGE_SIZE) + 1; @@ -175,5 +175,5 @@ export default class AbstractList extends React.PureComponent { } ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_details.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_details.tsx index 6a18c461be..7f7205d121 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_details.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_details.tsx @@ -272,7 +272,7 @@ export default class ChannelDetails extends React.PureComponent { const currentValueIndex = this.state.channelPermissions.findIndex((element) => element.name === name); @@ -321,7 +321,7 @@ export default class ChannelDetails extends React.PureComponent { const groups = [...this.state.groups, ...groupIDs.map((gid: string) => this.props.allGroups[gid])]; @@ -607,20 +607,20 @@ export default class ChannelDetails extends React.PureComponent { const {isLocalArchived} = this.state; const isServerArchived = this.props.channel.delete_at !== 0; return !isLocalArchived && isServerArchived; - } + }; private addRolesToUpdate = (userId: string, schemeUser: boolean, schemeAdmin: boolean) => { const {rolesToUpdate} = this.state; rolesToUpdate[userId] = {schemeUser, schemeAdmin}; this.setState({rolesToUpdate: {...rolesToUpdate}, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; private addUserToRemove = (user: UserProfile) => { let {usersToRemoveCount} = this.state; @@ -634,7 +634,7 @@ export default class ChannelDetails extends React.PureComponent { let {usersToRemoveCount} = this.state; @@ -649,7 +649,7 @@ export default class ChannelDetails extends React.PureComponent { const {isLocalArchived, serverError, previousServerError} = this.state; diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_members/channel_members.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_members/channel_members.tsx index 45b40c898b..57958b9c65 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_members/channel_members.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_members/channel_members.tsx @@ -126,29 +126,29 @@ export default class ChannelMembers extends React.PureComponent { private setStateLoading = (loading: boolean) => { this.setState({loading}); - } + }; private loadPage = async (page: number) => { const {loadProfilesAndReloadChannelMembers} = this.props.actions; const {channelId, filters} = this.props; await loadProfilesAndReloadChannelMembers(page + 1, PROFILE_CHUNK_SIZE, channelId, '', {active: true, ...filters}); - } + }; private removeUser = (user: UserProfile) => { this.props.onRemoveCallback(user); - } + }; private onAddCallback = (users: UserProfile[]) => { this.props.onAddCallback(users); - } + }; private onSearch = async (term: string) => { this.props.actions.setUserGridSearch(term); - } + }; private updateMembership = (membership: BaseMembership) => { this.props.updateRole(membership.user_id, membership.scheme_user, membership.scheme_admin); - } + }; private onFilter = async (filterOptions: FilterOptions) => { const roles = filterOptions.role.values; @@ -181,7 +181,7 @@ export default class ChannelMembers extends React.PureComponent { } else { this.props.actions.setUserGridFilters(filters); } - } + }; render = () => { const {users, channel, channelId, usersToAdd, usersToRemove, channelMembers, totalCount, searchTerm, isDisabled} = this.props; @@ -294,5 +294,5 @@ export default class ChannelMembers extends React.PureComponent { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_moderation.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_moderation.tsx index 80caca67ae..22b4944242 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_moderation.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_moderation.tsx @@ -353,7 +353,7 @@ export default class ChannelModeration extends React.PureComponent { ); } return errorMessages; - } + }; render = (): JSX.Element => { const {channelPermissions, guestAccountsEnabled, onChannelPermissionsChanged, readOnly} = this.props; @@ -421,5 +421,5 @@ export default class ChannelModeration extends React.PureComponent { ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/channel/list/channel_list.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/channel/list/channel_list.tsx index 8c5e607f52..89c9d7bf34 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/channel/list/channel_list.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/channel/list/channel_list.tsx @@ -69,7 +69,7 @@ export default class ChannelList extends React.PureComponent { return term.length > 0 || Object.keys(filters).length > 0; - } + }; getPaginationProps = () => { const {page, term, filters} = this.state; @@ -78,7 +78,7 @@ export default class ChannelList extends React.PureComponent total ? total : endCount; return {startCount, endCount, total}; - } + }; loadPage = async (page = 0, term = '', filters = {}) => { this.setState({loading: true, term, filters}); @@ -93,7 +93,7 @@ export default class ChannelList extends React.PureComponent { let channels = []; @@ -106,21 +106,21 @@ export default class ChannelList extends React.PureComponent this.searchChannels(page, term, filters), 300, false, () => {}); nextPage = () => { this.loadPage(this.state.page + 1, this.state.term, this.state.filters); - } + }; previousPage = () => { this.setState({page: this.state.page - 1}); - } + }; onSearch = async (term = '') => { this.loadPage(0, term, this.state.filters); - } + }; getColumns = (): Column[] => { const name: JSX.Element = ( @@ -167,7 +167,7 @@ export default class ChannelList extends React.PureComponent { const {data} = this.props; @@ -245,7 +245,7 @@ export default class ChannelList extends React.PureComponent getHistory().push(`/admin_console/user_management/channels/${channel.id}`), }; }); - } + }; onFilter = (filterOptions: FilterOptions) => { const filters: ChannelSearchOpts = {}; @@ -285,7 +285,7 @@ export default class ChannelList extends React.PureComponent { const {term, searchErrored} = this.state; @@ -414,5 +414,5 @@ export default class ChannelList extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_list.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_list.tsx index 40ab2ccba3..c6b39b93ca 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_list.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_list.tsx @@ -69,7 +69,7 @@ export default class GroupList extends React.PureComponent { isDisabled={this.props.isDisabled} /> ); - } + }; render(): JSX.Element { return ( diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_members_modal.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_members_modal.tsx index b9ded53e82..c1f9e29d44 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_members_modal.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_members_modal.tsx @@ -36,11 +36,11 @@ export default class GroupMembersModal extends React.PureComponent handleHide = () => { this.setState({show: false}); - } + }; handleExit = () => { this.props.onExited(); - } + }; render() { const {group} = this.props; diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_row.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_row.tsx index d94d8258d6..433db20631 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_row.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_row.tsx @@ -63,7 +63,7 @@ export default class GroupRow extends React.PureComponent { return teamAdmin; } return member; - } + }; displayRoleToBe = () => { const {group, type} = this.props; @@ -73,7 +73,7 @@ export default class GroupRow extends React.PureComponent { return localizeMessage('admin.team_channel_settings.group_row.teamAdmin', 'Team Admin'); } return localizeMessage('admin.team_channel_settings.group_row.member', 'Member'); - } + }; render = () => { const {group} = this.props; diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_users/users_to_remove.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_users/users_to_remove.tsx index d7a8874a7a..eb33177005 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/group/group_users/users_to_remove.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/group/group_users/users_to_remove.tsx @@ -83,7 +83,7 @@ export default class UsersToRemove extends React.PureComponent { setStateLoading = (loading: boolean) => { this.setState({loading}); - } + }; componentWillUnmount() { this.props.actions.setModalSearchTerm(''); @@ -98,23 +98,23 @@ export default class UsersToRemove extends React.PureComponent { } else if (scope === 'team') { await loadTeamMembersForProfilesList(profiles, scopeId); } - } + }; previousPage = async () => { const page = this.state.page < 1 ? 0 : this.state.page - 1; this.setState({page}); - } + }; nextPage = async () => { const {total} = this.props; const page = (this.state.page + 1) * GROUP_MEMBERS_PAGE_SIZE >= total ? this.state.page : this.state.page + 1; this.setState({page}); - } + }; onSearch = (term: string) => { this.props.actions.setModalSearchTerm(term); this.setState({page: 0}); - } + }; private onFilter = async (filterOptions: FilterOptions) => { const roles = filterOptions.role.values; @@ -147,7 +147,7 @@ export default class UsersToRemove extends React.PureComponent { } this.props.actions.setModalFilters(filters); this.setState({page: 0}); - } + }; private getPaginationProps = () => { const {page} = this.state; @@ -161,7 +161,7 @@ export default class UsersToRemove extends React.PureComponent { const firstPage = page === 0; return {startCount, endCount, page, lastPage, firstPage, total}; - } + }; private getRows = (): Row[] => { const {members, memberships, scope} = this.props; @@ -201,7 +201,7 @@ export default class UsersToRemove extends React.PureComponent { }, }; }); - } + }; private getColumns = (): Column[] => { return [ @@ -236,7 +236,7 @@ export default class UsersToRemove extends React.PureComponent { width: 3, }, ]; - } + }; private getFilterOptions = (): FilterOptions => { const filterOptions: FilterOptions = { @@ -325,7 +325,7 @@ export default class UsersToRemove extends React.PureComponent { } return filterOptions; - } + }; public render = (): JSX.Element => { const rows: Row[] = this.getRows(); @@ -360,5 +360,5 @@ export default class UsersToRemove extends React.PureComponent { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_details.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_details.tsx index 2a39371139..03a8314afd 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_details.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_details.tsx @@ -135,7 +135,7 @@ export default class TeamDetails extends React.PureComponent { return g; }); this.processGroupsChange(groups); - } + }; handleSubmit = async () => { this.setState({showRemoveConfirmation: false, saving: true}); @@ -290,7 +290,7 @@ export default class TeamDetails extends React.PureComponent { getHistory().push('/admin_console/user_management/teams'); } }); - } + }; setToggles = (syncChecked: boolean, allAllowedChecked: boolean, allowedDomainsChecked: boolean, allowedDomains: string) => { this.setState({ @@ -301,7 +301,7 @@ export default class TeamDetails extends React.PureComponent { allowedDomains, }, () => this.processGroupsChange(this.state.groups)); this.props.actions.setNavigationBlocked(true); - } + }; async processGroupsChange(groups: Group[]) { const {teamID, actions} = this.props; @@ -348,7 +348,7 @@ export default class TeamDetails extends React.PureComponent { }); this.setState({usersToAdd: {...usersToAddCopy}, usersToRemove: {...usersToRemove}, usersToRemoveCount, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; addUserToRemove = (user: UserProfile) => { let {usersToRemoveCount} = this.state; @@ -362,26 +362,26 @@ export default class TeamDetails extends React.PureComponent { delete rolesToUpdate[user.id]; this.setState({usersToRemove: {...usersToRemove}, usersToAdd: {...usersToAdd}, rolesToUpdate: {...rolesToUpdate}, usersToRemoveCount, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; addRolesToUpdate = (userId: string, schemeUser: boolean, schemeAdmin: boolean) => { const {rolesToUpdate} = this.state; rolesToUpdate[userId] = {schemeUser, schemeAdmin}; this.setState({rolesToUpdate: {...rolesToUpdate}, saveNeeded: true}); this.props.actions.setNavigationBlocked(true); - } + }; handleGroupRemoved = (gid: string) => { const groups = this.state.groups.filter((g) => g.id !== gid); this.setState({totalGroups: this.state.totalGroups - 1}); this.processGroupsChange(groups); - } + }; handleGroupChange = (groupIDs: string[]) => { const groups = [...this.state.groups, ...groupIDs.map((gid) => this.props.allGroups[gid])]; this.setState({totalGroups: this.state.totalGroups + groupIDs.length}); this.processGroupsChange(groups); - } + }; hideRemoveUsersModal = () => this.setState({showRemoveConfirmation: false}); @@ -395,19 +395,19 @@ export default class TeamDetails extends React.PureComponent { } else { this.handleSubmit(); } - } + }; teamToBeArchived = () => { const {isLocalArchived} = this.state; const isServerArchived = this.props.team.delete_at !== 0; return isLocalArchived && !isServerArchived; - } + }; teamToBeRestored = () => { const {isLocalArchived} = this.state; const isServerArchived = this.props.team.delete_at !== 0; return !isLocalArchived && isServerArchived; - } + }; onToggleArchive = () => { const {isLocalArchived, serverError, previousServerError} = this.state; diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_members/team_members.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_members/team_members.tsx index deafb9e8fe..eff236e3d3 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_members/team_members.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/team/details/team_members/team_members.tsx @@ -126,25 +126,25 @@ export default class TeamMembers extends React.PureComponent { private setStateLoading = (loading: boolean) => { this.setState({loading}); - } + }; private loadPage = async (page: number) => { const {loadProfilesAndReloadTeamMembers} = this.props.actions; const {teamId, filters} = this.props; await loadProfilesAndReloadTeamMembers(page + 1, PROFILE_CHUNK_SIZE, teamId, {active: true, ...filters}); - } + }; private removeUser = (user: UserProfile) => { this.props.onRemoveCallback(user); - } + }; private onAddCallback = (users: UserProfile[]) => { this.props.onAddCallback(users); - } + }; private onSearch = async (term: string) => { this.props.actions.setUserGridSearch(term); - } + }; private onFilter = async (filterOptions: FilterOptions) => { const roles = filterOptions.role.values; @@ -177,11 +177,11 @@ export default class TeamMembers extends React.PureComponent { } else { this.props.actions.setUserGridFilters(filters); } - } + }; private updateMembership = (membership: BaseMembership) => { this.props.updateRole(membership.user_id, membership.scheme_user, membership.scheme_admin); - } + }; public render = () => { const {users, team, usersToAdd, usersToRemove, teamMembers, totalCount, searchTerm, isDisabled} = this.props; @@ -294,5 +294,5 @@ export default class TeamMembers extends React.PureComponent { /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.tsx index 6fe1d7461b..459c173ceb 100644 --- a/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.tsx +++ b/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.tsx @@ -61,7 +61,7 @@ export default class TeamList extends React.PureComponent { isSearching = (term: string, filters: TeamSearchOpts) => { return (term.length + Object.keys(filters).length) > 0; - } + }; getPaginationProps = () => { const {page, term, filters} = this.state; @@ -70,7 +70,7 @@ export default class TeamList extends React.PureComponent { let endCount = (page + 1) * PAGE_SIZE; endCount = endCount > total ? total : endCount; return {startCount, endCount, total}; - } + }; loadPage = async (page = 0, term = '', filters = {}) => { this.setState({loading: true, term, filters}); @@ -86,7 +86,7 @@ export default class TeamList extends React.PureComponent { await this.props.actions.getData(page, PAGE_SIZE); this.setState({page, loading: false}); - } + }; searchTeams = async (page = 0, term = '', filters = {}) => { let teams: Team[] = []; @@ -99,17 +99,17 @@ export default class TeamList extends React.PureComponent { searchErrored = false; } this.setState({page, loading: false, teams, total, searchErrored}); - } + }; searchTeamsDebounced = debounce((page, term, filters = {}) => this.searchTeams(page, term, filters), 300, false, () => {}); nextPage = () => { this.loadPage(this.state.page + 1, this.state.term, this.state.filters); - } + }; previousPage = () => { this.setState({page: this.state.page - 1}); - } + }; onSearch = (term = '') => { this.loadPage(0, term, this.state.filters); @@ -151,7 +151,7 @@ export default class TeamList extends React.PureComponent { } this.loadPage(0, this.state.term, filters); - } + }; getColumns = (): Column[] => { const name = ( @@ -186,7 +186,7 @@ export default class TeamList extends React.PureComponent { fixed: true, }, ]; - } + }; renderManagementMethodText = (team: Team) => { if (team.group_constrained) { @@ -210,7 +210,7 @@ export default class TeamList extends React.PureComponent { defaultMessage='Invite Only' /> ); - } + }; getRows = () => { const {data} = this.props; @@ -278,7 +278,7 @@ export default class TeamList extends React.PureComponent { onClick: () => getHistory().push(`/admin_console/user_management/teams/${team.id}`), }; }); - } + }; render() { const {term, searchErrored} = this.state; diff --git a/webapp/channels/src/components/admin_console/text_setting.test.tsx b/webapp/channels/src/components/admin_console/text_setting.test.tsx index 6693cb72c2..3e68110712 100644 --- a/webapp/channels/src/components/admin_console/text_setting.test.tsx +++ b/webapp/channels/src/components/admin_console/text_setting.test.tsx @@ -2,14 +2,15 @@ // See LICENSE.txt for license information. import React from 'react'; -import {shallow} from 'enzyme'; import AdminTextSetting from './text_setting'; +import {renderWithIntl} from 'tests/react_testing_utils'; +import {screen} from '@testing-library/react'; describe('components/admin_console/TextSetting', () => { test('render component with required props', () => { const onChange = jest.fn(); - const wrapper = shallow( + renderWithIntl( { type='input' />, ); - expect(wrapper).toMatchInlineSnapshot(` - - `); + + screen.getByText('some label', {exact: false}); + expect(screen.getByTestId('string.idinput')).toHaveProperty('id', 'string.id'); + expect(screen.getByTestId('string.idinput')).toHaveValue('some value'); }); }); diff --git a/webapp/channels/src/components/admin_console/user_grid/user_grid.tsx b/webapp/channels/src/components/admin_console/user_grid/user_grid.tsx index b85144ae7c..7abe32ff04 100644 --- a/webapp/channels/src/components/admin_console/user_grid/user_grid.tsx +++ b/webapp/channels/src/components/admin_console/user_grid/user_grid.tsx @@ -70,32 +70,32 @@ export default class UserGrid extends React.PureComponent { this.setState({loading: true}); this.props.loadPage(page); this.setState({page, loading: false}); - } + }; private nextPage = () => { this.loadPage(this.state.page + 1); - } + }; private previousPage = () => { this.loadPage(this.state.page - 1); - } + }; private onSearch = async (term: string) => { this.props.onSearch(term); this.setState({page: 0}); - } + }; private onFilter = async (filters: FilterOptions) => { this.props.filterProps?.onFilter(filters); this.setState({page: 0}); - } + }; private getVisibleTotalCount = (): number => { const {includeUsers, excludeUsers, totalCount} = this.props; const includeUsersCount = Object.keys(includeUsers).length; const excludeUsersCount = Object.keys(excludeUsers).length; return totalCount + (includeUsersCount - excludeUsersCount); - } + }; public getPaginationProps = (): {startCount: number; endCount: number; total: number} => { const {includeUsers, excludeUsers, term} = this.props; @@ -120,7 +120,7 @@ export default class UserGrid extends React.PureComponent { endCount = endCount > total ? total : endCount; return {startCount, endCount, total}; - } + }; private removeUser = (user: UserProfile) => { const {excludeUsers} = this.props; @@ -137,7 +137,7 @@ export default class UserGrid extends React.PureComponent { } this.setState({page}); - } + }; private updateMembership = (membership: BaseMembership) => { const {membershipsToUpdate} = this.state; @@ -150,7 +150,7 @@ export default class UserGrid extends React.PureComponent { this.props.updateMembership(membership); this.setState({membershipsToUpdate}, this.forceUpdate); - } + }; private newMembership = (user: UserProfile): BaseMembership => { return { @@ -158,7 +158,7 @@ export default class UserGrid extends React.PureComponent { scheme_admin: false, scheme_user: !user.roles.includes('guest'), }; - } + }; private getRows = (): Row[] => { const {page, membershipsToUpdate} = this.state; @@ -226,7 +226,7 @@ export default class UserGrid extends React.PureComponent { }, }; }); - } + }; private getColumns = (): Column[] => { const name: JSX.Element = ( @@ -268,7 +268,7 @@ export default class UserGrid extends React.PureComponent { fixed: true, }, ]; - } + }; public render = (): JSX.Element => { const rows: Row[] = this.getRows(); @@ -304,5 +304,5 @@ export default class UserGrid extends React.PureComponent { filterProps={{...this.props.filterProps, onFilter: this.onFilter}} /> ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/user_grid/user_grid_name.tsx b/webapp/channels/src/components/admin_console/user_grid/user_grid_name.tsx index 4e9b38709b..e7ae48653a 100644 --- a/webapp/channels/src/components/admin_console/user_grid/user_grid_name.tsx +++ b/webapp/channels/src/components/admin_console/user_grid/user_grid_name.tsx @@ -34,5 +34,5 @@ export default class UserGridName extends React.Component { ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/user_grid/user_grid_remove.tsx b/webapp/channels/src/components/admin_console/user_grid/user_grid_remove.tsx index 8036f800df..68eb2883e2 100644 --- a/webapp/channels/src/components/admin_console/user_grid/user_grid_remove.tsx +++ b/webapp/channels/src/components/admin_console/user_grid/user_grid_remove.tsx @@ -20,7 +20,7 @@ export default class UserGridRemove extends React.PureComponent { return; } this.props.removeUser(this.props.user); - } + }; public render = (): JSX.Element => { const {isDisabled} = this.props; @@ -39,5 +39,5 @@ export default class UserGridRemove extends React.PureComponent {
); - } + }; } diff --git a/webapp/channels/src/components/admin_console/user_grid/user_grid_role_dropdown.tsx b/webapp/channels/src/components/admin_console/user_grid/user_grid_role_dropdown.tsx index 21697abb18..5f9b3dbcbd 100644 --- a/webapp/channels/src/components/admin_console/user_grid/user_grid_role_dropdown.tsx +++ b/webapp/channels/src/components/admin_console/user_grid/user_grid_role_dropdown.tsx @@ -47,7 +47,7 @@ export default class UserGridRoleDropdown extends React.PureComponent { makeAdmin: Utils.localizeMessage('channel_members_dropdown.make_channel_admin', 'Make Channel Admin'), makeMember: Utils.localizeMessage('channel_members_dropdown.make_channel_member', 'Make Channel Member'), }; - } + }; private getCurrentRole = (): Role => { const {user, membership, scope} = this.props; @@ -77,7 +77,7 @@ export default class UserGridRoleDropdown extends React.PureComponent { } return 'guest'; - } + }; private getLocalizedRole = (role: Role) => { switch (role) { @@ -95,7 +95,7 @@ export default class UserGridRoleDropdown extends React.PureComponent { default: return Utils.localizeMessage('admin.user_grid.guest', 'Guest'); } - } + }; private handleMakeAdmin = () => { this.props.handleUpdateMembership({ @@ -103,7 +103,7 @@ export default class UserGridRoleDropdown extends React.PureComponent { scheme_admin: true, scheme_user: true, }); - } + }; private handleMakeUser = () => { this.props.handleUpdateMembership({ @@ -111,7 +111,7 @@ export default class UserGridRoleDropdown extends React.PureComponent { scheme_admin: false, scheme_user: true, }); - } + }; private getAriaLabel = () => { const {scope} = this.props; @@ -119,7 +119,7 @@ export default class UserGridRoleDropdown extends React.PureComponent { return Utils.localizeMessage('team_members_dropdown.menuAriaLabel', 'Change the role of a team member'); } return Utils.localizeMessage('channel_members_dropdown.menuAriaLabel', 'Change the role of channel member'); - } + }; public render = (): React.ReactNode => { if (!this.props.membership) { @@ -194,5 +194,5 @@ export default class UserGridRoleDropdown extends React.PureComponent { ); - } + }; } diff --git a/webapp/channels/src/components/admin_console/workspace-optimization/dashboard.data.tsx b/webapp/channels/src/components/admin_console/workspace-optimization/dashboard.data.tsx index b9477f36de..dd5ee9b565 100644 --- a/webapp/channels/src/components/admin_console/workspace-optimization/dashboard.data.tsx +++ b/webapp/channels/src/components/admin_console/workspace-optimization/dashboard.data.tsx @@ -18,8 +18,9 @@ import {getLicense} from 'mattermost-redux/selectors/entities/general'; import {GlobalState} from '@mattermost/types/store'; -import {CloudLinks, ConsolePages, DocLinks, LicenseLinks} from 'utils/constants'; +import {CloudLinks, ConsolePages, DocLinks} from 'utils/constants'; import {daysToLicenseExpire, isEnterpriseOrE20License, getIsStarterLicense} from '../../../utils/license_utils'; +import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; export type DataModel = { [key: string]: { @@ -84,8 +85,10 @@ const useMetricsData = () => { const isEnterpriseLicense = isEnterpriseOrE20License(license); const isStarterLicense = getIsStarterLicense(license); + const [, contactSalesLink] = useOpenSalesLink(); + const trialOrEnterpriseCtaConfig = { - configUrl: canStartTrial ? ConsolePages.LICENSE : LicenseLinks.CONTACT_SALES, + configUrl: canStartTrial ? ConsolePages.LICENSE : contactSalesLink, configText: canStartTrial ? formatMessage({id: 'admin.reporting.workspace_optimization.cta.startTrial', defaultMessage: 'Start trial'}) : formatMessage({id: 'admin.reporting.workspace_optimization.cta.upgradeLicense', defaultMessage: 'Contact sales'}), }; diff --git a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx index 14b461b3a8..b0679ea814 100644 --- a/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx +++ b/webapp/channels/src/components/advanced_create_comment/advanced_create_comment.tsx @@ -220,7 +220,7 @@ class AdvancedCreateComment extends React.PureComponent { static defaultProps = { focusOnMount: true, - } + }; static getDerivedStateFromProps(props: Props, state: State) { let updatedState: Partial = { @@ -332,7 +332,7 @@ class AdvancedCreateComment extends React.PureComponent { getChannelMemberCountsByGroup(channelId, isTimezoneEnabled); } } - } + }; saveDraftOnUnmount = () => { if (!this.isDraftEdited || !this.state.draft) { @@ -346,7 +346,7 @@ class AdvancedCreateComment extends React.PureComponent { } as PostDraft; this.props.onUpdateCommentDraft(updatedDraft, true); - } + }; saveDraftWithShow = () => { this.setState((prev) => { @@ -366,7 +366,7 @@ class AdvancedCreateComment extends React.PureComponent { }, () => { this.saveDraft(true); }); - } + }; saveDraft = (save = false) => { if (this.saveDraftFrame) { @@ -374,11 +374,11 @@ class AdvancedCreateComment extends React.PureComponent { this.props.onUpdateCommentDraft(this.state.draft, save); this.saveDraftFrame = null; } - } + }; setShowPreview = (newPreviewValue: boolean) => { this.props.setShowPreview(newPreviewValue); - } + }; focusTextboxIfNecessary = (e: KeyboardEvent) => { // Should only focus if RHS is expanded or if thread view @@ -397,7 +397,7 @@ class AdvancedCreateComment extends React.PureComponent { this.focusTextbox(); this.toggleAdvanceTextEditor(); } - } + }; setCaretPosition = (newCaretPosition: number) => { const textbox = this.textboxRef.current && this.textboxRef.current.getInputBox(); @@ -407,7 +407,7 @@ class AdvancedCreateComment extends React.PureComponent { }, () => { Utils.setCaretPosition(textbox, newCaretPosition); }); - } + }; pasteHandler = (e: ClipboardEvent) => { // we need to cast the TextboxElement type onto the EventTarget here since the ClipboardEvent is not generic @@ -447,11 +447,11 @@ class AdvancedCreateComment extends React.PureComponent { this.handleDraftChange(updatedDraft); this.setState({draft: updatedDraft}); - } + }; handleNotifyAllConfirmation = () => { this.doSubmit(); - } + }; showNotifyAllModal = (mentions: string[], channelTimezoneCount: number, memberNotifyCount: number) => { this.props.openModal({ @@ -464,7 +464,7 @@ class AdvancedCreateComment extends React.PureComponent { onConfirm: () => this.handleNotifyAllConfirmation(), }, }); - } + }; toggleEmojiPicker = (e?: React.MouseEvent): void => { e?.stopPropagation(); @@ -474,7 +474,7 @@ class AdvancedCreateComment extends React.PureComponent { hideEmojiPicker = () => { this.setState({showEmojiPicker: false}); - } + }; handleEmojiClick = (emoji: Emoji) => { const emojiAlias = ('short_name' in emoji && emoji.short_name) || emoji.name; @@ -512,7 +512,7 @@ class AdvancedCreateComment extends React.PureComponent { showEmojiPicker: false, draft: modifiedDraft, }); - } + }; handleGifClick = (gif: string) => { const draft = this.state.draft!; @@ -540,11 +540,11 @@ class AdvancedCreateComment extends React.PureComponent { }); this.focusTextbox(); - } + }; handlePostError = (postError: React.ReactNode) => { this.setState({postError}); - } + }; handleSubmit = async (e: React.FormEvent | React.MouseEvent) => { e.preventDefault(); @@ -642,7 +642,7 @@ class AdvancedCreateComment extends React.PureComponent { } await this.doSubmit(e); - } + }; doSubmit = async (e?: React.FormEvent) => { if (e) { @@ -714,7 +714,7 @@ class AdvancedCreateComment extends React.PureComponent { this.isDraftSubmitting = false; this.setState({draft: {...this.props.draft, uploadsInProgress: []}}); this.draftsForPost[this.props.rootId] = null; - } + }; commentMsgKeyPress = (e: React.KeyboardEvent) => { const {ctrlSend, codeBlockOnCtrlEnter} = this.props; @@ -743,7 +743,7 @@ class AdvancedCreateComment extends React.PureComponent { } this.emitTypingEvent(); - } + }; reactToLastMessage = (e: React.KeyboardEvent) => { e.preventDefault(); @@ -753,12 +753,12 @@ class AdvancedCreateComment extends React.PureComponent { // Here we are not handling conditions such as check for modals, popups etc. as shortcut is only trigger on // textbox input focus. Since all of them will already be closed as soon as they loose focus. emitShortcutReactToLastPostFrom(Locations.RHS_ROOT); - } + }; emitTypingEvent = () => { const {channelId, rootId} = this.props; GlobalActions.emitLocalUserTypingEvent(channelId, rootId); - } + }; handleChange = (e: React.ChangeEvent) => { const message = e.target.value; @@ -780,7 +780,7 @@ class AdvancedCreateComment extends React.PureComponent { } }); this.draftsForPost[this.props.rootId] = updatedDraft; - } + }; handleDraftChange = (draft: PostDraft, rootId?: string, save = false, instant = false) => { this.isDraftEdited = true; @@ -805,17 +805,17 @@ class AdvancedCreateComment extends React.PureComponent { }, Constants.SAVE_DRAFT_TIMEOUT); } this.draftsForPost[this.props.rootId] = draft; - } + }; handleMouseUpKeyUp = (e: React.MouseEvent | React.KeyboardEvent) => { this.setState({ caretPosition: (e.target as TextboxElement).selectionStart || 0, }); - } + }; handleSelect = (e: React.SyntheticEvent) => { Utils.adjustSelection(this.textboxRef.current?.getInputBox(), e); - } + }; handleKeyDown = (e: React.KeyboardEvent) => { const ctrlOrMetaKeyPressed = e.ctrlKey || e.metaKey; @@ -976,7 +976,7 @@ class AdvancedCreateComment extends React.PureComponent { if (lastMessageReactionKeyCombo) { this.reactToLastMessage(e); } - } + }; applyMarkdown = (options: ApplyMarkdownOptions) => { if (this.props.shouldShowPreview) { @@ -999,12 +999,12 @@ class AdvancedCreateComment extends React.PureComponent { const textbox = this.textboxRef.current?.getInputBox(); Utils.setSelectionRange(textbox, res.selectionStart, res.selectionEnd); }); - } + }; handleFileUploadChange = () => { this.isDraftEdited = true; this.focusTextbox(); - } + }; handleUploadStart = (clientIds: string[]) => { const draft = this.state.draft!; @@ -1021,12 +1021,12 @@ class AdvancedCreateComment extends React.PureComponent { // this is a bit redundant with the code that sets focus when the file input is clicked, // but this also resets the focus after a drag and drop this.focusTextbox(); - } + }; handleUploadProgress = (filePreviewInfo: FilePreviewInfo) => { const uploadsProgressPercent = {...this.state.uploadsProgressPercent, [filePreviewInfo.clientId]: filePreviewInfo}; this.setState({uploadsProgressPercent}); - } + }; handleFileUploadComplete = (fileInfos: FileInfo[], clientIds: string[], _: string, rootId?: string) => { const draft = this.draftsForPost[rootId!]!; @@ -1051,7 +1051,7 @@ class AdvancedCreateComment extends React.PureComponent { if (this.props.rootId === rootId) { this.setState({draft: modifiedDraft}); } - } + }; handleUploadError = (err: string | ServerError | null, clientId: string | number = -1, _?: string, rootId = '') => { if (clientId !== -1) { @@ -1084,7 +1084,7 @@ class AdvancedCreateComment extends React.PureComponent { this.props.scrollToBottom(); } }); - } + }; removePreview = (id: string) => { const draft = this.state.draft!; @@ -1127,11 +1127,11 @@ class AdvancedCreateComment extends React.PureComponent { } this.saveDraftFrame = window.setTimeout(() => {}, Constants.SAVE_DRAFT_TIMEOUT); - } + }; getFileUploadTarget = () => { return this.textboxRef.current?.getInputBox(); - } + }; toggleAdvanceTextEditor = () => { this.setState({ @@ -1144,13 +1144,13 @@ class AdvancedCreateComment extends React.PureComponent { name: AdvancedTextEditorConst.COMMENT, value: String(!this.state.isFormattingBarHidden), }]); - } + }; focusTextbox = (keepFocus = false) => { if (this.textboxRef.current && (keepFocus || !UserAgent.isMobile())) { this.textboxRef.current.focus(); } - } + }; shouldEnableAddButton = () => { const {draft} = this.state; @@ -1163,21 +1163,21 @@ class AdvancedCreateComment extends React.PureComponent { } return isErrorInvalidSlashCommand(this.state.serverError); - } + }; showPostDeletedModal = () => { this.props.openModal({ modalId: ModalIdentifiers.POST_DELETED_MODAL, dialogType: PostDeletedModal, }); - } + }; handleBlur = () => { if (!this.isDraftSubmitting) { this.saveDraftWithShow(); } this.lastBlurAt = Date.now(); - } + }; render() { const draft = this.state.draft!; diff --git a/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx b/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx index 13923c5278..630ad71188 100644 --- a/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx +++ b/webapp/channels/src/components/advanced_create_post/advanced_create_post.tsx @@ -372,11 +372,11 @@ class AdvancedCreatePost extends React.PureComponent { actions.getChannelMemberCountsByGroup(currentChannel.id, isTimezoneEnabled); } } - } + }; unloadHandler = () => { this.saveDraftWithShow(); - } + }; saveDraftWithShow = (props = this.props) => { if (this.saveDraftFrame && props.currentChannel) { @@ -393,7 +393,7 @@ class AdvancedCreatePost extends React.PureComponent { } this.saveDraft(props, true); - } + }; saveDraft = (props = this.props, save = false) => { if (this.saveDraftFrame && props.currentChannel) { @@ -402,11 +402,11 @@ class AdvancedCreatePost extends React.PureComponent { clearTimeout(this.saveDraftFrame); this.saveDraftFrame = null; } - } + }; setShowPreview = (newPreviewValue: boolean) => { this.props.actions.setShowPreview(newPreviewValue); - } + }; setOrientationListeners = () => { if (window.screen.orientation && 'onchange' in window.screen.orientation) { @@ -448,22 +448,22 @@ class AdvancedCreatePost extends React.PureComponent { } this.lastOrientation = orientation; - } + }; handlePostError = (postError: React.ReactNode) => { if (this.state.postError !== postError) { this.setState({postError}); } - } + }; toggleEmojiPicker = (e?: React.MouseEvent): void => { e?.stopPropagation(); this.setState({showEmojiPicker: !this.state.showEmojiPicker}); - } + }; hideEmojiPicker = () => { this.handleEmojiClose(); - } + }; doSubmit = async (e?: React.FormEvent) => { const channelId = this.props.currentChannel.id; @@ -576,11 +576,11 @@ class AdvancedCreatePost extends React.PureComponent { this.isDraftSubmitting = false; this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, null, channelId); this.draftsForChannel[channelId] = null; - } + }; handleNotifyAllConfirmation = () => { this.doSubmit(); - } + }; showNotifyAllModal = (mentions: string[], channelTimezoneCount: number, memberNotifyCount: number) => { this.props.actions.openModal({ @@ -593,7 +593,7 @@ class AdvancedCreatePost extends React.PureComponent { onConfirm: () => this.handleNotifyAllConfirmation(), }, }); - } + }; getStatusFromSlashCommand = () => { const {message} = this.state; @@ -721,7 +721,7 @@ class AdvancedCreatePost extends React.PureComponent { } await this.doSubmit(e); - } + }; sendMessage = async (originalPost: Post) => { const { @@ -780,7 +780,7 @@ class AdvancedCreatePost extends React.PureComponent { this.isDraftSubmitting = false; return {data: true}; - } + }; sendReaction(isReaction: RegExpExecArray) { const channelId = this.props.currentChannel.id; @@ -807,7 +807,7 @@ class AdvancedCreatePost extends React.PureComponent { if (this.textboxRef.current && (keepFocus || !UserAgent.isMobile())) { this.textboxRef.current.focus(); } - } + }; postMsgKeyPress = (e: React.KeyboardEvent) => { const {ctrlSend, codeBlockOnCtrlEnter} = this.props; @@ -852,12 +852,12 @@ class AdvancedCreatePost extends React.PureComponent { } this.emitTypingEvent(); - } + }; emitTypingEvent = () => { const channelId = this.props.currentChannel.id; GlobalActions.emitLocalUserTypingEvent(channelId, ''); - } + }; handleChange = (e: React.ChangeEvent) => { const message = e.target.value; @@ -878,7 +878,7 @@ class AdvancedCreatePost extends React.PureComponent { }; this.handleDraftChange(draft); - } + }; handleDraftChange = (draft: PostDraft, instant = false) => { const channelId = this.props.currentChannel.id; @@ -896,7 +896,7 @@ class AdvancedCreatePost extends React.PureComponent { } this.draftsForChannel[channelId] = draft; - } + }; pasteHandler = (e: ClipboardEvent) => { /** @@ -933,7 +933,7 @@ class AdvancedCreatePost extends React.PureComponent { const newCaretPosition = formattedMessage.length - (originalSize - this.state.caretPosition); this.setMessageAndCaretPostion(formattedMessage, newCaretPosition); this.handlePostPasteDraft(formattedMessage); - } + }; handlePostPasteDraft = (message: string) => { const draft = { @@ -944,11 +944,11 @@ class AdvancedCreatePost extends React.PureComponent { const channelId = this.props.currentChannel.id; this.props.actions.setDraft(StoragePrefixes.DRAFT + channelId, draft, channelId); this.draftsForChannel[channelId] = draft; - } + }; handleFileUploadChange = () => { this.focusTextbox(); - } + }; handleUploadStart = (clientIds: string[], channelId: string) => { const uploadsInProgress = [...this.props.draft.uploadsInProgress, ...clientIds]; @@ -964,7 +964,7 @@ class AdvancedCreatePost extends React.PureComponent { // this is a bit redundant with the code that sets focus when the file input is clicked, // but this also resets the focus after a drag and drop this.focusTextbox(); - } + }; handleUploadProgress = (filePreviewInfo: FilePreviewInfo) => { const uploadsProgressPercent = { @@ -972,7 +972,7 @@ class AdvancedCreatePost extends React.PureComponent { [filePreviewInfo.clientId]: filePreviewInfo, }; this.setState({uploadsProgressPercent}); - } + }; handleFileUploadComplete = (fileInfos: FileInfo[], clientIds: string[], channelId: string) => { const draft = {...this.draftsForChannel[channelId]!}; @@ -993,7 +993,7 @@ class AdvancedCreatePost extends React.PureComponent { } this.handleDraftChange(draft, true); - } + }; handleUploadError = (err: string | ServerError, clientId?: string, channelId?: string) => { let serverError = null; @@ -1092,7 +1092,7 @@ class AdvancedCreatePost extends React.PureComponent { if (shouldFocusMainTextbox(e, document.activeElement)) { this.focusTextbox(); } - } + }; documentKeyHandler = (e: KeyboardEvent) => { const ctrlOrMetaKeyPressed = e.ctrlKey || e.metaKey; @@ -1103,11 +1103,11 @@ class AdvancedCreatePost extends React.PureComponent { } this.focusTextboxIfNecessary(e); - } + }; getFileUploadTarget = () => { return this.textboxRef.current?.getInputBox(); - } + }; fillMessageFromHistory() { const lastMessage = this.props.messageInHistoryItem; @@ -1122,11 +1122,11 @@ class AdvancedCreatePost extends React.PureComponent { this.setState({ caretPosition: (e.target as HTMLInputElement).selectionStart || 0, }); - } + }; handleSelect = (e: React.SyntheticEvent) => { Utils.adjustSelection(this.textboxRef.current?.getInputBox(), e as React.KeyboardEvent); - } + }; handleKeyDown = (e: React.KeyboardEvent) => { const messageIsEmpty = this.state.message.length === 0; @@ -1294,7 +1294,7 @@ class AdvancedCreatePost extends React.PureComponent { } else if (ctrlAltCombo && Utils.isKeyPressed(e, KeyCodes.T)) { this.toggleAdvanceTextEditor(); } - } + }; editLastPost = (e: React.KeyboardEvent) => { e.preventDefault(); @@ -1314,7 +1314,7 @@ class AdvancedCreatePost extends React.PureComponent { this.textboxRef.current.blur(); } this.props.actions.setEditingPost(lastPost.id, 'post_textbox', type); - } + }; replyToLastPost = (e: React.KeyboardEvent) => { e.preventDefault(); @@ -1326,17 +1326,17 @@ class AdvancedCreatePost extends React.PureComponent { if (latestReplyablePostId) { this.props.actions.selectPostFromRightHandSideSearchByPostId(latestReplyablePostId); } - } + }; loadPrevMessage = (e: React.KeyboardEvent) => { e.preventDefault(); this.props.actions.moveHistoryIndexBack(Posts.MESSAGE_TYPES.POST).then(() => this.fillMessageFromHistory()); - } + }; loadNextMessage = (e: React.KeyboardEvent) => { e.preventDefault(); this.props.actions.moveHistoryIndexForward(Posts.MESSAGE_TYPES.POST).then(() => this.fillMessageFromHistory()); - } + }; applyMarkdown = (params: ApplyMarkdownOptions) => { if (this.props.shouldShowPreview) { @@ -1358,7 +1358,7 @@ class AdvancedCreatePost extends React.PureComponent { this.handleDraftChange(draft); }); - } + }; reactToLastMessage = (e: KeyboardEvent) => { e.preventDefault(); @@ -1374,7 +1374,7 @@ class AdvancedCreatePost extends React.PureComponent { if (!rhsExpanded && noModalsAreOpen && noPopupsDropdownsAreOpen) { emitShortcutReactToLastPostFrom(Locations.CENTER); } - } + }; handleBlur = () => { if (!this.isDraftSubmitting) { @@ -1382,11 +1382,11 @@ class AdvancedCreatePost extends React.PureComponent { } this.lastBlurAt = Date.now(); - } + }; handleEmojiClose = () => { this.setState({showEmojiPicker: false}); - } + }; setMessageAndCaretPostion = (newMessage: string, newCaretPosition: number) => { const textbox = this.textboxRef.current?.getInputBox(); @@ -1404,7 +1404,7 @@ class AdvancedCreatePost extends React.PureComponent { this.handleDraftChange(draft); }); - } + }; prefillMessage = (message: string, shouldFocus?: boolean) => { this.setMessageAndCaretPostion(message, message.length); @@ -1417,7 +1417,7 @@ class AdvancedCreatePost extends React.PureComponent { } this.focusTextbox(true); } - } + }; handleEmojiClick = (emoji: Emoji) => { const emojiAlias = ('short_names' in emoji && emoji.short_names && emoji.short_names[0]) || emoji.name; @@ -1444,7 +1444,7 @@ class AdvancedCreatePost extends React.PureComponent { } this.handleEmojiClose(); - } + }; handleGifClick = (gif: string) => { if (this.state.message === '') { @@ -1461,7 +1461,7 @@ class AdvancedCreatePost extends React.PureComponent { this.handleDraftChange(draft); } this.handleEmojiClose(); - } + }; toggleAdvanceTextEditor = () => { this.setState({ @@ -1474,11 +1474,11 @@ class AdvancedCreatePost extends React.PureComponent { name: AdvancedTextEditorConst.POST, value: String(!this.state.isFormattingBarHidden), }]); - } + }; handleRemovePriority = () => { this.handlePostPriorityApply(); - } + }; handlePostPriorityApply = (settings?: PostPriorityMetadata) => { const updatedDraft = { @@ -1524,7 +1524,7 @@ class AdvancedCreatePost extends React.PureComponent { this.props.draft.metadata.priority.requested_ack ) ); - } + }; render() { let centerClass = ''; diff --git a/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx b/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx index b3c683c4a2..9b76d8bd7a 100644 --- a/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx +++ b/webapp/channels/src/components/advanced_text_editor/advanced_text_editor.tsx @@ -131,7 +131,7 @@ const AdvanceTextEditor = ({ canUploadFiles, enableEmojiPicker, enableGifPicker, - handleBlur, + handleBlur: onBlur, handlePostError, emitTypingEvent, handleMouseUpKeyUp, @@ -170,6 +170,7 @@ const AdvanceTextEditor = ({ const [scrollbarWidth, setScrollbarWidth] = useState(0); const [renderScrollbar, setRenderScrollbar] = useState(false); const [showFormattingSpacer, setShowFormattingSpacer] = useState(shouldShowPreview); + const [keepEditorInFocus, setKeepEditorInFocus] = useState(false); const input = textboxRef.current?.getInputBox(); @@ -187,6 +188,15 @@ const AdvanceTextEditor = ({ setShowPreview(!shouldShowPreview); }, [shouldShowPreview, setShowPreview]); + const handleBlur = useCallback(() => { + onBlur?.(); + setKeepEditorInFocus(false); + }, [onBlur]); + + const handleFocus = useCallback(() => { + setKeepEditorInFocus(true); + }, []); + let serverErrorJsx = null; if (serverError) { serverErrorJsx = ( @@ -422,6 +432,7 @@ const AdvanceTextEditor = ({ /> )} slot2={null} + shouldScrollIntoView={keepEditorInFocus} /> ); @@ -479,6 +490,7 @@ const AdvanceTextEditor = ({ handlePostError={handlePostError} value={messageValue} onBlur={handleBlur} + onFocus={handleFocus} emojiEnabled={enableEmojiPicker} createMessage={createMessage} channelId={channelId} diff --git a/webapp/channels/src/components/alert_banner.tsx b/webapp/channels/src/components/alert_banner.tsx index ebd3adaae8..b091a555ec 100644 --- a/webapp/channels/src/components/alert_banner.tsx +++ b/webapp/channels/src/components/alert_banner.tsx @@ -21,6 +21,7 @@ import './alert_banner.scss'; export type ModeType = 'danger' | 'warning' | 'info' | 'success'; export type AlertBannerProps = { + id?: string; mode: ModeType; title?: React.ReactNode; message?: React.ReactNode; @@ -35,6 +36,7 @@ export type AlertBannerProps = { } const AlertBanner = ({ + id, mode, title, message, @@ -70,6 +72,7 @@ const AlertBanner = ({ return (
{(text) => {text}} diff --git a/webapp/channels/src/components/analytics/doughnut_chart.tsx b/webapp/channels/src/components/analytics/doughnut_chart.tsx index 01fce5025a..9366f5d4a5 100644 --- a/webapp/channels/src/components/analytics/doughnut_chart.tsx +++ b/webapp/channels/src/components/analytics/doughnut_chart.tsx @@ -52,7 +52,7 @@ export default class DoughnutChart extends React.PureComponent { } else { this.chart = new Chart(ctx, {type: 'doughnut', data: dataCopy, options: {}}); } - } + }; public render(): JSX.Element { let content; diff --git a/webapp/channels/src/components/analytics/line_chart.tsx b/webapp/channels/src/components/analytics/line_chart.tsx index 0c38879109..8207177b64 100644 --- a/webapp/channels/src/components/analytics/line_chart.tsx +++ b/webapp/channels/src/components/analytics/line_chart.tsx @@ -18,7 +18,7 @@ type Props = { } export default class LineChart extends React.PureComponent { - private canvasRef = React.createRef() + private canvasRef = React.createRef(); public static propTypes = { /* @@ -94,7 +94,7 @@ export default class LineChart extends React.PureComponent { if (this.chart && this.canvasRef.current && this.chart.options.responsive) { this.canvasRef.current.style.width = '100%'; } - } + }; public initChart = (update?: boolean): void => { if (!this.canvasRef.current) { @@ -113,7 +113,7 @@ export default class LineChart extends React.PureComponent { } else { this.chart = new Chart(ctx, {type: 'line', data: dataCopy, options: options || {}}); } - } + }; public render(): JSX.Element { let content; diff --git a/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx b/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx index b760279651..151941ee2a 100644 --- a/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx +++ b/webapp/channels/src/components/analytics/system_analytics/system_analytics.tsx @@ -348,7 +348,7 @@ export default class SystemAnalytics extends React.PureComponent { title={ } icon='fa-users' diff --git a/webapp/channels/src/components/analytics/team_analytics/team_analytics.tsx b/webapp/channels/src/components/analytics/team_analytics/team_analytics.tsx index d8659cca9a..532002b35d 100644 --- a/webapp/channels/src/components/analytics/team_analytics/team_analytics.tsx +++ b/webapp/channels/src/components/analytics/team_analytics/team_analytics.tsx @@ -126,7 +126,7 @@ export default class TeamAnalytics extends React.PureComponent { recentlyActiveUsers, newUsers, }); - } + }; private handleTeamChange = (e: React.ChangeEvent): void => { const teamId = e.target.value; @@ -143,7 +143,7 @@ export default class TeamAnalytics extends React.PureComponent { }); this.props.actions.setGlobalItem(LAST_ANALYTICS_TEAM, teamId); - } + }; public render(): JSX.Element { if (this.props.teams.length === 0 || !this.state.team || !this.props.stats[this.state.team.id]) { diff --git a/webapp/channels/src/components/announcement_bar/announcement_bar_controller.tsx b/webapp/channels/src/components/announcement_bar/announcement_bar_controller.tsx index 4285704544..ea14eaa5b1 100644 --- a/webapp/channels/src/components/announcement_bar/announcement_bar_controller.tsx +++ b/webapp/channels/src/components/announcement_bar/announcement_bar_controller.tsx @@ -4,6 +4,7 @@ import React from 'react'; import {ToYearlyNudgeBannerDismissable} from 'components/admin_console/billing/billing_subscriptions/to_yearly_nudge_banner'; +import {ToPaidPlanBannerDismissable} from 'components/admin_console/billing/billing_subscriptions/to_paid_plan_nudge_banner'; import {ClientLicense, ClientConfig, WarnMetricStatus} from '@mattermost/types/config'; import withGetCloudSubscription from '../common/hocs/cloud/with_get_cloud_subscription'; @@ -72,6 +73,7 @@ class AnnouncementBarController extends React.PureComponent { let cloudDelinquencyAnnouncementBar = null; let notifyAdminDowngradeDelinquencyBar = null; let toYearlyNudgeBannerDismissable = null; + let toPaidPlanNudgeBannerDismissable = null; if (this.props.license?.Cloud === 'true') { paymentAnnouncementBar = ( @@ -89,6 +91,7 @@ class AnnouncementBarController extends React.PureComponent { ); toYearlyNudgeBannerDismissable = (); + toPaidPlanNudgeBannerDismissable = (); } let autoStartTrialModal = null; @@ -108,6 +111,7 @@ class AnnouncementBarController extends React.PureComponent { {cloudDelinquencyAnnouncementBar} {notifyAdminDowngradeDelinquencyBar} {toYearlyNudgeBannerDismissable} + {toPaidPlanNudgeBannerDismissable} {this.props.license?.Cloud !== 'true' && } {autoStartTrialModal} diff --git a/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/cloud_trial_announcement_bar.tsx b/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/cloud_trial_announcement_bar.tsx index 4bf0069172..8224463d43 100644 --- a/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/cloud_trial_announcement_bar.tsx +++ b/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/cloud_trial_announcement_bar.tsx @@ -18,6 +18,8 @@ import PricingModal from 'components/pricing_modal'; import {ModalData} from 'types/actions'; +import {AlertCircleOutlineIcon, AlertOutlineIcon} from '@mattermost/compass-icons/components'; + import { Preferences, CloudBanners, @@ -38,6 +40,7 @@ type Props = { daysLeftOnTrial: number; isCloud: boolean; subscription?: Subscription; + reverseTrial: boolean; actions: { savePreferences: (userId: string, preferences: PreferenceType[]) => void; getCloudSubscription: () => void; @@ -83,12 +86,12 @@ class CloudTrialAnnouncementBar extends React.PureComponent { name: CloudBanners.TRIAL, value: `${dismissValue}`, }]); - } + }; shouldShowBanner = () => { const {isFreeTrial, userIsAdmin, isCloud} = this.props; return isFreeTrial && userIsAdmin && isCloud; - } + }; isDismissable = () => { const {daysLeftOnTrial} = this.props; @@ -98,7 +101,7 @@ class CloudTrialAnnouncementBar extends React.PureComponent { dismissable = false; } return dismissable; - } + }; showModal = () => { const {daysLeftOnTrial} = this.props; @@ -117,7 +120,7 @@ class CloudTrialAnnouncementBar extends React.PureComponent { modalId: ModalIdentifiers.PRICING_MODAL, dialogType: PricingModal, }); - } + }; render() { const {daysLeftOnTrial, preferences} = this.props; @@ -132,7 +135,7 @@ class CloudTrialAnnouncementBar extends React.PureComponent { return null; } - const trialMoreThan3DaysMsg = ( + let trialMoreThan7DaysMsg = ( { /> ); - const trialLessThan3DaysMsg = ( + let modalButtonText = t('admin.billing.subscription.cloudTrial.subscribeButton'); + let modalButtonDefaultText = 'Upgrade Now'; + + if (this.props.reverseTrial) { + modalButtonText = t('admin.billing.subscription.cloudReverseTrial.subscribeButton'); + modalButtonDefaultText = 'Review your options'; + } + + if (this.props.reverseTrial) { + const trialEnd = getLocaleDateFromUTC((this.props.subscription?.trial_end_at as number / 1000), 'MMMM Do'); + trialMoreThan7DaysMsg = ( + + ); + } + + let trialLessThan7DaysMsg = ( { /> ); - const userEndTrialDate = getLocaleDateFromUTC((this.props.subscription?.trial_end_at as number / 1000), 'MMMM Do YYYY'); - const userEndTrialHour = getLocaleDateFromUTC((this.props.subscription?.trial_end_at as number / 1000), 'HH:mm:ss', this.props.currentUser.timezone?.automaticTimezone as string); + if (this.props.reverseTrial) { + trialLessThan7DaysMsg = ( + + ); + } - const trialLastDaysMsg = ( + const userEndTrialDate = getLocaleDateFromUTC((this.props.subscription?.trial_end_at as number / 1000), 'MMMM Do YYYY'); + const userEndTrialHour = getLocaleDateFromUTC((this.props.subscription?.trial_end_at as number / 1000), 'HH:mm', this.props.currentUser.timezone?.automaticTimezone as string); + + let trialLastDaysMsg = ( { /> ); + if (this.props.reverseTrial) { + trialLastDaysMsg = ( + + ); + } + let bannerMessage; let icon; - switch (daysLeftOnTrial) { - case TrialPeriodDays.TRIAL_WARNING_THRESHOLD: - case TrialPeriodDays.TRIAL_2_DAYS: - bannerMessage = trialLessThan3DaysMsg; - break; - case TrialPeriodDays.TRIAL_1_DAY: - case TrialPeriodDays.TRIAL_0_DAYS: + + if (daysLeftOnTrial >= TrialPeriodDays.TRIAL_2_DAYS && daysLeftOnTrial <= TrialPeriodDays.TRIAL_WARNING_THRESHOLD) { + bannerMessage = trialLessThan7DaysMsg; + icon = ; + } else if (daysLeftOnTrial <= TrialPeriodDays.TRIAL_1_DAY && daysLeftOnTrial >= TrialPeriodDays.TRIAL_0_DAYS) { bannerMessage = trialLastDaysMsg; - break; - default: - bannerMessage = trialMoreThan3DaysMsg; - icon = ; - break; + icon = ; + } else { + bannerMessage = trialMoreThan7DaysMsg; + icon = ; } const dismissable = this.isDismissable(); @@ -184,8 +223,8 @@ class CloudTrialAnnouncementBar extends React.PureComponent { showCloseButton={dismissable} handleClose={this.handleClose} onButtonClick={this.showModal} - modalButtonText={t('admin.billing.subscription.cloudTrial.subscribeButton')} - modalButtonDefaultText={'Upgrade Now'} + modalButtonText={modalButtonText} + modalButtonDefaultText={modalButtonDefaultText} message={bannerMessage} showLinkAsButton={true} icon={icon} diff --git a/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/index.ts b/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/index.ts index 9b6bbfc443..3d7e4fd871 100644 --- a/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/index.ts +++ b/webapp/channels/src/components/announcement_bar/cloud_trial_announcement_bar/index.ts @@ -21,6 +21,7 @@ import {Preferences, TrialPeriodDays} from 'utils/constants'; import {getRemainingDaysFromFutureTimestamp} from 'utils/utils'; import CloudTrialAnnouncementBar from './cloud_trial_announcement_bar'; +import {getConfig} from 'mattermost-redux/selectors/entities/admin'; function mapStateToProps(state: GlobalState) { const getCategory = makeGetCategory(); @@ -29,6 +30,7 @@ function mapStateToProps(state: GlobalState) { const isCloud = getLicense(state).Cloud === 'true'; let isFreeTrial = false; let daysLeftOnTrial = 0; + const config = getConfig(state); if (isCloud && subscription?.is_free_trial === 'true') { isFreeTrial = true; @@ -46,6 +48,7 @@ function mapStateToProps(state: GlobalState) { isCloud, subscription, preferences: getCategory(state, Preferences.CLOUD_TRIAL_BANNER), + reverseTrial: Boolean(config.FeatureFlags?.CloudReverseTrial), }; } diff --git a/webapp/channels/src/components/announcement_bar/contact_sales/contact_us.tsx b/webapp/channels/src/components/announcement_bar/contact_sales/contact_us.tsx index 48abe4a4dd..74b576192d 100644 --- a/webapp/channels/src/components/announcement_bar/contact_sales/contact_us.tsx +++ b/webapp/channels/src/components/announcement_bar/contact_sales/contact_us.tsx @@ -6,8 +6,9 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; import {trackEvent} from 'actions/telemetry_actions'; +import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; + import './contact_us.scss'; -import {LicenseLinks} from '../../../utils/constants'; export interface Props { buttonTextElement?: JSX.Element; @@ -16,10 +17,12 @@ export interface Props { } const ContactUsButton: React.FC = (props: Props) => { + const [openContactSales] = useOpenSalesLink(); + const handleContactUsLinkClick = async (e: React.MouseEvent) => { e.preventDefault(); trackEvent('admin', props.eventID || 'in_trial_contact_sales'); - window.open(LicenseLinks.CONTACT_SALES, '_blank'); + openContactSales(); }; return ( diff --git a/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx b/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx index 0a9c4d6574..f93791291a 100644 --- a/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx +++ b/webapp/channels/src/components/announcement_bar/default_announcement_bar/announcement_bar.tsx @@ -19,6 +19,7 @@ import ToggleModalButton from 'components/toggle_modal_button'; import {trackEvent} from 'actions/telemetry_actions.jsx'; type Props = { + id?: string; showCloseButton: boolean; color: string; textColor: string; @@ -69,7 +70,7 @@ export default class AnnouncementBar extends React.PureComponent { showLinkAsButton: false, isTallBanner: false, showCTA: true, - } + }; enableToolTipIfNeeded = () => { const elm = this.messageRef.current; @@ -82,7 +83,7 @@ export default class AnnouncementBar extends React.PureComponent { return; } this.setState({showTooltip: false}); - } + }; componentDidMount() { this.props.actions.incrementAnnouncementBarCount(); @@ -107,7 +108,7 @@ export default class AnnouncementBar extends React.PureComponent { if (this.props.handleClose) { this.props.handleClose(); } - } + }; render() { if (!this.props.message) { @@ -172,6 +173,7 @@ export default class AnnouncementBar extends React.PureComponent { style={barStyle} // eslint-disable-next-line react/no-unknown-property css={{gridArea: 'announcement'}} + data-testid={this.props.id} > { + const [openContactSales] = useOpenSalesLink(); const dispatch = useDispatch(); const stats = useSelector((state: GlobalState) => state.entities.admin.analytics) || {}; const isAdmin = useSelector(isCurrentUserSystemAdmin); @@ -90,7 +92,7 @@ const OverageUsersBanner = () => { const handleContactSalesClick = (e: React.MouseEvent) => { e.preventDefault(); trackEventFn('Contact Sales'); - window.open(LicenseLinks.CONTACT_SALES, '_blank'); + openContactSales(); }; const handleClick = isExpandable ? handleUpdateSeatsSelfServeClick : handleContactSalesClick; diff --git a/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx b/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx index 212c9dadae..dedd30a7c9 100644 --- a/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx +++ b/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx @@ -7,7 +7,7 @@ import {fireEvent, screen} from '@testing-library/react'; import {DeepPartial} from '@mattermost/types/utilities'; import {GlobalState} from 'types/store'; import {General} from 'mattermost-redux/constants'; -import {LicenseLinks, OverActiveUserLimits, Preferences, StatTypes} from 'utils/constants'; +import {OverActiveUserLimits, Preferences, StatTypes} from 'utils/constants'; import {renderWithIntlAndStore} from 'tests/react_testing_utils'; import {savePreferences} from 'mattermost-redux/actions/preferences'; import {trackEvent} from 'actions/telemetry_actions'; @@ -249,7 +249,10 @@ describe('components/overage_users_banner', () => { fireEvent.click(screen.getByText(contactSalesTextLink)); expect(windowSpy).toBeCalledTimes(1); - expect(windowSpy).toBeCalledWith(LicenseLinks.CONTACT_SALES, '_blank'); + + // only the email is encoded and other params are empty. See logic for useOpenSalesLink hook + const salesLinkWithEncodedParams = 'https://mattermost.com/contact-sales/?qk=&qp=&qw=&qx=dGVzdEBtYXR0ZXJtb3N0LmNvbQ==&utm_source=mattermost&utm_medium=in-product'; + expect(windowSpy).toBeCalledWith(salesLinkWithEncodedParams, '_blank'); expect(trackEvent).toBeCalledTimes(1); expect(trackEvent).toBeCalledWith('insights', 'click_true_up_warning', { cta: 'Contact Sales', @@ -368,7 +371,10 @@ describe('components/overage_users_banner', () => { fireEvent.click(screen.getByText(contactSalesTextLink)); expect(windowSpy).toBeCalledTimes(1); - expect(windowSpy).toBeCalledWith(LicenseLinks.CONTACT_SALES, '_blank'); + + // only the email is encoded and other params are empty. See logic for useOpenSalesLink hook + const salesLinkWithEncodedParams = 'https://mattermost.com/contact-sales/?qk=&qp=&qw=&qx=dGVzdEBtYXR0ZXJtb3N0LmNvbQ==&utm_source=mattermost&utm_medium=in-product'; + expect(windowSpy).toBeCalledWith(salesLinkWithEncodedParams, '_blank'); expect(trackEvent).toBeCalledTimes(1); expect(trackEvent).toBeCalledWith('insights', 'click_true_up_error', { cta: 'Contact Sales', diff --git a/webapp/channels/src/components/announcement_bar/payment_announcement_bar/payment_announcement_bar.tsx b/webapp/channels/src/components/announcement_bar/payment_announcement_bar/payment_announcement_bar.tsx index bd052684cf..5fe7c7fa4b 100644 --- a/webapp/channels/src/components/announcement_bar/payment_announcement_bar/payment_announcement_bar.tsx +++ b/webapp/channels/src/components/announcement_bar/payment_announcement_bar/payment_announcement_bar.tsx @@ -35,7 +35,7 @@ class PaymentAnnouncementBar extends React.PureComponent { isMostRecentPaymentFailed = () => { return this.props.subscription?.last_invoice?.status === 'failed'; - } + }; shouldShowBanner = () => { const {userIsAdmin, isCloud, subscription} = this.props; @@ -62,11 +62,11 @@ class PaymentAnnouncementBar extends React.PureComponent { } return true; - } + }; updatePaymentInfo = () => { getHistory().push('/admin_console/billing/payment_info'); - } + }; render() { if (isEmpty(this.props.customer) || isEmpty(this.props.subscription)) { diff --git a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx index 7582add168..9dae6a38d0 100644 --- a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx +++ b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx @@ -3,13 +3,46 @@ import React from 'react'; import {ReactWrapper} from 'enzyme'; +import {Provider} from 'react-redux'; import {act} from 'react-dom/test-utils'; import {Client4} from 'mattermost-redux/client'; import {mountWithIntl} from 'tests/helpers/intl-test-helper'; +import mockStore from 'tests/test_store'; import RenewalLink from './renewal_link'; +const initialState = { + views: { + announcementBar: { + announcementBarState: { + announcementBarCount: 1, + }, + }, + }, + entities: { + general: { + config: { + CWSURL: '', + }, + license: { + IsLicensed: 'true', + Cloud: 'true', + }, + }, + users: { + currentUserId: 'current_user_id', + profiles: { + current_user_id: {roles: 'system_user'}, + }, + }, + preferences: { + myPreferences: {}, + }, + cloud: {}, + }, +}; + const actImmediate = (wrapper: ReactWrapper) => act( () => @@ -40,7 +73,8 @@ describe('components/RenewalLink', () => { }); }); getRenewalLinkSpy.mockImplementation(() => promise); - const wrapper = mountWithIntl(); + const store = mockStore(initialState); + const wrapper = mountWithIntl(); // wait for the promise to resolve and component to update await actImmediate(wrapper); @@ -54,7 +88,8 @@ describe('components/RenewalLink', () => { reject(new Error('License cannot be renewed from portal')); }); getRenewalLinkSpy.mockImplementation(() => promise); - const wrapper = mountWithIntl(); + const store = mockStore(initialState); + const wrapper = mountWithIntl(); // wait for the promise to resolve and component to update await actImmediate(wrapper); diff --git a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx index 3ca79b1e11..dfae9f3ea1 100644 --- a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx +++ b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.tsx @@ -11,9 +11,9 @@ import {trackEvent} from 'actions/telemetry_actions'; import {ModalData} from 'types/actions'; import { - LicenseLinks, ModalIdentifiers, } from 'utils/constants'; +import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; import NoInternetConnection from '../no_internet_connection/no_internet_connection'; @@ -31,6 +31,9 @@ export interface RenewalLinkProps { const RenewalLink = (props: RenewalLinkProps) => { const [renewalLink, setRenewalLink] = useState(''); const [manualInterventionRequired, setManualInterventionRequired] = useState(false); + + const [openContactSales] = useOpenSalesLink(); + useEffect(() => { Client4.getRenewalLink().then(({renewal_link: renewalLinkParam}) => { try { @@ -55,7 +58,7 @@ const RenewalLink = (props: RenewalLinkProps) => { } window.open(renewalLink, '_blank'); } else if (manualInterventionRequired) { - window.open(LicenseLinks.CONTACT_SALES, '_blank'); + openContactSales(); } else { showConnectionErrorModal(); } diff --git a/webapp/channels/src/components/announcement_bar/show_start_trial_modal/show_start_trial_modal.tsx b/webapp/channels/src/components/announcement_bar/show_start_trial_modal/show_start_trial_modal.tsx index 93ddc7f2f6..4393ea478d 100644 --- a/webapp/channels/src/components/announcement_bar/show_start_trial_modal/show_start_trial_modal.tsx +++ b/webapp/channels/src/components/announcement_bar/show_start_trial_modal/show_start_trial_modal.tsx @@ -13,8 +13,8 @@ import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users'; import {savePreferences} from 'mattermost-redux/actions/preferences'; +import useOpenStartTrialFormModal from 'components/common/hooks/useOpenStartTrialFormModal'; -import {openModal} from 'actions/views/modals'; import {GlobalState} from 'types/store'; import { @@ -24,13 +24,12 @@ import { ModalIdentifiers, } from 'utils/constants'; -import StartTrialModal from 'components/start_trial_modal'; - import {trackEvent} from 'actions/telemetry_actions'; import {isModalOpen} from 'selectors/views/modals'; const ShowStartTrialModal = () => { const isUserAdmin = useSelector((state: GlobalState) => isCurrentUserSystemAdmin(state)); + const openStartTrialFormModal = useOpenStartTrialFormModal(); const dispatch = useDispatch(); const getCategory = makeGetCategory(); @@ -81,11 +80,7 @@ const ShowStartTrialModal = () => { const hasEnvMoreThan10Users = Number(totalUsers) > userThreshold; const hadAdminDismissedModal = preferences.some((pref: PreferenceType) => pref.name === Constants.TRIAL_MODAL_AUTO_SHOWN && pref.value === TRUE); if (isUserAdmin && !isBenefitsModalOpened && hasEnvMoreThan10Users && hasEnvMoreThan6Hours && !hadAdminDismissedModal && !isLicensedOrPreviousLicensed) { - dispatch(openModal({ - modalId: ModalIdentifiers.START_TRIAL_MODAL, - dialogType: StartTrialModal, - dialogProps: {onClose: handleOnClose}, - })); + openStartTrialFormModal({trackingLocation: 'show_start_trial_modal'}, handleOnClose); trackEvent( TELEMETRY_CATEGORIES.SELF_HOSTED_START_TRIAL_AUTO_MODAL, 'trigger_start_trial_auto_modal', diff --git a/webapp/channels/src/components/announcement_bar/text_dismissable_bar.tsx b/webapp/channels/src/components/announcement_bar/text_dismissable_bar.tsx index 3a630dff06..5895aa0c1d 100644 --- a/webapp/channels/src/components/announcement_bar/text_dismissable_bar.tsx +++ b/webapp/channels/src/components/announcement_bar/text_dismissable_bar.tsx @@ -53,7 +53,7 @@ export default class TextDismissableBar extends React.PureComponent { reloadPage = () => { window.location.reload(); - } + }; render() { const {buildHashOnAppLoad} = this.state; diff --git a/webapp/channels/src/components/app_bar/__snapshots__/app_bar.test.tsx.snap b/webapp/channels/src/components/app_bar/__snapshots__/app_bar.test.tsx.snap index 0f2403dc6b..528d89c426 100644 --- a/webapp/channels/src/components/app_bar/__snapshots__/app_bar.test.tsx.snap +++ b/webapp/channels/src/components/app_bar/__snapshots__/app_bar.test.tsx.snap @@ -1,63 +1,38 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`components/app_bar/app_bar should match snapshot on mount 1`] = ` -.c0:last-child, -.c0:first-child { - display: none; -} -
- - - - Playbooks Tooltip - - - } - placement="left" - trigger={ - Array [ - "hover", - "focus", - ] + Playbooks Tooltip - + } placement="left" trigger={ @@ -67,77 +42,73 @@ exports[`components/app_bar/app_bar should match snapshot on mount 1`] = ` ] } > -
+ + Playbooks Tooltip + + + } + placement="left" + trigger={ + Array [ + "hover", + "focus", + ] + } >
- fallback_component +
+ fallback_component +
-
+
- -
- <_StyledHr - className="app-bar__divider" - key="divider" - > +
- - - - - Create Subscription - - - } - placement="left" - trigger={ - Array [ - "hover", - "focus", - ] + Create Subscription - + } placement="left" trigger={ @@ -147,25 +118,49 @@ exports[`components/app_bar/app_bar should match snapshot on mount 1`] = ` ] } > -
+ + Create Subscription + + + } + placement="left" + trigger={ + Array [ + "hover", + "focus", + ] + } >
- +
+ +
-
+
- -
+ +
`; diff --git a/webapp/channels/src/components/app_bar/app_bar.scss b/webapp/channels/src/components/app_bar/app_bar.scss index c45afabf44..ce7813b3c9 100644 --- a/webapp/channels/src/components/app_bar/app_bar.scss +++ b/webapp/channels/src/components/app_bar/app_bar.scss @@ -1,6 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +@import 'utils/mixins'; + $app-bar-icon-size: 24px; $app-bar-width: 48px; @@ -10,129 +12,143 @@ $app-bar-width: 48px; display: none; } - position: relative; - width: $app-bar-width; - padding-top: 16px; + display: flex; + min-height: 0; + flex-flow: column; + border-left: solid 1px rgba(var(--center-channel-color-rgb), 0.12); background-color: var(--center-channel-bg); - -ms-overflow-style: none; - overflow-x: hidden; - overflow-y: scroll; - scrollbar-width: none; - text-align: center; - &::before { - position: absolute; - top: 0; - display: block; - width: 100%; - height: 100%; - border-left: solid 1px rgba(var(--center-channel-color-rgb), 0.12); - background-color: rgba(var(--center-channel-color-rgb), 0.04); - content: ''; - } - - .app-bar__icon { + &__top { position: relative; - // Render App Bar icons on top of the RHS background div - //(see `@media screen and (min-width: 769px) > #sidebar-right` in sass/layout/_sidebar-right.scss) - z-index: 21; - width: 100%; - border-left: none; - margin-bottom: 16px; - cursor: pointer; + display: flex; + width: $app-bar-width; + flex: 1; + flex-flow: column; + padding-top: 16px; + background-color: rgba(var(--center-channel-color-rgb), 0.04); + -ms-overflow-style: none; + overflow-x: hidden; + overflow-y: scroll; + scrollbar-width: none; + text-align: center; - &--active { - &::before { - position: absolute; - top: 0; - left: 0; - width: 3px; - height: $app-bar-icon-size; - background-color: var(--sidebar-text-active-border); - border-radius: 0 2px 2px 0; - content: ''; + .app-bar__icon { + position: relative; + // Render App Bar icons on top of the RHS background div + //(see `@media screen and (min-width: 769px) > #sidebar-right` in sass/layout/_sidebar-right.scss) + z-index: 21; + width: 100%; + border-left: none; + margin-bottom: 16px; + cursor: pointer; + + &--active { + &::before { + position: absolute; + top: 0; + left: 0; + width: 3px; + height: $app-bar-icon-size; + background-color: var(--sidebar-text-active-border); + border-radius: 0 2px 2px 0; + content: ''; + } + + .app-bar__icon-inner, + span:not(.pulsating_dot) { + // if we want to show a tourtip/pulsating dot in any of the app bar icons, these styles must be ommitted when span.pulsating_dot + box-shadow: 0 0 0 2px var(--sidebar-text-active-border); + + &:hover { + box-shadow: 0 0 0 2px rgba(var(--sidebar-text-active-border-rgb), 0.92) !important; + } + } } .app-bar__icon-inner, span:not(.pulsating_dot) { - // if we want to show a tourtip/pulsating dot in any of the app bar icons, these styles must be ommitted when span.pulsating_dot - box-shadow: 0 0 0 2px var(--sidebar-text-active-border); - - &:hover { - box-shadow: 0 0 0 2px rgba(var(--sidebar-text-active-border-rgb), 0.92) !important; - } - } - } - - .app-bar__icon-inner, - span:not(.pulsating_dot) { - display: block; - overflow: hidden; - width: $app-bar-icon-size; - height: $app-bar-icon-size; - margin: 0 auto; - border-radius: 50%; - line-height: 1; - - &:hover { - box-shadow: 0 0 0 2px rgba(var(--center-channel-color-rgb), 0.16); - } - - img { + display: block; + overflow: hidden; width: $app-bar-icon-size; height: $app-bar-icon-size; + margin: 0 auto; border-radius: 50%; - } - } + line-height: 1; - span:not(.pulsating_dot) { - padding: 2px; - background-color: white; - fill: var(--button-bg); - font-size: 14px; - line-height: 20px; - vertical-align: middle; + &:hover { + box-shadow: 0 0 0 2px rgba(var(--center-channel-color-rgb), 0.16); + } - &.CompassIcon, - &.icon-brand-zoom { - font-size: 20px; - - &::before { - margin: 0 0 0 0.5px; + img { + width: $app-bar-icon-size; + height: $app-bar-icon-size; + border-radius: 50%; } } - } - .app-bar__old-icon { - color: rgba(var(--center-channel-color-rgb), 0.56); + span:not(.pulsating_dot) { + padding: 2px; + background-color: white; + fill: var(--button-bg); + font-size: 14px; + line-height: 20px; + vertical-align: middle; - &:hover, - &--active { - color: rgba(var(--center-channel-color-rgb), 0.72); + &.CompassIcon, + &.icon-brand-zoom { + font-size: 20px; + + &::before { + margin: 0 0 0 0.5px; + } + } + } + + .app-bar__old-icon { + color: rgba(var(--center-channel-color-rgb), 0.56); + + &:hover, + &--active { + color: rgba(var(--center-channel-color-rgb), 0.72); + } + } + + .app-bar__icon-inner--centered { + display: grid; + place-items: center; } } - .app-bar__icon-inner--centered { - display: grid; - place-items: center; + .app-bar__divider { + width: 28px; + border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.16); + margin-top: 14px; + margin-bottom: 14px; + } + + .app-bar__icon.channel-header__icon--active { + background: rgba(var(--button-bg-rgb), 0.08); + color: var(--button-bg); + fill: var(--button-bg); } } - .app-bar__divider { - width: 28px; - border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.16); - margin-top: 14px; - margin-bottom: 14px; - } + &__bottom { + display: flex; + flex-flow: column; + align-items: center; + padding-top: 24px; + padding-bottom: 36px; + background-color: rgba(var(--center-channel-color-rgb), 0.04); - .app-bar__icon.channel-header__icon--active { - background: rgba(var(--button-bg-rgb), 0.08); - color: var(--button-bg); - fill: var(--button-bg); + .app_bar__marketplace_button { + @include icon-button; + @include icon-button-small-compact; + } } } // This style is defined outside the .app-bar block above because it doesn't seem to work when defined there -.app-bar::-webkit-scrollbar { +.app-bar__top::-webkit-scrollbar { display: none; } diff --git a/webapp/channels/src/components/app_bar/app_bar.test.tsx b/webapp/channels/src/components/app_bar/app_bar.test.tsx index 03598dbf3d..3f8d429853 100644 --- a/webapp/channels/src/components/app_bar/app_bar.test.tsx +++ b/webapp/channels/src/components/app_bar/app_bar.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react'; -import {mount} from 'enzyme'; +import {mount, shallow} from 'enzyme'; import 'jest-styled-components'; import {AppBinding} from '@mattermost/types/apps'; @@ -10,6 +10,7 @@ import {AppBinding} from '@mattermost/types/apps'; import {PluginComponent} from 'types/store/plugins'; import {GlobalState} from 'types/store'; +import {Permissions} from 'mattermost-redux/constants'; import {AppBindingLocations} from 'mattermost-redux/constants/apps'; import AppBar from './app_bar'; @@ -82,6 +83,21 @@ describe('components/app_bar/app_bar', () => { myPreferences: { }, } as any, + users: { + currentUserId: 'user1', + profiles: { + user1: { + roles: 'system_user', + }, + }, + } as any, + roles: { + roles: { + system_user: { + permissions: [], + }, + }, + } as any, }, } as GlobalState; }); @@ -134,4 +150,48 @@ describe('components/app_bar/app_bar', () => { expect(wrapper).toMatchSnapshot(); }); + + test('should not show marketplace if disabled or user does not have SYSCONSOLE_WRITE_PLUGINS permission', async () => { + mockState.entities.general = { + config: { + EnableAppBar: 'true', + FeatureFlagAppsEnabled: 'true', + EnableMarketplace: 'true', + PluginsEnabled: 'true', + }, + } as any; + + const wrapper = shallow( + , + ); + + expect(wrapper.find('AppBarMarketplace').exists()).toEqual(false); + }); + + test('should show marketplace if enabled and user has SYSCONSOLE_WRITE_PLUGINS permission', async () => { + mockState.entities.general = { + config: { + EnableAppBar: 'true', + FeatureFlagAppsEnabled: 'true', + EnableMarketplace: 'true', + PluginsEnabled: 'true', + }, + } as any; + + mockState.entities.roles = { + roles: { + system_user: { + permissions: [ + Permissions.SYSCONSOLE_WRITE_PLUGINS, + ], + }, + }, + } as any; + + const wrapper = shallow( + , + ); + + expect(wrapper.find('AppBarMarketplace').exists()).toEqual(true); + }); }); diff --git a/webapp/channels/src/components/app_bar/app_bar.tsx b/webapp/channels/src/components/app_bar/app_bar.tsx index ec05a5bd19..3ae5815c2a 100644 --- a/webapp/channels/src/components/app_bar/app_bar.tsx +++ b/webapp/channels/src/components/app_bar/app_bar.tsx @@ -12,8 +12,15 @@ import {getAppBarAppBindings} from 'mattermost-redux/selectors/entities/apps'; import {getAppBarPluginComponents, getChannelHeaderPluginComponents, shouldShowAppBar} from 'selectors/plugins'; import {suitePluginIds} from 'utils/constants'; +import {Permissions} from 'mattermost-redux/constants'; +import {isMarketplaceEnabled} from 'mattermost-redux/selectors/entities/general'; +import {haveICurrentTeamPermission} from 'mattermost-redux/selectors/entities/roles'; + +import {GlobalState} from '@mattermost/types/store'; + import AppBarPluginComponent, {isAppBarPluginComponent} from './app_bar_plugin_component'; import AppBarBinding, {isAppBinding} from './app_bar_binding'; +import AppBarMarketplace from './app_bar_marketplace'; import './app_bar.scss'; @@ -24,6 +31,10 @@ export default function AppBar() { const currentProduct = useCurrentProduct(); const currentProductId = useCurrentProductId(); const enabled = useSelector(shouldShowAppBar); + const canOpenMarketplace = useSelector((state: GlobalState) => ( + isMarketplaceEnabled(state) && + haveICurrentTeamPermission(state, Permissions.SYSCONSOLE_WRITE_PLUGINS) + )); if ( !enabled || @@ -40,11 +51,15 @@ export default function AppBar() { const items: ReactNode[] = [ ...coreProductComponents, - divider, + getDivider(coreProductComponents.length, (pluginComponents.length + channelHeaderComponents.length + appBarBindings.length)), ...pluginComponents, ...channelHeaderComponents, ...appBarBindings, ].map((x) => { + if (!x) { + return x; + } + if (isAppBarPluginComponent(x)) { if (!inScope(x.supportedProductIds ?? null, currentProductId, currentProduct?.pluginId)) { return null; @@ -69,26 +84,23 @@ export default function AppBar() { return x; }); - if (!items.some((x) => Boolean(x) && x !== divider)) { - return null; - } - return (
- {items} +
+ {items} +
+ {canOpenMarketplace && ( +
+ +
+ )}
); } -const divider = ( +const getDivider = (beforeCount: number, afterCount: number) => (beforeCount && afterCount ? (
-); +) : null); diff --git a/webapp/channels/src/components/app_bar/app_bar_marketplace.tsx b/webapp/channels/src/components/app_bar/app_bar_marketplace.tsx new file mode 100644 index 0000000000..1bbfe5cafe --- /dev/null +++ b/webapp/channels/src/components/app_bar/app_bar_marketplace.tsx @@ -0,0 +1,55 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback} from 'react'; +import {useDispatch} from 'react-redux'; +import {useIntl} from 'react-intl'; +import {Tooltip} from 'react-bootstrap'; +import {openModal} from 'actions/views/modals'; + +import MarketplaceModal from 'components/plugin_marketplace/marketplace_modal'; +import OverlayTrigger from 'components/overlay_trigger'; + +import {Constants, ModalIdentifiers} from 'utils/constants'; +import {ViewGridPlusOutlineIcon} from '@mattermost/compass-icons/components'; + +const AppBarMarketplace = () => { + const {formatMessage} = useIntl(); + const dispatch = useDispatch(); + + const handleOpenMarketplace = useCallback(() => { + dispatch( + openModal({ + modalId: ModalIdentifiers.PLUGIN_MARKETPLACE, + dialogType: MarketplaceModal, + dialogProps: {openedFrom: 'app_bar'}, + }), + ); + }, [dispatch]); + + const label = formatMessage({id: 'app_bar.marketplace', defaultMessage: 'App Marketplace'}); + + return ( + + {label} + + )} + > + + + ); +}; + +export default AppBarMarketplace; diff --git a/webapp/channels/src/components/apps_form/apps_form_component.tsx b/webapp/channels/src/components/apps_form/apps_form_component.tsx index f6c3864982..a83eb11274 100644 --- a/webapp/channels/src/components/apps_form/apps_form_component.tsx +++ b/webapp/channels/src/components/apps_form/apps_form_component.tsx @@ -132,7 +132,7 @@ export class AppsForm extends React.PureComponent { } return hasErrors; - } + }; handleSubmit = async (e: React.FormEvent, submitName?: string, value?: string) => { e.preventDefault(); @@ -286,7 +286,7 @@ export class AppsForm extends React.PureComponent { return []; } } - } + }; onHide = () => { this.handleHide(false); diff --git a/webapp/channels/src/components/apps_form/apps_form_container.tsx b/webapp/channels/src/components/apps_form/apps_form_container.tsx index 90496775a4..2a816bb5d8 100644 --- a/webapp/channels/src/components/apps_form/apps_form_container.tsx +++ b/webapp/channels/src/components/apps_form/apps_form_container.tsx @@ -185,7 +185,7 @@ class AppsFormContainer extends React.PureComponent { creq.query = userInput; return this.props.actions.doAppLookup(creq, intl); - } + }; render() { const {form} = this.state; diff --git a/webapp/channels/src/components/apps_form/apps_form_field/apps_form_field.tsx b/webapp/channels/src/components/apps_form/apps_form_field/apps_form_field.tsx index b0497bcf80..5f6f399861 100644 --- a/webapp/channels/src/components/apps_form/apps_form_field/apps_form_field.tsx +++ b/webapp/channels/src/components/apps_form/apps_form_field/apps_form_field.tsx @@ -56,7 +56,7 @@ export default class AppsFormField extends React.PureComponent { } else { onChange(name, option); } - } + }; render() { const { diff --git a/webapp/channels/src/components/apps_form/apps_form_field/apps_form_select_field.tsx b/webapp/channels/src/components/apps_form/apps_form_field/apps_form_select_field.tsx index 8ce3684fbb..59fbe98db7 100644 --- a/webapp/channels/src/components/apps_form/apps_form_field/apps_form_select_field.tsx +++ b/webapp/channels/src/components/apps_form/apps_form_field/apps_form_select_field.tsx @@ -81,11 +81,11 @@ export default class AppsFormSelectField extends React.PureComponent { this.props.onChange(selectedOption); - } + }; loadDynamicOptions = async (userInput: string): Promise => { return this.props.performLookup(this.props.field.name, userInput); - } + }; loadDynamicUserOptions = async (userInput: string): Promise => { const usersSearchResults: UserAutocomplete = await this.props.actions.autocompleteUsers(userInput.toLowerCase()); @@ -95,7 +95,7 @@ export default class AppsFormSelectField extends React.PureComponent => { let channelsSearchResults: Channel[] = []; @@ -105,7 +105,7 @@ export default class AppsFormSelectField extends React.PureComponent {}); return channelsSearchResults.map((channel) => ({...channel, label: channel.display_name, value: channel.id})); - } + }; renderDynamicSelect() { const {field} = this.props; diff --git a/webapp/channels/src/components/at_mention/at_mention.tsx b/webapp/channels/src/components/at_mention/at_mention.tsx index d6fc9c99cd..4bb914369f 100644 --- a/webapp/channels/src/components/at_mention/at_mention.tsx +++ b/webapp/channels/src/components/at_mention/at_mention.tsx @@ -46,7 +46,7 @@ export default class AtMention extends React.PureComponent { hasMention: false, disableHighlight: false, disableGroupHighlight: false, - } + }; constructor(props: Props) { super(props); @@ -65,12 +65,12 @@ export default class AtMention extends React.PureComponent { const placement = popOverOverlayPosition(targetBounds, getViewportSize().h, getViewportSize().h - 240); this.setState({target, show: !this.state.show, placement}); } - } + }; handleClick = (e: React.MouseEvent) => { e.preventDefault(); this.showOverlay(e.target as HTMLAnchorElement); - } + }; handleKeyDown = (e: React.KeyboardEvent) => { if (isKeyPressed(e, Constants.KeyCodes.ENTER) || isKeyPressed(e, Constants.KeyCodes.SPACE)) { @@ -80,11 +80,11 @@ export default class AtMention extends React.PureComponent { e.stopPropagation(); this.showOverlay(e.target as HTMLAnchorElement); } - } + }; hideOverlay = () => { this.setState({show: false}); - } + }; render() { const user = getUserOrGroupFromMentionName(this.props.usersByUsername, this.props.mentionName) as UserProfile | ''; diff --git a/webapp/channels/src/components/audio_video_preview/audio_video_preview.tsx b/webapp/channels/src/components/audio_video_preview/audio_video_preview.tsx index 6f4eacb678..3200a0c535 100644 --- a/webapp/channels/src/components/audio_video_preview/audio_video_preview.tsx +++ b/webapp/channels/src/components/audio_video_preview/audio_video_preview.tsx @@ -58,13 +58,13 @@ export default class AudioVideoPreview extends React.PureComponent this.setState({ canPlay: true, }); - } + }; handleLoadError = () => { this.setState({ canPlay: false, }); - } + }; stop = () => { if (this.videoRef.current) { @@ -72,7 +72,7 @@ export default class AudioVideoPreview extends React.PureComponent video.pause(); video.currentTime = 0; } - } + }; render() { if (!this.state.canPlay) { diff --git a/webapp/channels/src/components/authorize/authorize.tsx b/webapp/channels/src/components/authorize/authorize.tsx index 9058b91276..0f36351340 100644 --- a/webapp/channels/src/components/authorize/authorize.tsx +++ b/webapp/channels/src/components/authorize/authorize.tsx @@ -79,7 +79,7 @@ export default class Authorize extends React.PureComponent { } }, ); - } + }; public handleDeny = (): void => { const redirectUri = (new URLSearchParams(this.props.location.search)).get('redirect_uri'); @@ -89,7 +89,7 @@ export default class Authorize extends React.PureComponent { } getHistory().replace('/error'); - } + }; public render(): ReactNode { const app = this.state.app; diff --git a/webapp/channels/src/components/autocomplete_selector.jsx b/webapp/channels/src/components/autocomplete_selector.jsx index f5d1632bd1..b14a5ece91 100644 --- a/webapp/channels/src/components/autocomplete_selector.jsx +++ b/webapp/channels/src/components/autocomplete_selector.jsx @@ -47,7 +47,7 @@ export default class AutocompleteSelector extends React.PureComponent { } this.setState({input: e.target.value}); - } + }; handleSelected = (selected) => { this.setState({input: ''}); @@ -61,11 +61,11 @@ export default class AutocompleteSelector extends React.PureComponent { this.suggestionRef.blur(); } }); - } + }; setSuggestionRef = (ref) => { this.suggestionRef = ref; - } + }; onFocus = () => { this.setState({focused: true}); @@ -73,7 +73,7 @@ export default class AutocompleteSelector extends React.PureComponent { if (this.props.toggleFocus) { this.props.toggleFocus(true); } - } + }; onBlur = () => { this.setState({focused: false}); @@ -81,7 +81,7 @@ export default class AutocompleteSelector extends React.PureComponent { if (this.props.toggleFocus) { this.props.toggleFocus(false); } - } + }; render() { const { diff --git a/webapp/channels/src/components/autosize_textarea.tsx b/webapp/channels/src/components/autosize_textarea.tsx index a8259e0cb9..83a30afb07 100644 --- a/webapp/channels/src/components/autosize_textarea.tsx +++ b/webapp/channels/src/components/autosize_textarea.tsx @@ -61,7 +61,7 @@ export class AutosizeTextarea extends React.PureComponent { this.props.onHeightChange?.(height, parseInt(style.maxHeight || '0', 10)); } - } + }; private recalculatePadding = () => { if (!this.referenceRef.current || !this.textarea) { @@ -74,7 +74,7 @@ export class AutosizeTextarea extends React.PureComponent { if (paddingRight && paddingRight !== this.referenceRef.current.style.paddingRight) { this.referenceRef.current.style.paddingRight = paddingRight; } - } + }; private recalculateWidth = () => { if (!this.measuringRef) { @@ -87,7 +87,7 @@ export class AutosizeTextarea extends React.PureComponent { this.props.onWidthChange?.(width); }); } - } + }; private setTextareaRef = (textarea: HTMLTextAreaElement) => { if (this.props.forwardedRef) { @@ -99,7 +99,7 @@ export class AutosizeTextarea extends React.PureComponent { } this.textarea = textarea; - } + }; render() { const props = {...this.props}; diff --git a/webapp/channels/src/components/channel_header/channel_header.tsx b/webapp/channels/src/components/channel_header/channel_header.tsx index 0ac89b7669..268b832655 100644 --- a/webapp/channels/src/components/channel_header/channel_header.tsx +++ b/webapp/channels/src/components/channel_header/channel_header.tsx @@ -201,7 +201,7 @@ class ChannelHeader extends React.PureComponent { removeTooltipLink = () => { // Bootstrap adds the attr dynamically, removing it to prevent a11y readout this.toggleFavoriteRef.current?.removeAttribute('aria-describedby'); - } + }; setTitleMenuOpen = (open: boolean) => this.setState({titleMenuOpen: open}); @@ -218,7 +218,7 @@ class ChannelHeader extends React.PureComponent { }; actions.openModal(modalData); - } + }; showChannelHeaderPopover = (headerText: string) => { const headerDescriptionRect = this.headerDescriptionRef.current?.getBoundingClientRect(); @@ -235,7 +235,7 @@ class ChannelHeader extends React.PureComponent { const topOffset = (announcementBarSize * this.props.announcementBarCount) + 40; this.setState({topOffset}); - } + }; toggleChannelMembersRHS = () => { if (this.props.rhsState === RHSStates.CHANNEL_MEMBERS) { @@ -249,7 +249,7 @@ class ChannelHeader extends React.PureComponent { const headerDescriptionRect = this.headerDescriptionRef.current?.getBoundingClientRect(); const ellipsisWidthAdjustment = 10; this.setState({popoverOverlayWidth: (headerDescriptionRect?.width ?? 0) + ellipsisWidthAdjustment}); - } + }; handleFormattedTextClick = (e: MouseEvent) => handleFormattedTextClick(e, this.props.currentRelativeTeamUrl); @@ -276,7 +276,7 @@ class ChannelHeader extends React.PureComponent { /> ); - } + }; render() { const { diff --git a/webapp/channels/src/components/channel_header_dropdown/menu_items/close_channel/close_channel.tsx b/webapp/channels/src/components/channel_header_dropdown/menu_items/close_channel/close_channel.tsx index 25b026de8c..1ab246786b 100644 --- a/webapp/channels/src/components/channel_header_dropdown/menu_items/close_channel/close_channel.tsx +++ b/webapp/channels/src/components/channel_header_dropdown/menu_items/close_channel/close_channel.tsx @@ -17,7 +17,7 @@ type Props = { export default class CloseChannel extends React.PureComponent { private handleClose = () => { this.props.actions.goToLastViewedChannel(); - } + }; render() { return ( diff --git a/webapp/channels/src/components/channel_header_dropdown/menu_items/close_message/close_message.tsx b/webapp/channels/src/components/channel_header_dropdown/menu_items/close_message/close_message.tsx index e76c512e2f..609140a559 100644 --- a/webapp/channels/src/components/channel_header_dropdown/menu_items/close_message/close_message.tsx +++ b/webapp/channels/src/components/channel_header_dropdown/menu_items/close_message/close_message.tsx @@ -86,7 +86,7 @@ export default class CloseMessage extends React.PureComponent { savePreferences(currentUser.id, [{user_id: currentUser.id, category, name, value: 'false'}]); getHistory().push(`/${currentTeam.name}/channels/${redirectChannel}`); - } + }; render(): React.ReactNode { const {id, channel} = this.props; diff --git a/webapp/channels/src/components/channel_header_dropdown/menu_items/leave_channel/leave_channel.tsx b/webapp/channels/src/components/channel_header_dropdown/menu_items/leave_channel/leave_channel.tsx index 020ce50197..b251c242f4 100644 --- a/webapp/channels/src/components/channel_header_dropdown/menu_items/leave_channel/leave_channel.tsx +++ b/webapp/channels/src/components/channel_header_dropdown/menu_items/leave_channel/leave_channel.tsx @@ -40,7 +40,7 @@ export default class LeaveChannel extends React.PureComponent { static defaultProps = { isDefault: true, isGuestUser: false, - } + }; handleLeave = (e: Event) => { e.preventDefault(); @@ -64,7 +64,7 @@ export default class LeaveChannel extends React.PureComponent { } else { leaveChannel(channel.id); } - } + }; render() { const {channel, isDefault, isGuestUser, id} = this.props; diff --git a/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_favorite_channel/toggle_favorite_channel.tsx b/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_favorite_channel/toggle_favorite_channel.tsx index a490c3d1ce..ebca3142d7 100644 --- a/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_favorite_channel/toggle_favorite_channel.tsx +++ b/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_favorite_channel/toggle_favorite_channel.tsx @@ -24,7 +24,7 @@ type Props = { export default class ToggleFavoriteChannel extends React.PureComponent { static defaultProps = { show: true, - } + }; toggleFavoriteChannel = (channelId: string) => { const { @@ -41,7 +41,7 @@ export default class ToggleFavoriteChannel extends React.PureComponent { handleClick = (e: React.MouseEvent): void => { e.preventDefault(); this.toggleFavoriteChannel(this.props.channel.id); - } + }; render() { let text; diff --git a/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_mute_channel/toggle_mute_channel.tsx b/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_mute_channel/toggle_mute_channel.tsx index 80a94944bb..4a33da1b15 100644 --- a/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_mute_channel/toggle_mute_channel.tsx +++ b/webapp/channels/src/components/channel_header_dropdown/menu_items/toggle_mute_channel/toggle_mute_channel.tsx @@ -58,7 +58,7 @@ export default class MenuItemToggleMuteChannel extends React.PureComponent { } else { showPinnedPosts(channel.id); } - } + }; render() { return ( diff --git a/webapp/channels/src/components/channel_header_dropdown/mobile_channel_header_dropdown.tsx b/webapp/channels/src/components/channel_header_dropdown/mobile_channel_header_dropdown.tsx index 3fc87ad70d..c2d4b8ef73 100644 --- a/webapp/channels/src/components/channel_header_dropdown/mobile_channel_header_dropdown.tsx +++ b/webapp/channels/src/components/channel_header_dropdown/mobile_channel_header_dropdown.tsx @@ -45,7 +45,7 @@ class MobileChannelHeaderDropdown extends React.PureComponent { return displayName; } return channel.display_name; - } + }; render() { const {teammateIsBot, teammateStatus} = this.props; diff --git a/webapp/channels/src/components/channel_header_mobile/channel_header_mobile.tsx b/webapp/channels/src/components/channel_header_mobile/channel_header_mobile.tsx index 42a4aa0ac9..47c6e4c345 100644 --- a/webapp/channels/src/components/channel_header_mobile/channel_header_mobile.tsx +++ b/webapp/channels/src/components/channel_header_mobile/channel_header_mobile.tsx @@ -62,7 +62,7 @@ export default class ChannelHeaderMobile extends React.PureComponent { this.props.actions.closeRhsMenu(); } } - } + }; render() { const {user, channel, isMuted, inGlobalThreads, inDrafts} = this.props; diff --git a/webapp/channels/src/components/channel_header_mobile/show_search_button/show_search_button.tsx b/webapp/channels/src/components/channel_header_mobile/show_search_button/show_search_button.tsx index 32e0138339..de2e327693 100644 --- a/webapp/channels/src/components/channel_header_mobile/show_search_button/show_search_button.tsx +++ b/webapp/channels/src/components/channel_header_mobile/show_search_button/show_search_button.tsx @@ -18,7 +18,7 @@ type Props = { export default class ShowSearchButton extends React.PureComponent { handleClick = () => { this.props.actions.openRHSSearch(); - } + }; render() { return ( diff --git a/webapp/channels/src/components/channel_header_mobile/unmute_channel_button/unmute_channel_button.tsx b/webapp/channels/src/components/channel_header_mobile/unmute_channel_button/unmute_channel_button.tsx index a5d0cc1d21..76ca31e942 100644 --- a/webapp/channels/src/components/channel_header_mobile/unmute_channel_button/unmute_channel_button.tsx +++ b/webapp/channels/src/components/channel_header_mobile/unmute_channel_button/unmute_channel_button.tsx @@ -28,7 +28,7 @@ export default class UnmuteChannelButton extends React.PureComponent { } = this.props; updateChannelNotifyProps(user.id, channel.id, {mark_unread: NotificationLevels.ALL} as ChannelNotifyProps); - } + }; render(): JSX.Element { return ( diff --git a/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx b/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx index a9de0e72fd..4babb664d7 100644 --- a/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.test.tsx @@ -3,8 +3,11 @@ import React from 'react'; -import {Channel, ChannelStats} from '@mattermost/types/channels'; +import {act} from '@testing-library/react'; + import {renderWithIntl} from 'tests/react_testing_utils'; + +import {Channel, ChannelStats} from '@mattermost/types/channels'; import {UserProfile} from '@mattermost/types/users'; import {Team} from '@mattermost/types/teams'; @@ -40,6 +43,7 @@ describe('channel_info_rhs', () => { showChannelFiles: jest.fn(), showPinnedPosts: jest.fn(), showChannelMembers: jest.fn(), + getChannelStats: jest.fn().mockImplementation(() => Promise.resolve({data: {}})), }, }; let props = {...OriginalProps}; @@ -49,20 +53,24 @@ describe('channel_info_rhs', () => { }); describe('about area', () => { - test('should be editable', () => { + test('should be editable', async () => { renderWithIntl( , ); + await act(async () => { + props.actions.getChannelStats(); + }); + expect(mockAboutArea).toHaveBeenCalledWith( expect.objectContaining({ canEditChannelProperties: true, }), ); }); - test('should not be editable in archived channel', () => { + test('should not be editable in archived channel', async () => { props.isArchived = true; renderWithIntl( @@ -71,6 +79,10 @@ describe('channel_info_rhs', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + expect(mockAboutArea).toHaveBeenCalledWith( expect.objectContaining({ canEditChannelProperties: false, diff --git a/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.tsx b/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.tsx index f16b9c77ea..7f75970911 100644 --- a/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.tsx +++ b/webapp/channels/src/components/channel_info_rhs/channel_info_rhs.tsx @@ -64,6 +64,7 @@ export interface Props { showChannelFiles: (channelId: string) => void; showPinnedPosts: (channelId: string | undefined) => void; showChannelMembers: (channelId: string) => void; + getChannelStats: (channelId: string) => Promise<{data: ChannelStats}>; }; } @@ -192,6 +193,7 @@ const ChannelInfoRhs = ({ showChannelFiles: actions.showChannelFiles, showPinnedPosts: actions.showPinnedPosts, showChannelMembers: actions.showChannelMembers, + getChannelStats: actions.getChannelStats, }} /> diff --git a/webapp/channels/src/components/channel_info_rhs/index.ts b/webapp/channels/src/components/channel_info_rhs/index.ts index 09d6e8e49d..f30d8ebb8b 100644 --- a/webapp/channels/src/components/channel_info_rhs/index.ts +++ b/webapp/channels/src/components/channel_info_rhs/index.ts @@ -16,7 +16,7 @@ import {Constants, ModalIdentifiers} from 'utils/constants'; import {getCurrentUser} from 'mattermost-redux/selectors/entities/common'; import {getIsMobileView} from 'selectors/views/browser'; import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; -import {unfavoriteChannel, favoriteChannel} from 'mattermost-redux/actions/channels'; +import {unfavoriteChannel, favoriteChannel, getChannelStats} from 'mattermost-redux/actions/channels'; import {muteChannel, unmuteChannel} from 'actions/channel_actions'; import {openModal} from 'actions/views/modals'; import {getDisplayNameByUser, getUserIdFromChannelId} from 'utils/utils'; @@ -92,6 +92,7 @@ function mapDispatchToProps(dispatch: Dispatch) { showChannelFiles, showPinnedPosts, showChannelMembers, + getChannelStats, }, dispatch), }; } diff --git a/webapp/channels/src/components/channel_info_rhs/menu.test.tsx b/webapp/channels/src/components/channel_info_rhs/menu.test.tsx index 1e4a8d5537..d68f9a2392 100644 --- a/webapp/channels/src/components/channel_info_rhs/menu.test.tsx +++ b/webapp/channels/src/components/channel_info_rhs/menu.test.tsx @@ -2,12 +2,13 @@ // See LICENSE.txt for license information. import React from 'react'; -import {fireEvent, screen} from '@testing-library/react'; +import {act, fireEvent, screen} from '@testing-library/react'; -import {Channel, ChannelStats} from '@mattermost/types/channels'; import {renderWithIntl} from 'tests/react_testing_utils'; import Constants from 'utils/constants'; +import {Channel, ChannelStats} from '@mattermost/types/channels'; + import Menu from './menu'; describe('channel_info_rhs/menu', () => { @@ -20,6 +21,7 @@ describe('channel_info_rhs/menu', () => { showChannelFiles: jest.fn(), showPinnedPosts: jest.fn(), showChannelMembers: jest.fn(), + getChannelStats: jest.fn().mockImplementation(() => Promise.resolve({data: {files_count: 3, pinnedpost_count: 12, member_count: 32}})), }, }; @@ -29,10 +31,11 @@ describe('channel_info_rhs/menu', () => { showChannelFiles: jest.fn(), showPinnedPosts: jest.fn(), showChannelMembers: jest.fn(), + getChannelStats: jest.fn().mockImplementation(() => Promise.resolve({data: {files_count: 3, pinnedpost_count: 12, member_count: 32}})), }; }); - test('should display notifications preferences', () => { + test('should display notifications preferences', async () => { const props = {...defaultProps}; props.actions.openNotificationSettings = jest.fn(); @@ -42,13 +45,17 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + expect(screen.getByText('Notification Preferences')).toBeInTheDocument(); fireEvent.click(screen.getByText('Notification Preferences')); expect(props.actions.openNotificationSettings).toHaveBeenCalled(); }); - test('should NOT display notifications preferences in a DM', () => { + test('should NOT display notifications preferences in a DM', async () => { const props = { ...defaultProps, channel: {type: Constants.DM_CHANNEL} as Channel, @@ -60,10 +67,14 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + expect(screen.queryByText('Notification Preferences')).not.toBeInTheDocument(); }); - test('should NOT display notifications preferences in an archived channel', () => { + test('should NOT display notifications preferences in an archived channel', async () => { const props = { ...defaultProps, isArchived: true, @@ -75,10 +86,14 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + expect(screen.queryByText('Notification Preferences')).not.toBeInTheDocument(); }); - test('should display the number of files', () => { + test('should display the number of files', async () => { const props = {...defaultProps}; props.actions.showChannelFiles = jest.fn(); @@ -88,6 +103,10 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + const fileItem = screen.getByText('Files'); expect(fileItem).toBeInTheDocument(); expect(fileItem.parentElement).toHaveTextContent('3'); @@ -96,7 +115,7 @@ describe('channel_info_rhs/menu', () => { expect(props.actions.showChannelFiles).toHaveBeenCalled(); }); - test('should display the pinned messages', () => { + test('should display the pinned messages', async () => { const props = {...defaultProps}; props.actions.showPinnedPosts = jest.fn(); @@ -106,6 +125,10 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + const fileItem = screen.getByText('Pinned Messages'); expect(fileItem).toBeInTheDocument(); expect(fileItem.parentElement).toHaveTextContent('12'); @@ -114,7 +137,7 @@ describe('channel_info_rhs/menu', () => { expect(props.actions.showPinnedPosts).toHaveBeenCalled(); }); - test('should display members', () => { + test('should display members', async () => { const props = {...defaultProps}; props.actions.showChannelMembers = jest.fn(); @@ -124,6 +147,10 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + const membersItem = screen.getByText('Members'); expect(membersItem).toBeInTheDocument(); expect(membersItem.parentElement).toHaveTextContent('32'); @@ -132,7 +159,7 @@ describe('channel_info_rhs/menu', () => { expect(props.actions.showChannelMembers).toHaveBeenCalled(); }); - test('should NOT display members in DM', () => { + test('should NOT display members in DM', async () => { const props = { ...defaultProps, channel: {type: Constants.DM_CHANNEL} as Channel, @@ -144,6 +171,10 @@ describe('channel_info_rhs/menu', () => { />, ); + await act(async () => { + props.actions.getChannelStats(); + }); + const membersItem = screen.queryByText('Members'); expect(membersItem).not.toBeInTheDocument(); }); diff --git a/webapp/channels/src/components/channel_info_rhs/menu.tsx b/webapp/channels/src/components/channel_info_rhs/menu.tsx index 1092294e72..a45657c319 100644 --- a/webapp/channels/src/components/channel_info_rhs/menu.tsx +++ b/webapp/channels/src/components/channel_info_rhs/menu.tsx @@ -1,12 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {useEffect, useState} from 'react'; import styled from 'styled-components'; import {useIntl} from 'react-intl'; import {Constants} from 'utils/constants'; +import LoadingSpinner from 'components/widgets/loading/loading_spinner'; + import {Channel, ChannelStats} from '@mattermost/types/channels'; const MenuItemContainer = styled.div` @@ -32,6 +34,9 @@ const RightSide = styled.div` const Badge = styled.div` font-size: 12px; line-height: 18px; + width: 20px; + display: flex; + place-content: center; `; interface MenuItemProps { @@ -39,7 +44,7 @@ interface MenuItemProps { icon: JSX.Element; text: string; opensSubpanel?: boolean; - badge?: string|number; + badge?: string|number|JSX.Element; onClick: () => void; } @@ -94,14 +99,26 @@ interface MenuProps { showChannelFiles: (channelId: string) => void; showPinnedPosts: (channelId: string | undefined) => void; showChannelMembers: (channelId: string) => void; + getChannelStats: (channelId: string) => Promise<{data: ChannelStats}>; }; } const Menu = ({channel, channelStats, isArchived, className, actions}: MenuProps) => { const {formatMessage} = useIntl(); + const [loadingStats, setLoadingStats] = useState(true); const showNotificationPreferences = channel.type !== Constants.DM_CHANNEL && !isArchived; const showMembers = channel.type !== Constants.DM_CHANNEL; + const fileCount = channelStats?.files_count >= 0 ? channelStats?.files_count : 0; + + useEffect(() => { + actions.getChannelStats(channel.id).then(() => { + setLoadingStats(false); + }); + return () => { + setLoadingStats(true); + }; + }, [channel.id]); return (
} text={formatMessage({id: 'channel_info_rhs.menu.files', defaultMessage: 'Files'})} opensSubpanel={true} - badge={channelStats?.files_count} + badge={loadingStats ? : fileCount} onClick={() => actions.showChannelFiles(channel.id)} />
diff --git a/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.tsx b/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.tsx index 2ca85d0d41..a24f097c7f 100644 --- a/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.tsx +++ b/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.tsx @@ -231,13 +231,13 @@ export default class ChannelInviteModal extends React.PureComponent): UserProfileValue[] => { return users.filter((user) => { return user.delete_at === 0 && !excludeUserIds.has(user.id); }) as UserProfileValue[]; - } + }; renderOption = (option: UserProfileValue, isSelected: boolean, onAdd: (user: UserProfileValue) => void, onMouseMove: (user: UserProfileValue) => void) => { let rowSelected = ''; @@ -352,24 +352,21 @@ export default class ChannelInviteModal extends React.PureComponent { + const InviteModalLink = (props: {inviteAsGuest?: boolean; children: React.ReactNode}) => { return ( - {children} + {props.children} ); }; @@ -457,5 +454,5 @@ export default class ChannelInviteModal extends React.PureComponent ); - } + }; } diff --git a/webapp/channels/src/components/channel_layout/channel_identifier_router/channel_identifier_router.tsx b/webapp/channels/src/components/channel_layout/channel_identifier_router/channel_identifier_router.tsx index fd1c2add2e..4e4ed3b079 100644 --- a/webapp/channels/src/components/channel_layout/channel_identifier_router/channel_identifier_router.tsx +++ b/webapp/channels/src/components/channel_layout/channel_identifier_router/channel_identifier_router.tsx @@ -62,7 +62,7 @@ export default class ChannelIdentifierRouter extends React.PureComponent getHistory().replace(channelUrl); }, Constants.PERMALINK_FADEOUT); } - } + }; render() { return ; diff --git a/webapp/channels/src/components/channel_members_modal/channel_members_modal.tsx b/webapp/channels/src/components/channel_members_modal/channel_members_modal.tsx index f2cf842c48..d861d4ef0d 100644 --- a/webapp/channels/src/components/channel_members_modal/channel_members_modal.tsx +++ b/webapp/channels/src/components/channel_members_modal/channel_members_modal.tsx @@ -51,7 +51,7 @@ export default class ChannelMembersModal extends React.PureComponent { this.setState({show: false}); - } + }; onAddNewMembersButton = () => { const {channel, actions} = this.props; @@ -63,7 +63,7 @@ export default class ChannelMembersModal extends React.PureComponent { this.updateSection(NotificationSections.NONE); this.props.onExited(); - } + }; updateSection = (section = NotificationSections.NONE) => { this.setState({activeSection: section}); @@ -112,7 +112,7 @@ export default class ChannelNotificationsModal extends React.PureComponent) => { const { @@ -127,7 +127,7 @@ export default class ChannelNotificationsModal extends React.PureComponent { const channelNotifyProps = this.props.channelMember && this.props.channelMember.notify_props as ChannelMemberNotifyProps; @@ -144,7 +144,7 @@ export default class ChannelNotificationsModal extends React.PureComponent this.setState({desktopNotifyLevel}); @@ -161,7 +161,7 @@ export default class ChannelNotificationsModal extends React.PureComponent this.setState({markUnreadNotifyLevel}); @@ -179,7 +179,7 @@ export default class ChannelNotificationsModal extends React.PureComponent this.setState({pushNotifyLevel}); handleUpdatePushThreadsNotificationLevel = (pushThreadsNotifyLevel: UserNotifyProps['push_threads']) => this.setState({pushThreadsNotifyLevel}); @@ -196,7 +196,7 @@ export default class ChannelNotificationsModal extends React.PureComponent { this.props.onChange(e.target.value); - } + }; handleOnChangeThreads = (e) => { const value = e.target.checked ? NotificationLevels.ALL : NotificationLevels.MENTION; this.props.onChangeThreads(value); - } + }; handleExpandSection = () => { this.props.onUpdateSection(this.props.section); - } + }; handleCollapseSection = () => { this.props.onUpdateSection(NotificationSections.NONE); - } + }; render() { const { diff --git a/webapp/channels/src/components/channel_select/channel_select.tsx b/webapp/channels/src/components/channel_select/channel_select.tsx index d6b3a8e882..b7c32449d9 100644 --- a/webapp/channels/src/components/channel_select/channel_select.tsx +++ b/webapp/channels/src/components/channel_select/channel_select.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {ChangeEventHandler} from 'react'; import {Channel} from '@mattermost/types/channels'; @@ -10,7 +10,7 @@ import * as Utils from 'utils/utils'; type Props = { channels: Channel[]; - onChange?: () => void; + onChange?: ChangeEventHandler; value?: string; selectOpen: boolean; selectPrivate: boolean; diff --git a/webapp/channels/src/components/channel_selector_modal/channel_selector_modal.tsx b/webapp/channels/src/components/channel_selector_modal/channel_selector_modal.tsx index 6e1f351ed8..1628ea64e2 100644 --- a/webapp/channels/src/components/channel_selector_modal/channel_selector_modal.tsx +++ b/webapp/channels/src/components/channel_selector_modal/channel_selector_modal.tsx @@ -44,8 +44,8 @@ type State = { const CHANNELS_PER_PAGE = 50; export default class ChannelSelectorModal extends React.PureComponent { - searchTimeoutId = 0 - selectedItemRef = React.createRef() + searchTimeoutId = 0; + selectedItemRef = React.createRef(); state: State = { values: [], @@ -89,13 +89,13 @@ export default class ChannelSelectorModal extends React.PureComponent { this.props.actions.setModalSearchTerm(''); this.setState({show: false}); - } + }; handleExit = () => { if (this.props.onModalDismissed) { this.props.onModalDismissed(); } - } + }; handleSubmit = (e: any) => { if (e) { @@ -110,7 +110,7 @@ export default class ChannelSelectorModal extends React.PureComponent { const values = [...this.state.values]; @@ -119,13 +119,13 @@ export default class ChannelSelectorModal extends React.PureComponent { this.setState({ loadingChannels: loadingState, }); - } + }; handlePageChange = (page: number, prevPage: number) => { if (page > prevPage) { @@ -142,18 +142,18 @@ export default class ChannelSelectorModal extends React.PureComponent { this.setState({values}); - } + }; search = (term: string, multiselectComponent: MultiSelect) => { if (multiselectComponent.state.page !== 0) { multiselectComponent.setState({page: 0}); } this.props.actions.setModalSearchTerm(term); - } + }; renderOption = ( option: ChannelWithTeamDataValue, @@ -192,7 +192,7 @@ export default class ChannelSelectorModal extends React.PureComponent ); - } + }; renderValue(props: {data: ChannelWithTeamDataValue}) { return props.data.display_name + ' (' + props.data.team_display_name + ')'; diff --git a/webapp/channels/src/components/channel_view/channel_view.tsx b/webapp/channels/src/components/channel_view/channel_view.tsx index c3c76625c8..54177a1f2f 100644 --- a/webapp/channels/src/components/channel_view/channel_view.tsx +++ b/webapp/channels/src/components/channel_view/channel_view.tsx @@ -37,7 +37,7 @@ export default class ChannelView extends React.PureComponent { data-a11y-order-reversed={true} />, ); - } + }; static getDerivedStateFromProps(props: Props, state: State) { let updatedState = {}; @@ -79,11 +79,11 @@ export default class ChannelView extends React.PureComponent { getChannelView = () => { return this.channelViewRef.current; - } + }; onClickCloseChannel = () => { this.props.goToLastViewedChannel(); - } + }; componentDidUpdate(prevProps: Props) { if (prevProps.channelId !== this.props.channelId || prevProps.channelIsArchived !== this.props.channelIsArchived) { diff --git a/webapp/channels/src/components/choose_different_shipping/choose_different_shipping.scss b/webapp/channels/src/components/choose_different_shipping/choose_different_shipping.scss new file mode 100644 index 0000000000..ab86a14982 --- /dev/null +++ b/webapp/channels/src/components/choose_different_shipping/choose_different_shipping.scss @@ -0,0 +1,43 @@ +@import '../payment_form/mixins'; + +.shipping-address-section { + display: flex; + align-items: center; + padding-bottom: 24px; + font-weight: normal; + + button.no-style { + height: auto; + padding-left: 0; + border: none; + background: transparent; + outline: unset; + text-align: left; + + &:focus { + outline: unset; + } + } + + #address-same-than-billing-address { + width: 17px; + height: 17px; + flex-shrink: 0; + } + + .Form-checkbox-label { + padding-left: 12px; + cursor: default; + font-family: 'Open Sans', sans-serif; + } + + .billing_address_btn_text { + color: var(--center-channel-color); + font-family: 'Open Sans', sans-serif; + font-weight: bold; + } +} + +.PurchaseModal .shipping-address-section { + @include payment-form-padding; +} diff --git a/webapp/channels/src/components/choose_different_shipping/index.tsx b/webapp/channels/src/components/choose_different_shipping/index.tsx new file mode 100644 index 0000000000..43b810f2e8 --- /dev/null +++ b/webapp/channels/src/components/choose_different_shipping/index.tsx @@ -0,0 +1,45 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import {useIntl} from 'react-intl'; + +import './choose_different_shipping.scss'; + +interface Props { + shippingIsSame: boolean; + setShippingIsSame: (different: boolean) => void; +} +export default function ChooseDifferentShipping(props: Props) { + const intl = useIntl(); + const toggle = () => props.setShippingIsSame(!props.shippingIsSame); + + return ( +
+ + + + +
+ ); +} diff --git a/webapp/channels/src/components/cloud_subscribe_result_modal/error.tsx b/webapp/channels/src/components/cloud_subscribe_result_modal/error.tsx index 0b61d3598e..2340430c02 100644 --- a/webapp/channels/src/components/cloud_subscribe_result_modal/error.tsx +++ b/webapp/channels/src/components/cloud_subscribe_result_modal/error.tsx @@ -13,9 +13,8 @@ import PaymentFailedSvg from 'components/common/svg_images_components/payment_fa import IconMessage from 'components/purchase_modal/icon_message'; import FullScreenModal from 'components/widgets/modals/full_screen_modal'; -import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink'; +import {useOpenCloudZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm'; -import {InquiryType} from 'selectors/cloud'; import {closeModal} from 'actions/views/modals'; import {ModalIdentifiers} from 'utils/constants'; import {isModalOpen} from 'selectors/views/modals'; @@ -31,7 +30,8 @@ type Props = { function ErrorModal(props: Props) { const dispatch = useDispatch(); const subscriptionProduct = useSelector(getSubscriptionProduct); - const openContactUs = useOpenSalesLink(undefined, InquiryType.Technical); + + const [openContactSupport] = useOpenCloudZendeskSupportForm('Cloud Subscription', ''); const isSuccessModalOpen = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.ERROR_MODAL), @@ -97,7 +97,7 @@ function ErrorModal(props: Props) { } /> } - tertiaryButtonHandler={openContactUs} + tertiaryButtonHandler={openContactSupport} buttonHandler={onBackButtonPress} className={'success'} /> diff --git a/webapp/channels/src/components/code_preview.tsx b/webapp/channels/src/components/code_preview.tsx index fe9acaac80..dfdcd6e90e 100644 --- a/webapp/channels/src/components/code_preview.tsx +++ b/webapp/channels/src/components/code_preview.tsx @@ -87,7 +87,7 @@ export default class CodePreview extends React.PureComponent { } catch (e) { this.handleReceivedError(); } - } + }; handleReceivedCode = async (data: string | Node) => { let code = data as string; @@ -102,11 +102,11 @@ export default class CodePreview extends React.PureComponent { loading: false, success: true, }); - } + }; handleReceivedError = () => { this.setState({loading: false, success: false}); - } + }; static supports(fileInfo: FileInfo | LinkInfo) { return Boolean(SyntaxHighlighting.getLanguageFromFileExtension(fileInfo.extension)); diff --git a/webapp/channels/src/components/color_input.tsx b/webapp/channels/src/components/color_input.tsx index 05ce57e9b5..5c16234e2f 100644 --- a/webapp/channels/src/components/color_input.tsx +++ b/webapp/channels/src/components/color_input.tsx @@ -96,7 +96,7 @@ export default class ColorInput extends React.PureComponent { if (event.target) { event.target.setSelectionRange(1, event.target.value.length); } - } + }; private onBlur = () => { const value = this.state.value; @@ -146,6 +146,7 @@ export default class ColorInput extends React.PureComponent { onKeyDown={this.onKeyDown} maxLength={7} disabled={this.props.isDisabled} + data-testid='color-inputColorValue' /> {!this.props.isDisabled && diff --git a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx index dd736d202f..ab763acb45 100644 --- a/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx +++ b/webapp/channels/src/components/commercial_support_modal/commercial_support_modal.tsx @@ -46,19 +46,19 @@ export default class CommercialSupportModal extends React.PureComponent { this.setState({show: false}); - } + }; updateBannerWarning = (showBannerWarning: boolean) => { this.setState({showBannerWarning}); - } + }; hideBannerWarning = () => { this.updateBannerWarning(false); - } + }; render() { const {showBannerWarning} = this.state; diff --git a/webapp/channels/src/components/common/chip/chip.tsx b/webapp/channels/src/components/common/chip/chip.tsx index 20805947b8..9e7a904be5 100644 --- a/webapp/channels/src/components/common/chip/chip.tsx +++ b/webapp/channels/src/components/common/chip/chip.tsx @@ -56,7 +56,7 @@ export default class Chip extends React.PureComponent { onClick = (e: React.MouseEvent) => { e.preventDefault(); this.props.onClick?.(); - } + }; render() { return ( diff --git a/webapp/channels/src/components/common/comment_icon.tsx b/webapp/channels/src/components/common/comment_icon.tsx index 0b1b7876d1..e0fdeb0b70 100644 --- a/webapp/channels/src/components/common/comment_icon.tsx +++ b/webapp/channels/src/components/common/comment_icon.tsx @@ -26,7 +26,7 @@ export default class CommentIcon extends React.PureComponent { searchStyle: '', commentCount: 0, extraClass: '', - } + }; public render(): JSX.Element { let commentCountSpan: JSX.Element | null = null; diff --git a/webapp/channels/src/components/common/hocs/cloud/with_open_start_trial_form_modal.tsx b/webapp/channels/src/components/common/hocs/cloud/with_open_start_trial_form_modal.tsx new file mode 100644 index 0000000000..bbfcc533b3 --- /dev/null +++ b/webapp/channels/src/components/common/hocs/cloud/with_open_start_trial_form_modal.tsx @@ -0,0 +1,18 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {ComponentType} from 'react'; + +import useOpenStartTrialFormModal from 'components/common/hooks/useOpenStartTrialFormModal'; + +export default function withOpenStartTrialFormModal(WrappedComponent: ComponentType) { + return (props: T) => { + const openTrialForm = useOpenStartTrialFormModal(); + return ( + + ); + }; +} diff --git a/webapp/channels/src/components/common/hooks/useCWSAvailabilityCheck.ts b/webapp/channels/src/components/common/hooks/useCWSAvailabilityCheck.ts index 4c9e70a85d..63e3b20e04 100644 --- a/webapp/channels/src/components/common/hooks/useCWSAvailabilityCheck.ts +++ b/webapp/channels/src/components/common/hooks/useCWSAvailabilityCheck.ts @@ -8,14 +8,16 @@ import {Client4} from 'mattermost-redux/client'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; export default function useCWSAvailabilityCheck() { - const [canReachCWS, setCanReachCWS] = useState(false); + const [canReachCWS, setCanReachCWS] = useState(undefined); const config = useSelector(getConfig); const isEnterpriseReady = config.BuildEnterpriseReady === 'true'; useEffect(() => { if (!isEnterpriseReady) { return; } - Client4.cwsAvailabilityCheck().then(() => setCanReachCWS(true)); + Client4.cwsAvailabilityCheck().then(() => { + setCanReachCWS(true); + }).catch(() => setCanReachCWS(false)); }, [isEnterpriseReady]); return canReachCWS; diff --git a/webapp/channels/src/components/common/hooks/useOpenSalesLink.ts b/webapp/channels/src/components/common/hooks/useOpenSalesLink.ts index aecb58844f..1bc2c87e31 100644 --- a/webapp/channels/src/components/common/hooks/useOpenSalesLink.ts +++ b/webapp/channels/src/components/common/hooks/useOpenSalesLink.ts @@ -3,11 +3,35 @@ import {useSelector} from 'react-redux'; -import {getCloudContactUsLink, InquiryType, SalesInquiryIssue} from 'selectors/cloud'; +import {getCloudCustomer, isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud'; +import {getCurrentUser} from 'mattermost-redux/selectors/entities/users'; +import {buildMMURL, goToMattermostContactSalesForm} from 'utils/contact_support_sales'; +import {LicenseLinks} from 'utils/constants'; -export default function useOpenSalesLink(issue?: SalesInquiryIssue, inquireType: InquiryType = InquiryType.Sales) { - const contactSalesLink = useSelector(getCloudContactUsLink)(inquireType, issue); +export default function useOpenSalesLink(): [() => void, string] { + const isCloud = useSelector(isCurrentLicenseCloud); + const customer = useSelector(getCloudCustomer); + const currentUser = useSelector(getCurrentUser); + let customerEmail = ''; + let firstName = ''; + let lastName = ''; + let companyName = ''; + const utmSource = 'mattermost'; + let utmMedium = 'in-product'; - return () => window.open(contactSalesLink, '_blank'); + if (isCloud && customer) { + customerEmail = customer.email || ''; + firstName = customer.contact_first_name || ''; + lastName = customer.contact_last_name || ''; + companyName = customer.name || ''; + utmMedium = 'in-product-cloud'; + } else { + customerEmail = currentUser?.email || ''; + } + + const contactSalesLink = buildMMURL(LicenseLinks.CONTACT_SALES, firstName, lastName, companyName, customerEmail, utmSource, utmMedium); + const goToSalesLinkFunc = () => { + goToMattermostContactSalesForm(firstName, lastName, companyName, customerEmail, utmSource, utmMedium); + }; + return [goToSalesLinkFunc, contactSalesLink]; } - diff --git a/webapp/channels/src/components/common/hooks/useOpenStartTrialFormModal.ts b/webapp/channels/src/components/common/hooks/useOpenStartTrialFormModal.ts new file mode 100644 index 0000000000..ec6a456d9d --- /dev/null +++ b/webapp/channels/src/components/common/hooks/useOpenStartTrialFormModal.ts @@ -0,0 +1,23 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {useDispatch} from 'react-redux'; + +import {openModal} from 'actions/views/modals'; +import {ModalIdentifiers} from 'utils/constants'; +import StartTrialFormModal from 'components/start_trial_form_modal'; +import {TelemetryProps} from './useOpenPricingModal'; + +export default function useOpenStartTrialFormModal() { + const dispatch = useDispatch(); + return (telemetryProps?: TelemetryProps, onClose?: () => void) => { + dispatch(openModal({ + modalId: ModalIdentifiers.START_TRIAL_FORM_MODAL, + dialogType: StartTrialFormModal, + dialogProps: { + page: telemetryProps?.trackingLocation, + onClose, + }, + })); + }; +} diff --git a/webapp/channels/src/components/common/hooks/useOpenZendeskForm.ts b/webapp/channels/src/components/common/hooks/useOpenZendeskForm.ts new file mode 100644 index 0000000000..16df9d9a02 --- /dev/null +++ b/webapp/channels/src/components/common/hooks/useOpenZendeskForm.ts @@ -0,0 +1,26 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {useSelector} from 'react-redux'; + +import {getCloudCustomer} from 'mattermost-redux/selectors/entities/cloud'; +import {getCurrentUser} from 'mattermost-redux/selectors/entities/users'; +import {getCloudSupportLink, getSelfHostedSupportLink, goToCloudSupportForm, goToSelfHostedSupportForm} from 'utils/contact_support_sales'; + +export function useOpenCloudZendeskSupportForm(subject: string, description: string): [() => void, string] { + const customer = useSelector(getCloudCustomer); + const customerEmail = customer?.email || ''; + + const url = getCloudSupportLink(customerEmail, subject, description, window.location.host); + + return [() => goToCloudSupportForm(customerEmail, subject, description, window.location.host), url]; +} + +export function useOpenSelfHostedZendeskSupportForm(subject: string): [() => void, string] { + const currentUser = useSelector(getCurrentUser); + const customerEmail = currentUser.email || ''; + + const url = getSelfHostedSupportLink(customerEmail, subject); + + return [() => goToSelfHostedSupportForm(customerEmail, subject), url]; +} diff --git a/webapp/channels/src/components/common/infinite_scroll.tsx b/webapp/channels/src/components/common/infinite_scroll.tsx index 8fa1a97f1f..6056d62962 100644 --- a/webapp/channels/src/components/common/infinite_scroll.tsx +++ b/webapp/channels/src/components/common/infinite_scroll.tsx @@ -94,11 +94,11 @@ export default class InfiniteScroll extends React.PureComponent { return SCROLL_BUFFER; } return Math.abs(buffer); - } + }; getAmountOfPages = (total: number, freq: number): number => { return Math.ceil(total / freq); - } + }; handleScroll = (): void => { const {isFetching, isEndofData} = this.state; @@ -135,7 +135,7 @@ export default class InfiniteScroll extends React.PureComponent { } }); } - } + }; debounceHandleScroll = debounce(this.handleScroll, DEBOUNCE_WAIT_TIME); diff --git a/webapp/channels/src/components/common/site_name_and_description.tsx b/webapp/channels/src/components/common/site_name_and_description.tsx index 033b725840..5f08f02065 100644 --- a/webapp/channels/src/components/common/site_name_and_description.tsx +++ b/webapp/channels/src/components/common/site_name_and_description.tsx @@ -12,7 +12,7 @@ type Props = { export default class SiteNameAndDescription extends React.PureComponent { public static defaultProps: Partial = { siteName: 'Mattermost', - } + }; public render(): JSX.Element { const { diff --git a/webapp/channels/src/components/common/svg_images_components/airgapped_trial_activation_confirm_svg.tsx b/webapp/channels/src/components/common/svg_images_components/airgapped_trial_activation_confirm_svg.tsx new file mode 100644 index 0000000000..30cdf300a3 --- /dev/null +++ b/webapp/channels/src/components/common/svg_images_components/airgapped_trial_activation_confirm_svg.tsx @@ -0,0 +1,621 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +type SvgProps = { + height?: number; + width?: number; +} + +const AirgappedTrialActivationConfirmSvg = ({height = 474, width = 578}: SvgProps) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export default AirgappedTrialActivationConfirmSvg; diff --git a/webapp/channels/src/components/common/svg_images_components/laptop_with_warning_symbol_svg.tsx b/webapp/channels/src/components/common/svg_images_components/laptop_with_warning_symbol_svg.tsx new file mode 100644 index 0000000000..dafef4fb56 --- /dev/null +++ b/webapp/channels/src/components/common/svg_images_components/laptop_with_warning_symbol_svg.tsx @@ -0,0 +1,76 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +type SvgProps = { + width?: number; + height?: number; +} + +const Svg = (props: SvgProps) => ( + + + + + + + + + + + + + + +); + +export default Svg; diff --git a/webapp/channels/src/components/common/svg_images_components/magnifying_glass_svg.tsx b/webapp/channels/src/components/common/svg_images_components/magnifying_glass_svg.tsx deleted file mode 100644 index 75b2ec8d3d..0000000000 --- a/webapp/channels/src/components/common/svg_images_components/magnifying_glass_svg.tsx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {SVGProps} from 'react'; - -const SvgComponent = (props: SVGProps) => ( - - - - - - - -); - -export default SvgComponent; diff --git a/webapp/channels/src/components/compass_theme_provider/compass_theme_provider.tsx b/webapp/channels/src/components/compass_theme_provider/compass_theme_provider.tsx index c8081975c2..60d6cbf20f 100644 --- a/webapp/channels/src/components/compass_theme_provider/compass_theme_provider.tsx +++ b/webapp/channels/src/components/compass_theme_provider/compass_theme_provider.tsx @@ -3,7 +3,7 @@ import React, {useState, useEffect} from 'react'; -import ThemeProvider, {lightTheme} from '@mattermost/compass-components/utilities/theme'; +import ThemeProvider, {lightTheme} from '@mattermost/compass-components/utilities/theme'; // eslint-disable-line no-restricted-imports import {Theme} from 'mattermost-redux/selectors/entities/preferences'; diff --git a/webapp/channels/src/components/confirm_modal.tsx b/webapp/channels/src/components/confirm_modal.tsx index 79eb0286fc..685438b459 100644 --- a/webapp/channels/src/components/confirm_modal.tsx +++ b/webapp/channels/src/components/confirm_modal.tsx @@ -84,7 +84,7 @@ export default class ConfirmModal extends React.Component { confirmButtonClass: 'btn btn-primary', confirmButtonText: '', modalClass: '', - } + }; constructor(props: Props) { super(props); @@ -103,15 +103,15 @@ export default class ConfirmModal extends React.Component { handleCheckboxChange = (e: React.ChangeEvent) => { this.setState({checked: e.target.checked}); - } + }; handleConfirm = () => { this.props.onConfirm?.(this.state.checked); - } + }; handleCancel = () => { this.props.onCancel?.(this.state.checked); - } + }; render() { let checkbox; diff --git a/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.tsx b/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.tsx index 80935dd469..eb67fd62b6 100644 --- a/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.tsx +++ b/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.tsx @@ -45,11 +45,11 @@ export default class ConvertChannelModal extends React.PureComponent { this.setState({show: false}); - } + }; render() { const { diff --git a/webapp/channels/src/components/copy_url_context_menu/copy_url_context_menu.tsx b/webapp/channels/src/components/copy_url_context_menu/copy_url_context_menu.tsx index 597e8b2257..a3dab0944b 100644 --- a/webapp/channels/src/components/copy_url_context_menu/copy_url_context_menu.tsx +++ b/webapp/channels/src/components/copy_url_context_menu/copy_url_context_menu.tsx @@ -39,7 +39,7 @@ export default class CopyUrlContextMenu extends React.PureComponent { } this.props.actions.copyToClipboard(link); - } + }; render(): JSX.Element { const contextMenu = ( diff --git a/webapp/channels/src/components/create_team/components/display_name.tsx b/webapp/channels/src/components/create_team/components/display_name.tsx index 231d86d8c0..f4001000a0 100644 --- a/webapp/channels/src/components/create_team/components/display_name.tsx +++ b/webapp/channels/src/components/create_team/components/display_name.tsx @@ -79,16 +79,16 @@ export default class TeamSignupDisplayNamePage extends React.PureComponent): void => { e.preventDefault(); e.currentTarget.select(); - } + }; handleDisplayNameChange = (e: React.ChangeEvent): void => { this.setState({teamDisplayName: e.target.value}); - } + }; render(): React.ReactNode { let nameError = null; diff --git a/webapp/channels/src/components/create_team/components/team_url/team_url.tsx b/webapp/channels/src/components/create_team/components/team_url/team_url.tsx index 87b7e2a529..0988cb22bf 100644 --- a/webapp/channels/src/components/create_team/components/team_url/team_url.tsx +++ b/webapp/channels/src/components/create_team/components/team_url/team_url.tsx @@ -78,7 +78,7 @@ export default class TeamUrl extends React.PureComponent { const newState = this.props.state; newState.wizard = 'display_name'; this.props.updateParent(newState); - } + }; public submitNext = async (e: React.MouseEvent) => { e.preventDefault(); @@ -177,16 +177,16 @@ export default class TeamUrl extends React.PureComponent { this.setState({nameError: error.message}); this.setState({isLoading: false}); } - } + }; public handleFocus = (e: React.FocusEvent) => { e.preventDefault(); e.currentTarget.select(); - } + }; public handleTeamURLInputChange = (e: React.ChangeEvent) => { this.setState({teamURL: e.target.value}); - } + }; render() { let nameError = null; diff --git a/webapp/channels/src/components/create_user_groups_modal/create_user_groups_modal.tsx b/webapp/channels/src/components/create_user_groups_modal/create_user_groups_modal.tsx index e8adf2d9b3..f499c835cd 100644 --- a/webapp/channels/src/components/create_user_groups_modal/create_user_groups_modal.tsx +++ b/webapp/channels/src/components/create_user_groups_modal/create_user_groups_modal.tsx @@ -65,10 +65,10 @@ export default class CreateUserGroupsModal extends React.PureComponent { this.setState({show: false}); - } + }; isSaveEnabled = () => { return this.state.name.length > 0 && this.state.mention.length > 0 && this.state.usersToAdd.length > 0; - } + }; updateNameState = (e: React.ChangeEvent) => { const value = e.target.value; let mention = this.state.mention; @@ -79,12 +79,12 @@ export default class CreateUserGroupsModal extends React.PureComponent) => { const value = e.target.value; this.setState({mention: value, mentionUpdatedManually: true}); - } + }; private addUserCallback = (usersToAdd: UserProfile[]): void => { this.setState({usersToAdd}); @@ -99,7 +99,7 @@ export default class CreateUserGroupsModal extends React.PureComponent { this.setState({showUnknownError: false, mentionInputErrorText: '', nameInputErrorText: '', saving: true}); @@ -161,7 +161,7 @@ export default class CreateUserGroupsModal extends React.PureComponent {text} diff --git a/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx b/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx index 64c32488d1..7111f0c0fe 100644 --- a/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_emoji.test.tsx @@ -12,8 +12,8 @@ import mockStore from 'tests/test_store'; import CustomStatusEmoji from './custom_status_emoji'; +jest.mock('mattermost-redux/selectors/entities/timezone'); jest.mock('selectors/views/custom_status'); -jest.mock('selectors/general'); describe('components/custom_status/custom_status_emoji', () => { const store = mockStore({}); diff --git a/webapp/channels/src/components/custom_status/custom_status_emoji.tsx b/webapp/channels/src/components/custom_status/custom_status_emoji.tsx index 43ad92d45a..f4359fae1f 100644 --- a/webapp/channels/src/components/custom_status/custom_status_emoji.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_emoji.tsx @@ -6,8 +6,9 @@ import {useSelector} from 'react-redux'; import {CustomStatusDuration} from '@mattermost/types/users'; +import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone'; + import {GlobalState} from 'types/store'; -import {getCurrentUserTimezone} from 'selectors/general'; import {makeGetCustomStatus, isCustomStatusEnabled, isCustomStatusExpired} from 'selectors/views/custom_status'; import Constants from 'utils/constants'; @@ -41,7 +42,7 @@ function CustomStatusEmoji({ const getCustomStatus = useMemo(makeGetCustomStatus, []); const customStatus = useSelector((state: GlobalState) => getCustomStatus(state, userID)); - const timezone = useSelector(getCurrentUserTimezone); + const timezone = useSelector(getCurrentTimezone); const customStatusExpired = useSelector((state: GlobalState) => isCustomStatusExpired(state, customStatus)); const customStatusEnabled = useSelector(isCustomStatusEnabled); diff --git a/webapp/channels/src/components/custom_status/custom_status_modal.tsx b/webapp/channels/src/components/custom_status/custom_status_modal.tsx index 35844581f4..28f2efd9aa 100644 --- a/webapp/channels/src/components/custom_status/custom_status_modal.tsx +++ b/webapp/channels/src/components/custom_status/custom_status_modal.tsx @@ -11,6 +11,7 @@ import {useRouteMatch} from 'react-router-dom'; import {setCustomStatus, unsetCustomStatus, removeRecentCustomStatus} from 'mattermost-redux/actions/users'; import {setCustomStatusInitialisationState} from 'mattermost-redux/actions/preferences'; import {Preferences} from 'mattermost-redux/constants'; +import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone'; import {loadCustomEmojisIfNeeded} from 'actions/emoji_actions'; import {closeModal} from 'actions/views/modals'; @@ -20,7 +21,6 @@ import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay'; import RenderEmoji from 'components/emoji/render_emoji'; import QuickInput, {MaxLengthInput} from 'components/quick_input'; import {makeGetCustomStatus, getRecentCustomStatuses, showStatusDropdownPulsatingDot, isCustomStatusExpired} from 'selectors/views/custom_status'; -import {getCurrentUserTimezone} from 'selectors/general'; import {GlobalState} from 'types/store'; import {getCurrentMomentForTimezone} from 'utils/timezone'; import {A11yCustomEventTypes, A11yFocusEventDetail, Constants, ModalIdentifiers} from 'utils/constants'; @@ -115,7 +115,7 @@ const CustomStatusModal: React.FC = (props: Props) => { const [duration, setDuration] = useState(initialDuration === undefined ? defaultDuration : initialDuration); const isStatusSet = Boolean(emoji || text); const firstTimeModalOpened = useSelector(showStatusDropdownPulsatingDot); - const timezone = useSelector(getCurrentUserTimezone); + const timezone = useSelector(getCurrentTimezone); const inCustomEmojiPath = useRouteMatch('/:team/emoji'); const currentTime = getCurrentMomentForTimezone(timezone); diff --git a/webapp/channels/src/components/custom_status/date_time_input.tsx b/webapp/channels/src/components/custom_status/date_time_input.tsx index d5837f4e3a..8dde00eded 100644 --- a/webapp/channels/src/components/custom_status/date_time_input.tsx +++ b/webapp/channels/src/components/custom_status/date_time_input.tsx @@ -9,7 +9,7 @@ import {DateTime} from 'luxon'; import moment, {Moment} from 'moment-timezone'; -import IconButton from '@mattermost/compass-components/components/icon-button'; +import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports import MenuWrapper from 'components/widgets/menu/menu_wrapper'; import Input from 'components/widgets/inputs/input/input'; diff --git a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx index 6a00a9681c..f543d9f0ae 100644 --- a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx +++ b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx @@ -77,7 +77,7 @@ export default class DataPrefetch extends React.PureComponent { } } return this.props.actions.prefetchChannelPosts(channelId, delay); - } + }; private prefetchData = () => { const {prefetchRequestStatus, prefetchQueueObj} = this.props; @@ -93,7 +93,7 @@ export default class DataPrefetch extends React.PureComponent { } } } - } + }; render() { return null; diff --git a/webapp/channels/src/components/delete_category_modal/delete_category_modal.tsx b/webapp/channels/src/components/delete_category_modal/delete_category_modal.tsx index a322d9d4c2..5afd6bae5d 100644 --- a/webapp/channels/src/components/delete_category_modal/delete_category_modal.tsx +++ b/webapp/channels/src/components/delete_category_modal/delete_category_modal.tsx @@ -36,7 +36,7 @@ export default class DeleteCategoryModal extends React.PureComponent { this.props.actions.deleteCategory(this.props.category.id); - } + }; render() { return ( diff --git a/webapp/channels/src/components/delete_channel_modal/delete_channel_modal.tsx b/webapp/channels/src/components/delete_channel_modal/delete_channel_modal.tsx index 8ce74db444..08172a8206 100644 --- a/webapp/channels/src/components/delete_channel_modal/delete_channel_modal.tsx +++ b/webapp/channels/src/components/delete_channel_modal/delete_channel_modal.tsx @@ -42,11 +42,11 @@ export default class DeleteChannelModal extends React.PureComponent { this.setState({show: false}); - } + }; render() { const {canViewArchivedChannels} = this.props; diff --git a/webapp/channels/src/components/delete_post_modal/delete_post_modal.tsx b/webapp/channels/src/components/delete_post_modal/delete_post_modal.tsx index ebbd6ef2a5..422a416336 100644 --- a/webapp/channels/src/components/delete_post_modal/delete_post_modal.tsx +++ b/webapp/channels/src/components/delete_post_modal/delete_post_modal.tsx @@ -77,11 +77,11 @@ export default class DeletePostModal extends React.PureComponent { if (result.data) { this.onHide(); } - } + }; handleEntered = () => { this.deletePostBtn?.current?.focus(); - } + }; onHide = () => { this.setState({show: false}); @@ -97,7 +97,7 @@ export default class DeletePostModal extends React.PureComponent { element.focus(); } } - } + }; render() { let commentWarning: React.ReactNode = ''; diff --git a/webapp/channels/src/components/dnd_custom_time_picker_modal/dnd_custom_time_picker_modal.tsx b/webapp/channels/src/components/dnd_custom_time_picker_modal/dnd_custom_time_picker_modal.tsx index e0e389c3a6..8e83fb47cd 100644 --- a/webapp/channels/src/components/dnd_custom_time_picker_modal/dnd_custom_time_picker_modal.tsx +++ b/webapp/channels/src/components/dnd_custom_time_picker_modal/dnd_custom_time_picker_modal.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; import {DayPickerProps} from 'react-day-picker'; -import IconButton from '@mattermost/compass-components/components/icon-button'; +import IconButton from '@mattermost/compass-components/components/icon-button'; // eslint-disable-line no-restricted-imports import classNames from 'classnames'; @@ -87,7 +87,7 @@ export default class DndCustomTimePicker extends React.PureComponent { return DateTime.fromJSDate(date).toFormat('yyyy-MM-dd'); - } + }; getText = () => { const modalHeaderText = ( @@ -107,7 +107,7 @@ export default class DndCustomTimePicker extends React.PureComponent { if (this.state.isPopperOpen) { @@ -128,7 +128,7 @@ export default class DndCustomTimePicker extends React.PureComponent { this.setState({ @@ -168,9 +168,9 @@ export default class DndCustomTimePicker extends React.PureComponent { + handlePopperOpenState = (isOpen: boolean) => { this.setState({ isPopperOpen: isOpen, }); diff --git a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap index 9970088867..490e16e2da 100644 --- a/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap +++ b/webapp/channels/src/components/dot_menu/__snapshots__/dot_menu.test.tsx.snap @@ -107,113 +107,6 @@ Object { } `; -exports[`components/dot_menu/DotMenu should match snapshot, hide "New" badge on forward post 1`] = ` -Object { - "asFragment": [Function], - "baseElement": -
- -
- , - "container":
- -
, - "debug": [Function], - "findAllByAltText": [Function], - "findAllByDisplayValue": [Function], - "findAllByLabelText": [Function], - "findAllByPlaceholderText": [Function], - "findAllByRole": [Function], - "findAllByTestId": [Function], - "findAllByText": [Function], - "findAllByTitle": [Function], - "findByAltText": [Function], - "findByDisplayValue": [Function], - "findByLabelText": [Function], - "findByPlaceholderText": [Function], - "findByRole": [Function], - "findByTestId": [Function], - "findByText": [Function], - "findByTitle": [Function], - "getAllByAltText": [Function], - "getAllByDisplayValue": [Function], - "getAllByLabelText": [Function], - "getAllByPlaceholderText": [Function], - "getAllByRole": [Function], - "getAllByTestId": [Function], - "getAllByText": [Function], - "getAllByTitle": [Function], - "getByAltText": [Function], - "getByDisplayValue": [Function], - "getByLabelText": [Function], - "getByPlaceholderText": [Function], - "getByRole": [Function], - "getByTestId": [Function], - "getByText": [Function], - "getByTitle": [Function], - "queryAllByAltText": [Function], - "queryAllByDisplayValue": [Function], - "queryAllByLabelText": [Function], - "queryAllByPlaceholderText": [Function], - "queryAllByRole": [Function], - "queryAllByTestId": [Function], - "queryAllByText": [Function], - "queryAllByTitle": [Function], - "queryByAltText": [Function], - "queryByDisplayValue": [Function], - "queryByLabelText": [Function], - "queryByPlaceholderText": [Function], - "queryByRole": [Function], - "queryByTestId": [Function], - "queryByText": [Function], - "queryByTitle": [Function], - "rerender": [Function], - "unmount": [Function], -} -`; - exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = ` `; - -exports[`components/dot_menu/DotMenu should match snapshot, show "New" badge on forward post 1`] = ` -Object { - "asFragment": [Function], - "baseElement": -
- -
- , - "container":
- -
, - "debug": [Function], - "findAllByAltText": [Function], - "findAllByDisplayValue": [Function], - "findAllByLabelText": [Function], - "findAllByPlaceholderText": [Function], - "findAllByRole": [Function], - "findAllByTestId": [Function], - "findAllByText": [Function], - "findAllByTitle": [Function], - "findByAltText": [Function], - "findByDisplayValue": [Function], - "findByLabelText": [Function], - "findByPlaceholderText": [Function], - "findByRole": [Function], - "findByTestId": [Function], - "findByText": [Function], - "findByTitle": [Function], - "getAllByAltText": [Function], - "getAllByDisplayValue": [Function], - "getAllByLabelText": [Function], - "getAllByPlaceholderText": [Function], - "getAllByRole": [Function], - "getAllByTestId": [Function], - "getAllByText": [Function], - "getAllByTitle": [Function], - "getByAltText": [Function], - "getByDisplayValue": [Function], - "getByLabelText": [Function], - "getByPlaceholderText": [Function], - "getByRole": [Function], - "getByTestId": [Function], - "getByText": [Function], - "getByTitle": [Function], - "queryAllByAltText": [Function], - "queryAllByDisplayValue": [Function], - "queryAllByLabelText": [Function], - "queryAllByPlaceholderText": [Function], - "queryAllByRole": [Function], - "queryAllByTestId": [Function], - "queryAllByText": [Function], - "queryAllByTitle": [Function], - "queryByAltText": [Function], - "queryByDisplayValue": [Function], - "queryByLabelText": [Function], - "queryByPlaceholderText": [Function], - "queryByRole": [Function], - "queryByTestId": [Function], - "queryByText": [Function], - "queryByTitle": [Function], - "rerender": [Function], - "unmount": [Function], -} -`; diff --git a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx index e807940ead..402cf954b1 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx @@ -146,7 +146,6 @@ describe('components/dot_menu/DotMenu', () => { threadReplyCount: 0, userId: 'user_id_1', isMilitaryTime: false, - showForwardPostNewLabel: false, }; test('should match snapshot, on Center', () => { @@ -181,32 +180,6 @@ describe('components/dot_menu/DotMenu', () => { expect(wrapper).toMatchSnapshot(); }); - test('should match snapshot, show "New" badge on forward post', () => { - const props = { - ...baseProps, - showForwardPostNewLabel: true, - }; - const wrapper = renderWithIntlAndStore( - , - initialState, - ); - - expect(wrapper).toMatchSnapshot(); - }); - - test('should match snapshot, hide "New" badge on forward post', () => { - const props = { - ...baseProps, - showForwardPostNewLabel: false, - }; - const wrapper = renderWithIntlAndStore( - , - initialState, - ); - - expect(wrapper).toMatchSnapshot(); - }); - test('should show mark as unread when channel is not archived', () => { const props = { ...baseProps, diff --git a/webapp/channels/src/components/dot_menu/dot_menu.tsx b/webapp/channels/src/components/dot_menu/dot_menu.tsx index 135fb04593..46067b6abe 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu.tsx @@ -25,7 +25,7 @@ import { import Permissions from 'mattermost-redux/constants/permissions'; -import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS, Preferences} from 'utils/constants'; +import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS} from 'utils/constants'; import DeletePostModal from 'components/delete_post_modal'; import DelayedAction from 'utils/delayed_action'; import * as PostUtils from 'utils/post_utils'; @@ -33,12 +33,10 @@ import * as Menu from 'components/menu'; import * as Utils from 'utils/utils'; import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate'; import {ModalData} from 'types/actions'; -import {PluginComponent} from 'types/store/plugins'; import {UserThread} from '@mattermost/types/threads'; import {Post} from '@mattermost/types/posts'; import ForwardPostModal from '../forward_post_modal'; -import Tag from '../widgets/tag/tag'; import {ChangeEvent, trackDotMenuEvent} from './utils'; @@ -70,20 +68,11 @@ type Props = { postEditTimeLimit?: string; // TechDebt: Made non-mandatory while converting to typescript enableEmojiPicker?: boolean; // TechDebt: Made non-mandatory while converting to typescript channelIsArchived?: boolean; // TechDebt: Made non-mandatory while converting to typescript - currentTeamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript teamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript isMobileView: boolean; - showForwardPostNewLabel: boolean; timezone?: string; isMilitaryTime: boolean; - /** - * Components for overriding provided by plugins - */ - components: { - [componentName: string]: PluginComponent[]; - }; - actions: { /** @@ -154,7 +143,7 @@ export class DotMenuClass extends React.PureComponent { isFlagged: false, isReadOnly: false, location: Locations.CENTER, - } + }; private editDisableAction: DelayedAction; private buttonRef: React.RefObject; private canPostBeForwarded: boolean; @@ -210,7 +199,7 @@ export class DotMenuClass extends React.PureComponent { handleEditDisable = (): void => { this.setState({canEdit: false}); - } + }; handleFlagMenuItemActivated = (e: ChangeEvent): void => { if (this.props.isFlagged) { @@ -220,7 +209,7 @@ export class DotMenuClass extends React.PureComponent { trackDotMenuEvent(e, TELEMETRY_LABELS.SAVE); this.props.actions.flagPost(this.props.post.id); } - } + }; // listen to clicks/taps on add reaction menu item and pass to parent handler handleAddReactionMenuItemActivated = (e: ChangeEvent): void => { @@ -230,17 +219,17 @@ export class DotMenuClass extends React.PureComponent { if (this.props.handleAddReactionClick) { this.props.handleAddReactionClick(); } - } + }; copyLink = (e: ChangeEvent) => { trackDotMenuEvent(e, TELEMETRY_LABELS.COPY_LINK); Utils.copyToClipboard(`${this.props.teamUrl}/pl/${this.props.post.id}`); - } + }; copyText = (e: ChangeEvent) => { trackDotMenuEvent(e, TELEMETRY_LABELS.COPY_TEXT); Utils.copyToClipboard(this.props.post.message); - } + }; handlePinMenuItemActivated = (e: ChangeEvent): void => { if (this.props.post.is_pinned) { @@ -250,13 +239,13 @@ export class DotMenuClass extends React.PureComponent { trackDotMenuEvent(e, TELEMETRY_LABELS.PIN); this.props.actions.pinPost(this.props.post.id); } - } + }; handleMarkPostAsUnread = (e: ChangeEvent): void => { e.preventDefault(); trackDotMenuEvent(e, TELEMETRY_LABELS.UNREAD); this.props.actions.markPostAsUnread(this.props.post, this.props.location); - } + }; handleDeleteMenuItemActivated = (e: ChangeEvent): void => { e.preventDefault(); @@ -272,7 +261,7 @@ export class DotMenuClass extends React.PureComponent { }; this.props.actions.openModal(deletePostModalData); - } + }; handleForwardMenuItemActivated = (e: ChangeEvent): void => { if (!this.canPostBeForwarded) { @@ -292,11 +281,8 @@ export class DotMenuClass extends React.PureComponent { }, }; - if (this.props.showForwardPostNewLabel) { - this.props.actions.setGlobalItem(Preferences.FORWARD_POST_VIEWED, false); - } this.props.actions.openModal(forwardPostModalData); - } + }; handleEditMenuItemActivated = (e: ChangeEvent): void => { trackDotMenuEvent(e, TELEMETRY_LABELS.EDIT); @@ -307,7 +293,7 @@ export class DotMenuClass extends React.PureComponent { this.props.post.root_id ? Utils.localizeMessage('rhs_comment.comment', 'Comment') : Utils.localizeMessage('create_post.post', 'Post'), this.props.location === Locations.RHS_ROOT || this.props.location === Locations.RHS_COMMENT || this.props.location === Locations.SEARCH, ); - } + }; handleSetThreadFollow = (e: ChangeEvent) => { const {actions, teamId, threadId, userId, isFollowingThread, isMentionedInRootPost} = this.props; @@ -331,16 +317,16 @@ export class DotMenuClass extends React.PureComponent { threadId, followingThread, ); - } + }; handleCommentClick = (e: ChangeEvent) => { trackDotMenuEvent(e, TELEMETRY_LABELS.REPLY); this.props.handleCommentClick?.(e); - } + }; isKeyboardEvent = (e: React.KeyboardEvent): any => { return (e).getModifierState !== undefined; - } + }; onShortcutKeyDown = (e: React.KeyboardEvent): void => { e.preventDefault(); @@ -410,17 +396,17 @@ export class DotMenuClass extends React.PureComponent { this.handleDropdownOpened(false); break; } - } + }; handleDropdownOpened = (open: boolean) => { this.props.handleDropdownOpened?.(open); this.setState({closeMenuManually: true}); - } + }; handleMenuToggle = (open: boolean) => { this.props.handleDropdownOpened?.(open); this.setState({closeMenuManually: false}); - } + }; render(): JSX.Element { const {formatMessage} = this.props.intl; @@ -441,15 +427,6 @@ export class DotMenuClass extends React.PureComponent { id='forward_post_button.label' defaultMessage='Forward' /> - {this.props.showForwardPostNewLabel && ( - - )} ); @@ -519,12 +496,12 @@ export class DotMenuClass extends React.PureComponent { class: classNames('post-menu__item', { 'post-menu__item--active': this.props.isMenuOpen, }), - 'aria-label': this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}), + 'aria-label': formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}), children: , }} menu={{ id: `${this.props.location}_dropdown_${this.props.post.id}`, - 'aria-label': this.props.intl.formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}), + 'aria-label': formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}), onKeyDown: this.onShortcutKeyDown, width: '264px', onToggle: this.handleMenuToggle, @@ -532,7 +509,7 @@ export class DotMenuClass extends React.PureComponent { }} menuButtonTooltip={{ id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`, - text: this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}), + text: formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}), class: 'hidden-xs', }} > diff --git a/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx index dd9b38594b..c5b2e454d1 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu_empty.test.tsx @@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu returning empty ("")', () => { threadId: 'post_id_1', userId: 'user_id_1', isMilitaryTime: false, - showForwardPostNewLabel: false, }; const wrapper = shallow( diff --git a/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx index a6ecb1761c..cd3f1d23a8 100644 --- a/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx +++ b/webapp/channels/src/components/dot_menu/dot_menu_mobile.test.tsx @@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu on mobile view', () => { threadId: 'post_id_1', userId: 'user_id_1', isMilitaryTime: false, - showForwardPostNewLabel: false, }; const wrapper = shallow( diff --git a/webapp/channels/src/components/dot_menu/index.ts b/webapp/channels/src/components/dot_menu/index.ts index fa1623fa2c..1aea3d476c 100644 --- a/webapp/channels/src/components/dot_menu/index.ts +++ b/webapp/channels/src/components/dot_menu/index.ts @@ -12,7 +12,7 @@ import {getCurrentTeamId, getCurrentTeam, getTeam} from 'mattermost-redux/select import {makeGetThreadOrSynthetic} from 'mattermost-redux/selectors/entities/threads'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {getBool, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences'; -import {getCurrentUserTimezone} from 'selectors/general'; +import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone'; import {isSystemMessage} from 'mattermost-redux/utils/post_utils'; import {GenericAction} from 'mattermost-redux/types/actions'; import {setThreadFollow} from 'mattermost-redux/actions/threads'; @@ -44,7 +44,6 @@ import {matchUserMentionTriggersWithMessageMentions} from 'utils/post_utils'; import {Post} from '@mattermost/types/posts'; import {setGlobalItem} from '../../actions/storage'; -import {getGlobalItem} from '../../selectors/storage'; import DotMenu from './dot_menu'; @@ -110,8 +109,6 @@ function makeMapStateToProps() { } } - const showForwardPostNewLabel = getGlobalItem(state, Preferences.FORWARD_POST_VIEWED, true); - return { channelIsArchived: isArchivedChannel(channel), components: state.plugins.components, @@ -129,8 +126,7 @@ function makeMapStateToProps() { isCollapsedThreadsEnabled: collapsedThreads, threadReplyCount, isMobileView: getIsMobileView(state), - showForwardPostNewLabel, - timezone: getCurrentUserTimezone(state), + timezone: getCurrentTimezone(state), isMilitaryTime, }; }; diff --git a/webapp/channels/src/components/drafts/draft_actions/__snapshots__/delete_draft_modal.test.tsx.snap b/webapp/channels/src/components/drafts/draft_actions/__snapshots__/delete_draft_modal.test.tsx.snap index 092e043646..bcffa0da8f 100644 --- a/webapp/channels/src/components/drafts/draft_actions/__snapshots__/delete_draft_modal.test.tsx.snap +++ b/webapp/channels/src/components/drafts/draft_actions/__snapshots__/delete_draft_modal.test.tsx.snap @@ -4,6 +4,7 @@ exports[`components/drafts/draft_actions/delete_draft_modal should have called o div { - z-index: 999999; + z-index: $dropdown_input_index; padding: 10px 24px; cursor: pointer; line-height: 16px; @@ -51,3 +53,33 @@ .DropdownInput__option.focused > div { background-color: rgba(var(--center-channel-color-rgb), 0.08); } + +.second-dropdown-sibling-wrapper { + .DropdownInput { + z-index: $dropdown_input_index - 1; + } + + .DropdownInput__option > div { + z-index: $dropdown_input_index - 1; + } +} + +.third-dropdown-sibling-wrapper { + .DropdownInput { + z-index: $dropdown_input_index - 2; + } + + .DropdownInput__option > div { + z-index: $dropdown_input_index - 2; + } +} + +.fourth-dropdown-sibling-wrapper { + .DropdownInput { + z-index: $dropdown_input_index - 3; + } + + .DropdownInput__option > div { + z-index: $dropdown_input_index - 3; + } +} diff --git a/webapp/channels/src/components/edit_category_modal/edit_category_modal.tsx b/webapp/channels/src/components/edit_category_modal/edit_category_modal.tsx index dd5c8786bf..99c8f83381 100644 --- a/webapp/channels/src/components/edit_category_modal/edit_category_modal.tsx +++ b/webapp/channels/src/components/edit_category_modal/edit_category_modal.tsx @@ -44,15 +44,15 @@ export default class EditCategoryModal extends React.PureComponent handleClear = () => { this.setState({categoryName: ''}); - } + }; handleChange = (e: React.ChangeEvent) => { this.setState({categoryName: e.target.value}); - } + }; handleCancel = () => { this.handleClear(); - } + }; handleConfirm = () => { if (this.props.categoryId) { @@ -61,12 +61,12 @@ export default class EditCategoryModal extends React.PureComponent this.props.actions.createCategory(this.props.currentTeamId, this.state.categoryName, this.props.channelIdsToAdd); trackEvent('ui', 'ui_sidebar_created_category'); } - } + }; isConfirmDisabled = () => { return !this.state.categoryName || (Boolean(this.props.initialCategoryName) && this.props.initialCategoryName === this.state.categoryName) || this.state.categoryName.length > MAX_LENGTH; - } + }; getText = () => { let modalHeaderText; @@ -112,7 +112,7 @@ export default class EditCategoryModal extends React.PureComponent editButtonText, helpText, }; - } + }; render() { const { diff --git a/webapp/channels/src/components/edit_channel_header_modal/edit_channel_header_modal.tsx b/webapp/channels/src/components/edit_channel_header_modal/edit_channel_header_modal.tsx index c1fc225c1d..c61e3a48db 100644 --- a/webapp/channels/src/components/edit_channel_header_modal/edit_channel_header_modal.tsx +++ b/webapp/channels/src/components/edit_channel_header_modal/edit_channel_header_modal.tsx @@ -87,17 +87,17 @@ export default class EditChannelHeaderModal extends React.PureComponent { this.props.actions.setShowPreview(newState); - } + }; private handleChange = (e: React.ChangeEvent): void => { this.setState({ header: e.target.value, }); - } + }; public handleSave = async (): Promise => { const header = this.state.header?.trim() ?? ''; @@ -113,29 +113,29 @@ export default class EditChannelHeaderModal extends React.PureComponent { this.setState({ show: false, }); - } + }; private focusTextbox = (): void => { if (this.editChannelHeaderTextboxRef.current) { this.editChannelHeaderTextboxRef.current.focus(); } - } + }; private blurTextbox = (): void => { if (this.editChannelHeaderTextboxRef.current) { this.editChannelHeaderTextboxRef.current.blur(); } - } + }; private handleEntering = (): void => { this.focusTextbox(); - } + }; private handleKeyDown = (e: React.KeyboardEvent): void => { const {ctrlSend} = this.props; @@ -146,7 +146,7 @@ export default class EditChannelHeaderModal extends React.PureComponent): void => { const {ctrlSend} = this.props; @@ -157,11 +157,11 @@ export default class EditChannelHeaderModal extends React.PureComponent { this.setState({postError}); - } + }; private renderError = (): (JSX.Element | null) => { const {serverError} = this.state; @@ -192,7 +192,7 @@ export default class EditChannelHeaderModal extends React.PureComponent ); - } + }; public render(): JSX.Element { let headerTitle = null; diff --git a/webapp/channels/src/components/edit_channel_purpose_modal/edit_channel_purpose_modal.tsx b/webapp/channels/src/components/edit_channel_purpose_modal/edit_channel_purpose_modal.tsx index aace31bfb8..0f932581e0 100644 --- a/webapp/channels/src/components/edit_channel_purpose_modal/edit_channel_purpose_modal.tsx +++ b/webapp/channels/src/components/edit_channel_purpose_modal/edit_channel_purpose_modal.tsx @@ -55,11 +55,11 @@ export class EditChannelPurposeModal extends React.PureComponent { if (this.purpose.current) { Utils.placeCaretAtEnd(this.purpose.current); } - } + }; onHide = () => { this.setState({show: false}); - } + }; handleKeyDown = (e: React.KeyboardEvent) => { const {ctrlSend} = this.props; @@ -75,7 +75,7 @@ export class EditChannelPurposeModal extends React.PureComponent { e.preventDefault(); this.handleSave(); } - } + }; handleSave = async () => { const {channel, actions: {patchChannel}} = this.props; @@ -96,12 +96,12 @@ export class EditChannelPurposeModal extends React.PureComponent { if (data) { this.onHide(); } - } + }; handleChange = (e: ChangeEvent) => { e.preventDefault(); this.setState({purpose: e.target.value}); - } + }; render() { let serverError = null; diff --git a/webapp/channels/src/components/emoji/add_emoji/add_emoji.tsx b/webapp/channels/src/components/emoji/add_emoji/add_emoji.tsx index 519f94c9ea..168b3c7c1b 100644 --- a/webapp/channels/src/components/emoji/add_emoji/add_emoji.tsx +++ b/webapp/channels/src/components/emoji/add_emoji/add_emoji.tsx @@ -65,11 +65,11 @@ export default class AddEmoji extends React.PureComponent): Promise => { return this.handleSubmit(e); - } + }; handleSaveButtonClick = async (e: React.MouseEvent): Promise => { return this.handleSubmit(e); - } + }; handleSubmit = async (e: SyntheticEvent): Promise => { const {actions, emojiMap, user, team} = this.props; diff --git a/webapp/channels/src/components/emoji/emoji_list_item/emoji_list_item.tsx b/webapp/channels/src/components/emoji/emoji_list_item/emoji_list_item.tsx index f0d0b27af1..2daa92db44 100644 --- a/webapp/channels/src/components/emoji/emoji_list_item/emoji_list_item.tsx +++ b/webapp/channels/src/components/emoji/emoji_list_item/emoji_list_item.tsx @@ -29,7 +29,7 @@ export default class EmojiListItem extends React.PureComponent { emoji: {} as CustomEmoji, currentUserId: '', creatorDisplayName: '', - } + }; handleDelete = (): void => { if (this.props.onDelete) { @@ -37,7 +37,7 @@ export default class EmojiListItem extends React.PureComponent { } this.props.actions.deleteCustomEmoji(this.props.emoji.id); - } + }; render(): JSX.Element { const emoji = this.props.emoji; diff --git a/webapp/channels/src/components/emoji/emoji_page.tsx b/webapp/channels/src/components/emoji/emoji_page.tsx index dcc8291b70..cfba20e435 100644 --- a/webapp/channels/src/components/emoji/emoji_page.tsx +++ b/webapp/channels/src/components/emoji/emoji_page.tsx @@ -30,7 +30,7 @@ export default class EmojiPage extends React.PureComponent { teamName: '', teamDisplayName: '', siteName: '', - } + }; componentDidMount() { this.updateTitle(); @@ -44,7 +44,7 @@ export default class EmojiPage extends React.PureComponent { updateTitle = () => { document.title = Utils.localizeMessage('custom_emoji.header', 'Custom Emoji') + ' - ' + this.props.teamDisplayName + ' ' + this.props.siteName; - } + }; componentDidUpdate(prevProps: Props) { if (this.props.siteName !== prevProps.siteName) { diff --git a/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx b/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx index 8db5b3c03c..20a3f561a2 100644 --- a/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx +++ b/webapp/channels/src/components/emoji_picker/components/emoji_picker_skin.tsx @@ -52,18 +52,18 @@ export class EmojiPickerSkin extends React.PureComponent { { skinName: Emoji.SkinTranslations.get(skin), }); - } + }; hideSkinTonePicker = (skin: string) => { this.setState({pickerExtended: false}); if (skin !== this.props.userSkinTone) { this.props.onSkinSelected(skin); } - } + }; showSkinTonePicker = () => { this.setState({pickerExtended: true}); - } + }; extended() { const closeButtonLabel = this.props.intl.formatMessage({ diff --git a/webapp/channels/src/components/external_image/external_image.tsx b/webapp/channels/src/components/external_image/external_image.tsx index f58bb337af..ba52ce48a3 100644 --- a/webapp/channels/src/components/external_image/external_image.tsx +++ b/webapp/channels/src/components/external_image/external_image.tsx @@ -24,12 +24,12 @@ export default class ExternalImage extends React.PureComponent { } return this.props.imageMetadata.format === 'svg'; - } + }; shouldRenderImage = () => { // Return true unless the image is an SVG and we have SVG rendering disabled return this.props.enableSVGs || !this.isSVGImage(); - } + }; render() { let src = getImageSrc(this.props.src, this.props.hasImageProxy); diff --git a/webapp/channels/src/components/favicon_title_handler/favicon_title_handler.tsx b/webapp/channels/src/components/favicon_title_handler/favicon_title_handler.tsx index bb57d2f8f5..2957eea26a 100644 --- a/webapp/channels/src/components/favicon_title_handler/favicon_title_handler.tsx +++ b/webapp/channels/src/components/favicon_title_handler/favicon_title_handler.tsx @@ -132,7 +132,7 @@ export class FaviconTitleHandlerClass extends React.PureComponent { } else { document.title = formatMessage({id: 'sidebar.team_select', defaultMessage: '{siteName} - Join a team'}, {siteName: currentSiteName || 'Mattermost'}); } - } + }; updateFavicon = (badgeStatus: BadgeStatus) => { if (!(UserAgent.isFirefox() || UserAgent.isChrome())) { @@ -177,7 +177,7 @@ export class FaviconTitleHandlerClass extends React.PureComponent { link96x96!.href = getFavicon(faviconDefault96x96); } } - } + }; render() { return null; diff --git a/webapp/channels/src/components/feature_restricted_modal/feature_restricted_modal.tsx b/webapp/channels/src/components/feature_restricted_modal/feature_restricted_modal.tsx index d24ca68c7e..547dcd9fc5 100644 --- a/webapp/channels/src/components/feature_restricted_modal/feature_restricted_modal.tsx +++ b/webapp/channels/src/components/feature_restricted_modal/feature_restricted_modal.tsx @@ -132,7 +132,7 @@ const FeatureRestrictedModal = ({ trialBtn = ( @@ -140,7 +140,8 @@ const FeatureRestrictedModal = ({ } else { trialBtn = ( void; @@ -28,23 +28,35 @@ const DowngradeFeedbackModal = (props: Props) => { defaultMessage: 'Downgrade', }); - const downgradeFeedbackOptions = [ - props.intl.formatMessage({ - id: 'feedback.downgradeWorkspace.technicalIssues', - defaultMessage: 'Experienced technical issues', - }), - props.intl.formatMessage({ - id: 'feedback.downgradeWorkspace.noLongerNeeded', - defaultMessage: 'No longer need Cloud Professional features', - }), - props.intl.formatMessage({ - id: 'feedback.downgradeWorkspace.exploringOptions', - defaultMessage: 'Exploring other solutions', - }), - props.intl.formatMessage({ - id: 'feedback.downgradeWorkspace.tooExpensive', - defaultMessage: 'Too expensive', - }), + const downgradeFeedbackOptions: FeedbackOption[] = [ + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.downgradeWorkspace.technicalIssues', + defaultMessage: 'Experienced technical issues', + }), + submissionValue: 'Experienced technical issues', + }, + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.downgradeWorkspace.noLongerNeeded', + defaultMessage: 'No longer need Cloud Professional features', + }), + submissionValue: 'No longer need Cloud Professional features', + }, + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.downgradeWorkspace.exploringOptions', + defaultMessage: 'Exploring other solutions', + }), + submissionValue: 'Exploring other solutions', + }, + { + translatedMessage: props.intl.formatMessage({ + id: 'feedback.downgradeWorkspace.tooExpensive', + defaultMessage: 'Too expensive', + }), + submissionValue: 'Too expensive', + }, ]; return ( diff --git a/webapp/channels/src/components/feedback_modal/feedback.tsx b/webapp/channels/src/components/feedback_modal/feedback.tsx index af8daaac91..3f612017be 100644 --- a/webapp/channels/src/components/feedback_modal/feedback.tsx +++ b/webapp/channels/src/components/feedback_modal/feedback.tsx @@ -15,18 +15,23 @@ import {ModalIdentifiers} from 'utils/constants'; import './feedback.scss'; +export interface FeedbackOption { + translatedMessage: string; + submissionValue: string; +} + type Props = { onSubmit: (deleteFeedback: Feedback) => void; title: string; submitText: string; - feedbackOptions: string[]; + feedbackOptions: FeedbackOption[]; freeformTextPlaceholder: string; } & WrappedComponentProps function FeedbackModal(props: Props) { const maxFreeFormTextLength = 500; - const optionOther = props.intl.formatMessage({id: 'feedback.other', defaultMessage: 'Other'}); - const feedbackModalOptions: string[] = [ + const optionOther = {translatedMessage: props.intl.formatMessage({id: 'feedback.other', defaultMessage: 'Other'}), submissionValue: 'Other'}; + const feedbackModalOptions: FeedbackOption[] = [ ...props.feedbackOptions, optionOther, ]; @@ -34,9 +39,9 @@ function FeedbackModal(props: Props) { const [reason, setReason] = useState(''); const [comments, setComments] = useState(''); const reasonNotSelected = reason === ''; - const reasonOther = reason === optionOther; + const reasonOther = reason === optionOther.submissionValue; const commentsNotProvided = comments.trim() === ''; - const submitDisabled = reasonNotSelected || (reason === optionOther && commentsNotProvided); + const submitDisabled = reasonNotSelected || (reasonOther && commentsNotProvided); const dispatch = useDispatch(); @@ -71,15 +76,15 @@ function FeedbackModal(props: Props) { testId='FeedbackModalRadioGroup' values={feedbackModalOptions.map((option) => { return { - value: option, - key: option, - testId: option, + value: option.submissionValue, + key: option.translatedMessage, + testId: option.submissionValue, }; })} value={reason} onChange={(e) => setReason(e.target.value)} /> - {reason === optionOther && + {reasonOther && <>