From b43a74808d978c5738cd8e64e38e9c8fa0051e38 Mon Sep 17 00:00:00 2001 From: Caleb Roseland Date: Wed, 3 May 2023 09:32:51 -0500 Subject: [PATCH] MM-52265: Boards ESLint improvements (#23218) * eslint changes * sync max-lines with channels rule * eslint fixes * remove dupe rules --- webapp/boards/.eslintrc.json | 590 +++++++++++++++++- webapp/boards/jest.config.js | 62 +- .../boards/loaders/globalScssClassLoader.js | 1 + webapp/boards/package.json | 2 + webapp/boards/src/app.tsx | 4 +- webapp/boards/src/archiver.ts | 4 +- webapp/boards/src/blockIcons.ts | 1 + webapp/boards/src/blocks/block.test.ts | 2 +- webapp/boards/src/blocks/block.ts | 1 + webapp/boards/src/blocks/board.test.ts | 6 +- webapp/boards/src/blocks/board.ts | 4 +- webapp/boards/src/blocks/card.ts | 1 + webapp/boards/src/blocks/filterGroup.ts | 2 + webapp/boards/src/boardUtils.ts | 12 +- webapp/boards/src/cardFilter.ts | 26 + .../components/addContentMenuItem.test.tsx | 2 - .../src/components/addContentMenuItem.tsx | 3 +- .../src/components/blockIconSelector.test.tsx | 1 - .../blocksEditor/blockContent.test.tsx | 10 +- .../components/blocksEditor/blockContent.tsx | 3 + .../blocks/attachment/attachment.test.tsx | 2 +- .../blocksEditor/blocks/attachment/index.tsx | 2 +- .../blocks/checkbox/checkbox.test.tsx | 2 +- .../blocksEditor/blocks/checkbox/index.tsx | 4 +- .../blocksEditor/blocks/divider/index.tsx | 1 + .../blocksEditor/blocks/h1/h1.test.tsx | 2 +- .../blocksEditor/blocks/h1/index.tsx | 4 +- .../blocksEditor/blocks/h2/h2.test.tsx | 2 +- .../blocksEditor/blocks/h2/index.tsx | 4 +- .../blocksEditor/blocks/h3/h3.test.tsx | 2 +- .../blocksEditor/blocks/h3/index.tsx | 4 +- .../blocksEditor/blocks/image/image.test.tsx | 2 +- .../blocksEditor/blocks/image/index.tsx | 3 +- .../components/blocksEditor/blocks/index.tsx | 2 + .../blocksEditor/blocks/list-item/index.tsx | 3 +- .../blocks/list-item/list-item.test.tsx | 2 +- .../blocksEditor/blocks/quote/index.tsx | 4 +- .../blocksEditor/blocks/quote/quote.test.tsx | 2 +- .../blocksEditor/blocks/text-dev/index.tsx | 4 +- .../blocksEditor/blocks/text/index.tsx | 1 + .../blocksEditor/blocks/text/text.test.tsx | 4 +- .../blocksEditor/blocks/video/index.tsx | 3 +- .../blocksEditor/blocks/video/video.test.tsx | 2 +- .../blocksEditor/blocksEditor.test.tsx | 10 +- .../components/blocksEditor/blocksEditor.tsx | 6 +- .../components/blocksEditor/editor.test.tsx | 6 +- .../src/components/blocksEditor/editor.tsx | 4 +- .../blocksEditor/rootInput.test.tsx | 2 +- .../src/components/boardSelector.test.tsx | 15 +- .../boards/src/components/boardSelector.tsx | 35 +- .../src/components/boardSelectorItem.test.tsx | 6 +- .../src/components/boardSelectorItem.tsx | 3 +- .../boardTemplateSelector.test.tsx | 19 +- .../boardTemplateSelector.tsx | 10 +- .../boardTemplateSelectorItem.test.tsx | 8 +- .../boardTemplateSelectorPreview.tsx | 4 +- .../boardsSwitcher/boardsSwitcher.tsx | 2 +- .../boardSwitcherDialog.test.tsx | 2 +- .../boardSwitcherDialog.tsx | 10 +- .../boardsUnfurl/boardsUnfurl.test.tsx | 1 + .../components/boardsUnfurl/boardsUnfurl.tsx | 9 +- .../components/calculations/calculations.ts | 26 +- .../src/components/calculations/options.tsx | 5 +- .../components/calendar/fullCalendar.test.tsx | 2 +- .../src/components/calendar/fullCalendar.tsx | 8 +- webapp/boards/src/components/cardBadges.tsx | 2 + .../src/components/cardDetail/cardDetail.tsx | 16 +- .../cardDetail/cardDetailContents.test.tsx | 2 +- .../cardDetail/cardDetailContents.tsx | 5 +- .../cardDetailContentsMenu.test.tsx | 2 +- .../cardDetail/cardDetailContentsMenu.tsx | 2 + .../cardDetail/cardDetailContext.tsx | 5 +- .../cardDetail/cardDetailProperties.test.tsx | 6 +- .../cardDetail/cardDetailProperties.tsx | 1 + .../components/cardDetail/comment.test.tsx | 2 +- .../components/cardDetail/commentsList.tsx | 1 + .../src/components/cardDetail/imagePaste.tsx | 3 +- .../boards/src/components/cardDialog.test.tsx | 3 +- webapp/boards/src/components/cardDialog.tsx | 6 +- .../src/components/cardLimitNotification.tsx | 12 +- .../src/components/centerPanel.test.tsx | 4 +- webapp/boards/src/components/centerPanel.tsx | 22 +- .../confirmAddUserForNotifications.tsx | 4 +- .../content/archivedFile/archivedFile.tsx | 1 + .../components/content/attachmentElement.tsx | 3 + .../content/checkboxElement.test.tsx | 4 +- .../components/content/checkboxElement.tsx | 2 + .../content/contentElement.test.tsx | 3 +- .../src/components/content/contentElement.tsx | 1 + .../components/content/contentRegistry.tsx | 3 +- .../components/content/textElement.test.tsx | 5 +- .../src/components/contentBlock.test.tsx | 4 +- .../createBoardFromTemplate.test.tsx | 11 +- .../components/createBoardFromTemplate.tsx | 33 +- .../createCategory/createCategory.tsx | 3 +- .../boards/src/components/error_boundary.tsx | 2 + .../src/components/flashMessages.test.tsx | 9 +- .../boards/src/components/flashMessages.tsx | 3 +- .../src/components/gallery/gallery.test.tsx | 4 +- .../boards/src/components/gallery/gallery.tsx | 2 +- .../components/gallery/galleryCard.test.tsx | 2 +- .../src/components/gallery/galleryCard.tsx | 5 +- .../globalHeaderSettingsMenu.test.tsx | 2 +- .../globalHeader/globalHeaderSettingsMenu.tsx | 6 +- .../hiddenCardCount/hiddenCardCount.tsx | 1 + .../kanban/calculation/calculationOptions.tsx | 4 +- .../kanban/calculation/kanbanOption.tsx | 8 +- .../src/components/kanban/kanban.test.tsx | 6 +- .../boards/src/components/kanban/kanban.tsx | 14 +- .../src/components/kanban/kanbanCard.tsx | 4 +- .../src/components/kanban/kanbanColumn.tsx | 1 + .../kanban/kanbanColumnHeader.test.tsx | 6 +- .../components/kanban/kanbanColumnHeader.tsx | 13 +- .../kanban/kanbanHiddenColumnItem.tsx | 2 +- .../block-types/codeBlockStrategy.ts | 8 +- .../inline-styles/boldStyleStrategy.ts | 2 + .../headingDelimiterStyleStrategy.ts | 1 + .../inline-styles/inlineCodeStyleStrategy.ts | 1 + .../inline-styles/italicStyleStrategy.ts | 2 + .../inline-styles/olDelimiterStyleStrategy.ts | 1 + .../inline-styles/quoteStyleStrategy.ts | 2 + .../strikethroughStyleStrategy.ts | 2 + .../inline-styles/ulDelimiterStyleStrategy.ts | 1 + .../liveMarkdownPlugin.ts | 11 +- .../src/components/markdownEditor.test.tsx | 2 +- .../boards/src/components/markdownEditor.tsx | 5 +- .../markdownEditorInput.tsx | 24 +- .../components/messages/versionMessage.tsx | 10 +- webapp/boards/src/components/modal.tsx | 3 +- .../src/components/newVersionBanner.tsx | 2 +- .../addProperties/add_properties.tsx | 2 +- .../sidebarCategories/sidebarCategories.tsx | 4 +- .../permissions/boardPermissionGate.test.tsx | 3 +- .../permissions/boardPermissionGate.tsx | 1 + .../src/components/personSelector.test.tsx | 10 +- .../boards/src/components/personSelector.tsx | 2 + .../components/propertyValueElement.test.tsx | 4 +- .../src/components/propertyValueElement.tsx | 1 + .../components/rhsChannelBoardItem.test.tsx | 8 +- .../src/components/rhsChannelBoardItem.tsx | 8 +- .../src/components/rhsChannelBoards.test.tsx | 6 +- .../src/components/rhsChannelBoards.tsx | 10 +- .../src/components/rhsChannelBoardsHeader.tsx | 2 +- webapp/boards/src/components/rootPortal.tsx | 3 +- .../components/searchDialog/searchDialog.tsx | 2 +- .../shareBoard/channelPermissionsRow.tsx | 6 +- .../components/shareBoard/shareBoard.test.tsx | 8 +- .../src/components/shareBoard/shareBoard.tsx | 20 +- .../shareBoard/shareBoardButton.test.tsx | 2 +- .../shareBoard/shareBoardButton.tsx | 1 + .../shareBoard/teamPermissionsRow.tsx | 4 +- .../sidebar/deleteBoardDialog.test.tsx | 1 + .../components/sidebar/deleteBoardDialog.tsx | 4 +- .../components/sidebar/registrationLink.tsx | 4 +- .../boards/src/components/sidebar/sidebar.tsx | 12 +- .../components/sidebar/sidebarBoardItem.tsx | 3 + .../sidebar/sidebarCategory.test.tsx | 2 +- .../components/sidebar/sidebarCategory.tsx | 13 +- .../sidebar/sidebarSettingsMenu.test.tsx | 4 +- .../sidebar/sidebarSettingsMenu.tsx | 6 +- .../table/calculation/calculationRow.tsx | 2 +- .../src/components/table/table.test.tsx | 8 +- webapp/boards/src/components/table/table.tsx | 7 +- .../table/tableColumnResizeContext.tsx | 7 +- .../src/components/table/tableGroup.tsx | 4 +- .../components/table/tableGroupHeaderRow.tsx | 8 +- .../src/components/table/tableHeaderMenu.tsx | 1 + .../src/components/table/tableHeaders.tsx | 5 +- .../src/components/table/tableRow.test.tsx | 1 + .../boards/src/components/table/tableRow.tsx | 8 +- webapp/boards/src/components/topBar.tsx | 1 + .../src/components/tutorial_tour_tip/hooks.ts | 2 + .../tutorial_tour_tip/tutorial_tour_tip.tsx | 1 + .../tutorial_tour_tip_manager.tsx | 6 +- .../tutorial_tour_tip/useElementAvailable.ts | 5 +- .../components/viewHeader/dateFilter.test.tsx | 3 +- .../src/components/viewHeader/dateFilter.tsx | 5 +- .../viewHeader/emptyCardButton.test.tsx | 2 +- .../viewHeader/filterComponent.test.tsx | 2 +- .../components/viewHeader/filterComponent.tsx | 6 +- .../viewHeader/filterEntry.test.tsx | 2 +- .../src/components/viewHeader/filterEntry.tsx | 1 + .../viewHeader/filterValue.test.tsx | 2 +- .../src/components/viewHeader/filterValue.tsx | 1 + .../viewHeader/newCardButton.test.tsx | 2 +- .../components/viewHeader/newCardButton.tsx | 1 + .../newCardButtonTemplateItem.test.tsx | 2 +- .../components/viewHeader/viewHeader.test.tsx | 3 +- .../src/components/viewHeader/viewHeader.tsx | 6 +- .../viewHeader/viewHeaderActionsMenu.test.tsx | 2 +- .../viewHeader/viewHeaderActionsMenu.tsx | 2 +- .../viewHeader/viewHeaderGroupByMenu.test.tsx | 2 +- .../viewHeader/viewHeaderSearch.tsx | 8 +- .../viewHeader/viewHeaderSortMenu.test.tsx | 2 +- .../viewHeader/viewHeaderSortMenu.tsx | 1 + .../viewLImitDialog/viewLimitDialog.test.tsx | 1 - .../viewLimitDialogWrapper.test.tsx | 1 - webapp/boards/src/components/viewMenu.tsx | 4 +- .../boards/src/components/viewTitle.test.tsx | 2 +- webapp/boards/src/components/viewTitle.tsx | 4 +- .../boards/src/components/withWebSockets.tsx | 2 + .../boards/src/components/workspace.test.tsx | 9 +- webapp/boards/src/components/workspace.tsx | 17 +- webapp/boards/src/csvExporter.ts | 22 +- webapp/boards/src/errors.ts | 3 + webapp/boards/src/hooks/permissions.tsx | 4 +- webapp/boards/src/hooks/sortable.tsx | 8 +- webapp/boards/src/i18n.tsx | 2 + webapp/boards/src/index.tsx | 65 +- webapp/boards/src/mutator.ts | 24 +- webapp/boards/src/octoClient.ts | 52 +- webapp/boards/src/octoUtils.tsx | 6 + .../boards/src/pages/boardPage/boardPage.tsx | 21 +- .../boardPage/teamToBoardAndViewRedirect.tsx | 4 +- .../src/pages/boardPage/undoRedoHotKeys.tsx | 1 + webapp/boards/src/pages/errorPage.tsx | 2 +- webapp/boards/src/pages/loginPage.tsx | 2 +- webapp/boards/src/pages/registerPage.tsx | 2 +- .../boards/src/pages/welcome/welcomePage.tsx | 9 +- .../boards/src/properties/baseTextEditor.tsx | 7 +- .../src/properties/checkbox/checkbox.tsx | 1 + .../src/properties/checkbox/property.tsx | 2 +- .../properties/createdBy/createdBy.test.tsx | 5 +- .../src/properties/createdBy/property.tsx | 2 +- .../properties/createdTime/createdTime.tsx | 1 + .../boards/src/properties/date/date.test.tsx | 5 +- webapp/boards/src/properties/date/date.tsx | 8 +- .../boards/src/properties/date/property.tsx | 5 +- webapp/boards/src/properties/email/email.tsx | 1 + .../boards/src/properties/email/property.tsx | 2 +- .../multiperson/multiperson.test.tsx | 7 +- .../src/properties/multiperson/property.tsx | 2 +- .../properties/multiselect/multiselect.tsx | 10 +- .../src/properties/multiselect/property.tsx | 6 +- .../src/properties/number/number.test.tsx | 4 +- .../properties/person/confirmPerson.test.tsx | 6 +- .../src/properties/person/confirmPerson.tsx | 2 +- .../src/properties/person/person.test.tsx | 9 +- .../boards/src/properties/person/property.tsx | 2 +- .../boards/src/properties/phone/property.tsx | 2 +- .../boards/src/properties/select/property.tsx | 5 +- .../src/properties/select/select.test.tsx | 4 +- .../boards/src/properties/select/select.tsx | 5 +- .../boards/src/properties/text/property.tsx | 2 +- webapp/boards/src/properties/types.tsx | 4 +- .../src/properties/updatedBy/property.tsx | 2 +- .../properties/updatedBy/updatedBy.test.tsx | 6 +- .../updatedTime/updatedTime.test.tsx | 2 +- webapp/boards/src/properties/url/property.tsx | 2 +- webapp/boards/src/properties/url/url.tsx | 5 +- webapp/boards/src/route.tsx | 10 +- webapp/boards/src/router.tsx | 15 +- webapp/boards/src/store/attachments.ts | 6 +- webapp/boards/src/store/boards.ts | 12 +- webapp/boards/src/store/cards.ts | 14 +- webapp/boards/src/store/channels.ts | 2 +- webapp/boards/src/store/clientConfig.ts | 2 +- webapp/boards/src/store/comments.ts | 9 +- webapp/boards/src/store/contents.ts | 8 +- webapp/boards/src/store/globalError.ts | 2 +- webapp/boards/src/store/globalTemplates.ts | 3 +- webapp/boards/src/store/hooks.ts | 2 +- webapp/boards/src/store/initialLoad.ts | 4 + webapp/boards/src/store/language.ts | 3 +- webapp/boards/src/store/limits.ts | 2 +- webapp/boards/src/store/searchText.ts | 2 +- webapp/boards/src/store/sidebar.ts | 4 +- webapp/boards/src/store/teams.ts | 3 +- webapp/boards/src/store/users.ts | 13 +- webapp/boards/src/store/views.ts | 7 +- webapp/boards/src/test/fetchMock.ts | 2 + webapp/boards/src/test/testBlockFactory.ts | 8 +- webapp/boards/src/testUtils.tsx | 4 +- webapp/boards/src/testUtilsKeys.ts | 3 +- webapp/boards/src/theme.ts | 1 + .../src/types/mattermost-webapp/index.d.ts | 4 +- webapp/boards/src/undoManager.test.ts | 1 + webapp/boards/src/undomanager.ts | 3 + webapp/boards/src/userSettings.ts | 4 +- webapp/boards/src/utils.test.ts | 4 +- webapp/boards/src/utils.ts | 32 +- .../src/widgets/adminBadge/adminBadge.tsx | 1 + webapp/boards/src/widgets/editable.tsx | 3 +- .../boards/src/widgets/editableDayPicker.tsx | 2 + webapp/boards/src/widgets/emojiPicker.tsx | 2 +- webapp/boards/src/widgets/guestBadge.tsx | 1 + webapp/boards/src/widgets/label.tsx | 1 + .../boards/src/widgets/menu/colorOption.tsx | 1 + .../boards/src/widgets/menu/subMenuOption.tsx | 8 +- .../src/widgets/menu/textInputOption.tsx | 2 +- webapp/boards/src/widgets/menuWrapper.tsx | 9 +- webapp/boards/src/widgets/propertyMenu.tsx | 3 +- webapp/boards/src/widgets/switch.tsx | 1 + webapp/boards/src/widgets/tooltip.tsx | 1 + webapp/boards/src/widgets/valueSelector.tsx | 4 +- webapp/boards/src/wsclient.ts | 5 + webapp/boards/webpack.config.js | 2 +- webapp/package-lock.json | 280 +++++++++ 298 files changed, 1890 insertions(+), 628 deletions(-) diff --git a/webapp/boards/.eslintrc.json b/webapp/boards/.eslintrc.json index f31eeaf6c1..a0bb15cbdd 100644 --- a/webapp/boards/.eslintrc.json +++ b/webapp/boards/.eslintrc.json @@ -11,7 +11,8 @@ "formatjs", "unused-imports", "no-relative-import-paths", - "import-newlines" + "import-newlines", + "eslint-comments" ], "parser": "@typescript-eslint/parser", "settings": { @@ -27,21 +28,101 @@ "line", " Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.\n See LICENSE.txt for license information." ], - "max-lines": "off", - "no-unused-expressions": 0, - "babel/no-unused-expressions": [ + "array-bracket-spacing": [ 2, - { - "allowShortCircuit": true - } + "never" ], - "eol-last": [ + "array-callback-return": 2, + "arrow-body-style": 0, + "arrow-parens": [ 2, "always" ], - "import/no-unresolved": 2, - "import/order": [ + "arrow-spacing": [ 2, + { + "before": true, + "after": true + } + ], + "block-scoped-var": 2, + "brace-style": [ + 2, + "1tbs", + { + "allowSingleLine": false + } + ], + "capitalized-comments": 0, + "class-methods-use-this": 0, + "comma-dangle": [ + 2, + "always-multiline" + ], + "comma-spacing": [ + 2, + { + "before": false, + "after": true + } + ], + "comma-style": [ + 2, + "last" + ], + "complexity": [ + 0, + 10 + ], + "computed-property-spacing": [ + 2, + "never" + ], + "consistent-return": 2, + "consistent-this": [ + 2, + "self" + ], + "constructor-super": 2, + "curly": [ + 2, + "all" + ], + "dot-location": [ + 2, + "property" + ], + "dot-notation": 2, + "eqeqeq": [ + 2, + "smart" + ], + "func-call-spacing": [ + 2, + "never" + ], + "func-name-matching": 0, + "func-names": 2, + "func-style": [ + 2, + "declaration", + { + "allowArrowFunctions": true + } + ], + "generator-star-spacing": [ + 2, + { + "before": false, + "after": true + } + ], + "global-require": 2, + "guard-for-in": 2, + "id-blacklist": 0, + "import/no-unresolved": 0, // ts handles this better + "import/order": [ + "error", { "newlines-between": "always-and-inside-groups", "groups": [ @@ -56,27 +137,413 @@ ] } ], + "indent": 0, // ts handles this + "jsx-quotes": [ + 2, + "prefer-single" + ], + "key-spacing": [ + 2, + { + "beforeColon": false, + "afterColon": true, + "mode": "strict" + } + ], + "keyword-spacing": [ + 2, + { + "before": true, + "after": true, + "overrides": {} + } + ], + "line-comment-position": 0, + "linebreak-style": 2, + "lines-around-comment": [ + 2, + { + "beforeBlockComment": true, + "beforeLineComment": true, + "allowBlockStart": true, + "allowBlockEnd": true + } + ], + "max-lines": [ + 2, + { + "max": 800, + "skipBlankLines": true, + "skipComments": true + } + ], + "max-statements-per-line": [ + 2, + { + "max": 1 + } + ], + "multiline-ternary": [ + 1, + "never" + ], + "new-cap": 2, + "new-parens": 2, + "padding-line-between-statements": [ + 2, + { + "blankLine": "always", + "prev": "*", + "next": "return" + } + ], + "newline-per-chained-call": 0, + "no-alert": 2, + "no-array-constructor": 2, + "no-await-in-loop": 2, + "no-caller": 2, + "no-case-declarations": 2, + "no-class-assign": 2, + "no-compare-neg-zero": 2, + "no-cond-assign": [ + 2, + "except-parens" + ], + "no-confusing-arrow": 2, + "no-console": 2, + "no-const-assign": 2, + "no-constant-condition": 2, + "no-debugger": 2, + "no-div-regex": 2, + "no-dupe-args": 2, + "no-dupe-class-members": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-duplicate-imports": [ + 2, + { + "includeExports": true + } + ], + "no-else-return": 2, + "no-empty": 2, + "no-empty-function": 2, + "no-empty-pattern": 2, + "no-eval": 2, + "no-ex-assign": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-extra-label": 2, + "no-extra-parens": 0, + "no-extra-semi": 2, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-func-assign": 2, + "no-global-assign": 2, + "no-implicit-coercion": 2, + "no-implicit-globals": 0, + "no-implied-eval": 2, + "no-inner-declarations": 0, + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-iterator": 2, + "no-labels": 2, + "no-lone-blocks": 2, + "no-lonely-if": 2, + "no-loop-func": 2, + "no-magic-numbers": [ + 0, + { + "ignore": [ + -1, + 0, + 1, + 2 + ], + "enforceConst": true, + "detectObjects": true + } + ], + "no-mixed-operators": [ + 2, + { + "allowSamePrecedence": false + } + ], + "no-mixed-spaces-and-tabs": 2, + "no-multi-assign": 2, + "no-multi-spaces": [ + 2, + { + "exceptions": { + "Property": false + } + } + ], + "no-multi-str": 0, + "no-multiple-empty-lines": [ + 2, + { + "max": 1 + } + ], + "no-native-reassign": 2, + "no-negated-condition": 2, + "no-nested-ternary": 2, + "no-new": 2, + "no-new-func": 2, + "no-new-object": 2, + "no-new-symbol": 2, + "no-new-wrappers": 2, + "no-octal-escape": 2, + "no-param-reassign": 2, + "no-process-env": 2, + "no-process-exit": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-return-assign": [ + 2, + "always" + ], + "no-return-await": 2, + "no-script-url": 2, + "no-self-assign": [ + 2, + { + "props": true + } + ], + "no-self-compare": 2, + "no-sequences": 2, + "no-shadow-restricted-names": 2, + "no-spaced-func": 2, + "no-tabs": 0, + "no-template-curly-in-string": 2, + "no-ternary": 0, + "no-this-before-super": 2, + "no-throw-literal": 2, + "no-trailing-spaces": [ + 2, + { + "skipBlankLines": false + } + ], + "no-undef-init": 2, "no-undefined": 0, - "react/jsx-filename-extension": 0, + "no-underscore-dangle": 2, + "no-unexpected-multiline": 2, + "no-unmodified-loop-condition": 2, + "no-unneeded-ternary": [ + 2, + { + "defaultAssignment": false + } + ], + "no-unreachable": 2, + "no-unsafe-finally": 2, + "no-unsafe-negation": 2, + "no-unused-expressions": 2, + "no-unused-vars": [ + 2, + { + "vars": "all", + "args": "after-used" + } + ], + "no-use-before-define": 0, + "no-useless-computed-key": 2, + "no-useless-concat": 2, + "no-useless-constructor": 2, + "no-useless-escape": 2, + "no-useless-rename": 2, + "no-useless-return": 2, + "no-var": 0, + "no-void": 2, + "no-warning-comments": 1, + "no-whitespace-before-property": 2, + "no-with": 2, + "object-curly-newline": 0, + "object-curly-spacing": [ + 2, + "never" + ], + "object-property-newline": [ + 2, + { + "allowMultiplePropertiesPerLine": true + } + ], + "object-shorthand": [ + 2, + "always" + ], + "one-var": [ + 2, + "never" + ], + "one-var-declaration-per-line": 0, + "operator-assignment": [ + 2, + "always" + ], + "operator-linebreak": [ + 2, + "after" + ], + "padded-blocks": [ + 2, + "never" + ], + "prefer-arrow-callback": 2, + "prefer-const": 2, + "prefer-destructuring": 0, + "prefer-numeric-literals": 2, + "prefer-promise-reject-errors": 2, + "prefer-rest-params": 2, + "prefer-spread": 2, + "prefer-template": 0, + "quote-props": [ + 2, + "as-needed" + ], + "quotes": [ + 2, + "single", + "avoid-escape" + ], + "radix": 2, + "react/display-name": [ + 0, + { + "ignoreTranspilerName": false + } + ], + "react/forbid-component-props": 0, + "react/forbid-elements": [ + 2, + { + "forbid": [ + "embed" + ] + } + ], + "react/jsx-boolean-value": [ + 2, + "always" + ], + "react/jsx-closing-bracket-location": [ + 2, + { + "location": "tag-aligned" + } + ], + "react/jsx-curly-spacing": [ + 2, + "never" + ], + "react/jsx-equals-spacing": [ + 2, + "never" + ], + "react/jsx-filename-extension": 2, + "react/jsx-first-prop-new-line": [ + 2, + "multiline" + ], + "react/jsx-handler-names": 0, + "react/jsx-indent": [ + 2, + 4 + ], + "react/jsx-indent-props": [ + 2, + 4 + ], + "react/jsx-key": 2, + "react/jsx-max-props-per-line": [ + 2, + { + "maximum": 1 + } + ], + "react/jsx-no-bind": 0, + "react/jsx-no-comment-textnodes": 2, + "react/jsx-no-duplicate-props": [ + 2, + { + "ignoreCase": false + } + ], + "react/jsx-no-literals": 2, + "react/jsx-no-target-blank": 2, + "react/jsx-no-undef": 2, + "react/jsx-pascal-case": 2, + "react/jsx-tag-spacing": [ + 2, + { + "closingSlash": "never", + "beforeSelfClosing": "never", + "afterOpening": "never" + } + ], + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/jsx-wrap-multilines": 2, + "react/no-array-index-key": 1, + "react/no-children-prop": 2, + "react/no-danger": 0, + "react/no-danger-with-children": 2, + "react/no-deprecated": 1, + "react/no-did-mount-set-state": 2, + "react/no-did-update-set-state": 2, + "react/no-direct-mutation-state": 2, + "react/no-find-dom-node": 1, + "react/no-is-mounted": 2, + "react/no-multi-comp": [ + 2, + { + "ignoreStateless": true + } + ], + "react/no-render-return-value": 2, + "react/no-set-state": 0, + "react/no-string-refs": 0, + "react/no-unescaped-entities": 2, + "react/no-unknown-property": 2, + "react/no-unused-prop-types": [ + 1, + { + "skipShapeProps": true + } + ], + "react/prefer-es6-class": 2, + "react/prefer-stateless-function": 2, "react/prop-types": [ 2, { "ignore": [ "location", "history", - "component" + "component", + "className" ] } ], - "react/no-string-refs": 2, - "no-only-tests/no-only-tests": [ - 2, - { - "focus": [ - "only", - "skip" - ] - } + "react/require-default-props": 0, + "react/require-optimization": 1, + "react/require-render-return": 2, + "react/self-closing-comp": 2, + "react/sort-comp": 0, + "react/style-prop-object": [ + 2, + { + "allow": [ + "FormattedNumber", + "FormattedDuration", + "FormattedRelativeTime", + "Timestamp" + ] + } ], "max-nested-callbacks": [ 2, @@ -95,11 +562,84 @@ 2, 3 ], - "object-curly-spacing": [ + "formatjs/no-multiple-whitespaces": 2, + "require-yield": 2, + "rest-spread-spacing": [ 2, "never" ], - "formatjs/no-multiple-whitespaces": 2 + "semi": [ + 2, + "always" + ], + "semi-spacing": [ + 2, + { + "before": false, + "after": true + } + ], + "sort-imports": [ + 2, + { + "ignoreDeclarationSort": true + } + ], + "sort-keys": 0, + "space-before-blocks": [ + 2, + "always" + ], + "space-before-function-paren": [ + 2, + { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + } + ], + "space-in-parens": [ + 2, + "never" + ], + "space-infix-ops": 2, + "space-unary-ops": [ + 2, + { + "words": true, + "nonwords": false + } + ], + "symbol-description": 2, + "template-curly-spacing": [ + 2, + "never" + ], + "valid-typeof": [ + 2, + { + "requireStringLiterals": false + } + ], + "vars-on-top": 0, + "wrap-iife": [ + 2, + "outside" + ], + "wrap-regex": 2, + "yoda": [ + 2, + "never", + { + "exceptRange": false, + "onlyEquality": false + } + ], + "eol-last": [ + 2, + "always" + ], + "eslint-comments/no-unused-disable": 2 }, "overrides": [ { @@ -206,7 +746,9 @@ "global-require": 0, "new-cap": 0, "prefer-arrow-callback": 0, - "no-import-assign": 0 + "no-import-assign": 0, + "no-console": 0, + "max-lines": 0 } } ] diff --git a/webapp/boards/jest.config.js b/webapp/boards/jest.config.js index 85b8e69719..517bc921e6 100644 --- a/webapp/boards/jest.config.js +++ b/webapp/boards/jest.config.js @@ -5,63 +5,63 @@ const config = { transform: { - "^.+\\.(t|j)sx?$": ["@swc/jest"] + '^.+\\.(t|j)sx?$': ['@swc/jest'], }, moduleFileExtensions: [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" + 'ts', + 'tsx', + 'js', + 'jsx', + 'json', + 'node', ], extensionsToTreatAsEsm: ['.ts', '.tsx'], transformIgnorePatterns: [ - "/nanoevents/", - "node_modules/(?!react-native|react-router|react-day-picker)" + '/nanoevents/', + 'node_modules/(?!react-native|react-router|react-day-picker)', ], - testEnvironment: "jsdom", + testEnvironment: 'jsdom', collectCoverage: true, collectCoverageFrom: [ - "src/**/*.{ts,tsx,js,jsx}", - "!src/test/**" + 'src/**/*.{ts,tsx,js,jsx}', + '!src/test/**', ], testPathIgnorePatterns: [ - "/node_modules/", + '/node_modules/', ], clearMocks: true, coverageReporters: [ - "lcov", - "text-summary" + '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", + '^.+\\.(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", + 'src', + 'node_modules', ], reporters: [ - "default", - "jest-junit" + 'default', + 'jest-junit', ], setupFiles: [ - "jest-canvas-mock" + 'jest-canvas-mock', ], setupFilesAfterEnv: [ - "/src/test/setup.tsx" + '/src/test/setup.tsx', ], testTimeout: 60000, testEnvironmentOptions: { - url: "http://localhost:8065" - } + url: 'http://localhost:8065', + }, }; module.exports = config; diff --git a/webapp/boards/loaders/globalScssClassLoader.js b/webapp/boards/loaders/globalScssClassLoader.js index 80b58e7ad3..4e0f25229e 100644 --- a/webapp/boards/loaders/globalScssClassLoader.js +++ b/webapp/boards/loaders/globalScssClassLoader.js @@ -19,5 +19,6 @@ module.exports = function loader(source) { newSource.push(line); } }); + return newSource.join('\n'); }; diff --git a/webapp/boards/package.json b/webapp/boards/package.json index 6a16614cd5..b4f9fbf841 100644 --- a/webapp/boards/package.json +++ b/webapp/boards/package.json @@ -106,6 +106,8 @@ "css-loader": "6.7.1", "eslint-import-resolver-webpack": "0.13.2", "eslint-plugin-babel": "^5.3.1", + "eslint-plugin-eslint-comments": "3.2.0", + "eslint-plugin-formatjs": "4.9.0", "eslint-plugin-header": "3.1.1", "eslint-plugin-import": "2.25.4", "eslint-plugin-import-newlines": "1.3.1", diff --git a/webapp/boards/src/app.tsx b/webapp/boards/src/app.tsx index 75aa8a5115..245c046703 100644 --- a/webapp/boards/src/app.tsx +++ b/webapp/boards/src/app.tsx @@ -14,8 +14,8 @@ import FlashMessages from './components/flashMessages' import NewVersionBanner from './components/newVersionBanner' import {Utils} from './utils' import {fetchMe, getMe} from './store/users' -import {getLanguage, fetchLanguage} from './store/language' -import {useAppSelector, useAppDispatch} from './store/hooks' +import {fetchLanguage, getLanguage} from './store/language' +import {useAppDispatch, useAppSelector} from './store/hooks' import {fetchClientConfig} from './store/clientConfig' import FocalboardRouter from './router' diff --git a/webapp/boards/src/archiver.ts b/webapp/boards/src/archiver.ts index c1b313b65a..01dfb30f28 100644 --- a/webapp/boards/src/archiver.ts +++ b/webapp/boards/src/archiver.ts @@ -21,8 +21,8 @@ class Archiver { private static exportArchive(prom: Promise): void { // TODO: don't download whole archive before presenting SaveAs dialog. prom.then((response) => { - response.blob(). - then((blob) => { + response.blob() + .then((blob) => { const link = document.createElement('a') link.style.display = 'none' diff --git a/webapp/boards/src/blockIcons.ts b/webapp/boards/src/blockIcons.ts index f7b88ca1ee..2390f0acf3 100644 --- a/webapp/boards/src/blockIcons.ts +++ b/webapp/boards/src/blockIcons.ts @@ -8,6 +8,7 @@ class BlockIcons { randomIcon(): string { const index = Math.floor(Math.random() * randomEmojiList.length) const icon = randomEmojiList[index] + return icon } } diff --git a/webapp/boards/src/blocks/block.test.ts b/webapp/boards/src/blocks/block.test.ts index d2fe33a32a..3da8d852a5 100644 --- a/webapp/boards/src/blocks/block.test.ts +++ b/webapp/boards/src/blocks/block.test.ts @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import {TestBlockFactory} from 'src/test/testBlockFactory' -import {createPatchesFromBlocks, createBlock} from './block' +import {createBlock, createPatchesFromBlocks} from './block' describe('block tests', () => { const board = TestBlockFactory.createBoard() diff --git a/webapp/boards/src/blocks/block.ts b/webapp/boards/src/blocks/block.ts index 47dbc5c493..0e9e4e3a9b 100644 --- a/webapp/boards/src/blocks/block.ts +++ b/webapp/boards/src/blocks/block.ts @@ -53,6 +53,7 @@ interface FileInfo { function createBlock(block?: Block): Block { const now = Date.now() + return { id: block?.id || Utils.createGuid(Utils.blockTypeToIDType(block?.type)), schema: 1, diff --git a/webapp/boards/src/blocks/board.test.ts b/webapp/boards/src/blocks/board.test.ts index f421e7f3e3..2b3ff84e2c 100644 --- a/webapp/boards/src/blocks/board.test.ts +++ b/webapp/boards/src/blocks/board.test.ts @@ -3,10 +3,10 @@ import {TestBlockFactory} from 'src/test/testBlockFactory' import { - createPatchesFromBoards, - createBoard, IPropertyTemplate, - createPatchesFromBoardsAndBlocks + createBoard, + createPatchesFromBoards, + createPatchesFromBoardsAndBlocks, } from './board' import {createBlock} from './block' diff --git a/webapp/boards/src/blocks/board.ts b/webapp/boards/src/blocks/board.ts index 3a69f042d4..b00a5c68ed 100644 --- a/webapp/boards/src/blocks/board.ts +++ b/webapp/boards/src/blocks/board.ts @@ -3,7 +3,7 @@ import difference from 'lodash/difference' -import {Utils, IDType} from 'src/utils' +import {IDType, Utils} from 'src/utils' import {Block, BlockPatch, createPatchesFromBlocks} from './block' import {Card} from './card' @@ -54,7 +54,7 @@ type BoardPatch = { // eslint-disable-next-line @typescript-eslint/no-explicit-any updatedProperties?: Record deletedProperties?: string[] - // eslint-disable-next-line @typescript-eslint/no-explicit-any + updatedCardProperties?: IPropertyTemplate[] deletedCardProperties?: string[] } diff --git a/webapp/boards/src/blocks/card.ts b/webapp/boards/src/blocks/card.ts index 9dd287283f..ba047e0a72 100644 --- a/webapp/boards/src/blocks/card.ts +++ b/webapp/boards/src/blocks/card.ts @@ -27,6 +27,7 @@ function createCard(block?: Block): Card { } } } + return { ...createBlock(block), type: 'card', diff --git a/webapp/boards/src/blocks/filterGroup.ts b/webapp/boards/src/blocks/filterGroup.ts index 157e14a315..e304e38edc 100644 --- a/webapp/boards/src/blocks/filterGroup.ts +++ b/webapp/boards/src/blocks/filterGroup.ts @@ -21,9 +21,11 @@ function createFilterGroup(o?: FilterGroup): FilterGroup { if (isAFilterGroupInstance(p)) { return createFilterGroup(p) } + return createFilterClause(p) }) } + return { operation: o?.operation || 'and', filters, diff --git a/webapp/boards/src/boardUtils.ts b/webapp/boards/src/boardUtils.ts index bb0776f917..f8d9484ca6 100644 --- a/webapp/boards/src/boardUtils.ts +++ b/webapp/boards/src/boardUtils.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import {Card} from './blocks/card' -import {IPropertyTemplate, IPropertyOption, BoardGroup} from './blocks/board' +import {BoardGroup, IPropertyOption, IPropertyTemplate} from './blocks/board' function groupCardsByOptions(cards: Card[], optionIds: string[], groupByProperty?: IPropertyTemplate): BoardGroup[] { const groups = [] @@ -22,6 +22,7 @@ function groupCardsByOptions(cards: Card[], optionIds: string[], groupByProperty // Empty group const emptyGroupCards = cards.filter((card) => { const groupByOptionId = card.fields.properties[groupByProperty?.id || ''] + return !groupByOptionId || !groupByProperty?.options.find((option) => option.id === groupByOptionId) }) const group: BoardGroup = { @@ -31,15 +32,16 @@ function groupCardsByOptions(cards: Card[], optionIds: string[], groupByProperty groups.push(group) } } + return groups } function getOptionGroups(cards: Card[], visibleOptionIds: string[], hiddenOptionIds: string[], groupByProperty?: IPropertyTemplate): {visible: BoardGroup[], hidden: BoardGroup[]} { let unassignedOptionIds: string[] = [] if (groupByProperty) { - unassignedOptionIds = groupByProperty.options. - filter((o: IPropertyOption) => !visibleOptionIds.includes(o.id) && !hiddenOptionIds.includes(o.id)). - map((o: IPropertyOption) => o.id) + unassignedOptionIds = groupByProperty.options + .filter((o: IPropertyOption) => !visibleOptionIds.includes(o.id) && !hiddenOptionIds.includes(o.id)) + .map((o: IPropertyOption) => o.id) } const allVisibleOptionIds = [...visibleOptionIds, ...unassignedOptionIds] @@ -50,6 +52,7 @@ function getOptionGroups(cards: Card[], visibleOptionIds: string[], hiddenOption const visibleGroups = groupCardsByOptions(cards, allVisibleOptionIds, groupByProperty) const hiddenGroups = groupCardsByOptions(cards, hiddenOptionIds, groupByProperty) + return {visible: visibleGroups, hidden: hiddenGroups} } export function getVisibleAndHiddenGroups(cards: Card[], visibleOptionIds: string[], hiddenOptionIds: string[], groupByProperty?: IPropertyTemplate): {visible: BoardGroup[], hidden: BoardGroup[]} { @@ -70,6 +73,7 @@ function getPersonGroups(cards: Card[], groupByProperty: IPropertyTemplate, hidd } const curGroup = unique[key] ?? [] + return {...unique, [key]: [...curGroup, item]} }, {}) diff --git a/webapp/boards/src/cardFilter.ts b/webapp/boards/src/cardFilter.ts index 17a0bd4f04..ae4da8b7f7 100644 --- a/webapp/boards/src/cardFilter.ts +++ b/webapp/boards/src/cardFilter.ts @@ -27,6 +27,7 @@ class CardFilter { } } } + return dateProperty } @@ -51,6 +52,7 @@ class CardFilter { return true } } + return false } Utils.assert(filterGroup.operation === 'and') @@ -63,6 +65,7 @@ class CardFilter { return false } } + return true } @@ -95,12 +98,14 @@ class CardFilter { if (filter.values?.length < 1) { break } // No values = ignore clause (always met) + return (filter.values.find((cValue) => (Array.isArray(value) ? value.includes(cValue) : cValue === value)) !== undefined) } case 'notIncludes': { if (filter.values?.length < 1) { break } // No values = ignore clause (always met) + return (filter.values.find((cValue) => (Array.isArray(value) ? value.includes(cValue) : cValue === value)) === undefined) } case 'isEmpty': { @@ -128,50 +133,59 @@ class CardFilter { if (dateValue.from) { return dateValue.from > (numericFilter - halfDay) && dateValue.from < (numericFilter + halfDay) } + return false } if (dateValue.from && dateValue.to) { return dateValue.from <= numericFilter && dateValue.to >= numericFilter } + return dateValue.from === numericFilter } + return filter.values[0]?.toLowerCase() === value } case 'contains': { if (filter.values.length === 0) { return true } + return (value as string || '').includes(filter.values[0]?.toLowerCase()) } case 'notContains': { if (filter.values.length === 0) { return true } + return !(value as string || '').includes(filter.values[0]?.toLowerCase()) } case 'startsWith': { if (filter.values.length === 0) { return true } + return (value as string || '').startsWith(filter.values[0]?.toLowerCase()) } case 'notStartsWith': { if (filter.values.length === 0) { return true } + return !(value as string || '').startsWith(filter.values[0]?.toLowerCase()) } case 'endsWith': { if (filter.values.length === 0) { return true } + return (value as string || '').endsWith(filter.values[0]?.toLowerCase()) } case 'notEndsWith': { if (filter.values.length === 0) { return true } + return !(value as string || '').endsWith(filter.values[0]?.toLowerCase()) } case 'isBefore': { @@ -187,11 +201,13 @@ class CardFilter { if (dateValue.from) { return dateValue.from < (numericFilter - halfDay) } + return false } return dateValue.from ? dateValue.from < numericFilter : false } + return false } case 'isAfter': { @@ -207,14 +223,17 @@ class CardFilter { if (dateValue.from) { return dateValue.from > (numericFilter + halfDay) } + return false } if (dateValue.to) { return dateValue.to > numericFilter } + return dateValue.from ? dateValue.from > numericFilter : false } + return false } @@ -222,6 +241,7 @@ class CardFilter { Utils.assertFailure(`Invalid filter condition ${filter.condition}`) } } + return true } @@ -243,6 +263,7 @@ class CardFilter { if (property.value) { result[property.id] = property.value } + return result } @@ -254,6 +275,7 @@ class CardFilter { result[property.id] = property.value } }) + return result } @@ -261,6 +283,7 @@ class CardFilter { const template = templates.find((o) => o.id === filterClause.propertyId) if (!template) { Utils.assertFailure(`propertyThatMeetsFilterClause. Cannot find template: ${filterClause.propertyId}`) + return {id: filterClause.propertyId} } @@ -273,6 +296,7 @@ class CardFilter { if (filterClause.values.length < 1) { return {id: filterClause.propertyId} } + return {id: filterClause.propertyId, value: filterClause.values[0]} } case 'notIncludes': { @@ -285,8 +309,10 @@ class CardFilter { if (template.type === 'select') { if (template.options.length > 0) { const option = template.options[0] + return {id: filterClause.propertyId, value: option.id} } + return {id: filterClause.propertyId} } diff --git a/webapp/boards/src/components/addContentMenuItem.test.tsx b/webapp/boards/src/components/addContentMenuItem.test.tsx index cefb9c6292..34cab3d6ef 100644 --- a/webapp/boards/src/components/addContentMenuItem.test.tsx +++ b/webapp/boards/src/components/addContentMenuItem.test.tsx @@ -4,7 +4,6 @@ import React, {ReactElement, ReactNode} from 'react' import {render, screen, waitFor} from '@testing-library/react' - import {mocked} from 'jest-mock' import userEvent from '@testing-library/user-event' @@ -114,6 +113,5 @@ describe('components/addContentMenuItem', () => { ) expect(console.error).toBeCalledWith(expect.stringContaining('addContentMenu, unknown content type: unknown')) expect(container).toMatchSnapshot() - }) }) diff --git a/webapp/boards/src/components/addContentMenuItem.tsx b/webapp/boards/src/components/addContentMenuItem.tsx index 1e147b2563..b9fc829c49 100644 --- a/webapp/boards/src/components/addContentMenuItem.tsx +++ b/webapp/boards/src/components/addContentMenuItem.tsx @@ -4,7 +4,7 @@ import React from 'react' import {useIntl} from 'react-intl' -import {BlockTypes, Block} from 'src/blocks/block' +import {Block, BlockTypes} from 'src/blocks/block' import {Card} from 'src/blocks/card' import mutator from 'src/mutator' import octoClient from 'src/octoClient' @@ -27,6 +27,7 @@ const AddContentMenuItem = (props: Props): JSX.Element => { const handler = contentRegistry.getHandler(type) if (!handler) { Utils.logError(`addContentMenu, unknown content type: ${type}`) + return <> } diff --git a/webapp/boards/src/components/blockIconSelector.test.tsx b/webapp/boards/src/components/blockIconSelector.test.tsx index bcce99f771..7ee9190535 100644 --- a/webapp/boards/src/components/blockIconSelector.test.tsx +++ b/webapp/boards/src/components/blockIconSelector.test.tsx @@ -6,7 +6,6 @@ import {fireEvent, render, screen} from '@testing-library/react' import userEvent from '@testing-library/user-event' - import {mocked} from 'jest-mock' import mutator from 'src/mutator' diff --git a/webapp/boards/src/components/blocksEditor/blockContent.test.tsx b/webapp/boards/src/components/blocksEditor/blockContent.test.tsx index 0a4ca74a17..3badc576e8 100644 --- a/webapp/boards/src/components/blocksEditor/blockContent.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blockContent.test.tsx @@ -4,17 +4,17 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' import { + act, + fireEvent, render, screen, - fireEvent, - act } from '@testing-library/react' import { mockDOM, - wrapDNDIntl, mockStateStore, - setup + setup, + wrapDNDIntl, } from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' @@ -146,7 +146,7 @@ describe('components/blocksEditor/blockContent', () => { test('should call onSave on hit enter in the input', async () => { const onSave = jest.fn() - + const {user} = setup(wrapDNDIntl( ) } + return null } 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 ed4f9ee20f..a0631be397 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/attachment/attachment.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/attachment/attachment.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import {mocked} from 'jest-mock' import octoClient from 'src/octoClient' diff --git a/webapp/boards/src/components/blocksEditor/blocks/attachment/index.tsx b/webapp/boards/src/components/blocksEditor/blocks/attachment/index.tsx index 584caeea48..3aa19d7df8 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/attachment/index.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/attachment/index.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useRef, useEffect, useState} from 'react' +import React, {useEffect, useRef, useState} from 'react' import {BlockInputProps, ContentType} from 'src/components/blocksEditor/blocks/types' import octoClient from 'src/octoClient' diff --git a/webapp/boards/src/components/blocksEditor/blocks/checkbox/checkbox.test.tsx b/webapp/boards/src/components/blocksEditor/blocks/checkbox/checkbox.test.tsx index b49f9a630a..2f95eee369 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/checkbox/checkbox.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/checkbox/checkbox.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import CheckboxBlock from '.' diff --git a/webapp/boards/src/components/blocksEditor/blocks/checkbox/index.tsx b/webapp/boards/src/components/blocksEditor/blocks/checkbox/index.tsx index 7be8c4d0ff..42d41f94bd 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/checkbox/index.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/checkbox/index.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useRef, useEffect} from 'react' +import React, {useEffect, useRef} from 'react' import {marked} from 'marked' import {BlockInputProps, ContentType} from 'src/components/blocksEditor/blocks/types' @@ -23,6 +23,7 @@ const Checkbox: ContentType = { Display: (props: BlockInputProps) => { const renderer = new marked.Renderer() const html = marked(props.value.value || '', {renderer, breaks: true}) + return (
= { useEffect(() => { ref.current?.focus() }, []) + return (
{ props.onSave(props.value) }, []) + return null }, } diff --git a/webapp/boards/src/components/blocksEditor/blocks/h1/h1.test.tsx b/webapp/boards/src/components/blocksEditor/blocks/h1/h1.test.tsx index 5cec74a838..b912c3288a 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/h1/h1.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/h1/h1.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import H1Block from '.' diff --git a/webapp/boards/src/components/blocksEditor/blocks/h1/index.tsx b/webapp/boards/src/components/blocksEditor/blocks/h1/index.tsx index 2b8f9ade70..1deb2fcf6a 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/h1/index.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/h1/index.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useRef, useEffect} from 'react' +import React, {useEffect, useRef} from 'react' import {marked} from 'marked' import {BlockInputProps, ContentType} from 'src/components/blocksEditor/blocks/types' @@ -17,6 +17,7 @@ const H1: ContentType = { Display: (props: BlockInputProps) => { const renderer = new marked.Renderer() const html = marked('# ' + props.value, {renderer, breaks: true}) + return (
{ ref.current?.focus() }, []) + return ( { const renderer = new marked.Renderer() const html = marked('## ' + props.value, {renderer, breaks: true}) + return (
{ ref.current?.focus() }, []) + return ( { const renderer = new marked.Renderer() const html = marked('### ' + props.value, {renderer, breaks: true}) + return (
{ ref.current?.focus() }, []) + return ( = { /> ) } + return null }, Input: (props: BlockInputProps) => { diff --git a/webapp/boards/src/components/blocksEditor/blocks/index.tsx b/webapp/boards/src/components/blocksEditor/blocks/index.tsx index db39ca8d44..bc29366c84 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/index.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/index.tsx @@ -45,6 +45,7 @@ export function isSubPrefix(text: string): boolean { return true } } + return false } @@ -58,6 +59,7 @@ export function getBySlashCommandPrefix(slashCommandPrefix: string): ContentType return ct } } + return null } diff --git a/webapp/boards/src/components/blocksEditor/blocks/list-item/index.tsx b/webapp/boards/src/components/blocksEditor/blocks/list-item/index.tsx index c6f80de385..dcf90099cf 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/list-item/index.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/list-item/index.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useRef, useEffect} from 'react' +import React, {useEffect, useRef} from 'react' import {BlockInputProps, ContentType} from 'src/components/blocksEditor/blocks/types' @@ -20,6 +20,7 @@ const ListItem: ContentType = { useEffect(() => { ref.current?.focus() }, []) + return (
  • diff --git a/webapp/boards/src/components/blocksEditor/blocks/list-item/list-item.test.tsx b/webapp/boards/src/components/blocksEditor/blocks/list-item/list-item.test.tsx index 1df8a9858c..ae77d35d3d 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/list-item/list-item.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/list-item/list-item.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import ListItemBlock from '.' diff --git a/webapp/boards/src/components/blocksEditor/blocks/quote/index.tsx b/webapp/boards/src/components/blocksEditor/blocks/quote/index.tsx index fcdad22458..c7607e23fb 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/quote/index.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/quote/index.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useRef, useEffect} from 'react' +import React, {useEffect, useRef} from 'react' import {marked} from 'marked' import {BlockInputProps, ContentType} from 'src/components/blocksEditor/blocks/types' @@ -15,6 +15,7 @@ const Quote: ContentType = { Display: (props: BlockInputProps) => { const renderer = new marked.Renderer() const html = marked('> ' + props.value, {renderer, breaks: true}) + return (
    { ref.current?.focus() }, []) + return (
    { const html: string = Utils.htmlFromMarkdown(props.value || '') + return (
    { ref.current?.focus() }, []) + return ( { const html: string = Utils.htmlFromMarkdown(props.value || '') + return (
    = { ) } + return null }, Input: (props: BlockInputProps) => { 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 c4f980a7bd..2168fac0de 100644 --- a/webapp/boards/src/components/blocksEditor/blocks/video/video.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocks/video/video.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import {mocked} from 'jest-mock' import octoClient from 'src/octoClient' diff --git a/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx b/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx index 2e713f56de..c1ef18db9e 100644 --- a/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx +++ b/webapp/boards/src/components/blocksEditor/blocksEditor.test.tsx @@ -4,21 +4,20 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' import { + act, + fireEvent, render, screen, - fireEvent, - act } from '@testing-library/react' import { mockDOM, - wrapDNDIntl, mockStateStore, - setup + setup, + wrapDNDIntl, } from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' - import {BlockData} from './blocks/types' import BlocksEditor from './blocksEditor' @@ -120,7 +119,6 @@ describe('components/blocksEditor/blocksEditor', () => { await user.keyboard('{Enter}') }) - expect(onBlockCreated).toBeCalledWith(expect.objectContaining({value: 'test'})) }) diff --git a/webapp/boards/src/components/blocksEditor/blocksEditor.tsx b/webapp/boards/src/components/blocksEditor/blocksEditor.tsx index 9868d6910b..41b4023b40 100644 --- a/webapp/boards/src/components/blocksEditor/blocksEditor.tsx +++ b/webapp/boards/src/components/blocksEditor/blocksEditor.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useMemo} from 'react' +import React, {useMemo, useState} from 'react' import {DndProvider} from 'react-dnd' import {HTML5Backend} from 'react-dnd-html5-backend' @@ -22,6 +22,7 @@ function BlocksEditor(props: Props) { const [editing, setEditing] = useState(null) const [afterBlock, setAfterBlock] = useState(null) const contentOrder = useMemo(() => props.blocks.filter((b) => b.id).map((b) => b.id!), [props.blocks]) + return (
    )} diff --git a/webapp/boards/src/components/blocksEditor/editor.test.tsx b/webapp/boards/src/components/blocksEditor/editor.test.tsx index 239e5e466e..f546a96f26 100644 --- a/webapp/boards/src/components/blocksEditor/editor.test.tsx +++ b/webapp/boards/src/components/blocksEditor/editor.test.tsx @@ -3,13 +3,13 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' -import {render, screen, act} from '@testing-library/react' +import {act, render, screen} from '@testing-library/react' import { mockDOM, - wrapDNDIntl, mockStateStore, - setup + setup, + wrapDNDIntl, } from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' diff --git a/webapp/boards/src/components/blocksEditor/editor.tsx b/webapp/boards/src/components/blocksEditor/editor.tsx index 21c2d8adc7..46d3626623 100644 --- a/webapp/boards/src/components/blocksEditor/editor.tsx +++ b/webapp/boards/src/components/blocksEditor/editor.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect} from 'react' +import React, {useEffect, useState} from 'react' import * as contentBlocks from './blocks/' -import {ContentType, BlockData} from './blocks/types' +import {BlockData, ContentType} from './blocks/types' import RootInput from './rootInput' import './editor.scss' diff --git a/webapp/boards/src/components/blocksEditor/rootInput.test.tsx b/webapp/boards/src/components/blocksEditor/rootInput.test.tsx index 947189b0c4..568c35450f 100644 --- a/webapp/boards/src/components/blocksEditor/rootInput.test.tsx +++ b/webapp/boards/src/components/blocksEditor/rootInput.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import RootInput from './rootInput' diff --git a/webapp/boards/src/components/boardSelector.test.tsx b/webapp/boards/src/components/boardSelector.test.tsx index 6f27ef27f1..369f2dc792 100644 --- a/webapp/boards/src/components/boardSelector.test.tsx +++ b/webapp/boards/src/components/boardSelector.test.tsx @@ -4,19 +4,18 @@ import React from 'react' import {Provider as ReduxProvider} from 'react-redux' import { + act, + fireEvent, render, screen, - act, - fireEvent } from '@testing-library/react' import {mocked} from 'jest-mock' import userEvent from '@testing-library/user-event' import octoClient from 'src/octoClient' -import {mockStateStore} from 'src/testUtils' +import {mockStateStore, wrapIntl} from 'src/testUtils' import {createBoard} from 'src/blocks/board' -import {wrapIntl} from 'src/testUtils' import BoardSelector from './boardSelector' @@ -97,7 +96,7 @@ describe('components/boardSelector', () => { expect(container).toMatchSnapshot() }) - it("escape button should unmount the component", () => { + it('escape button should unmount the component', () => { mockedOctoClient.searchLinkableBoards.mockResolvedValueOnce([]) const store = mockStateStore([], state) @@ -114,10 +113,10 @@ describe('components/boardSelector', () => { expect(store.dispatch).toHaveBeenCalledTimes(0) fireEvent.keyDown(getByText(/Link boards/i), { - key: "Escape", - code: "Escape", + key: 'Escape', + code: 'Escape', keyCode: 27, - charCode: 27 + charCode: 27, }) expect(store.dispatch).toHaveBeenCalledTimes(2) diff --git a/webapp/boards/src/components/boardSelector.tsx b/webapp/boards/src/components/boardSelector.tsx index a6e8a0dcea..7c4be33d73 100644 --- a/webapp/boards/src/components/boardSelector.tsx +++ b/webapp/boards/src/components/boardSelector.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useMemo, useCallback} from 'react' -import {IntlProvider, useIntl, FormattedMessage} from 'react-intl' +import React, {useCallback, useMemo, useState} from 'react' +import {FormattedMessage, IntlProvider, useIntl} from 'react-intl' import debounce from 'lodash/debounce' import {SuiteWindow} from 'src/types/index' @@ -13,10 +13,10 @@ import {useWebsockets} from 'src/hooks/websockets' import octoClient from 'src/octoClient' import mutator from 'src/mutator' -import {getCurrentTeamId, getAllTeams, Team} from 'src/store/teams' -import {createBoard, Board} from 'src/blocks/board' -import {useAppSelector, useAppDispatch} from 'src/store/hooks' -import {EmptySearch, EmptyResults} from 'src/components/searchDialog/searchDialog' +import {Team, getAllTeams, getCurrentTeamId} from 'src/store/teams' +import {Board, createBoard} from 'src/blocks/board' +import {useAppDispatch, useAppSelector} from 'src/store/hooks' +import {EmptyResults, EmptySearch} from 'src/components/searchDialog/searchDialog' import ConfirmationDialog from 'src/components/confirmationDialogBox' import Dialog from 'src/components/dialog' import SearchIcon from 'src/widgets/icons/search' @@ -67,7 +67,7 @@ const BoardSelector = () => { let updated = false results.forEach((board, idx) => { for (const newBoard of boards) { - if (newBoard.id == board.id) { + if (newBoard.id === board.id) { newResults[idx] = newBoard updated = true } @@ -95,6 +95,7 @@ const BoardSelector = () => { const linkBoard = async (board: Board, confirmed?: boolean): Promise => { if (!confirmed) { setShowLinkBoardConfirmation(board) + return } const newBoard = createBoard({...board, channelId: currentChannel}) @@ -117,7 +118,7 @@ const BoardSelector = () => { } let confirmationSubText - if (showLinkBoardConfirmation?.channelId !== '') { + if (showLinkBoardConfirmation?.channelId) { confirmationSubText = intl.formatMessage({ id: 'boardSelector.confirm-link-board-subtext-with-other-channel', defaultMessage: '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.{lineBreak} This board is currently linked to another channel. It will be unlinked if you choose to link it here.', @@ -138,7 +139,7 @@ const BoardSelector = () => { } const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.key == 'Escape') { + if (event.key === 'Escape') { closeDialog() } } @@ -197,13 +198,15 @@ const BoardSelector = () => {
    {/*When there are results to show*/} {searchQuery && results.length > 0 && - results.map((result) => ())} + results.map((result) => ( + + ))} {/*when user searched for something and there were no results*/} {emptyResult && } diff --git a/webapp/boards/src/components/boardSelectorItem.test.tsx b/webapp/boards/src/components/boardSelectorItem.test.tsx index 50202d1e96..f5d393baec 100644 --- a/webapp/boards/src/components/boardSelectorItem.test.tsx +++ b/webapp/boards/src/components/boardSelectorItem.test.tsx @@ -14,7 +14,7 @@ import BoardSelectorItem from './boardSelectorItem' describe('components/boardSelectorItem', () => { it('renders board without title', async () => { const board = createBoard() - board.title = "" + board.title = '' const {container} = render(wrapIntl( { it('renders linked board', async () => { const board = createBoard() - board.title = "Test title" + board.title = 'Test title' const {container} = render(wrapIntl( { it('renders not linked board', async () => { const board = createBoard() - board.title = "Test title" + board.title = 'Test title' const {container} = render(wrapIntl( { const intl = useIntl() const untitledBoardTitle = intl.formatMessage({id: 'ViewTitle.untitled-board', defaultMessage: 'Untitled board'}) const resultTitle = item.title || untitledBoardTitle + return (
    diff --git a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.test.tsx b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.test.tsx index 83c5b84b89..3f5806110e 100644 --- a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.test.tsx +++ b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.test.tsx @@ -5,7 +5,7 @@ import { render, screen, waitFor, - within + within, } from '@testing-library/react' import userEvent from '@testing-library/user-event' import React from 'react' @@ -20,7 +20,7 @@ import {MemoryRouter, Router} from 'react-router-dom' import Mutator from 'src/mutator' import {Team} from 'src/store/teams' -import {createBoard, Board} from 'src/blocks/board' +import {Board, createBoard} from 'src/blocks/board' import {IUser} from 'src/user' import {mockDOM, mockStateStore, wrapDNDIntl} from 'src/testUtils' @@ -288,7 +288,7 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => { const useTemplateButton = screen.getByText('Use this template').parentElement expect(useTemplateButton).not.toBeNull() - + await userEvent.click(useTemplateButton!) await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledTimes(1)) @@ -313,11 +313,10 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => { expect(divBoardToSelect).not.toBeNull() await userEvent.click(divBoardToSelect!) - const useTemplateButton = screen.getByText('Use this template').parentElement expect(useTemplateButton).not.toBeNull() - + await userEvent.click(useTemplateButton!) await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledTimes(1)) @@ -339,12 +338,12 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => { expect(divBoardToSelect).not.toBeNull() await userEvent.click(divBoardToSelect!) - + const useTemplateButton = screen.getByText('Use this template').parentElement expect(useTemplateButton).not.toBeNull() - + await userEvent.click(useTemplateButton!) - + await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledTimes(1)) await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledWith(team1.id, expect.anything(), expect.anything(), expect.anything(), 'global-1', team1.id)) await waitFor(() => expect(mockedTelemetry.trackEvent).toBeCalledWith('boards', 'createBoardViaTemplate', {boardTemplateId: 'template_id_global'})) @@ -367,9 +366,9 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => { const useTemplateButton = screen.getByText('Use this template').parentElement expect(useTemplateButton).not.toBeNull() - + await userEvent.click(useTemplateButton!) - + await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledTimes(1)) await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledWith(team1.id, expect.anything(), expect.anything(), expect.anything(), '2', team1.id)) await waitFor(() => expect(mockedTelemetry.trackEvent).toBeCalledWith('boards', 'createBoardViaTemplate', {boardTemplateId: 'template_id_2'})) diff --git a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.tsx b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.tsx index 3a3821407e..1dfeae7659 100644 --- a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.tsx +++ b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelector.tsx @@ -1,10 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, { - useEffect, - useState, useCallback, - useMemo + useEffect, + useMemo, + useState, } from 'react' import {FormattedMessage, useIntl} from 'react-intl' import {useHistory, useRouteMatch} from 'react-router-dom' @@ -18,8 +18,8 @@ import CloseIcon from 'src/widgets/icons/close' import Button from 'src/widgets/buttons/button' import octoClient from 'src/octoClient' import mutator from 'src/mutator' -import {getTemplates, getCurrentBoardId} from 'src/store/boards' -import {getCurrentTeam, Team} from 'src/store/teams' +import {getCurrentBoardId, getTemplates} from 'src/store/boards' +import {Team, getCurrentTeam} from 'src/store/teams' import {fetchGlobalTemplates, getGlobalTemplates} from 'src/store/globalTemplates' import {useAppDispatch, useAppSelector} from 'src/store/hooks' import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' diff --git a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorItem.test.tsx b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorItem.test.tsx index ee629334b0..945d047b1f 100644 --- a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorItem.test.tsx +++ b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorItem.test.tsx @@ -1,17 +1,17 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import { - render, - within, act, - waitFor + render, + waitFor, + within, } from '@testing-library/react' import userEvent from '@testing-library/user-event' import React from 'react' import {MockStoreEnhanced} from 'redux-mock-store' import {Provider as ReduxProvider} from 'react-redux' -import {Board, MemberRole, IPropertyTemplate} from 'src/blocks/board' +import {Board, IPropertyTemplate, MemberRole} from 'src/blocks/board' import {mockStateStore, wrapDNDIntl} from 'src/testUtils' import {IUser} from 'src/user' diff --git a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorPreview.tsx b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorPreview.tsx index 8ea77b2708..96c2ff3d1a 100644 --- a/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorPreview.tsx +++ b/webapp/boards/src/components/boardTemplateSelector/boardTemplateSelectorPreview.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect, useState, useMemo} from 'react' +import React, {useEffect, useMemo, useState} from 'react' import {Board} from 'src/blocks/board' import {Card} from 'src/blocks/card' @@ -45,6 +45,7 @@ const BoardTemplateSelectorPreview = (props: Props) => { } }) } + return () => { isSubscribed = false } @@ -62,6 +63,7 @@ const BoardTemplateSelectorPreview = (props: Props) => { if (!activeView) { return {visible: [], hidden: []} } + return getVisibleAndHiddenGroups(activeTemplateCards, activeView.fields.visibleOptionIds, activeView?.fields.hiddenOptionIds, groupByProperty) }, [activeTemplateCards, activeView, groupByProperty]) diff --git a/webapp/boards/src/components/boardsSwitcher/boardsSwitcher.tsx b/webapp/boards/src/components/boardsSwitcher/boardsSwitcher.tsx index a30f989946..f9030c435a 100644 --- a/webapp/boards/src/components/boardsSwitcher/boardsSwitcher.tsx +++ b/webapp/boards/src/components/boardsSwitcher/boardsSwitcher.tsx @@ -19,7 +19,7 @@ import AddIcon from 'src/widgets/icons/add' import BoardSwitcherDialog from 'src/components/boardsSwitcherDialog/boardSwitcherDialog' import {Utils} from 'src/utils' import {Constants} from 'src/constants' -import {TOUR_SIDEBAR, SidebarTourSteps} from 'src/components/onboardingTour' +import {SidebarTourSteps, TOUR_SIDEBAR} from 'src/components/onboardingTour' import IconButton from 'src/widgets/buttons/iconButton' import SearchForBoardsTourStep from 'src/components/onboardingTour/searchForBoards/searchForBoards' diff --git a/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.test.tsx b/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.test.tsx index 427a0188d2..97f77c975b 100644 --- a/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.test.tsx +++ b/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.test.tsx @@ -9,7 +9,7 @@ import {Provider as ReduxProvider} from 'react-redux' import {render} from '@testing-library/react' -import {createMemoryHistory, History} from 'history' +import {History, createMemoryHistory} from 'history' import {Router} from 'react-router-dom' diff --git a/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.tsx b/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.tsx index c45d87e5d0..cb50101ccc 100644 --- a/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.tsx +++ b/webapp/boards/src/components/boardsSwitcherDialog/boardSwitcherDialog.tsx @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, { + MutableRefObject, ReactNode, - useRef, createRef, - useState, useEffect, - MutableRefObject + useRef, + useState, } from 'react' import './boardSwitcherDialog.scss' @@ -19,7 +19,7 @@ import SearchDialog from 'src/components/searchDialog/searchDialog' import Globe from 'src/widgets/icons/globe' import LockOutline from 'src/widgets/icons/lockOutline' import {useAppSelector} from 'src/store/hooks' -import {getAllTeams, getCurrentTeam, Team} from 'src/store/teams' +import {Team, getAllTeams, getCurrentTeam} from 'src/store/teams' import {getMe} from 'src/store/users' import {Utils} from 'src/utils' import {BoardTypeOpen, BoardTypePrivate} from 'src/blocks/board' @@ -75,6 +75,7 @@ const BoardSwitcherDialog = (props: Props): JSX.Element => { const untitledBoardTitle = intl.formatMessage({id: 'ViewTitle.untitled-board', defaultMessage: 'Untitled board'}) refs.current = items.map((_, i) => refs.current[i] ?? createRef()) setRefs(refs) + return items.map((item, i) => { const resultTitle = item.title || untitledBoardTitle const teamTitle = teamsById[item.teamId].title @@ -83,6 +84,7 @@ const BoardSwitcherDialog = (props: Props): JSX.Element => { ...prevIDs, [i]: [item.teamId, item.id], })) + return (
    { }) const board = {...createBoard(), title: 'test board'} + // mockedOctoClient.getBoard.mockResolvedValueOnce(board) const component = ( diff --git a/webapp/boards/src/components/boardsUnfurl/boardsUnfurl.tsx b/webapp/boards/src/components/boardsUnfurl/boardsUnfurl.tsx index 08a9f5eb51..b0704693fe 100644 --- a/webapp/boards/src/components/boardsUnfurl/boardsUnfurl.tsx +++ b/webapp/boards/src/components/boardsUnfurl/boardsUnfurl.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect} from 'react' -import {IntlProvider, FormattedMessage, useIntl} from 'react-intl' +import React, {useEffect, useState} from 'react' +import {FormattedMessage, IntlProvider, useIntl} from 'react-intl' import WithWebSockets from 'src/components/withWebSockets' import {useWebsockets} from 'src/hooks/websockets' @@ -10,7 +10,7 @@ import {getLanguage} from 'src/store/language' import {useAppSelector} from 'src/store/hooks' import {getCurrentTeamId} from 'src/store/teams' -import {WSClient, MMWebSocketClient} from 'src/wsclient' +import {MMWebSocketClient, WSClient} from 'src/wsclient' import manifest from 'src/manifest' import {getMessages} from 'src/i18n' @@ -86,6 +86,7 @@ export const BoardsUnfurl = (props: Props): JSX.Element => { const [firstCard] = cards as Card[] if (!firstCard || !fetchedBoard || firstCard.type !== 'card') { setLoading(false) + return null } setCard(firstCard) @@ -102,12 +103,14 @@ export const BoardsUnfurl = (props: Props): JSX.Element => { const [firstContentBlock] = contentBlock if (!firstContentBlock) { setLoading(false) + return null } setContent(firstContentBlock) } setLoading(false) + return null } fetchData() diff --git a/webapp/boards/src/components/calculations/calculations.ts b/webapp/boards/src/components/calculations/calculations.ts index 86eb878754..bf1279926e 100644 --- a/webapp/boards/src/components/calculations/calculations.ts +++ b/webapp/boards/src/components/calculations/calculations.ts @@ -44,8 +44,8 @@ function fixTimestampToMinutesAccuracy(timestamp: number) { } function cardsWithValue(cards: readonly Card[], property: IPropertyTemplate): Card[] { - return cards. - filter((card) => Boolean(getCardProperty(card, property))) + return cards + .filter((card) => Boolean(getCardProperty(card, property))) } // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -66,6 +66,7 @@ function percentEmpty(cards: readonly Card[], property: IPropertyTemplate): stri if (cards.length === 0) { return '' } + return String((((cards.length - cardsWithValue(cards, property).length) / cards.length) * 100).toFixed(0)) + '%' } @@ -73,6 +74,7 @@ function percentNotEmpty(cards: readonly Card[], property: IPropertyTemplate): s if (cards.length === 0) { return '' } + return String(((cardsWithValue(cards, property).length / cards.length) * 100).toFixed(0)) + '%' } @@ -80,8 +82,8 @@ function countValueHelper(cards: readonly Card[], property: IPropertyTemplate): let values = 0 if (property.type === 'multiSelect') { - cardsWithValue(cards, property). - forEach((card) => { + cardsWithValue(cards, property) + .forEach((card) => { values += (getCardProperty(card, property) as string[]).length }) } else { @@ -140,8 +142,8 @@ function countUniqueValue(cards: readonly Card[], property: IPropertyTemplate): function sum(cards: readonly Card[], property: IPropertyTemplate): string { let result = 0 - cardsWithValue(cards, property). - forEach((card) => { + cardsWithValue(cards, property) + .forEach((card) => { result += parseFloat(getCardProperty(card, property) as string) }) @@ -156,12 +158,13 @@ function average(cards: readonly Card[], property: IPropertyTemplate): string { const result = parseFloat(sum(cards, property)) const avg = result / numCards + return String(Utils.roundTo(avg, ROUNDED_DECIMAL_PLACES)) } function median(cards: readonly Card[], property: IPropertyTemplate): string { - const sorted = cardsWithValue(cards, property). - sort((a, b) => { + const sorted = cardsWithValue(cards, property) + .sort((a, b) => { if (!getCardProperty(a, property)) { return 1 } @@ -231,6 +234,7 @@ function earliest(cards: readonly Card[], property: IPropertyTemplate, intl: Int return '' } const date = new Date(result) + return property.type === 'date' ? Utils.displayDate(date, intl) : Utils.displayDateTime(date, intl) } @@ -242,6 +246,7 @@ function earliestEpoch(cards: readonly Card[], property: IPropertyTemplate): num result = Math.min(result, timestamp) } }) + return result } @@ -251,6 +256,7 @@ function latest(cards: readonly Card[], property: IPropertyTemplate, intl: IntlS return '' } const date = new Date(result) + return property.type === 'date' ? Utils.displayDate(date, intl) : Utils.displayDateTime(date, intl) } @@ -262,6 +268,7 @@ function latestEpoch(cards: readonly Card[], property: IPropertyTemplate): numbe result = Math.max(result, timestamp) } }) + return result } @@ -276,10 +283,12 @@ function getTimestampsFromPropertyValue(value: number | string | string[]): numb } catch { return [] } + return [property.from, property.to].flatMap((e) => { return e ? [e] : [] }) } + return [] } @@ -292,6 +301,7 @@ function dateRange(cards: readonly Card[], property: IPropertyTemplate, intl: In if (resultLatest === Number.NEGATIVE_INFINITY) { return '' } + return moment.duration(resultLatest - resultEarliest, 'milliseconds').locale(intl.locale.toLowerCase()).humanize() } diff --git a/webapp/boards/src/components/calculations/options.tsx b/webapp/boards/src/components/calculations/options.tsx index 859da420ff..a35c68499b 100644 --- a/webapp/boards/src/components/calculations/options.tsx +++ b/webapp/boards/src/components/calculations/options.tsx @@ -2,10 +2,9 @@ // See LICENSE.txt for license information. import React from 'react' -import Select, {components, DropdownIndicatorProps, StylesConfig} from 'react-select' +import Select, {DropdownIndicatorProps, StylesConfig, components} from 'react-select' - -import {useIntl, IntlShape} from 'react-intl' +import {IntlShape, useIntl} from 'react-intl' import {getSelectBaseStyle} from 'src/theme' import ChevronUp from 'src/widgets/icons/chevronUp' diff --git a/webapp/boards/src/components/calendar/fullCalendar.test.tsx b/webapp/boards/src/components/calendar/fullCalendar.test.tsx index 556dcb85d1..77f9451dc2 100644 --- a/webapp/boards/src/components/calendar/fullCalendar.test.tsx +++ b/webapp/boards/src/components/calendar/fullCalendar.test.tsx @@ -5,7 +5,7 @@ import {render} from '@testing-library/react' import {Provider as ReduxProvider} from 'react-redux' import {TestBlockFactory} from 'src/test/testBlockFactory' -import {wrapIntl, mockStateStore} from 'src/testUtils' +import {mockStateStore, wrapIntl} from 'src/testUtils' import {IPropertyTemplate} from 'src/blocks/board' import CalendarView from './fullCalendar' diff --git a/webapp/boards/src/components/calendar/fullCalendar.tsx b/webapp/boards/src/components/calendar/fullCalendar.tsx index 1ba1a2c888..ffd67dfa8a 100644 --- a/webapp/boards/src/components/calendar/fullCalendar.tsx +++ b/webapp/boards/src/components/calendar/fullCalendar.tsx @@ -5,10 +5,10 @@ import React, {useCallback, useMemo, useState} from 'react' import {useIntl} from 'react-intl' import FullCalendar, { + DayCellContentArg, EventChangeArg, - EventInput, EventContentArg, - DayCellContentArg + EventInput, } from '@fullcalendar/react' import interactionPlugin from '@fullcalendar/interaction' @@ -60,6 +60,7 @@ function createDatePropertyFromCalendarDates(start: Date, end: Date): DateProper if (dateTo !== dateFrom) { dateProperty.to = dateTo } + return dateProperty } @@ -69,6 +70,7 @@ function createDatePropertyFromCalendarDate(start: Date): DateProperty { const dateFrom = start.getTime() - timeZoneOffset(start.getTime()) const dateProperty: DateProperty = {from: dateFrom} + return dateProperty } @@ -97,6 +99,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => { if (readonly || !dateDisplayProperty || propsRegistry.get(dateDisplayProperty.type).isReadOnly) { return false } + return true }, [readonly, dateDisplayProperty]) @@ -118,6 +121,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => { //full calendar end date is exclusive, so increment by 1 day. dateTo.setDate(dateTo.getDate() + 1) } + return [{ id: card.id, title: card.title, diff --git a/webapp/boards/src/components/cardBadges.tsx b/webapp/boards/src/components/cardBadges.tsx index bfba9df14a..2f2fd00817 100644 --- a/webapp/boards/src/components/cardBadges.tsx +++ b/webapp/boards/src/components/cardBadges.tsx @@ -64,6 +64,7 @@ const calculateBadges = (contents: ContentsType, comments: CommentBlock[]): Badg updateCounters(content) } } + return { description: text > 0, comments: comments.length, @@ -84,6 +85,7 @@ const CardBadges = (props: Props) => { } const intl = useIntl() const {checkboxes} = badges + return (
    {badges.description && diff --git a/webapp/boards/src/components/cardDetail/cardDetail.tsx b/webapp/boards/src/components/cardDetail/cardDetail.tsx index 872ebd33da..7ff6d17033 100644 --- a/webapp/boards/src/components/cardDetail/cardDetail.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetail.tsx @@ -1,14 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, { + Fragment, useCallback, useEffect, + useMemo, useRef, useState, - Fragment, - useMemo } from 'react' -import {FormattedMessage, useIntl, IntlShape} from 'react-intl' +import {FormattedMessage, IntlShape, useIntl} from 'react-intl' import {BlockIcons} from 'src/blockIcons' import {Card} from 'src/blocks/card' @@ -30,7 +30,7 @@ import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetr import BlockIconSelector from 'src/components/blockIconSelector' import {useAppDispatch, useAppSelector} from 'src/store/hooks' -import {updateCards, setCurrent as setCurrentCard} from 'src/store/cards' +import {setCurrent as setCurrentCard, updateCards} from 'src/store/cards' import {updateContents} from 'src/store/contents' import {Permission} from 'src/constants' import {useHasCurrentBoardPermissions} from 'src/hooks/permissions' @@ -102,6 +102,7 @@ async function addBlockNewEditor(card: Card, intl: IntlShape, title: string, fie const newBlock = await mutator.insertBlock(block.boardId, block, description, afterRedo, beforeUndo) dispatch(updateContents([newBlock])) + return newBlock } @@ -144,7 +145,7 @@ const CardDetail = (props: Props): JSX.Element|null => { useEffect(() => { return () => { - saveTitleRef.current && saveTitleRef.current() + saveTitleRef.current?.() } }, []) @@ -339,6 +340,7 @@ const CardDetail = (props: Props): JSX.Element|null => { } else { newBlock = await addBlockNewEditor(card, intl, block.value, {}, block.contentType, afterBlock?.id, dispatch) } + return {...block, id: newBlock.id} }} onBlockModified={async (block: any): Promise|null> => { @@ -351,6 +353,7 @@ const CardDetail = (props: Props): JSX.Element|null => { const description = intl.formatMessage({id: 'ContentBlock.DeleteAction', defaultMessage: 'delete'}) mutator.deleteBlock(originalContentBlock, description) + return null } const newBlock = { @@ -363,6 +366,7 @@ const CardDetail = (props: Props): JSX.Element|null => { newBlock.fields = {...newBlock.fields, value: block.value.checked} } mutator.updateBlock(card.boardId, newBlock, originalContentBlock, intl.formatMessage({id: 'ContentBlock.editCardText', defaultMessage: 'edit card text'})) + return block }} onBlockMoved={async (block: BlockData, beforeBlock: BlockData|null, afterBlock: BlockData|null): Promise => { @@ -372,6 +376,7 @@ const CardDetail = (props: Props): JSX.Element|null => { let sourceWhere: 'after'|'before' if (idx === -1) { Utils.logError('Unable to find the block id in the order of the current block') + return } if (idx === 0) { @@ -383,6 +388,7 @@ const CardDetail = (props: Props): JSX.Element|null => { } if (afterBlock && afterBlock.id) { await mutator.moveContentBlock(block.id, afterBlock.id, 'after', sourceBlockId, sourceWhere, intl.formatMessage({id: 'ContentBlock.moveBlock', defaultMessage: 'move card content'})) + return } if (beforeBlock && beforeBlock.id) { diff --git a/webapp/boards/src/components/cardDetail/cardDetailContents.test.tsx b/webapp/boards/src/components/cardDetail/cardDetailContents.test.tsx index a25a18c33b..c4149d2704 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailContents.test.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailContents.test.tsx @@ -9,7 +9,7 @@ import {act} from 'react-dom/test-utils' import {TestBlockFactory} from 'src/test/testBlockFactory' -import {mockDOM, wrapDNDIntl, mockStateStore} from 'src/testUtils' +import {mockDOM, mockStateStore, wrapDNDIntl} from 'src/testUtils' import CardDetailContents from './cardDetailContents' import {CardDetailProvider} from './cardDetailContext' diff --git a/webapp/boards/src/components/cardDetail/cardDetailContents.tsx b/webapp/boards/src/components/cardDetail/cardDetailContents.tsx index a6e0f636de..4896e573ed 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailContents.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailContents.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React from 'react' -import {useIntl, IntlShape} from 'react-intl' +import {IntlShape, useIntl} from 'react-intl' -import {IContentBlockWithCords, ContentBlock as ContentBlockType} from 'src/blocks/contentBlock' +import {ContentBlock as ContentBlockType, IContentBlockWithCords} from 'src/blocks/contentBlock' import {Card} from 'src/blocks/card' import {createTextBlock} from 'src/blocks/textBlock' import {Block} from 'src/blocks/block' @@ -182,6 +182,7 @@ const CardDetailContents = (props: Props) => {
    ) } + return (
    diff --git a/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.test.tsx b/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.test.tsx index c293560d34..4c48a1a823 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.test.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.test.tsx @@ -6,7 +6,7 @@ import {Provider as ReduxProvider} from 'react-redux' import userEvent from '@testing-library/user-event' -import {wrapIntl, mockStateStore, setup} from 'src/testUtils' +import {mockStateStore, setup, wrapIntl} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' diff --git a/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.tsx b/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.tsx index 441ee3876e..817f5825f7 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailContentsMenu.tsx @@ -17,6 +17,7 @@ function addContentMenu(intl: IntlShape, type: BlockTypes): JSX.Element { const handler = contentRegistry.getHandler(type) if (!handler) { Utils.logError(`addContentMenu, unknown content type: ${type}`) + return <> } const cardDetail = useCardDetailContext() @@ -39,6 +40,7 @@ function addContentMenu(intl: IntlShape, type: BlockTypes): JSX.Element { const CardDetailContentsMenu = () => { const intl = useIntl() + return (
    diff --git a/webapp/boards/src/components/cardDetail/cardDetailContext.tsx b/webapp/boards/src/components/cardDetail/cardDetailContext.tsx index 436f981700..d5c23e6f06 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailContext.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailContext.tsx @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, { - createContext, ReactElement, ReactNode, + createContext, + useCallback, useContext, useMemo, useState, - useCallback } from 'react' import {useIntl} from 'react-intl' @@ -37,6 +37,7 @@ export function useCardDetailContext(): CardDetailContextType { if (!cardDetailContext) { throw new Error('CardDetailContext is not available!') } + return cardDetailContext } diff --git a/webapp/boards/src/components/cardDetail/cardDetailProperties.test.tsx b/webapp/boards/src/components/cardDetail/cardDetailProperties.test.tsx index 3e16156102..b47c61f6fd 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailProperties.test.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailProperties.test.tsx @@ -3,10 +3,10 @@ import React from 'react' import { + act, + fireEvent, render, screen, - act, - fireEvent } from '@testing-library/react' import userEvent from '@testing-library/user-event' import {mocked} from 'jest-mock' @@ -206,7 +206,7 @@ describe('components/cardDetail/CardDetailProperties', () => { await act(() => userEvent.click(menuElement)) const numberType = screen.getByRole('button', {name: /number/i}) - await act( () => userEvent.click(numberType)) + await act(() => userEvent.click(numberType)) expect(mockedMutator.insertPropertyTemplate).toHaveBeenCalledTimes(1) diff --git a/webapp/boards/src/components/cardDetail/cardDetailProperties.tsx b/webapp/boards/src/components/cardDetail/cardDetailProperties.tsx index eb8a7ac72c..a24c89ac7f 100644 --- a/webapp/boards/src/components/cardDetail/cardDetailProperties.tsx +++ b/webapp/boards/src/components/cardDetail/cardDetailProperties.tsx @@ -63,6 +63,7 @@ const CardDetailProperties = (props: Props) => { // if only the name has changed, set the property without warning if (affectsNumOfCards === '0' || oldType === newType) { mutator.changePropertyTypeAndName(board, cards, propertyTemplate, newType.type, newName) + return } diff --git a/webapp/boards/src/components/cardDetail/comment.test.tsx b/webapp/boards/src/components/cardDetail/comment.test.tsx index 537c034009..141b426e4f 100644 --- a/webapp/boards/src/components/cardDetail/comment.test.tsx +++ b/webapp/boards/src/components/cardDetail/comment.test.tsx @@ -8,7 +8,7 @@ import moment from 'moment' import {mocked} from 'jest-mock' -import {wrapIntl, mockStateStore} from 'src/testUtils' +import {mockStateStore, wrapIntl} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' diff --git a/webapp/boards/src/components/cardDetail/commentsList.tsx b/webapp/boards/src/components/cardDetail/commentsList.tsx index f3b3c3f3c0..f60cdf3103 100644 --- a/webapp/boards/src/components/cardDetail/commentsList.tsx +++ b/webapp/boards/src/components/cardDetail/commentsList.tsx @@ -95,6 +95,7 @@ const CommentsList = (props: Props) => { // Only modify _own_ comments, EXCEPT for Admins, which can delete _any_ comment // NOTE: editing comments will exist in the future (in addition to deleting) const canDeleteComment: boolean = canDeleteOthersComments || me?.id === comment.modifiedBy + return ( { document.addEventListener('paste', onPaste) document.addEventListener('drop', onDrop) + return () => { document.removeEventListener('paste', onPaste) document.removeEventListener('drop', onDrop) diff --git a/webapp/boards/src/components/cardDialog.test.tsx b/webapp/boards/src/components/cardDialog.test.tsx index b39c5db502..1ac87815a7 100644 --- a/webapp/boards/src/components/cardDialog.test.tsx +++ b/webapp/boards/src/components/cardDialog.test.tsx @@ -93,7 +93,6 @@ describe('components/cardDialog', () => { jest.clearAllMocks() }) test('should match snapshot', async () => { - const {container} = render(wrapDNDIntl( { /> , )) - + expect(container).toMatchSnapshot() }) diff --git a/webapp/boards/src/components/cardDialog.tsx b/webapp/boards/src/components/cardDialog.tsx index b1187db750..3680b66a92 100644 --- a/webapp/boards/src/components/cardDialog.tsx +++ b/webapp/boards/src/components/cardDialog.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useCallback} from 'react' +import React, {useCallback, useState} from 'react' import {FormattedMessage, useIntl} from 'react-intl' import {Board} from 'src/blocks/board' @@ -67,6 +67,7 @@ const CardDialog = (props: Props): JSX.Element => { const makeTemplateClicked = async () => { if (!card) { Utils.assertFailure('card') + return } @@ -89,6 +90,7 @@ const CardDialog = (props: Props): JSX.Element => { const handleDeleteCard = async () => { if (!card) { Utils.assertFailure() + return } TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DeleteCard, {board: props.board.id, view: props.activeView.id, card: card.id}) @@ -111,6 +113,7 @@ const CardDialog = (props: Props): JSX.Element => { // so adding des if (card?.title === '' && card?.fields.contentOrder.length === 0) { handleDeleteCard() + return } @@ -266,6 +269,7 @@ const CardDialog = (props: Props): JSX.Element => { if (!isTemplate && !card?.limited) { return (<>{attachBtn()}{following ? unfollowBtn : followBtn}) } + return (<>{attachBtn()}) } diff --git a/webapp/boards/src/components/cardLimitNotification.tsx b/webapp/boards/src/components/cardLimitNotification.tsx index aadb94a765..65d9007e48 100644 --- a/webapp/boards/src/components/cardLimitNotification.tsx +++ b/webapp/boards/src/components/cardLimitNotification.tsx @@ -1,19 +1,19 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {useCallback, useEffect, useState} from 'react' -import {useIntl, FormattedMessage} from 'react-intl' +import {FormattedMessage, useIntl} from 'react-intl' import AlertIcon from 'src/widgets/icons/alert' -import {useAppSelector, useAppDispatch} from 'src/store/hooks' +import {useAppDispatch, useAppSelector} from 'src/store/hooks' import {IUser, UserConfigPatch} from 'src/user' import { + getCardHiddenWarningSnoozeUntil, + getCardLimitSnoozeUntil, getMe, patchProps, - getCardLimitSnoozeUntil, - getCardHiddenWarningSnoozeUntil } from 'src/store/users' -import {getCurrentBoardHiddenCardsCount, getCardHiddenWarning} from 'src/store/cards' +import {getCardHiddenWarning, getCurrentBoardHiddenCardsCount} from 'src/store/cards' import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' import CheckIcon from 'src/widgets/icons/check' import NotificationBox from 'src/widgets/notificationBox/notificationBox' @@ -103,10 +103,12 @@ const CardLimitNotification = (props: Props) => { useEffect(() => { if (!show) { const interval = setInterval(() => setTime(Date.now()), checkSnoozeInterval) + return () => { clearInterval(interval) } } + return () => null }, [show]) diff --git a/webapp/boards/src/components/centerPanel.test.tsx b/webapp/boards/src/components/centerPanel.test.tsx index 75fed7eee8..f16640357f 100644 --- a/webapp/boards/src/components/centerPanel.test.tsx +++ b/webapp/boards/src/components/centerPanel.test.tsx @@ -5,7 +5,7 @@ import { fireEvent, render, screen, - within + within, } from '@testing-library/react' import userEvent from '@testing-library/user-event' import React from 'react' @@ -375,7 +375,7 @@ describe('components/centerPanel', () => { )) const cardElement = screen.getByRole('textbox', {name: 'card1'}) expect(cardElement).not.toBeNull() - fireEvent.click(cardElement, {shiftKey: true}) + fireEvent.click(cardElement, {shiftKey: true}) expect(container).toMatchSnapshot() //delete diff --git a/webapp/boards/src/components/centerPanel.tsx b/webapp/boards/src/components/centerPanel.tsx index 96bbdd4e11..ff422041d5 100644 --- a/webapp/boards/src/components/centerPanel.tsx +++ b/webapp/boards/src/components/centerPanel.tsx @@ -1,11 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -/* eslint-disable max-lines */ + import React, { - useState, useCallback, useEffect, - useMemo + useMemo, + useState, } from 'react' import {useIntl} from 'react-intl' import {useHotkeys} from 'react-hotkeys-hook' @@ -15,32 +15,32 @@ import {ClientConfig} from 'src/config/clientConfig' import {Block} from 'src/blocks/block' import {BlockIcons} from 'src/blockIcons' import {Card, createCard} from 'src/blocks/card' -import {Board, IPropertyTemplate, BoardGroup} from 'src/blocks/board' +import {Board, BoardGroup, IPropertyTemplate} from 'src/blocks/board' import {BoardView} from 'src/blocks/boardView' import {CardFilter} from 'src/cardFilter' import mutator from 'src/mutator' import {Utils} from 'src/utils' import {UserSettings} from 'src/userSettings' import { - getCurrentCard, addCard as addCardAction, addTemplate as addTemplateAction, - showCardHiddenWarning + getCurrentCard, + showCardHiddenWarning, } from 'src/store/cards' import {getCardLimitTimestamp} from 'src/store/limits' import {updateView} from 'src/store/views' import {getVisibleAndHiddenGroups} from 'src/boardUtils' -import TelemetryClient, {TelemetryCategory, TelemetryActions} from 'src/telemetry/telemetryClient' +import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' import {getClientConfig} from 'src/store/clientConfig' import './centerPanel.scss' -import {useAppSelector, useAppDispatch} from 'src/store/hooks' +import {useAppDispatch, useAppSelector} from 'src/store/hooks' import { - getMe, getBoardUsers, + getMe, getOnboardingTourCategory, getOnboardingTourStarted, getOnboardingTourStep, @@ -72,7 +72,7 @@ import { BoardTourSteps, FINISHED, TOUR_BOARD, - TOUR_CARD + TOUR_CARD, } from './onboardingTour' import ShareBoardTourStep from './onboardingTour/shareBoard/shareBoard' @@ -393,6 +393,7 @@ const CenterPanel = (props: Props) => { defaultMessage: 'No {propertyName}', }, {propertyName: groupByProperty?.name}) } + return intl.formatMessage({id: 'centerPanel.unknown-user', defaultMessage: 'Unknown user'}) } @@ -408,6 +409,7 @@ const CenterPanel = (props: Props) => { }) } } + return {visible: vg, hidden: hg} }, [cards, activeView.fields.visibleOptionIds, activeView.fields.hiddenOptionIds, groupByProperty, boardUsers]) diff --git a/webapp/boards/src/components/confirmAddUserForNotifications.tsx b/webapp/boards/src/components/confirmAddUserForNotifications.tsx index be4c1bbc14..04347a605c 100644 --- a/webapp/boards/src/components/confirmAddUserForNotifications.tsx +++ b/webapp/boards/src/components/confirmAddUserForNotifications.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useRef} from 'react' +import React, {useRef, useState} from 'react' import Select from 'react-select' -import {useIntl, FormattedMessage} from 'react-intl' +import {FormattedMessage, useIntl} from 'react-intl' import {MemberRole} from 'src/blocks/board' diff --git a/webapp/boards/src/components/content/archivedFile/archivedFile.tsx b/webapp/boards/src/components/content/archivedFile/archivedFile.tsx index e87e8d917b..5a4c8c5d47 100644 --- a/webapp/boards/src/components/content/archivedFile/archivedFile.tsx +++ b/webapp/boards/src/components/content/archivedFile/archivedFile.tsx @@ -18,6 +18,7 @@ const ArchivedFile = (props: Props): JSX.Element => { const fileExtension = useCallback(() => { let extension = props.fileInfo.extension extension = extension?.startsWith('.') ? extension?.substring(1) : extension + return extension?.toUpperCase() }, [props.fileInfo.extension]) diff --git a/webapp/boards/src/components/content/attachmentElement.tsx b/webapp/boards/src/components/content/attachmentElement.tsx index 58efbdce9b..1b7d36d722 100644 --- a/webapp/boards/src/components/content/attachmentElement.tsx +++ b/webapp/boards/src/components/content/attachmentElement.tsx @@ -48,6 +48,7 @@ const AttachmentElement = (props: Props): JSX.Element|null => { name: block.title, extension: block.title.split('.').slice(0, -1).join('.'), }) + return } const attachmentInfo = await octoClient.getFileInfo(block.boardId, block.fields.fileId) @@ -65,8 +66,10 @@ const AttachmentElement = (props: Props): JSX.Element|null => { if (fName.length > 18) { let result = fName.slice(0, 15) result += '...' + return result } + return fName } setFileName(generateFileName(fileInfo.name)) diff --git a/webapp/boards/src/components/content/checkboxElement.test.tsx b/webapp/boards/src/components/content/checkboxElement.test.tsx index ba1c1cda00..500e94934a 100644 --- a/webapp/boards/src/components/content/checkboxElement.test.tsx +++ b/webapp/boards/src/components/content/checkboxElement.test.tsx @@ -6,7 +6,7 @@ import { fireEvent, render, screen, - waitFor + waitFor, } from '@testing-library/react' import {mocked} from 'jest-mock' import userEvent from '@testing-library/user-event' @@ -174,7 +174,7 @@ describe('components/content/checkboxElement', () => { )) const input = screen.getByRole('textbox') - // should delete if title is empty + // should delete if title is empty await userEvent.type(input, '{Escape}') expect(deleteElement).toHaveBeenCalledTimes(1) await userEvent.type(input, '{Enter}') diff --git a/webapp/boards/src/components/content/checkboxElement.tsx b/webapp/boards/src/components/content/checkboxElement.tsx index caf37d7b98..c284d3d7c2 100644 --- a/webapp/boards/src/components/content/checkboxElement.tsx +++ b/webapp/boards/src/components/content/checkboxElement.tsx @@ -68,6 +68,7 @@ const CheckboxElement = (props: Props) => { const {lastAddedBlock} = cardDetail if (title === '' && block.id === lastAddedBlock.id && lastAddedBlock.autoAdded && props.onDeleteElement) { props.onDeleteElement() + return } @@ -77,6 +78,7 @@ const CheckboxElement = (props: Props) => { // Wait for the change to happen setTimeout(props.onAddElement, 100) } + return } diff --git a/webapp/boards/src/components/content/contentElement.test.tsx b/webapp/boards/src/components/content/contentElement.test.tsx index 18cc909ac5..62897cdd54 100644 --- a/webapp/boards/src/components/content/contentElement.test.tsx +++ b/webapp/boards/src/components/content/contentElement.test.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React, {ReactElement, ReactNode} from 'react' - import {render} from '@testing-library/react' import {wrapIntl} from 'src/testUtils' @@ -53,7 +52,7 @@ describe('components/content/contentElement', () => { }) it('should return null for unknown type', () => { - jest.spyOn(console, 'error').mockImplementation() + jest.spyOn(console, 'error').mockImplementation() const block: ContentBlock = {...contentBlock, type: 'unknown'} const {container} = render(wrap( diff --git a/webapp/boards/src/components/content/contentElement.tsx b/webapp/boards/src/components/content/contentElement.tsx index 0d58c0e111..475fb81612 100644 --- a/webapp/boards/src/components/content/contentElement.tsx +++ b/webapp/boards/src/components/content/contentElement.tsx @@ -30,6 +30,7 @@ export default function ContentElement(props: Props): JSX.Element|null { const handler = contentRegistry.getHandler(block.type) if (!handler) { Utils.logError(`ContentElement, unknown content type: ${block.type}`) + return null } diff --git a/webapp/boards/src/components/content/contentRegistry.tsx b/webapp/boards/src/components/content/contentRegistry.tsx index d0836bcc54..84b38b5582 100644 --- a/webapp/boards/src/components/content/contentRegistry.tsx +++ b/webapp/boards/src/components/content/contentRegistry.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -/* eslint-disable react/require-optimization */ + import {IntlShape} from 'react-intl' import {BlockTypes} from 'src/blocks/block' @@ -25,6 +25,7 @@ class ContentRegistry { registerContentType(entry: ContentHandler) { if (this.isContentType(entry.type)) { Utils.logError(`registerContentType, already registered type: ${entry.type}`) + return } this.registry.set(entry.type, entry) diff --git a/webapp/boards/src/components/content/textElement.test.tsx b/webapp/boards/src/components/content/textElement.test.tsx index 2cac748982..b9979050a0 100644 --- a/webapp/boards/src/components/content/textElement.test.tsx +++ b/webapp/boards/src/components/content/textElement.test.tsx @@ -2,15 +2,14 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, act} from '@testing-library/react' +import {act, render} from '@testing-library/react' import {Provider as ReduxProvider} from 'react-redux' - import {mocked} from 'jest-mock' import {TextBlock} from 'src/blocks/textBlock' -import {mockDOM, wrapDNDIntl, mockStateStore} from 'src/testUtils' +import {mockDOM, mockStateStore, wrapDNDIntl} from 'src/testUtils' import {Utils} from 'src/utils' diff --git a/webapp/boards/src/components/contentBlock.test.tsx b/webapp/boards/src/components/contentBlock.test.tsx index 0991f3ae47..e6b97f357e 100644 --- a/webapp/boards/src/components/contentBlock.test.tsx +++ b/webapp/boards/src/components/contentBlock.test.tsx @@ -3,7 +3,7 @@ import {act, render, screen} from '@testing-library/react' -import React, {ReactNode, ReactElement} from 'react' +import React, {ReactElement, ReactNode} from 'react' import {mocked} from 'jest-mock' import {Provider as ReduxProvider} from 'react-redux' @@ -11,7 +11,7 @@ import userEvent from '@testing-library/user-event' import {Utils} from 'src/utils' import {TestBlockFactory} from 'src/test/testBlockFactory' -import {mockDOM, wrapDNDIntl, mockStateStore} from 'src/testUtils' +import {mockDOM, mockStateStore, wrapDNDIntl} from 'src/testUtils' import mutator from 'src/mutator' diff --git a/webapp/boards/src/components/createBoardFromTemplate.test.tsx b/webapp/boards/src/components/createBoardFromTemplate.test.tsx index cd83ce56b4..3655ed623a 100644 --- a/webapp/boards/src/components/createBoardFromTemplate.test.tsx +++ b/webapp/boards/src/components/createBoardFromTemplate.test.tsx @@ -6,13 +6,12 @@ import {act, render, screen} from '@testing-library/react' import userEvent from '@testing-library/user-event' -import {mockStateStore} from 'src/testUtils' -import {wrapIntl} from 'src/testUtils' +import {mockStateStore, wrapIntl} from 'src/testUtils' import CreateBoardFromTemplate from './createBoardFromTemplate' jest.mock('src/hooks/useGetAllTemplates', () => ({ - useGetAllTemplates: () => [{id: 'id', title: 'title', description: 'description', icon: '🍔'}] + useGetAllTemplates: () => [{id: 'id', title: 'title', description: 'description', icon: '🍔'}], })) describe('components/createBoardFromTemplate', () => { @@ -26,7 +25,7 @@ describe('components/createBoardFromTemplate', () => { const store = mockStateStore([], state) const setCanCreate = jest.fn const setAction = jest.fn - const newBoardInfoIcon = () + const newBoardInfoIcon = () const {container} = render(wrapIntl( @@ -41,11 +40,11 @@ describe('components/createBoardFromTemplate', () => { expect(container).toMatchSnapshot() }) - it('clicking checkbox toggles the templates selector', async () => { + it.only('clicking checkbox toggles the templates selector', async () => { const store = mockStateStore([], state) const setCanCreate = jest.fn const setAction = jest.fn - const newBoardInfoIcon = () + const newBoardInfoIcon = () render(wrapIntl( diff --git a/webapp/boards/src/components/createBoardFromTemplate.tsx b/webapp/boards/src/components/createBoardFromTemplate.tsx index b0ec3181c9..aa5da3fc55 100644 --- a/webapp/boards/src/components/createBoardFromTemplate.tsx +++ b/webapp/boards/src/components/createBoardFromTemplate.tsx @@ -4,19 +4,19 @@ import React, { useCallback, useEffect, useRef, - useState + useState, } from 'react' -import {createIntl, createIntlCache, IntlProvider} from 'react-intl' +import {IntlProvider, createIntl, createIntlCache} from 'react-intl' import Select from 'react-select/async' import { - components, FormatOptionLabelMeta, GroupBase, - PlaceholderProps + PlaceholderProps, + SingleValue, + components, } from 'react-select' -import {SingleValue} from 'react-select' import {CSSObject} from '@emotion/serialize' @@ -49,7 +49,7 @@ const TEMPLATE_DESCRIPTION_LENGTH = 70 const cache = createIntlCache() const intl = createIntl({ locale: getCurrentLanguage(), - messages: getMessages(getCurrentLanguage()) + messages: getMessages(getCurrentLanguage()), }, cache) const {ValueContainer, Placeholder} = components @@ -60,7 +60,7 @@ const CustomValueContainer = ({children, ...props}: any) => { {props.selectProps.placeholder} {React.Children.map(children, (child) => - child && child.type !== Placeholder ? child : null + (child && child.type !== Placeholder ? child : null) )} ) @@ -78,7 +78,6 @@ const CreateBoardFromTemplate = (props: Props) => { const templateIdRef = useRef('') templateIdRef.current = selectedBoardTemplateId - const showNewBoardTemplateSelector = async () => { setAddBoard((prev: boolean) => !prev) } @@ -86,14 +85,14 @@ const CreateBoardFromTemplate = (props: Props) => { // CreateBoardFromTemplate const addBoardToChannel = async (channelId: string, teamId: string) => { if (!addBoardRef.current || !templateIdRef.current) { - return + return undefined } const ACTION_DESCRIPTION = 'board created from channel' const LINKED_CHANNEL = 'linked channel' const asTemplate = false - let boardsAndBlocks = undefined + let boardsAndBlocks if (templateIdRef.current === EMPTY_BOARD) { boardsAndBlocks = await mutator.addEmptyBoard(teamId, intl) @@ -102,7 +101,8 @@ const CreateBoardFromTemplate = (props: Props) => { } const board = boardsAndBlocks.boards[0] - await mutator.updateBoard({...board, channelId: channelId}, board, LINKED_CHANNEL) + await mutator.updateBoard({...board, channelId}, board, LINKED_CHANNEL) + return board } @@ -127,6 +127,7 @@ const CreateBoardFromTemplate = (props: Props) => { if (wordBreakingIndex === -1) { return str } + return `${str.substring(0, (len + wordBreakingIndex))}…` } @@ -143,6 +144,7 @@ const CreateBoardFromTemplate = (props: Props) => { // do not show the description for the selected option so the input only show the icon and title of the template const selectedOption = id === optionLabel.selectValue[0]?.id + return (
    @@ -176,8 +178,9 @@ const CreateBoardFromTemplate = (props: Props) => { templates.push(emptyBoard) if (value !== '') { - templates = templates.filter(template => template.title.toLowerCase().includes(value.toLowerCase())) + templates = templates.filter((template) => template.title.toLowerCase().includes(value.toLowerCase())) } + return templates }, [allTemplates]) @@ -202,10 +205,11 @@ const CreateBoardFromTemplate = (props: Props) => { }), valueContainer: (baseStyles: CSSObject): CSSObject => ({ ...baseStyles, - overflow: 'visible' + overflow: 'visible', }), placeholder: (baseStyles: CSSObject, state: PlaceholderProps>): CSSObject => { const modifyPlaceholder = state.selectProps.menuIsOpen || (!state.selectProps.menuIsOpen && state.hasValue) + return { ...baseStyles, position: 'absolute', @@ -257,12 +261,13 @@ const CreateBoardFromTemplate = (props: Props) => { const IntlCreateBoardFromTemplate = (props: Props) => { const language = useAppSelector(getLanguage) + return ( - + ) } diff --git a/webapp/boards/src/components/createCategory/createCategory.tsx b/webapp/boards/src/components/createCategory/createCategory.tsx index 61ec3dc714..ddfc935501 100644 --- a/webapp/boards/src/components/createCategory/createCategory.tsx +++ b/webapp/boards/src/components/createCategory/createCategory.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, KeyboardEvent} from 'react' +import React, {KeyboardEvent, useState} from 'react' import {useIntl} from 'react-intl' @@ -49,6 +49,7 @@ const CreateCategory = (props: Props): JSX.Element => { const onCreate = async (categoryName: string) => { if (!me) { Utils.logError('me not initialized') + return } diff --git a/webapp/boards/src/components/error_boundary.tsx b/webapp/boards/src/components/error_boundary.tsx index 5b9ba178aa..2a9c759e9d 100644 --- a/webapp/boards/src/components/error_boundary.tsx +++ b/webapp/boards/src/components/error_boundary.tsx @@ -38,8 +38,10 @@ export default class ErrorBoundary extends React.Component { render(): React.ReactNode { if (this.state.hasError) { this.handleError() + return {this.msg} } + return this.props.children } } diff --git a/webapp/boards/src/components/flashMessages.test.tsx b/webapp/boards/src/components/flashMessages.test.tsx index ca3508451c..7ecc9f0141 100644 --- a/webapp/boards/src/components/flashMessages.test.tsx +++ b/webapp/boards/src/components/flashMessages.test.tsx @@ -4,17 +4,12 @@ import React from 'react' import { - render, act, + fireEvent, + render, screen, - fireEvent } from '@testing-library/react' - - - - - import {wrapIntl} from 'src/testUtils' import FlashMessages, {sendFlashMessage} from './flashMessages' diff --git a/webapp/boards/src/components/flashMessages.tsx b/webapp/boards/src/components/flashMessages.tsx index 7efe7fd2ee..d7c6d635de 100644 --- a/webapp/boards/src/components/flashMessages.tsx +++ b/webapp/boards/src/components/flashMessages.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect} from 'react' +import React, {useEffect, useState} from 'react' import {createNanoEvents} from 'nanoevents' import './flashMessages.scss' @@ -37,6 +37,7 @@ const FlashMessages = (props: Props) => { setMessage(newMessage) } }) + return () => { isSubscribed = false } diff --git a/webapp/boards/src/components/gallery/gallery.test.tsx b/webapp/boards/src/components/gallery/gallery.test.tsx index 98b40fc126..dbea5d77b6 100644 --- a/webapp/boards/src/components/gallery/gallery.test.tsx +++ b/webapp/boards/src/components/gallery/gallery.test.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React from 'react' -import {render, screen, fireEvent} from '@testing-library/react' +import {fireEvent, render, screen} from '@testing-library/react' import {Provider as ReduxProvider} from 'react-redux' @@ -10,7 +10,7 @@ import userEvent from '@testing-library/user-event' import {mocked} from 'jest-mock' -import {wrapDNDIntl, mockStateStore, blocksById} from 'src/testUtils' +import {blocksById, mockStateStore, wrapDNDIntl} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' diff --git a/webapp/boards/src/components/gallery/gallery.tsx b/webapp/boards/src/components/gallery/gallery.tsx index b3656d23c6..3f08f9f7f6 100644 --- a/webapp/boards/src/components/gallery/gallery.tsx +++ b/webapp/boards/src/components/gallery/gallery.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useMemo, useCallback} from 'react' +import React, {useCallback, useMemo} from 'react' import {FormattedMessage} from 'react-intl' import {Constants, Permission} from 'src/constants' diff --git a/webapp/boards/src/components/gallery/galleryCard.test.tsx b/webapp/boards/src/components/gallery/galleryCard.test.tsx index 125cc84346..dbfed5e084 100644 --- a/webapp/boards/src/components/gallery/galleryCard.test.tsx +++ b/webapp/boards/src/components/gallery/galleryCard.test.tsx @@ -12,7 +12,7 @@ import {mocked} from 'jest-mock' import {MockStoreEnhanced} from 'redux-mock-store' -import {wrapDNDIntl, mockStateStore} from 'src/testUtils' +import {mockStateStore, wrapDNDIntl} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' diff --git a/webapp/boards/src/components/gallery/galleryCard.tsx b/webapp/boards/src/components/gallery/galleryCard.tsx index 47fe71b79b..8e9fe732e0 100644 --- a/webapp/boards/src/components/gallery/galleryCard.tsx +++ b/webapp/boards/src/components/gallery/galleryCard.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useMemo, useState, useCallback} from 'react' -import {useIntl, FormattedMessage} from 'react-intl' +import React, {useCallback, useMemo, useState} from 'react' +import {FormattedMessage, useIntl} from 'react-intl' import {Board, IPropertyTemplate} from 'src/blocks/board' import {Card} from 'src/blocks/card' @@ -68,6 +68,7 @@ const GalleryCard = (props: Props) => { return contents[i] as ContentBlock } } + return undefined }, [contents]) diff --git a/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.test.tsx b/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.test.tsx index 555b2de592..91b9068d5b 100644 --- a/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.test.tsx +++ b/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.test.tsx @@ -14,7 +14,7 @@ import {mocked} from 'jest-mock' import {wrapIntl} from 'src/testUtils' -import TelemetryClient, {TelemetryCategory, TelemetryActions} from 'src/telemetry/telemetryClient' +import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' import client from 'src/octoClient' diff --git a/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.tsx b/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.tsx index bc0c7c3b4b..acfdaeeba2 100644 --- a/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.tsx +++ b/webapp/boards/src/components/globalHeader/globalHeaderSettingsMenu.tsx @@ -9,8 +9,8 @@ import Menu from 'src/widgets/menu' import MenuWrapper from 'src/widgets/menuWrapper' import {useAppDispatch, useAppSelector} from 'src/store/hooks' import {storeLanguage} from 'src/store/language' -import {patchProps, getMe} from 'src/store/users' -import {getCurrentTeam, Team} from 'src/store/teams' +import {getMe, patchProps} from 'src/store/users' +import {Team, getCurrentTeam} from 'src/store/teams' import {IUser, UserConfigPatch} from 'src/user' import octoClient from 'src/octoClient' import {UserSettings} from 'src/userSettings' @@ -18,7 +18,7 @@ import CheckIcon from 'src/widgets/icons/check' import SettingsIcon from 'src/widgets/icons/settings' import {Constants} from 'src/constants' -import TelemetryClient, {TelemetryCategory, TelemetryActions} from 'src/telemetry/telemetryClient' +import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' import './globalHeaderSettingsMenu.scss' diff --git a/webapp/boards/src/components/hiddenCardCount/hiddenCardCount.tsx b/webapp/boards/src/components/hiddenCardCount/hiddenCardCount.tsx index ace0cb7284..cd6339cfee 100644 --- a/webapp/boards/src/components/hiddenCardCount/hiddenCardCount.tsx +++ b/webapp/boards/src/components/hiddenCardCount/hiddenCardCount.tsx @@ -19,6 +19,7 @@ const HiddenCardCount = (props: Props): JSX.Element => { const onClickHandler = () => { props.showHiddenCardNotification(true) } + return (
    { return } - (optionsByType.get(property.type) || []). - forEach((typeOption) => { + (optionsByType.get(property.type) || []) + .forEach((typeOption) => { options.push({ ...typeOption, cardProperties: props.cardProperties, diff --git a/webapp/boards/src/components/kanban/calculation/kanbanOption.tsx b/webapp/boards/src/components/kanban/calculation/kanbanOption.tsx index 65dfd22942..b0fee41b83 100644 --- a/webapp/boards/src/components/kanban/calculation/kanbanOption.tsx +++ b/webapp/boards/src/components/kanban/calculation/kanbanOption.tsx @@ -34,12 +34,12 @@ const Option = (props: {data: OptionProps}): JSX.Element => { if (!calculationToProperties.get(props.data.value)) { const supportedPropertyTypes = new Map([]) if (typesByOptions.get(props.data.value)) { - (typesByOptions.get(props.data.value) || []). - forEach((propertyType) => supportedPropertyTypes.set(propertyType, true)) + (typesByOptions.get(props.data.value) || []) + .forEach((propertyType) => supportedPropertyTypes.set(propertyType, true)) } - const supportedProperties = props.data.cardProperties. - filter((property) => supportedPropertyTypes.get(property.type) || supportedPropertyTypes.get('common')) + const supportedProperties = props.data.cardProperties + .filter((property) => supportedPropertyTypes.get(property.type) || supportedPropertyTypes.get('common')) calculationToProperties.set(props.data.value, supportedProperties) setCalculationToProperties(calculationToProperties) diff --git a/webapp/boards/src/components/kanban/kanban.test.tsx b/webapp/boards/src/components/kanban/kanban.test.tsx index 0d83135d33..02372ef223 100644 --- a/webapp/boards/src/components/kanban/kanban.test.tsx +++ b/webapp/boards/src/components/kanban/kanban.test.tsx @@ -5,7 +5,7 @@ import { fireEvent, render, screen, - waitFor + waitFor, } from '@testing-library/react' import React from 'react' import {Provider as ReduxProvider} from 'react-redux' @@ -447,7 +447,7 @@ describe('src/component/kanban/kanban', () => { }) // TODO: fix this test: Mutator spyOn issue - // eslint-disable-next-line no-only-tests/no-only-tests + test.skip('return kanban and change title on KanbanColumnHeader', async () => { const user = userEvent.setup() const {container} = render(wrapDNDIntl( @@ -498,7 +498,7 @@ describe('src/component/kanban/kanban', () => { }) // TODO: fix this test: Mutator spyOn issue - // eslint-disable-next-line no-only-tests/no-only-tests + test.skip('return kanban and add a group', async () => { render(wrapDNDIntl( diff --git a/webapp/boards/src/components/kanban/kanban.tsx b/webapp/boards/src/components/kanban/kanban.tsx index a1e15c9334..17ea9ff6e1 100644 --- a/webapp/boards/src/components/kanban/kanban.tsx +++ b/webapp/boards/src/components/kanban/kanban.tsx @@ -1,11 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -/* eslint-disable max-lines */ + import React, { useCallback, - useState, + useEffect, useMemo, - useEffect + useState, } from 'react' import {FormattedMessage} from 'react-intl' @@ -17,14 +17,14 @@ import {Position} from 'src/components/cardDetail/cardDetailContents' import { Board, + BoardGroup, IPropertyOption, IPropertyTemplate, - BoardGroup } from 'src/blocks/board' import {Card} from 'src/blocks/card' import {BoardView} from 'src/blocks/boardView' import mutator from 'src/mutator' -import {Utils, IDType} from 'src/utils' +import {IDType, Utils} from 'src/utils' import Button from 'src/widgets/buttons/button' import {Constants, Permission} from 'src/constants' @@ -114,6 +114,7 @@ const Kanban = (props: Props) => { cardOrder = cardOrder.filter((id) => !setOfIds.has(id)) const lastCardIndex = cardOrder.indexOf(lastCardId) cardOrder.splice(lastCardIndex + 1, 0, ...cardIds) + return cardOrder }, [activeView, visibleGroups]) @@ -130,6 +131,7 @@ const Kanban = (props: Props) => { await mutator.performAsUndoGroup(async () => { const cardsById: { [key: string]: Card } = cards.reduce((acc: { [key: string]: Card }, c: Card): { [key: string]: Card } => { acc[c.id] = c + return acc }, {}) const draggedCards: Card[] = draggedCardIds.map((o: string) => cardsById[o]).filter((c) => c) @@ -186,6 +188,7 @@ const Kanban = (props: Props) => { // Update dstCard order const cardsById: { [key: string]: Card } = cards.reduce((acc: { [key: string]: Card }, card: Card): { [key: string]: Card } => { acc[card.id] = card + return acc }, {}) const draggedCards: Card[] = draggedCardIds.map((o: string) => cardsById[o]).filter((c) => c) @@ -223,6 +226,7 @@ const Kanban = (props: Props) => { if (!groupByProperty) { Utils.assertFailure('Board views must have groupByProperty set') + return
    } diff --git a/webapp/boards/src/components/kanban/kanbanCard.tsx b/webapp/boards/src/components/kanban/kanbanCard.tsx index 074174a60a..eaf55c154d 100644 --- a/webapp/boards/src/components/kanban/kanbanCard.tsx +++ b/webapp/boards/src/components/kanban/kanbanCard.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useCallback, useMemo} from 'react' +import React, {useCallback, useMemo, useState} from 'react' import {useRouteMatch} from 'react-router-dom' import {useIntl} from 'react-intl' @@ -51,6 +51,7 @@ const KanbanCard = (props: Props) => { const handleDeleteCard = useCallback(() => { if (!card) { Utils.assertFailure() + return } TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DeleteCard, {board: board.id, card: card.id}) @@ -74,6 +75,7 @@ const KanbanCard = (props: Props) => { // confirmation dialog if (card?.title === '' && card?.fields?.contentOrder?.length === 0) { handleDeleteCard() + return } setShowConfirmationDialogBox(true) diff --git a/webapp/boards/src/components/kanban/kanbanColumn.tsx b/webapp/boards/src/components/kanban/kanbanColumn.tsx index 116abbdcbc..0d1c5b0fa9 100644 --- a/webapp/boards/src/components/kanban/kanbanColumn.tsx +++ b/webapp/boards/src/components/kanban/kanbanColumn.tsx @@ -28,6 +28,7 @@ const KanbanColumn = (props: Props) => { if (isOver) { className += ' dragover' } + return (
    { )) expect(container).toMatchSnapshot() }) - test('return kanbanColumnHeader and edit title', async() => { + test('return kanbanColumnHeader and edit title', async () => { const mockedPropertyNameChanged = jest.fn() const {container} = render(wrapDNDIntl( diff --git a/webapp/boards/src/components/kanban/kanbanColumnHeader.tsx b/webapp/boards/src/components/kanban/kanbanColumnHeader.tsx index 5f2d6c1463..b3a90a1282 100644 --- a/webapp/boards/src/components/kanban/kanbanColumnHeader.tsx +++ b/webapp/boards/src/components/kanban/kanbanColumnHeader.tsx @@ -1,16 +1,16 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -/* eslint-disable max-lines */ -import React, {useState, useEffect, useRef} from 'react' + +import React, {useEffect, useRef, useState} from 'react' import {FormattedMessage, useIntl} from 'react-intl' -import {useDrop, useDrag} from 'react-dnd' +import {useDrag, useDrop} from 'react-dnd' import {Constants, Permission} from 'src/constants' import { + Board, + BoardGroup, IPropertyOption, IPropertyTemplate, - Board, - BoardGroup } from 'src/blocks/board' import {BoardView} from 'src/blocks/boardView' import {Card} from 'src/blocks/card' @@ -53,7 +53,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element { const intl = useIntl() const {board, activeView, group, groupByProperty} = props let readonly = props.readonly - if(!readonly){ + if (!readonly) { readonly = !useHasCurrentBoardPermissions([Permission.ManageBoardProperties]) } @@ -95,6 +95,7 @@ export default function KanbanColumnHeader(props: Props): JSX.Element { const groupCalculation = props.activeView.fields.kanbanCalculations[props.group.option.id] const calculationValue = groupCalculation ? groupCalculation.calculation : defaultCalculation const calculationProperty = groupCalculation ? props.board.cardProperties.find((property) => property.id === groupCalculation.propertyId) || defaultProperty : defaultProperty + return (
    { const isDelimiterBlock = i === 0 || i === codeBlockKeys.length - 1 const block = newContentState.getBlockForKey(blockKey) const newBlockMap = newContentState.getBlockMap() - const data = block. - getData(). - merge({language: isDelimiterBlock ? undefined : language}) + const data = block + .getData() + .merge({language: isDelimiterBlock ? undefined : language}) const newBlock = block.merge({data}) as ContentBlock newContentState = newContentState.merge({ blockMap: newBlockMap.set(blockKey, newBlock), diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/boldStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/boldStyleStrategy.ts index acc74d6bec..443af56a4c 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/boldStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/boldStyleStrategy.ts @@ -23,6 +23,7 @@ const createBoldStyleStrategy = (): InlineStrategy => { // e.g. [[0,6], [10,20]] const text = block.getText() const boldRanges = findRangesWithRegex(text, boldRegex) + return boldRanges }, findDelimiterRanges: (block, styleRanges) => { @@ -37,6 +38,7 @@ const createBoldStyleStrategy = (): InlineStrategy => { ).map((indices) => indices.map((x) => x + styleRange[0])) boldDelimiterRanges = boldDelimiterRanges.concat(delimiterRange) }) + return boldDelimiterRanges }, delimiterStyles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/headingDelimiterStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/headingDelimiterStyleStrategy.ts index 2b62c06085..47e87e47fd 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/headingDelimiterStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/headingDelimiterStyleStrategy.ts @@ -19,6 +19,7 @@ const createHeadingDelimiterStyleStrategy = (): InlineStrategy => { text, headingDelimiterRegex, ) + return headingDelimiterRanges }, styles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/inlineCodeStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/inlineCodeStyleStrategy.ts index 4929176af2..eaf02f5a68 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/inlineCodeStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/inlineCodeStyleStrategy.ts @@ -16,6 +16,7 @@ const createInlineCodeStyleStrategy = (): InlineStrategy => { const text = block.getText() const codeRanges = findRangesWithRegex(text, codeRegex) + return codeRanges }, styles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/italicStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/italicStyleStrategy.ts index 849323f8ec..4da9d0016e 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/italicStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/italicStyleStrategy.ts @@ -39,6 +39,7 @@ const createItalicStyleStrategy = (): InlineStrategy => { // e.g. [[0,6], [10,20]] const text = block.getText() const italicRanges = findRangesWithRegex(text, italicRegex) + return italicRanges }, findDelimiterRanges: (block, styleRanges) => { @@ -53,6 +54,7 @@ const createItalicStyleStrategy = (): InlineStrategy => { ).map((indices) => indices.map((x) => x + styleRange[0])) italicDelimiterRanges = italicDelimiterRanges.concat(delimiterRange) }) + return italicDelimiterRanges }, delimiterStyles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/olDelimiterStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/olDelimiterStyleStrategy.ts index eb972b5110..22077cb33b 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/olDelimiterStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/olDelimiterStyleStrategy.ts @@ -11,6 +11,7 @@ const createOLDelimiterStyleStrategy = (): InlineStrategy => { findStyleRanges: (block) => { const text = block.getText() const olDelimiterRanges = findRangesWithRegex(text, olDelimiterRegex) + return olDelimiterRanges }, styles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/quoteStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/quoteStyleStrategy.ts index 8c992d05f8..3ef0159ebd 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/quoteStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/quoteStyleStrategy.ts @@ -13,6 +13,7 @@ const createQuoteStyleStrategy = (): InlineStrategy => { findStyleRanges: (block) => { const text = block.getText() const quoteRanges = findRangesWithRegex(text, quoteRegex) + return quoteRanges }, findDelimiterRanges: (block, styleRanges) => { @@ -25,6 +26,7 @@ const createQuoteStyleStrategy = (): InlineStrategy => { ).map((indices) => indices.map((x) => x + styleRange[0])) quoteDelimiterRanges = quoteDelimiterRanges.concat(delimiterRange) }) + return quoteDelimiterRanges }, styles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/strikethroughStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/strikethroughStyleStrategy.ts index 89b0eca114..c8b810e7a2 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/strikethroughStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/strikethroughStyleStrategy.ts @@ -16,6 +16,7 @@ const createStrikethroughStyleStrategy = (): InlineStrategy => { // e.g. [[0,6], [10,20]] const text = block.getText() const strikethroughRanges = findRangesWithRegex(text, strikethroughRegex) + return strikethroughRanges }, findDelimiterRanges: (block, styleRanges) => { @@ -32,6 +33,7 @@ const createStrikethroughStyleStrategy = (): InlineStrategy => { delimiterRange, ) }) + return strikethroughDelimiterRanges }, styles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/inline-styles/ulDelimiterStyleStrategy.ts b/webapp/boards/src/components/live-markdown-plugin/inline-styles/ulDelimiterStyleStrategy.ts index 0dfe04d638..b1a2415d3b 100644 --- a/webapp/boards/src/components/live-markdown-plugin/inline-styles/ulDelimiterStyleStrategy.ts +++ b/webapp/boards/src/components/live-markdown-plugin/inline-styles/ulDelimiterStyleStrategy.ts @@ -11,6 +11,7 @@ const createULDelimiterStyleStrategy = (): InlineStrategy => { findStyleRanges: (block) => { const text = block.getText() const ulDelimiterRanges = findRangesWithRegex(text, ulDelimiterRegex) + return ulDelimiterRanges }, styles: { diff --git a/webapp/boards/src/components/live-markdown-plugin/liveMarkdownPlugin.ts b/webapp/boards/src/components/live-markdown-plugin/liveMarkdownPlugin.ts index afcb2bd02a..aa49c1211e 100644 --- a/webapp/boards/src/components/live-markdown-plugin/liveMarkdownPlugin.ts +++ b/webapp/boards/src/components/live-markdown-plugin/liveMarkdownPlugin.ts @@ -1,15 +1,15 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import { - EditorState, CharacterMetadata, - ContentState, ContentBlock, - EditorChangeType, + ContentState, DraftStyleMap, + EditorChangeType, + EditorState, } from 'draft-js' import {EditorPlugin} from '@draft-js-plugins/editor' -import {Repeat, List} from 'immutable' +import {List, Repeat} from 'immutable' // Inline style handlers import createBoldStyleStrategy from './inline-styles/boldStyleStrategy' @@ -64,10 +64,12 @@ function createLiveMarkdownPlugin(config: LiveMarkdownPluginConfig = {}): Editor // Construct the block style fn const blockStyleMap = blockTypeStrategies.reduce((map: Record, blockStrategy) => { map[blockStrategy.type] = blockStrategy.className + return map }, {}) const blockStyleFn = (block: ContentBlock) => { const blockType = block.getType() + return blockStyleMap[blockType] } @@ -257,6 +259,7 @@ const applyStyleRangesToCharacterMetadata = ( styledCharacterMetadataList = styledCharacterMetadataList.set(i, styled) } }) + return styledCharacterMetadataList } diff --git a/webapp/boards/src/components/markdownEditor.test.tsx b/webapp/boards/src/components/markdownEditor.test.tsx index 86c7247d61..a1b37c8f93 100644 --- a/webapp/boards/src/components/markdownEditor.test.tsx +++ b/webapp/boards/src/components/markdownEditor.test.tsx @@ -4,7 +4,7 @@ import {fireEvent, render, screen} from '@testing-library/react' import React from 'react' import {Provider as ReduxProvider} from 'react-redux' -import {mockDOM, wrapDNDIntl, mockStateStore} from 'src/testUtils' +import {mockDOM, mockStateStore, wrapDNDIntl} from 'src/testUtils' import {TestBlockFactory} from 'src/test/testBlockFactory' diff --git a/webapp/boards/src/components/markdownEditor.tsx b/webapp/boards/src/components/markdownEditor.tsx index 4910504b45..446287f524 100644 --- a/webapp/boards/src/components/markdownEditor.tsx +++ b/webapp/boards/src/components/markdownEditor.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, Suspense} from 'react' +import React, {Suspense, useState} from 'react' import {Utils} from 'src/utils' import './markdownEditor.scss' @@ -38,6 +38,7 @@ const MarkdownEditor = (props: Props): JSX.Element => { const element = e.target as Element if (element.tagName.toLowerCase() === LINK_TAG_NAME) { e.stopPropagation() + return } @@ -50,7 +51,7 @@ const MarkdownEditor = (props: Props): JSX.Element => { const editorOnBlur = (newText: string) => { setIsEditing(false) - onBlur && onBlur(newText) + onBlur?.(newText) } const editorElement = ( diff --git a/webapp/boards/src/components/markdownEditorInput/markdownEditorInput.tsx b/webapp/boards/src/components/markdownEditorInput/markdownEditorInput.tsx index 551861ac23..8900d4e39e 100644 --- a/webapp/boards/src/components/markdownEditorInput/markdownEditorInput.tsx +++ b/webapp/boards/src/components/markdownEditorInput/markdownEditorInput.tsx @@ -9,7 +9,7 @@ import { ContentState, DraftHandleValue, EditorState, - getDefaultKeyBinding + getDefaultKeyBinding, } from 'draft-js' import React, { ReactElement, @@ -17,7 +17,7 @@ import React, { useEffect, useMemo, useRef, - useState + useState, } from 'react' import {debounce} from 'lodash' @@ -86,8 +86,8 @@ const MarkdownEditorInput = (props: Props): ReactElement => { const excludeBots = true users = await octoClient.searchTeamUsers(term, excludeBots) } else { - users = boardUsers. - filter((user) => { + users = boardUsers + .filter((user) => { // no search term if (!term) { return true @@ -95,10 +95,10 @@ const MarkdownEditorInput = (props: Props): ReactElement => { // does the search term occur anywhere in the display name? return Utils.getUserDisplayName(user, clientConfig.teammateNameDisplay).includes(term) - }). + }) // first 10 results - slice(0, 10) + .slice(0, 10) } const mentions: MentionUser[] = users.map( @@ -124,6 +124,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => { const generateEditorState = (text?: string) => { const state = EditorState.createWithContent(ContentState.createFromText(text || '')) + return EditorState.moveSelectionToEnd(state) } @@ -188,6 +189,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => { emojiPlugin, markdownPlugin, ] + return {plugins, MentionSuggestions, EmojiSuggestions} }, []) @@ -195,7 +197,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => { // newEditorState. const newText = newEditorState.getCurrentContent().getPlainText() - onChange && onChange(newText) + onChange?.(newText) setEditorState(newEditorState) }, [onChange]) @@ -226,6 +228,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => { const handleKeyCommand = useCallback((command: string, currentState: EditorState): DraftHandleValue => { if (command === 'editor-blur') { ref.current?.blur() + return 'handled' } @@ -246,6 +249,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => { if (command === 'backspace') { if (props.onEditorCancel && editorState.getCurrentContent().getPlainText().length === 0) { props.onEditorCancel() + return 'handled' } } @@ -258,7 +262,7 @@ const MarkdownEditorInput = (props: Props): ReactElement => { return } const text = editorState.getCurrentContent().getPlainText() - onBlur && onBlur(text) + onBlur?.(text) }, [editorState.getCurrentContent().getPlainText(), onBlur, confirmAddUser]) const onMentionPopoverOpenChange = useCallback((open: boolean) => { @@ -282,9 +286,11 @@ const MarkdownEditorInput = (props: Props): ReactElement => { const handleReturn = (e: any, state: EditorState): DraftHandleValue => { if (!e.shiftKey) { const text = state.getCurrentContent().getPlainText() - onBlur && onBlur(text) + onBlur?.(text) + return 'handled' } + return 'not-handled' } diff --git a/webapp/boards/src/components/messages/versionMessage.tsx b/webapp/boards/src/components/messages/versionMessage.tsx index 7073a35c61..6ed76fd853 100644 --- a/webapp/boards/src/components/messages/versionMessage.tsx +++ b/webapp/boards/src/components/messages/versionMessage.tsx @@ -2,25 +2,25 @@ // See LICENSE.txt for license information. import React from 'react' -import {useIntl, FormattedMessage} from 'react-intl' +import {FormattedMessage, useIntl} from 'react-intl' import IconButton from 'src/widgets/buttons/iconButton' import Button from 'src/widgets/buttons/button' import CloseIcon from 'src/widgets/icons/close' -import {useAppSelector, useAppDispatch} from 'src/store/hooks' +import {useAppDispatch, useAppSelector} from 'src/store/hooks' import octoClient from 'src/octoClient' import {IUser, UserConfigPatch} from 'src/user' import { getMe, - patchProps, getVersionMessageCanceled, - versionProperty + patchProps, + versionProperty, } from 'src/store/users' import CompassIcon from 'src/widgets/icons/compassIcon' -import TelemetryClient, {TelemetryCategory, TelemetryActions} from 'src/telemetry/telemetryClient' +import TelemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' import './versionMessage.scss' const helpURL = 'https://mattermost.com/pl/whats-new-boards/' diff --git a/webapp/boards/src/components/modal.tsx b/webapp/boards/src/components/modal.tsx index 65826ff5bd..bd8ce7a7e8 100644 --- a/webapp/boards/src/components/modal.tsx +++ b/webapp/boards/src/components/modal.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useRef, useEffect, useCallback} from 'react' +import React, {useCallback, useEffect, useRef} from 'react' import IconButton from 'src/widgets/buttons/iconButton' import CloseIcon from 'src/widgets/icons/close' @@ -26,6 +26,7 @@ const Modal = (props: Props): JSX.Element => { useEffect(() => { document.addEventListener('click', closeOnBlur, true) + return () => { document.removeEventListener('click', closeOnBlur, true) } diff --git a/webapp/boards/src/components/newVersionBanner.tsx b/webapp/boards/src/components/newVersionBanner.tsx index a17b037302..b1a5cb1fad 100644 --- a/webapp/boards/src/components/newVersionBanner.tsx +++ b/webapp/boards/src/components/newVersionBanner.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect} from 'react' +import React, {useEffect, useState} from 'react' import {FormattedMessage} from 'react-intl' import wsClient from 'src/wsclient' diff --git a/webapp/boards/src/components/onboardingTour/addProperties/add_properties.tsx b/webapp/boards/src/components/onboardingTour/addProperties/add_properties.tsx index 6cdaddc960..8d14955373 100644 --- a/webapp/boards/src/components/onboardingTour/addProperties/add_properties.tsx +++ b/webapp/boards/src/components/onboardingTour/addProperties/add_properties.tsx @@ -13,7 +13,7 @@ import { BaseTourSteps, CardTourSteps, TOUR_BASE, - TOUR_CARD + TOUR_CARD, } from 'src/components/onboardingTour/index' import TourTipRenderer from 'src/components/onboardingTour/tourTipRenderer/tourTipRenderer' import {OnboardingBoardTitle, OnboardingCardTitle} from 'src/components/cardDetail/cardDetail' diff --git a/webapp/boards/src/components/onboardingTour/sidebarCategories/sidebarCategories.tsx b/webapp/boards/src/components/onboardingTour/sidebarCategories/sidebarCategories.tsx index 1bc791de8e..cc71c8f5de 100644 --- a/webapp/boards/src/components/onboardingTour/sidebarCategories/sidebarCategories.tsx +++ b/webapp/boards/src/components/onboardingTour/sidebarCategories/sidebarCategories.tsx @@ -9,10 +9,10 @@ import {FormattedMessage} from 'react-intl' import {useMeasurePunchouts} from 'src/components/tutorial_tour_tip/hooks' import TourTipRenderer from 'src/components/onboardingTour/tourTipRenderer/tourTipRenderer' import { + FINISHED, + SidebarTourSteps, TOUR_BOARD, TOUR_SIDEBAR, - SidebarTourSteps, - FINISHED } from 'src/components/onboardingTour/index' import {useAppDispatch, useAppSelector} from 'src/store/hooks' import { diff --git a/webapp/boards/src/components/permissions/boardPermissionGate.test.tsx b/webapp/boards/src/components/permissions/boardPermissionGate.test.tsx index da6344f7f9..355b868f31 100644 --- a/webapp/boards/src/components/permissions/boardPermissionGate.test.tsx +++ b/webapp/boards/src/components/permissions/boardPermissionGate.test.tsx @@ -5,11 +5,10 @@ import React from 'react' import {render} from '@testing-library/react' import {Provider as ReduxProvider} from 'react-redux' - import {TestBlockFactory} from 'src/test/testBlockFactory' import {Permission} from 'src/constants' -import {wrapIntl, mockStateStore} from 'src/testUtils' +import {mockStateStore, wrapIntl} from 'src/testUtils' import BoardPermissionGate from './boardPermissionGate' diff --git a/webapp/boards/src/components/permissions/boardPermissionGate.tsx b/webapp/boards/src/components/permissions/boardPermissionGate.tsx index f45102478d..02cce02c6b 100644 --- a/webapp/boards/src/components/permissions/boardPermissionGate.tsx +++ b/webapp/boards/src/components/permissions/boardPermissionGate.tsx @@ -33,6 +33,7 @@ const BoardPermissionGate = (props: Props): React.ReactElement|null => { if (allowed) { return (<>{props.children}) } + return null } diff --git a/webapp/boards/src/components/personSelector.test.tsx b/webapp/boards/src/components/personSelector.test.tsx index 8b925cbb91..57bd154f5e 100644 --- a/webapp/boards/src/components/personSelector.test.tsx +++ b/webapp/boards/src/components/personSelector.test.tsx @@ -8,7 +8,6 @@ import {render, waitFor} from '@testing-library/react' import configureStore from 'redux-mock-store' - import userEvent from '@testing-library/user-event' import {wrapIntl} from 'src/testUtils' @@ -95,6 +94,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) expect(container).toMatchSnapshot() @@ -129,6 +129,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) expect(container).toMatchSnapshot() @@ -156,6 +157,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) expect(container).toMatchSnapshot() @@ -198,6 +200,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) expect(container).toMatchSnapshot() @@ -234,6 +237,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) expect(container).toMatchSnapshot() @@ -260,6 +264,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) expect(container).toMatchSnapshot() @@ -303,6 +308,7 @@ describe('properties/person', () => { if (!renderResult.container) { return Promise.reject(new Error('container not found')) } + return Promise.resolve(renderResult.container) }) @@ -312,7 +318,7 @@ describe('properties/person', () => { // opening of the dropdown const userProperty = container.querySelector('.Person > div > div:nth-child(1) > div:nth-child(2) > input') expect(userProperty).not.toBeNull() - + await userEvent.click(userProperty as Element) const userList = container.querySelector('.Person-item') diff --git a/webapp/boards/src/components/personSelector.tsx b/webapp/boards/src/components/personSelector.tsx index 1c620b0cd0..eb20c919bb 100644 --- a/webapp/boards/src/components/personSelector.tsx +++ b/webapp/boards/src/components/personSelector.tsx @@ -140,6 +140,7 @@ const PersonSelector = (props: Props): JSX.Element => { u.nickname.toLowerCase().includes(value.toLowerCase()) }) } + return returnUsers } const excludeBots = true @@ -153,6 +154,7 @@ const PersonSelector = (props: Props): JSX.Element => { usersOutsideBoard.push(u) } } + return [ {label: intl.formatMessage({id: 'PersonProperty.board-members', defaultMessage: 'Board members'}), options: usersInsideBoard}, {label: intl.formatMessage({id: 'PersonProperty.non-board-members', defaultMessage: 'Not board members'}), options: usersOutsideBoard}, diff --git a/webapp/boards/src/components/propertyValueElement.test.tsx b/webapp/boards/src/components/propertyValueElement.test.tsx index b3b3d8d729..cde524f092 100644 --- a/webapp/boards/src/components/propertyValueElement.test.tsx +++ b/webapp/boards/src/components/propertyValueElement.test.tsx @@ -7,7 +7,7 @@ import userEvent from '@testing-library/user-event' import {wrapDNDIntl} from 'src/testUtils' import 'isomorphic-fetch' -import {IPropertyTemplate, IPropertyOption, Board} from 'src/blocks/board' +import {Board, IPropertyOption, IPropertyTemplate} from 'src/blocks/board' import {TestBlockFactory} from 'src/test/testBlockFactory' import {Card} from 'src/blocks/card' @@ -163,7 +163,7 @@ describe('components/propertyValueElement', () => { } const user = userEvent.setup() - + const component = wrapDNDIntl( { } const property = propsRegistry.get(propertyTemplate.type) const Editor = property.Editor + return ( { myBoardMemberships: { [board.id]: {userId: 'user_id_1', schemeAdmin: true}, }, - } + }, } board.updateAt = 1657311058157 board.title = 'Test board' @@ -37,7 +37,7 @@ describe('components/rhsChannelBoardItem', () => { const store = mockStateStore([], state) const {container} = render(wrapIntl( - + )) expect(container).toMatchSnapshot() @@ -57,7 +57,7 @@ describe('components/rhsChannelBoardItem', () => { myBoardMemberships: { [board.id]: {userId: 'user_id_1', schemeAdmin: true}, }, - } + }, } board.id = 'test_id' board.title = 'New board' @@ -66,7 +66,7 @@ describe('components/rhsChannelBoardItem', () => { const store = mockStateStore([], state) const {container} = render(wrapIntl( - + )) diff --git a/webapp/boards/src/components/rhsChannelBoardItem.tsx b/webapp/boards/src/components/rhsChannelBoardItem.tsx index cae3915d39..9b1eebc03b 100644 --- a/webapp/boards/src/components/rhsChannelBoardItem.tsx +++ b/webapp/boards/src/components/rhsChannelBoardItem.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react' +import React from 'react' import {FormattedMessage, useIntl} from 'react-intl' import {SuiteWindow} from 'src/types/index' @@ -8,7 +8,7 @@ import {SuiteWindow} from 'src/types/index' import mutator from 'src/mutator' import {Utils} from 'src/utils' import {getCurrentTeam} from 'src/store/teams' -import {createBoard, Board} from 'src/blocks/board' +import {Board, createBoard} from 'src/blocks/board' import {useAppSelector} from 'src/store/hooks' import IconButton from 'src/widgets/buttons/iconButton' import OptionsIcon from 'src/widgets/icons/options' @@ -55,6 +55,7 @@ const RHSChannelBoardItem = (props: Props) => { const untitledBoardTitle = intl.formatMessage({id: 'ViewTitle.untitled-board', defaultMessage: 'Untitled board'}) const markdownHtml = Utils.htmlFromMarkdown(description) + return (
    handleBoardClicked(id)} @@ -104,7 +105,8 @@ const RHSChannelBoardItem = (props: Props) => {
    -
    diff --git a/webapp/boards/src/components/rhsChannelBoards.test.tsx b/webapp/boards/src/components/rhsChannelBoards.test.tsx index 83285c5b1a..ca57a029a5 100644 --- a/webapp/boards/src/components/rhsChannelBoards.test.tsx +++ b/webapp/boards/src/components/rhsChannelBoards.test.tsx @@ -44,7 +44,7 @@ describe('components/rhsChannelBoards', () => { users: { me: { id: 'user-id', - permissions: ['create_post'] + permissions: ['create_post'], }, }, language: { @@ -115,7 +115,7 @@ describe('components/rhsChannelBoards', () => { }) it('renders the RHS for channel boards, no add', async () => { - const localState = {...state, users: {me:{id: 'user-id'}}} + const localState = {...state, users: {me: {id: 'user-id'}}} const store = mockStateStore([thunk], localState) let container: Element | DocumentFragment | null = null await act(async () => { @@ -133,7 +133,7 @@ describe('components/rhsChannelBoards', () => { }) it('renders with empty list of boards, cannot add', async () => { - const localState = {...state, users: {me:{id: 'user-id'}}, boards: {...state.boards, boards: {}}} + const localState = {...state, users: {me: {id: 'user-id'}}, boards: {...state.boards, boards: {}}} const store = mockStateStore([thunk], localState) let container: Element | DocumentFragment | null = null diff --git a/webapp/boards/src/components/rhsChannelBoards.tsx b/webapp/boards/src/components/rhsChannelBoards.tsx index e83a9b1e95..e9e4389ab7 100644 --- a/webapp/boards/src/components/rhsChannelBoards.tsx +++ b/webapp/boards/src/components/rhsChannelBoards.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect} from 'react' +import React, {useEffect} from 'react' import {FormattedMessage, IntlProvider, useIntl} from 'react-intl' import {getMessages} from 'src/i18n' @@ -11,17 +11,17 @@ import {useWebsockets} from 'src/hooks/websockets' import {Board, BoardMember} from 'src/blocks/board' import {getCurrentTeamId} from 'src/store/teams' import {IUser} from 'src/user' -import {getMe, fetchMe} from 'src/store/users' +import {fetchMe, getMe} from 'src/store/users' import {loadBoards, loadMyBoardsMemberships} from 'src/store/initialLoad' import {getCurrentChannel} from 'src/store/channels' import { + addMyBoardMemberships, getMySortedBoards, setLinkToChannel, updateBoards, updateMembersEnsuringBoardsAndUsers, - addMyBoardMemberships, } from 'src/store/boards' -import {useAppSelector, useAppDispatch} from 'src/store/hooks' +import {useAppDispatch, useAppSelector} from 'src/store/hooks' import AddIcon from 'src/widgets/icons/add' import Button from 'src/widgets/buttons/button' @@ -125,7 +125,7 @@ const RHSChannelBoards = () => { } diff --git a/webapp/boards/src/components/rhsChannelBoardsHeader.tsx b/webapp/boards/src/components/rhsChannelBoardsHeader.tsx index e705d61e99..be9f1434d4 100644 --- a/webapp/boards/src/components/rhsChannelBoardsHeader.tsx +++ b/webapp/boards/src/components/rhsChannelBoardsHeader.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react' +import React from 'react' import {FormattedMessage, IntlProvider} from 'react-intl' import {getMessages} from 'src/i18n' diff --git a/webapp/boards/src/components/rootPortal.tsx b/webapp/boards/src/components/rootPortal.tsx index 5c930a8d61..48b7c837ea 100644 --- a/webapp/boards/src/components/rootPortal.tsx +++ b/webapp/boards/src/components/rootPortal.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useLayoutEffect} from 'react' +import React, {useLayoutEffect, useState} from 'react' import ReactDOM from 'react-dom' type Props = { @@ -16,6 +16,7 @@ const RootPortal = (props: Props): JSX.Element => { if (rootPortal) { rootPortal.appendChild(el) } + return () => { if (rootPortal) { rootPortal.removeChild(el) diff --git a/webapp/boards/src/components/searchDialog/searchDialog.tsx b/webapp/boards/src/components/searchDialog/searchDialog.tsx index 05cc23479a..e793ea94f4 100644 --- a/webapp/boards/src/components/searchDialog/searchDialog.tsx +++ b/webapp/boards/src/components/searchDialog/searchDialog.tsx @@ -4,7 +4,7 @@ import React, { ReactNode, useEffect, useMemo, - useState + useState, } from 'react' import './searchDialog.scss' diff --git a/webapp/boards/src/components/shareBoard/channelPermissionsRow.tsx b/webapp/boards/src/components/shareBoard/channelPermissionsRow.tsx index 450e2b05c3..03eccb64da 100644 --- a/webapp/boards/src/components/shareBoard/channelPermissionsRow.tsx +++ b/webapp/boards/src/components/shareBoard/channelPermissionsRow.tsx @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect} from 'react' -import {useIntl, FormattedMessage} from 'react-intl' +import React, {useEffect, useState} from 'react' +import {FormattedMessage, useIntl} from 'react-intl' import MenuWrapper from 'src/widgets/menuWrapper' import Menu from 'src/widgets/menu' @@ -46,6 +46,7 @@ const ChannelPermissionsRow = (props: Props): JSX.Element => { useEffect(() => { if (!board.channelId) { setLinkedChannel(null) + return } const unknownChannel = { @@ -93,6 +94,7 @@ const ChannelPermissionsRow = (props: Props): JSX.Element => { let result = Utils.getUserDisplayName(users[userIds[0]], props.teammateNameDisplay || '') result += ', ' result += Utils.getUserDisplayName(users[userIds[1]], props.teammateNameDisplay || '') + return result } diff --git a/webapp/boards/src/components/shareBoard/shareBoard.test.tsx b/webapp/boards/src/components/shareBoard/shareBoard.test.tsx index 29fb0a47d3..d14a83584e 100644 --- a/webapp/boards/src/components/shareBoard/shareBoard.test.tsx +++ b/webapp/boards/src/components/shareBoard/shareBoard.test.tsx @@ -129,7 +129,6 @@ describe('src/components/shareBoard/shareBoard', () => { let store: ReturnType beforeEach(() => { - state = { teams: { current: {id: teamId, title: 'Test Team'}, @@ -188,7 +187,6 @@ describe('src/components/shareBoard/shareBoard', () => { }, } - store = mockStateStore([thunk], state) // mockedUtils.buildURL.mockImplementation((path) => (w.baseURL || '') + path) @@ -335,7 +333,7 @@ describe('src/components/shareBoard/shareBoard', () => { const regenerateTokenElement = screen.getByRole('button', {name: 'Regenerate token'}) expect(regenerateTokenElement).toBeDefined() await act(() => userEvent.click(regenerateTokenElement)) - + expect(mockedOctoClient.setSharing).toBeCalledTimes(1) expect(container).toMatchSnapshot() }) @@ -392,8 +390,8 @@ describe('src/components/shareBoard/shareBoard', () => { enableSharedBoards={true} /> - ),{wrapper: MemoryRouter}) - + ), {wrapper: MemoryRouter}) + mockedOctoClient.getSharing.mockResolvedValue({ id: boardId, enabled: true, diff --git a/webapp/boards/src/components/shareBoard/shareBoard.tsx b/webapp/boards/src/components/shareBoard/shareBoard.tsx index c5d040f6f2..7a88734096 100644 --- a/webapp/boards/src/components/shareBoard/shareBoard.tsx +++ b/webapp/boards/src/components/shareBoard/shareBoard.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useEffect} from 'react' +import React, {useEffect, useState} from 'react' -import {useIntl, FormattedMessage} from 'react-intl' +import {FormattedMessage, useIntl} from 'react-intl' import {generatePath, useRouteMatch} from 'react-router-dom' import Select from 'react-select/async' import {StylesConfig} from 'react-select' @@ -11,17 +11,17 @@ import {StylesConfig} from 'react-select' import {useAppSelector} from 'src/store/hooks' import {getCurrentBoard, getCurrentBoardMembers} from 'src/store/boards' import {Channel, ChannelTypeOpen, ChannelTypePrivate} from 'src/store/channels' -import {getMe, getBoardUsersList} from 'src/store/users' +import {getBoardUsersList, getMe} from 'src/store/users' import {ClientConfig} from 'src/config/clientConfig' import {getClientConfig} from 'src/store/clientConfig' -import {Utils, IDType} from 'src/utils' +import {IDType, Utils} from 'src/utils' import Tooltip from 'src/widgets/tooltip' import mutator from 'src/mutator' import {ISharing} from 'src/blocks/sharing' -import {BoardMember, createBoard, MemberRole} from 'src/blocks/board' +import {BoardMember, MemberRole, createBoard} from 'src/blocks/board' import client from 'src/octoClient' import Dialog from 'src/components/dialog' @@ -96,6 +96,7 @@ function isLastAdmin(members: BoardMember[]) { } } } + return true } @@ -135,6 +136,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { enabled: true, token: Utils.createGuid(IDType.Token), } + return newSharing } @@ -150,6 +152,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { const onLinkBoard = async (channel: Channel, confirmed?: boolean) => { if (!confirmed) { setShowLinkChannelConfirmation(channel) + return } setShowLinkChannelConfirmation(null) @@ -188,6 +191,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { const onUpdateBoardMember = (member: BoardMember, newPermission: string) => { if (member.userId === me?.id && isLastAdmin(Object.values(members))) { sendFlashMessage({content: intl.formatMessage({id: 'shareBoard.lastAdmin', defaultMessage: 'Boards must have at least one Administrator'}), severity: 'low'}) + return } @@ -239,6 +243,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { const onDeleteBoardMember = (member: BoardMember) => { if (member.userId === me?.id && isLastAdmin(Object.values(members))) { sendFlashMessage({content: intl.formatMessage({id: 'shareBoard.lastAdmin', defaultMessage: 'Boards must have at least one Administrator'}), severity: 'low'}) + return } mutator.deleteBoardMember(member) @@ -285,6 +290,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { const formatOptionLabel = (userOrChannel: IUser | Channel) => { if ((userOrChannel as IUser).username) { const user = userOrChannel as IUser + return (
    {channel.type === ChannelTypePrivate && } @@ -378,7 +385,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { defaultOptions={true} formatOptionLabel={formatOptionLabel} getOptionValue={({id}) => id} - getOptionLabel={(x) => isUser(x) ? x.username : x.display_name} + getOptionLabel={(x) => (isUser(x) ? x.username : x.display_name)} isMulti={false} placeholder={board.isTemplate ? intl.formatMessage({id: 'ShareTemplate.searchPlaceholder', defaultMessage: 'Search for people'}) : @@ -407,6 +414,7 @@ export default function ShareBoardDialog(props: Props): JSX.Element { if (members[user.id].synthetic) { return null } + return ( { if (board.type === BoardTypeOpen) { return } + return } diff --git a/webapp/boards/src/components/shareBoard/teamPermissionsRow.tsx b/webapp/boards/src/components/shareBoard/teamPermissionsRow.tsx index 25a5a8a6c0..dc27f4e228 100644 --- a/webapp/boards/src/components/shareBoard/teamPermissionsRow.tsx +++ b/webapp/boards/src/components/shareBoard/teamPermissionsRow.tsx @@ -12,10 +12,10 @@ import CompassIcon from 'src/widgets/icons/compassIcon' import { Board, - createBoard, BoardTypeOpen, BoardTypePrivate, - MemberRole + MemberRole, + createBoard, } from 'src/blocks/board' import {useAppSelector} from 'src/store/hooks' import {getCurrentTeam} from 'src/store/teams' diff --git a/webapp/boards/src/components/sidebar/deleteBoardDialog.test.tsx b/webapp/boards/src/components/sidebar/deleteBoardDialog.test.tsx index aa2821b265..6728fae44a 100644 --- a/webapp/boards/src/components/sidebar/deleteBoardDialog.test.tsx +++ b/webapp/boards/src/components/sidebar/deleteBoardDialog.test.tsx @@ -37,6 +37,7 @@ describe('components/sidebar/DeleteBoardDialog', () => { rootPortalDiv.id = 'focalboard-root-portal' const {container} = render(, {container: document.body.appendChild(rootPortalDiv)}) + return container } diff --git a/webapp/boards/src/components/sidebar/deleteBoardDialog.tsx b/webapp/boards/src/components/sidebar/deleteBoardDialog.tsx index 5790688a0e..1b83ac8081 100644 --- a/webapp/boards/src/components/sidebar/deleteBoardDialog.tsx +++ b/webapp/boards/src/components/sidebar/deleteBoardDialog.tsx @@ -65,7 +65,9 @@ export default function DeleteBoardDialog(props: Props): JSX.Element { emphasis={'tertiary'} onClick={(e: React.MouseEvent) => { e.stopPropagation() - !isSubmitting && props.onClose() + if (!isSubmitting) { + props.onClose() + } }} > { } window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) }, []) @@ -143,6 +145,7 @@ const Sidebar = (props: Props) => { const boardsCategory = sidebarCategories.find((c) => c.name === 'Boards') if (!boardsCategory) { Utils.logError('Boards category not found for user') + return } @@ -155,6 +158,7 @@ const Sidebar = (props: Props) => { } websocketClient.addOnChange(onCategoryReorderHandler, 'categoryOrder') + return () => { websocketClient.removeOnChange(onCategoryReorderHandler, 'categoryOrder') } @@ -214,6 +218,7 @@ const Sidebar = (props: Props) => { const toSidebarCategory = sidebarCategories.find((category) => category.id === toCategoryID) if (!toSidebarCategory) { Utils.logError(`toCategoryID not found in list of sidebar categories. toCategoryID: ${toCategoryID}`) + return } @@ -232,11 +237,13 @@ const Sidebar = (props: Props) => { if (!toSidebarCategory) { Utils.logError(`toCategoryID not found in list of sidebar categories. toCategoryID: ${toCategoryID}`) + return } if (!fromSidebarCategory) { Utils.logError(`fromCategoryID not found in list of sidebar categories. fromCategoryID: ${fromCategoryID}`) + return } @@ -261,12 +268,14 @@ const Sidebar = (props: Props) => { if (!team || !destination) { setDraggedItemID('') setIsCategoryBeingDragged(false) + return } if (destination.droppableId === source.droppableId && destination.index === source.index) { setDraggedItemID('') setIsCategoryBeingDragged(false) + return } @@ -337,6 +346,7 @@ const Sidebar = (props: Props) => { sortedBoards.push(b) } }) + return sortedBoards } diff --git a/webapp/boards/src/components/sidebar/sidebarBoardItem.tsx b/webapp/boards/src/components/sidebar/sidebarBoardItem.tsx index b798f834e3..040571aab7 100644 --- a/webapp/boards/src/components/sidebar/sidebarBoardItem.tsx +++ b/webapp/boards/src/components/sidebar/sidebarBoardItem.tsx @@ -107,6 +107,7 @@ const SidebarBoardItem = (props: Props) => { undefined, () => { Utils.showBoard(board.id, match, history) + return Promise.resolve() }, ) @@ -193,6 +194,7 @@ const SidebarBoardItem = (props: Props) => { const boardItemRef = useRef(null) const title = board.title || intl.formatMessage({id: 'Sidebar.untitled-board', defaultMessage: '(Untitled Board)'}) + return ( { setBoardsMenuOpen((menuState) => { const newState = {...menuState} newState[board.id] = open + return newState }) }} diff --git a/webapp/boards/src/components/sidebar/sidebarCategory.test.tsx b/webapp/boards/src/components/sidebar/sidebarCategory.test.tsx index ec233123dc..0e39923a75 100644 --- a/webapp/boards/src/components/sidebar/sidebarCategory.test.tsx +++ b/webapp/boards/src/components/sidebar/sidebarCategory.test.tsx @@ -195,7 +195,7 @@ describe('components/sidebarCategory', () => { // TODO: Remove when fetch is mocked correctly // https://mattermost.atlassian.net/browse/MM-52212 - // eslint-disable-next-line no-only-tests/no-only-tests + test.skip('sidebar template close other', async () => { const mockStore = configureStore([]) const store = mockStore(state) diff --git a/webapp/boards/src/components/sidebar/sidebarCategory.tsx b/webapp/boards/src/components/sidebar/sidebarCategory.tsx index 734490c9ed..358d11be14 100644 --- a/webapp/boards/src/components/sidebar/sidebarCategory.tsx +++ b/webapp/boards/src/components/sidebar/sidebarCategory.tsx @@ -6,7 +6,7 @@ import React, { useEffect, useMemo, useRef, - useState + useState, } from 'react' import {FormattedMessage, useIntl} from 'react-intl' import {generatePath, useHistory, useRouteMatch} from 'react-router-dom' @@ -40,10 +40,10 @@ import {getCurrentCard} from 'src/store/cards' import {Utils} from 'src/utils' import { - TOUR_SIDEBAR, + FINISHED, SidebarTourSteps, TOUR_BOARD, - FINISHED + TOUR_SIDEBAR, } from 'src/components/onboardingTour/index' import telemetryClient, {TelemetryActions, TelemetryCategory} from 'src/telemetry/telemetryClient' @@ -205,7 +205,7 @@ const SidebarCategory = (props: Props) => { }, 120) } else { setTimeout(() => { - const newPath = generatePath('/team/:teamId', {teamId: teamID,}) + const newPath = generatePath('/team/:teamId', {teamId: teamID}) history.push(newPath) }, 120) } @@ -215,8 +215,8 @@ const SidebarCategory = (props: Props) => { }, ) if ( - UserSettings.lastBoardId && - UserSettings.lastBoardId[deleteBoard.teamId] == deleteBoard.id + UserSettings.lastBoardId && + UserSettings.lastBoardId[deleteBoard.teamId] === deleteBoard.id ) { UserSettings.setLastBoardID(deleteBoard.teamId, null) UserSettings.setLastViewId(deleteBoard.id, null) @@ -387,6 +387,7 @@ const SidebarCategory = (props: Props) => { if (!isBoardVisible(board.id)) { return null } + return ( { , ) const {container} = render(component) - expect(card1.id ) + expect(card1.id) expect(container).toMatchSnapshot() }) test('should match snapshot with CreatedBy', async () => { - jest.spyOn(console, 'error').mockImplementation() + jest.spyOn(console, 'error').mockImplementation() const board = TestBlockFactory.createBoard() const createdById = Utils.createGuid(IDType.User) @@ -536,7 +536,7 @@ describe('components/table/Table extended', () => { // TODO fix test — fix personSelector expect(console.error).toHaveBeenCalledWith( - expect.stringContaining('Each child in a list should have a unique "key" prop'), + 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() diff --git a/webapp/boards/src/components/table/table.tsx b/webapp/boards/src/components/table/table.tsx index 59b5631c7b..9025644ec1 100644 --- a/webapp/boards/src/components/table/table.tsx +++ b/webapp/boards/src/components/table/table.tsx @@ -5,12 +5,12 @@ import React, {useCallback} from 'react' import {FormattedMessage} from 'react-intl' import { + Board, + BoardGroup, IPropertyOption, IPropertyTemplate, - Board, - BoardGroup } from 'src/blocks/board' -import {createBoardView, BoardView} from 'src/blocks/boardView' +import {BoardView, createBoardView} from 'src/blocks/boardView' import {Card} from 'src/blocks/card' import {Constants, Permission} from 'src/constants' import mutator from 'src/mutator' @@ -121,6 +121,7 @@ const Table = (props: Props): JSX.Element => { if (activeView.fields.groupById !== undefined) { const cardsById: { [key: string]: Card } = cards.reduce((acc: { [key: string]: Card }, card: Card): { [key: string]: Card } => { acc[card.id] = card + return acc }, {}) const draggedCards: Card[] = draggedCardIds.map((o: string) => cardsById[o]) diff --git a/webapp/boards/src/components/table/tableColumnResizeContext.tsx b/webapp/boards/src/components/table/tableColumnResizeContext.tsx index a95ef6532c..aa3ce1cf5b 100644 --- a/webapp/boards/src/components/table/tableColumnResizeContext.tsx +++ b/webapp/boards/src/components/table/tableColumnResizeContext.tsx @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, { - createContext, ReactElement, ReactNode, + createContext, useCallback, useContext, - useMemo + useMemo, } from 'react' import {Constants} from 'src/constants' @@ -26,6 +26,7 @@ export function useColumnResize(): ColumnResizeContextType { if (!context) { throw new Error('ColumnResizeContext is not available!') } + return context } @@ -69,8 +70,10 @@ export const ColumnResizeProvider = (props: ColumnResizeProviderProps): ReactEle const iter = columns.get(columnId)?.values() if (iter) { const {value, done} = iter.next() + return done ? value : iter.next().value } + return undefined }, width: (columnId) => { diff --git a/webapp/boards/src/components/table/tableGroup.tsx b/webapp/boards/src/components/table/tableGroup.tsx index e05a0f6608..645eece21d 100644 --- a/webapp/boards/src/components/table/tableGroup.tsx +++ b/webapp/boards/src/components/table/tableGroup.tsx @@ -1,15 +1,15 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -/* eslint-disable max-lines */ + import React from 'react' import {useDrop} from 'react-dnd' import { Board, + BoardGroup, IPropertyOption, IPropertyTemplate, - BoardGroup } from 'src/blocks/board' import {BoardView} from 'src/blocks/boardView' import {Card} from 'src/blocks/card' diff --git a/webapp/boards/src/components/table/tableGroupHeaderRow.tsx b/webapp/boards/src/components/table/tableGroupHeaderRow.tsx index a9e29935a8..4dc9fb3e89 100644 --- a/webapp/boards/src/components/table/tableGroupHeaderRow.tsx +++ b/webapp/boards/src/components/table/tableGroupHeaderRow.tsx @@ -1,15 +1,15 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -/* eslint-disable max-lines */ -import React, {useState, useEffect} from 'react' + +import React, {useEffect, useState} from 'react' import {FormattedMessage, useIntl} from 'react-intl' import {Constants} from 'src/constants' import { - IPropertyOption, Board, + BoardGroup, + IPropertyOption, IPropertyTemplate, - BoardGroup } from 'src/blocks/board' import {BoardView} from 'src/blocks/boardView' import {useSortable} from 'src/hooks/sortable' diff --git a/webapp/boards/src/components/table/tableHeaderMenu.tsx b/webapp/boards/src/components/table/tableHeaderMenu.tsx index 9c0866284c..84d4b24a25 100644 --- a/webapp/boards/src/components/table/tableHeaderMenu.tsx +++ b/webapp/boards/src/components/table/tableHeaderMenu.tsx @@ -22,6 +22,7 @@ type Props = { const TableHeaderMenu: FC = (props: Props): JSX.Element => { const {board, activeView, templateId, views, cards} = props const intl = useIntl() + return ( { if (sortOption) { sorted = sortOption.reversed ? 'down' : 'up' } + return ( { const Wrapper: React.FC = ({children}) => { const store = mockStore(state) + return wrapDNDIntl( { }, []) const onClick = useCallback((e: React.MouseEvent) => { - props.onClick && props.onClick(e, card) + props.onClick?.(e, card) }, [card, props.onClick]) const onSaveWithEnter = useCallback(() => { @@ -123,6 +123,7 @@ const TableRow = (props: Props) => { const handleDeleteCard = useCallback(async () => { if (!card) { Utils.assertFailure() + return } TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DeleteCard, {board: board.id, card: card.id}) @@ -146,6 +147,7 @@ const TableRow = (props: Props) => { // confirmation dialog if (card?.title === '' && card?.fields.contentOrder.length === 0) { handleDeleteCard() + return } setShowConfirmationDialogBox(true) diff --git a/webapp/boards/src/components/topBar.tsx b/webapp/boards/src/components/topBar.tsx index 4e31eb8dea..61aecf1c79 100644 --- a/webapp/boards/src/components/topBar.tsx +++ b/webapp/boards/src/components/topBar.tsx @@ -10,6 +10,7 @@ import {Constants} from 'src/constants' const TopBar = (): JSX.Element => { const feedbackUrl = 'https://www.focalboard.com/fwlink/feedback-boards.html?v=' + Constants.versionString + return (
    window.removeEventListener('resize', updateSize) }, []) @@ -56,5 +57,6 @@ export function useMeasurePunchouts(elementIds: string[], additionalDeps: any[], height: `${(maxY - minY) + (offset ? offset.height : 0)}px`, } }, [...elementIds, ...additionalDeps, size, elementsAvailable]) + return channelPunchout } diff --git a/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip.tsx b/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip.tsx index 2134775515..37eb89dcdd 100644 --- a/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip.tsx +++ b/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip.tsx @@ -131,6 +131,7 @@ const TutorialTourTip = ({ defaultMessage={'Got it'} /> ) + return buttonText } diff --git a/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip_manager.tsx b/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip_manager.tsx index 2c94d27288..94e5e41c27 100644 --- a/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip_manager.tsx +++ b/webapp/boards/src/components/tutorial_tour_tip/tutorial_tour_tip_manager.tsx @@ -5,12 +5,12 @@ import React, {useCallback, useEffect, useState} from 'react' import {useDispatch} from 'react-redux' -import {FINISHED, TourCategoriesMapToSteps, TOUR_ORDER} from 'src/components/onboardingTour' +import {FINISHED, TOUR_ORDER, TourCategoriesMapToSteps} from 'src/components/onboardingTour' import {useAppSelector} from 'src/store/hooks' import {getMe, getOnboardingTourStep, patchProps} from 'src/store/users' import {UserConfigPatch} from 'src/user' import octoClient from 'src/octoClient' -import {Utils, KeyCodes} from 'src/utils' +import {KeyCodes, Utils} from 'src/utils' import TelemetryClient, {TelemetryCategory} from 'src/telemetry/telemetryClient' export interface TutorialTourTipManager { @@ -107,6 +107,7 @@ const useTutorialTourTipManager = ({ useEffect(() => { window.addEventListener('keydown', handleKeyDown) + return () => window.removeEventListener('keydown', handleKeyDown) }, []) @@ -194,6 +195,7 @@ const useTutorialTourTipManager = ({ if (candidateMaxStep > maxStep && candidateMaxStep !== tourSteps.FINISHED) { return candidateMaxStep } + return maxStep }, Number.MIN_SAFE_INTEGER) } diff --git a/webapp/boards/src/components/tutorial_tour_tip/useElementAvailable.ts b/webapp/boards/src/components/tutorial_tour_tip/useElementAvailable.ts index 40c363ae82..09b84ecc04 100644 --- a/webapp/boards/src/components/tutorial_tour_tip/useElementAvailable.ts +++ b/webapp/boards/src/components/tutorial_tour_tip/useElementAvailable.ts @@ -13,9 +13,10 @@ export default function useElementAvailable( clearInterval(checkAvailableInterval.current) checkAvailableInterval.current = null } - return + + return undefined } else if (checkAvailableInterval.current) { - return + return undefined } checkAvailableInterval.current = setInterval(() => { if (elementIds.every((x) => document.querySelector(x))) { diff --git a/webapp/boards/src/components/viewHeader/dateFilter.test.tsx b/webapp/boards/src/components/viewHeader/dateFilter.test.tsx index 4cd13819aa..d4e3c1124c 100644 --- a/webapp/boards/src/components/viewHeader/dateFilter.test.tsx +++ b/webapp/boards/src/components/viewHeader/dateFilter.test.tsx @@ -7,12 +7,11 @@ import userEvent from '@testing-library/user-event' import {IntlProvider} from 'react-intl' import {mocked} from 'jest-mock' - import {wrapIntl} from 'src/testUtils' import mutator from 'src/mutator' import {TestBlockFactory} from 'src/test/testBlockFactory' -import {createFilterClause, FilterClause} from 'src/blocks/filterClause' +import {FilterClause, createFilterClause} from 'src/blocks/filterClause' import {createFilterGroup} from 'src/blocks/filterGroup' import DateFilter from './dateFilter' diff --git a/webapp/boards/src/components/viewHeader/dateFilter.tsx b/webapp/boards/src/components/viewHeader/dateFilter.tsx index 6c0dcb9fb9..ef51b3b029 100644 --- a/webapp/boards/src/components/viewHeader/dateFilter.tsx +++ b/webapp/boards/src/components/viewHeader/dateFilter.tsx @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState, useCallback} from 'react' +import React, {useCallback, useState} from 'react' import {useIntl} from 'react-intl' import {DateUtils} from 'react-day-picker' import MomentLocaleUtils from 'react-day-picker/moment' @@ -77,6 +77,7 @@ function DateFilter(props: Props): JSX.Element { if (date) { displayDate = Utils.displayDate(date, intl) } + return displayDate } @@ -129,6 +130,7 @@ function DateFilter(props: Props): JSX.Element { } const className = 'DateFilter' + return (