diff --git a/server/api.go b/server/api.go index 4aeeee120..ed0b276ed 100644 --- a/server/api.go +++ b/server/api.go @@ -370,6 +370,8 @@ func (p *Plugin) handlePostCallsChannel(w http.ResponseWriter, r *http.Request) if res.Err != "" { return } + + w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(storedChannel); err != nil { p.LogError(err.Error()) } diff --git a/standalone/package-lock.json b/standalone/package-lock.json index c4f90052f..ba4dda40f 100644 --- a/standalone/package-lock.json +++ b/standalone/package-lock.json @@ -94,7 +94,7 @@ "typescript": "^5.0.0" }, "peerDependencies": { - "@mattermost/types": "9.3.0", + "@mattermost/types": "^9.3.0 || ^10.0.0", "typescript": "^4.3.0 || ^5.0.0" }, "peerDependenciesMeta": { diff --git a/standalone/tsconfig.json b/standalone/tsconfig.json index 4320d013a..b849a8830 100644 --- a/standalone/tsconfig.json +++ b/standalone/tsconfig.json @@ -44,6 +44,9 @@ ], "plugin/*": [ "../webapp/src/*" + ], + "key-mirror": [ + "../webapp/mattermost-webapp/webapp/channels/src/types/external/key-mirror.d.ts" ] }, }, diff --git a/webapp/install_mattermost_webapp.sh b/webapp/install_mattermost_webapp.sh index 1ee2fe553..e911fc5ed 100755 --- a/webapp/install_mattermost_webapp.sh +++ b/webapp/install_mattermost_webapp.sh @@ -1,4 +1,4 @@ -readonly COMMITHASH=d2c3710265c293281c2b445d4f72f27871c2e127 +readonly COMMITHASH=e972d19d9b4b443a7edf015c3ddca639140de612 echo "\n\nInstalling mattermost-webapp from the mattermost repo, using commit hash $COMMITHASH\n" diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 9bad1b5ef..f7d3a7ebb 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -98,7 +98,7 @@ "@mattermost/client": "*", "@mattermost/compass-components": "^0.2.12", "@mattermost/compass-icons": "0.1.39", - "@mattermost/desktop-api": "5.8.0-5", + "@mattermost/desktop-api": "5.10.0-2", "@mattermost/types": "*", "@mui/base": "5.0.0-alpha.127", "@mui/material": "5.11.16", @@ -178,12 +178,11 @@ "smooth-scroll-into-view-if-needed": "1.1.33", "stream-browserify": "3.0.0", "styled-components": "5.3.6", - "stylelint": "13.13.1", "timezones.json": "1.6.1", "tinycolor2": "1.4.2", "turndown": "7.1.1", - "typescript": "5.3.3", - "web-vitals": "3.5.2", + "typescript": "5.5.4", + "web-vitals": "4.2.0", "zen-observable": "0.9.0" }, "devDependencies": { @@ -191,10 +190,12 @@ "@hot-loader/react-dom": "17.0.2", "@mattermost/calls-common": "0.27.0", "@mattermost/eslint-plugin": "*", + "@mattermost/mmjstool": "github:mattermost/mattermost-utilities#7b63833d208d482ba4a1c12230bb3e68dd9c5e5e", "@redux-devtools/extension": "3.2.3", "@stylistic/stylelint-plugin": "2.1.0", "@testing-library/jest-dom": "5.16.4", "@testing-library/react": "12.1.4", + "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "13.5.0", "@types/bootstrap": "4.5.0", "@types/country-list": "2.1.0", @@ -235,6 +236,7 @@ "enzyme-to-json": "3.6.2", "eslint-plugin-no-only-tests": "3.1.0", "external-remotes-plugin": "1.0.0", + "html-loader": "5.1.0", "html-webpack-plugin": "5.5.0", "identity-obj-proxy": "3.0.0", "image-webpack-loader": "8.1.0", @@ -247,7 +249,6 @@ "jest-environment-jsdom": "29.7.0", "jest-junit": "16.0.0", "jest-watch-typeahead": "2.2.2", - "mmjstool": "github:mattermost/mattermost-utilities#73e61d2ede0ebf802492df4cfbac481d35efed54", "nock": "13.2.8", "prettier": "2.3.2", "react-router-enzyme-context": "1.2.0", @@ -864,10 +865,11 @@ "dev": true }, "mattermost-webapp/webapp/channels/node_modules/@mattermost/desktop-api": { - "version": "5.8.0-5", - "resolved": "https://registry.npmjs.org/@mattermost/desktop-api/-/desktop-api-5.8.0-5.tgz", - "integrity": "sha512-YPtFRnduVFOXyK25GedJA+PkAKmFpLDKqfxvV/IIS+SMypv6BD17LJ8AkdBsguFFa6ZWLlZU40M5grKYBbjOuA==", + "version": "5.10.0-2", + "resolved": "https://registry.npmjs.org/@mattermost/desktop-api/-/desktop-api-5.10.0-2.tgz", + "integrity": "sha512-Okb+VP6gdwEBnSthzxiU3+oO5XLTocDvWlzoGYjBYrT4DN2/xxAzRYgp1VB6skQxEwVhbP/zaQvWbRtZrp8org==", "dev": true, + "license": "MIT", "peerDependencies": { "typescript": "^4.3.0 || ^5.0.0" }, @@ -3030,40 +3032,6 @@ "node": ">=10" } }, - "mattermost-webapp/webapp/channels/node_modules/mmjstool": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/mattermost/mattermost-utilities.git#e65ab00f22628cbdee736fd2e4f192f07225e82d", - "integrity": "sha512-u3kj5/hIC9flXBOwcPOqfOPvv0YHcJLB/902qKx1xaC0HhGKEfktIw0ai6s4TIikfi+uWuOuCCk762Pd8Wllhg==", - "dev": true, - "dependencies": { - "estree-walk": "^2.2.0", - "filehound": "^1.17.5", - "sort-json": "^2.0.0", - "webpack-cli": "^4.9.1", - "yargs": "^17.3.1" - }, - "bin": { - "mmjstool": "bin/mmjstool" - } - }, - "mattermost-webapp/webapp/channels/node_modules/mmjstool/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, "mattermost-webapp/webapp/channels/node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -3338,16 +3306,17 @@ } }, "mattermost-webapp/webapp/channels/node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "mattermost-webapp/webapp/channels/node_modules/uuid": { @@ -3385,6 +3354,13 @@ "node": ">=14" } }, + "mattermost-webapp/webapp/channels/node_modules/web-vitals": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.0.tgz", + "integrity": "sha512-ohj72kbtVWCpKYMxcbJ+xaOBV3En76hW47j52dG+tEGG36LZQgfFw5yHl9xyjmosy3XUMn8d/GBUAy4YPM839w==", + "dev": true, + "license": "Apache-2.0" + }, "mattermost-webapp/webapp/channels/node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -3500,7 +3476,7 @@ "typescript": "^5.0.0" }, "peerDependencies": { - "@mattermost/types": "9.3.0", + "@mattermost/types": "^9.3.0 || ^10.0.0", "typescript": "^4.3.0 || ^5.0.0" }, "peerDependenciesMeta": { @@ -8361,6 +8337,67 @@ } } }, + "node_modules/@mattermost/mmjstool": { + "name": "mmjstool", + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/mattermost/mattermost-utilities.git#7b63833d208d482ba4a1c12230bb3e68dd9c5e5e", + "integrity": "sha512-rO/erucxfGQLYeDulzTmbVAk89tA29eBsrXblZDKfot9/kBeevum4DXelQQPZbwziEo6ykmOAByNalmZglF8Hw==", + "dev": true, + "dependencies": { + "estree-walk": "^2.2.0", + "filehound": "^1.17.5", + "sort-json": "^2.0.0", + "webpack-cli": "^4.9.1", + "yargs": "^17.3.1" + }, + "bin": { + "mmjstool": "bin/mmjstool" + } + }, + "node_modules/@mattermost/mmjstool/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@mattermost/mmjstool/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@mattermost/mmjstool/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/@mattermost/types": { "resolved": "mattermost-webapp/webapp/platform/types", "link": true @@ -9285,6 +9322,37 @@ "react-dom": "*" } }, + "node_modules/@testing-library/react-hooks": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz", + "integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "react-error-boundary": "^3.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0", + "react": "^16.9.0 || ^17.0.0", + "react-dom": "^16.9.0 || ^17.0.0", + "react-test-renderer": "^16.9.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-test-renderer": { + "optional": true + } + } + }, "node_modules/@testing-library/react/node_modules/@testing-library/dom": { "version": "8.20.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", @@ -18327,6 +18395,59 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-loader": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-5.1.0.tgz", + "integrity": "sha512-Jb3xwDbsm0W3qlXrCZwcYqYGnYz55hb6aoKQTlzyZPXsPpi6tHXzAfqalecglMQgNvtEfxrCQPaKT90Irt5XDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "html-minifier-terser": "^7.2.0", + "parse5": "^7.1.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/html-loader/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-loader/node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -24829,6 +24950,23 @@ "react": "17.0.2" } }, + "node_modules/react-error-boundary": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz", + "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "react": ">=16.13.1" + } + }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -28447,12 +28585,6 @@ "node": ">= 8" } }, - "node_modules/web-vitals": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.2.tgz", - "integrity": "sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==", - "dev": true - }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/webapp/src/index.tsx b/webapp/src/index.tsx index 8b82a676a..003e45587 100644 --- a/webapp/src/index.tsx +++ b/webapp/src/index.tsx @@ -4,6 +4,10 @@ import {CallChannelState} from '@mattermost/calls-common/lib/types'; import WebSocketClient from '@mattermost/client/websocket'; import type {DesktopAPI} from '@mattermost/desktop-api'; import {PluginAnalyticsRow} from '@mattermost/types/admin'; +import {Channel} from '@mattermost/types/channels'; +import {FileInfo} from '@mattermost/types/files'; +import {CommandArgs} from '@mattermost/types/integrations'; +import {Post} from '@mattermost/types/posts'; import {Client4} from 'mattermost-redux/client'; import {getChannel, getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; import {getConfig, getServerVersion} from 'mattermost-redux/selectors/entities/general'; @@ -93,7 +97,7 @@ import {CALL_RECORDING_POST_TYPE, CALL_START_POST_TYPE, CALL_TRANSCRIPTION_POST_ import {desktopNotificationHandler} from 'src/desktop_notifications'; import RestClient from 'src/rest_client'; import slashCommandsHandler from 'src/slash_commands'; -import {CallActions, CurrentCallData, CurrentCallDataDefault, DesktopMessageType} from 'src/types/types'; +import {CallActions, CurrentCallData, CurrentCallDataDefault, DesktopMessageType, RealNewPostMessageProps} from 'src/types/types'; import {modals} from 'src/webapp_globals'; import { @@ -377,7 +381,7 @@ export default class Plugin { ], }); - registry.registerFilePreviewComponent((fi, post) => { + registry.registerFilePreviewComponent((fi: FileInfo, post?: Post) => { return String(post?.type) === CALL_RECORDING_POST_TYPE; }, RecordingsFilePreview); @@ -385,11 +389,11 @@ export default class Plugin { return getTranslations(locale); }); - registry.registerSlashCommandWillBePostedHook(async (message, args) => { + registry.registerSlashCommandWillBePostedHook(async (message: string, args: CommandArgs) => { return slashCommandsHandler(store, joinCall, message, args); }); - registry.registerDesktopNotificationHook?.(async (post, msgProps, channel, teamId, args) => { + registry.registerDesktopNotificationHook?.(async (post: Post, msgProps: RealNewPostMessageProps, channel: Channel, teamId: string, args: DesktopNotificationArgs) => { return desktopNotificationHandler(store, post, msgProps, channel, args); }); @@ -466,7 +470,7 @@ export default class Plugin { channelHeaderMenuButtonID = registry.registerCallButtonAction( ChannelHeaderButton, ChannelHeaderDropdownButton, - async (channel) => { + async (channel: Channel) => { joinCall(channel.id, channel.team_id); }, ); diff --git a/webapp/src/types/mattermost-webapp/index.d.ts b/webapp/src/types/mattermost-webapp/index.d.ts index e4ca90b28..f0f092acf 100644 --- a/webapp/src/types/mattermost-webapp/index.d.ts +++ b/webapp/src/types/mattermost-webapp/index.d.ts @@ -1,13 +1,23 @@ import {Channel} from '@mattermost/types/channels'; import {CommandArgs} from '@mattermost/types/integrations'; import {PluginConfiguration} from '@mattermost/types/plugins/user_settings'; -import {Post} from '@mattermost/types/posts'; import {GlobalState} from '@mattermost/types/store'; import {PluginSiteStatsHandler} from '@mattermost/types/store/plugin'; +import type { + AdminConsolePluginComponent, + AdminConsolePluginCustomSection, + CallButtonAction, + ChannelHeaderAction, + ChannelHeaderButtonAction, + CustomRouteComponent, + DesktopNotificationHook, + FilePreviewComponent, + NeedsTeamComponent, + SlashCommandWillBePostedHook, +} from '@mattermost/types/store/plugins'; import {ActionFuncAsync} from 'mattermost-redux/types/actions'; import {Store as BaseStore} from 'redux'; import {ThunkDispatch} from 'redux-thunk'; -import {RealNewPostMessageProps} from 'src/types/types'; export type Translations = { [key: string]: string; @@ -40,25 +50,22 @@ export interface PluginRegistry { registerChannelToastComponent(component: React.ElementType); - registerChannelHeaderButtonAction(component: React.ElementType, fn: (channel: Channel) => void); + registerChannelHeaderButtonAction(component: React.ElementType, action: ChannelHeaderButtonAction['action']); - registerChannelHeaderMenuAction(component: React.ElementType, fn: (channelID: string) => void); + registerChannelHeaderMenuAction(component: React.ElementType, action: ChannelHeaderAction['action']); registerWebSocketEventHandler(evType: string, fn: (event: WebSocketEvent) => void); - registerCustomRoute(route: string, component: React.ElementType); + registerCustomRoute(route: string, component: CustomRouteComponent['component']); - registerNeedsTeamRoute(route: string, component: React.ElementType); + registerNeedsTeamRoute(route: string, component: NeedsTeamComponent['component']); - registerSlashCommandWillBePostedHook(hook: (message: string, args: CommandArgs) => SlashCommandWillBePostedReturn); + registerSlashCommandWillBePostedHook(hook: SlashCommandWillBePostedHook['hook']); // registerDesktopNotificationHook requires MM v8.1 - registerDesktopNotificationHook(hook: (post: Post, msgProps: RealNewPostMessageProps, channel: Channel, teamId: string, args: DesktopNotificationArgs) => Promise<{ - error?: string; - args?: DesktopNotificationArgs; - }>) + registerDesktopNotificationHook(hook: DesktopNotificationHook['hook']) - registerCallButtonAction(button: React.ElementType, dropdownButton: React.ElementType, fn: (channel: Channel) => void); + registerCallButtonAction(button: React.ElementType, dropdownButton: React.ElementType, action: CallButtonAction['action']); unregisterComponent(componentID: string); @@ -68,15 +75,15 @@ export interface PluginRegistry { unregisterReconnectHandler(handler: () => void); - registerAdminConsoleCustomSetting(key: string, component: React.FunctionComponent, options?: { showTitle: boolean }); + registerAdminConsoleCustomSetting(key: string, component: AdminConsolePluginComponent['component'], options?: { showTitle: boolean }); registerTranslations(handler: (locale: string) => Translations | Promise); - registerFilePreviewComponent(overrideFn: (fi: FileInfo, post?: Post) => boolean, component: React.ElementType); + registerFilePreviewComponent(overrideFn: FilePreviewComponent['override'], component: FilePreviewComponent['component']); registerSiteStatisticsHandler(handler: PluginSiteStatsHandler); - registerAdminConsoleCustomSection(key: string, component: React.FunctionComponent<{ settingsList: ReactNode[]; }>); + registerAdminConsoleCustomSection(key: string, component: AdminConsolePluginCustomSection['component']); registerUserSettings(settings: PluginConfiguration); } diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json index ee139c8a4..276b3694e 100644 --- a/webapp/tsconfig.json +++ b/webapp/tsconfig.json @@ -40,6 +40,9 @@ ], "reselect": [ "./mattermost-webapp/webapp/channels/src/packages/mattermost-redux/src/selectors/create_selector/index" + ], + "key-mirror": [ + "./mattermost-webapp/webapp/channels/src/types/external/key-mirror.d.ts" ] } },