Migrating some files from javascript to typescript (#24663)

* Migrating some files to typescript

* Some other files migrated

* Migrating more javascript to typescript

* Migrating more javascript to typescript

* Fixing types

* Fixing linter errors

* Fixing some imports

* Fixing linter errors

* Renaming the snapshots

* Addressing PR review comments
Этот коммит содержится в:
Jesús Espino
2023-10-10 16:22:11 +02:00
коммит произвёл GitHub
родитель 4ae44810d3
Коммит bb4aa764bc
53 изменённых файлов: 942 добавлений и 381 удалений

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

@@ -43,7 +43,7 @@
"highlight.js": "11.6.0",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",
"html-to-react": "1.5.0",
"html-to-react": "1.6.0",
"inobounce": "0.2.1",
"katex": "0.16.3",
"key-mirror": "1.0.1",

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

@@ -10,7 +10,7 @@ import {Client4} from 'mattermost-redux/client';
import {emitUserLoggedOutEvent} from 'actions/global_actions';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import {getOnNavigationConfirmed} from 'selectors/views/admin';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {ActionTypes} from 'utils/constants';

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

@@ -38,11 +38,11 @@ import {getCurrentLocale} from 'selectors/i18n';
import {getIsRhsOpen, getPreviousRhsState, getRhsState} from 'selectors/rhs';
import BrowserStore from 'stores/browser_store';
import LocalStorageStore from 'stores/local_storage_store';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import SubMenuModal from 'components/widgets/menu/menu_modals/submenu_modal/submenu_modal';
import WebSocketClient from 'client/web_websocket_client.jsx';
import WebSocketClient from 'client/web_websocket_client';
import {getHistory} from 'utils/browser_history';
import {ActionTypes, PostTypes, RHSStates, ModalIdentifiers, PreviousViewedTypes} from 'utils/constants';
import {filterAndSortTeamsByDisplayName} from 'utils/team_utils';

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

@@ -1,9 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {IncomingWebhook, OutgoingWebhook, Command, OAuthApp} from '@mattermost/types/integrations';
import {getProfilesByIds} from 'mattermost-redux/actions/users';
import * as Actions from 'actions/integration_actions.jsx';
import * as Actions from 'actions/integration_actions';
import mockStore from 'tests/test_store';
@@ -13,6 +15,12 @@ jest.mock('mattermost-redux/actions/users', () => ({
}),
}));
interface CustomMatchers<R = unknown> {
arrayContainingExactly(stringArray: string[]): R;
}
type GreatExpectations = typeof expect & CustomMatchers;
describe('actions/integration_actions', () => {
const initialState = {
entities: {
@@ -35,14 +43,14 @@ describe('actions/integration_actions', () => {
describe('loadProfilesForIncomingHooks', () => {
test('load profiles for hooks including user we already have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForIncomingHooks([{user_id: 'current_user_id'}, {user_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id2']));
testStore.dispatch(Actions.loadProfilesForIncomingHooks([{user_id: 'current_user_id'}, {user_id: 'user_id2'}] as IncomingWebhook[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id2']));
});
test('load profiles for hooks including only users we don\'t have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForIncomingHooks([{user_id: 'user_id1'}, {user_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id1', 'user_id2']));
testStore.dispatch(Actions.loadProfilesForIncomingHooks([{user_id: 'user_id1'}, {user_id: 'user_id2'}] as IncomingWebhook[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id1', 'user_id2']));
});
test('load profiles for empty hooks', () => {
@@ -55,14 +63,14 @@ describe('actions/integration_actions', () => {
describe('loadProfilesForOutgoingHooks', () => {
test('load profiles for hooks including user we already have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForOutgoingHooks([{creator_id: 'current_user_id'}, {creator_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id2']));
testStore.dispatch(Actions.loadProfilesForOutgoingHooks([{creator_id: 'current_user_id'}, {creator_id: 'user_id2'}] as OutgoingWebhook[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id2']));
});
test('load profiles for hooks including only users we don\'t have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForOutgoingHooks([{creator_id: 'user_id1'}, {creator_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id1', 'user_id2']));
testStore.dispatch(Actions.loadProfilesForOutgoingHooks([{creator_id: 'user_id1'}, {creator_id: 'user_id2'}] as OutgoingWebhook[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id1', 'user_id2']));
});
test('load profiles for empty hooks', () => {
@@ -75,14 +83,14 @@ describe('actions/integration_actions', () => {
describe('loadProfilesForCommands', () => {
test('load profiles for commands including user we already have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForCommands([{creator_id: 'current_user_id'}, {creator_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id2']));
testStore.dispatch(Actions.loadProfilesForCommands([{creator_id: 'current_user_id'}, {creator_id: 'user_id2'}] as Command[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id2']));
});
test('load profiles for commands including only users we don\'t have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForCommands([{creator_id: 'user_id1'}, {creator_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id1', 'user_id2']));
testStore.dispatch(Actions.loadProfilesForCommands([{creator_id: 'user_id1'}, {creator_id: 'user_id2'}] as Command[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id1', 'user_id2']));
});
test('load profiles for empty commands', () => {
@@ -95,14 +103,14 @@ describe('actions/integration_actions', () => {
describe('loadProfilesForOAuthApps', () => {
test('load profiles for apps including user we already have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForOAuthApps([{creator_id: 'current_user_id'}, {creator_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id2']));
testStore.dispatch(Actions.loadProfilesForOAuthApps([{creator_id: 'current_user_id'}, {creator_id: 'user_id2'}] as OAuthApp[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id2']));
});
test('load profiles for apps including only users we don\'t have', () => {
const testStore = mockStore(initialState);
testStore.dispatch(Actions.loadProfilesForOAuthApps([{creator_id: 'user_id1'}, {creator_id: 'user_id2'}]));
expect(getProfilesByIds).toHaveBeenCalledWith(expect.arrayContainingExactly(['user_id1', 'user_id2']));
testStore.dispatch(Actions.loadProfilesForOAuthApps([{creator_id: 'user_id1'}, {creator_id: 'user_id2'}] as OAuthApp[]));
expect(getProfilesByIds).toHaveBeenCalledWith((expect as GreatExpectations).arrayContainingExactly(['user_id1', 'user_id2']));
});
test('load profiles for empty apps', () => {

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

@@ -1,26 +1,30 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {IncomingWebhook, OutgoingWebhook, Command, OAuthApp} from '@mattermost/types/integrations';
import * as IntegrationActions from 'mattermost-redux/actions/integrations';
import {getProfilesByIds} from 'mattermost-redux/actions/users';
import {appsEnabled} from 'mattermost-redux/selectors/entities/apps';
import {getUser} from 'mattermost-redux/selectors/entities/users';
import type {ActionFunc} from 'mattermost-redux/types/actions';
const DEFAULT_PAGE_SIZE = 100;
export function loadIncomingHooksAndProfilesForTeam(teamId, page = 0, perPage = DEFAULT_PAGE_SIZE) {
export function loadIncomingHooksAndProfilesForTeam(teamId: string, page = 0, perPage = DEFAULT_PAGE_SIZE): ActionFunc {
return async (dispatch) => {
const {data} = await dispatch(IntegrationActions.getIncomingHooks(teamId, page, perPage));
if (data) {
dispatch(loadProfilesForIncomingHooks(data));
}
return {data};
};
}
export function loadProfilesForIncomingHooks(hooks) {
export function loadProfilesForIncomingHooks(hooks: IncomingWebhook[]): ActionFunc {
return async (dispatch, getState) => {
const state = getState();
const profilesToLoad = {};
const profilesToLoad: {[key: string]: boolean} = {};
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i];
if (!getUser(state, hook.user_id)) {
@@ -30,26 +34,28 @@ export function loadProfilesForIncomingHooks(hooks) {
const list = Object.keys(profilesToLoad);
if (list.length === 0) {
return;
return {data: null};
}
dispatch(getProfilesByIds(list));
return {data: null};
};
}
export function loadOutgoingHooksAndProfilesForTeam(teamId, page = 0, perPage = DEFAULT_PAGE_SIZE) {
export function loadOutgoingHooksAndProfilesForTeam(teamId: string, page = 0, perPage = DEFAULT_PAGE_SIZE): ActionFunc {
return async (dispatch) => {
const {data} = await dispatch(IntegrationActions.getOutgoingHooks('', teamId, page, perPage));
if (data) {
dispatch(loadProfilesForOutgoingHooks(data));
}
return {data};
};
}
export function loadProfilesForOutgoingHooks(hooks) {
export function loadProfilesForOutgoingHooks(hooks: OutgoingWebhook[]): ActionFunc {
return async (dispatch, getState) => {
const state = getState();
const profilesToLoad = {};
const profilesToLoad: {[key: string]: boolean} = {};
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i];
if (!getUser(state, hook.creator_id)) {
@@ -59,26 +65,28 @@ export function loadProfilesForOutgoingHooks(hooks) {
const list = Object.keys(profilesToLoad);
if (list.length === 0) {
return;
return {data: null};
}
dispatch(getProfilesByIds(list));
return {data: null};
};
}
export function loadCommandsAndProfilesForTeam(teamId) {
export function loadCommandsAndProfilesForTeam(teamId: string): ActionFunc {
return async (dispatch) => {
const {data} = await dispatch(IntegrationActions.getCustomTeamCommands(teamId));
if (data) {
dispatch(loadProfilesForCommands(data));
}
return {data};
};
}
export function loadProfilesForCommands(commands) {
export function loadProfilesForCommands(commands: Command[]): ActionFunc {
return async (dispatch, getState) => {
const state = getState();
const profilesToLoad = {};
const profilesToLoad: {[key: string]: boolean} = {};
for (let i = 0; i < commands.length; i++) {
const command = commands[i];
if (!getUser(state, command.creator_id)) {
@@ -88,14 +96,15 @@ export function loadProfilesForCommands(commands) {
const list = Object.keys(profilesToLoad);
if (list.length === 0) {
return;
return {data: null};
}
dispatch(getProfilesByIds(list));
return {data: null};
};
}
export function loadOAuthAppsAndProfiles(page = 0, perPage = DEFAULT_PAGE_SIZE) {
export function loadOAuthAppsAndProfiles(page = 0, perPage = DEFAULT_PAGE_SIZE): ActionFunc {
return async (dispatch, getState) => {
if (appsEnabled(getState())) {
dispatch(IntegrationActions.getAppsOAuthAppIDs());
@@ -104,13 +113,14 @@ export function loadOAuthAppsAndProfiles(page = 0, perPage = DEFAULT_PAGE_SIZE)
if (data) {
dispatch(loadProfilesForOAuthApps(data));
}
return {data: null};
};
}
export function loadProfilesForOAuthApps(apps) {
export function loadProfilesForOAuthApps(apps: OAuthApp[]): ActionFunc {
return async (dispatch, getState) => {
const state = getState();
const profilesToLoad = {};
const profilesToLoad: {[key: string]: boolean} = {};
for (let i = 0; i < apps.length; i++) {
const app = apps[i];
if (!getUser(state, app.creator_id)) {
@@ -120,9 +130,10 @@ export function loadProfilesForOAuthApps(apps) {
const list = Object.keys(profilesToLoad);
if (list.length === 0) {
return;
return {data: null};
}
dispatch(getProfilesByIds(list));
return {data: null};
};
}

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

@@ -8,7 +8,7 @@ import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selecto
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {isDevModeEnabled} from 'selectors/general';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
const SUPPORTS_CLEAR_MARKS = isSupported([performance.clearMarks]);
const SUPPORTS_MARK = isSupported([performance.mark]);

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

@@ -28,7 +28,7 @@ import {calculateUnreadCount} from 'mattermost-redux/utils/channel_utils';
import {loadCustomEmojisForCustomStatusesByUserIds} from 'actions/emoji_actions';
import {loadStatusesForProfilesList, loadStatusesForProfilesMap} from 'actions/status_actions';
import {getDisplayedChannels} from 'selectors/views/channel_sidebar';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {Constants, Preferences, UserStatuses} from 'utils/constants';
import * as Utils from 'utils/utils';

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

@@ -110,12 +110,12 @@ import {incrementWsErrorCount, resetWsErrorCount} from 'actions/views/system';
import {updateThreadLastOpened} from 'actions/views/threads';
import {getSelectedChannelId, getSelectedPost} from 'selectors/rhs';
import {isThreadOpen, isThreadManuallyUnread} from 'selectors/views/threads';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import InteractiveDialog from 'components/interactive_dialog';
import RemovedFromChannelModal from 'components/removed_from_channel_modal';
import WebSocketClient from 'client/web_websocket_client.jsx';
import WebSocketClient from 'client/web_websocket_client';
import {loadPlugin, loadPluginsIfNecessary, removePlugin} from 'plugins';
import {getHistory} from 'utils/browser_history';
import {ActionTypes, Constants, AnnouncementBarMessages, SocketEvents, UserStatuses, ModalIdentifiers, WarnMetricTypes} from 'utils/constants';

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

@@ -13,7 +13,7 @@ import {getUser} from 'mattermost-redux/actions/users';
import {handleNewPost} from 'actions/post_actions';
import {syncPostsInChannel} from 'actions/views/channel';
import {closeRightHandSide} from 'actions/views/rhs';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import mergeObjects from 'packages/mattermost-redux/test/merge_objects';
import configureStore from 'tests/test_store';

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

@@ -3,5 +3,5 @@
import {WebSocketClient} from '@mattermost/client';
var WebClient = new WebSocketClient();
const WebClient = new WebSocketClient();
export default WebClient;

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

@@ -12,7 +12,7 @@ import {savePreferences} from 'mattermost-redux/actions/preferences';
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import AlertBanner from 'components/alert_banner';
import withOpenStartTrialFormModal from 'components/common/hocs/cloud/with_open_start_trial_form_modal';

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

@@ -4,7 +4,7 @@
import {shallow} from 'enzyme';
import React from 'react';
import 'tests/helpers/localstorage.jsx';
import 'tests/helpers/localstorage';
import AnnouncementBar from 'components/announcement_bar/default_announcement_bar/announcement_bar';

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

@@ -6,7 +6,7 @@ import {hot} from 'react-hot-loader/root';
import {Provider} from 'react-redux';
import {Router, Route} from 'react-router-dom';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {makeAsyncComponent} from 'components/async_load';
import CRTPostsChannelResetWatcher from 'components/threading/channel_threads/posts_channel_reset_watcher';

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

@@ -72,7 +72,7 @@ type Props = {
/**
* The function to call to fetch team commands
*/
loadCommandsAndProfilesForTeam: (teamId?: string) => any; // TechDebt-TODO: This needs to be changed to 'Promise<void>'
loadCommandsAndProfilesForTeam: (teamId: string) => any; // TechDebt-TODO: This needs to be changed to 'Promise<void>'
};
/**
@@ -95,7 +95,7 @@ export default class CommandsContainer extends React.PureComponent<Props, State>
componentDidMount() {
if (this.props.enableCommands) {
this.props.actions.loadCommandsAndProfilesForTeam(this.props.team?.id).then(
this.props.actions.loadCommandsAndProfilesForTeam(this.props.team?.id || '').then(
() => this.setState({loading: false}),
);
}

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

@@ -17,7 +17,7 @@ import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getUsers} from 'mattermost-redux/selectors/entities/users';
import type {ActionResult, GenericAction} from 'mattermost-redux/types/actions';
import {loadIncomingHooksAndProfilesForTeam} from 'actions/integration_actions.jsx';
import {loadIncomingHooksAndProfilesForTeam} from 'actions/integration_actions';
import InstalledIncomingWebhooks from './installed_incoming_webhooks';

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

@@ -9,7 +9,7 @@ import type {Team} from '@mattermost/types/teams';
import deepFreeze from 'mattermost-redux/utils/deep_freeze';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {mountWithThemedIntl} from 'tests/helpers/themed-intl-test-helper';
import {SelfHostedProducts} from 'utils/constants';

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

@@ -9,7 +9,7 @@ import type {Team} from '@mattermost/types/teams';
import deepFreeze from 'mattermost-redux/utils/deep_freeze';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {mountWithThemedIntl} from 'tests/helpers/themed-intl-test-helper';
import {SelfHostedProducts} from 'utils/constants';

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

@@ -14,7 +14,7 @@ import BrowserStore from 'stores/browser_store';
import LoadingScreen from 'components/loading_screen';
import WebSocketClient from 'client/web_websocket_client.jsx';
import WebSocketClient from 'client/web_websocket_client';
import Constants from 'utils/constants';
import {isKeyPressed} from 'utils/keyboard';
import {getBrowserTimezone} from 'utils/timezone';

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

@@ -8,7 +8,7 @@ import {IntlContext} from 'react-intl';
import type {IntlShape} from 'react-intl';
import {Provider} from 'react-redux';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
export type BaseOverlayTrigger = OriginalOverlayTrigger & {
hide: () => void;

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

@@ -14,7 +14,7 @@ import PostImage from 'components/post_view/post_image';
import PostMessagePreview from 'components/post_view/post_message_preview';
import YoutubeVideo from 'components/youtube_video';
import webSocketClient from 'client/web_websocket_client.jsx';
import webSocketClient from 'client/web_websocket_client';
import type {TextFormattingOptions} from 'utils/text_formatting';
import type {PostWillRenderEmbedPluginComponent} from 'types/store/plugins';

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

@@ -13,7 +13,7 @@ import {Client4} from 'mattermost-redux/client';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
import * as GlobalActions from 'actions/global_actions';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import Root from 'components/root/root';

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

@@ -49,7 +49,7 @@ import SystemNotice from 'components/system_notice';
import TeamSidebar from 'components/team_sidebar';
import WindowSizeObserver from 'components/window_size_observer/WindowSizeObserver';
import webSocketClient from 'client/web_websocket_client.jsx';
import webSocketClient from 'client/web_websocket_client';
import {initializePlugins} from 'plugins';
import Pluggable from 'plugins/pluggable';
import A11yController from 'utils/a11y_controller';

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

@@ -9,7 +9,7 @@ import {getMyChannels, getMyChannelMemberships} from 'mattermost-redux/selectors
import type {ActionResult} from 'mattermost-redux/types/actions.js';
import {sortChannelsByTypeAndDisplayName} from 'mattermost-redux/utils/channel_utils';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {Constants} from 'utils/constants';

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

@@ -9,7 +9,7 @@ import {autocompleteCustomEmojis} from 'mattermost-redux/actions/emojis';
import {getEmojiImageUrl, isSystemEmoji} from 'mattermost-redux/utils/emoji_utils';
import {getEmojiMap, getRecentEmojisNames} from 'selectors/emojis';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {Preferences} from 'utils/constants';
import {compareEmojis, emojiMatchesSkin} from 'utils/emoji_utils';

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

@@ -7,7 +7,7 @@ import type {ActionFunc} from 'mattermost-redux/types/actions.js';
import {isDirectChannel, isGroupChannel, sortChannelsByTypeListAndDisplayName} from 'mattermost-redux/utils/channel_utils';
import {getCurrentLocale} from 'selectors/i18n';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import Constants from 'utils/constants';

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

@@ -18,7 +18,7 @@ import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import type {ActionResult} from 'mattermost-redux/types/actions';
import {sortChannelsByTypeAndDisplayName} from 'mattermost-redux/utils/channel_utils';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {Constants} from 'utils/constants';

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

@@ -49,7 +49,7 @@ import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
import {isGuest} from 'mattermost-redux/utils/user_utils';
import {getPostDraft} from 'selectors/rhs';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import CustomStatusEmoji from 'components/custom_status/custom_status_emoji';
import ProfilePicture from 'components/profile_picture';

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

@@ -15,7 +15,7 @@ import {Provider} from 'react-redux';
import type {StatusOK} from '@mattermost/types/client4';
import type {UserProfile} from '@mattermost/types/users';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import ConfirmModal from 'components/confirm_modal';

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

@@ -6,7 +6,7 @@ import ReactDOM from 'react-dom';
import {logError} from 'mattermost-redux/actions/errors';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import App from 'components/app';

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

@@ -25,7 +25,7 @@ import zhCN from './zh-CN.json';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
// should match the values in model/config.go
const languages = {

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

@@ -11,8 +11,8 @@ import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {unregisterAdminConsolePlugin} from 'actions/admin_actions';
import {trackPluginInitialization} from 'actions/telemetry_actions';
import {unregisterPluginTranslationsSource} from 'actions/views/root';
import {unregisterAllPluginWebSocketEvents, unregisterPluginReconnectHandler} from 'actions/websocket_actions.jsx';
import store from 'stores/redux_store.jsx';
import {unregisterAllPluginWebSocketEvents, unregisterPluginReconnectHandler} from 'actions/websocket_actions';
import store from 'stores/redux_store';
import PluginRegistry from 'plugins/registry';
import {ActionTypes} from 'utils/constants';

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

@@ -1,239 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`plugins/Pluggable should match snapshot with extended component 1`] = `
<Pluggable
components={
Object {
"PopoverSection1": Array [
Object {
"component": [Function],
},
],
}
}
pluggableName="PopoverSection1"
theme={Object {}}
>
<PluggableErrorBoundary
key="PopoverSection1undefined"
>
<ProfilePopoverPlugin
theme={Object {}}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;
exports[`plugins/Pluggable should match snapshot with extended component with pluggableName 1`] = `
<Pluggable
components={
Object {
"PopoverSection1": Array [
Object {
"component": [Function],
},
],
}
}
pluggableName="PopoverSection1"
theme={Object {}}
>
<PluggableErrorBoundary
key="PopoverSection1undefined"
>
<ProfilePopoverPlugin
theme={Object {}}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;
exports[`plugins/Pluggable should match snapshot with no extended component 1`] = `
<Pluggable
components={Object {}}
pluggableName=""
theme={Object {}}
/>
`;
exports[`plugins/Pluggable should match snapshot with non-null pluggableId 1`] = `
<Pluggable
components={
Object {
"PopoverSection1": Array [
Object {
"component": [Function],
},
],
}
}
pluggableId="pluggableId"
pluggableName="PopoverSection1"
/>
`;
exports[`plugins/Pluggable should match snapshot with null pluggableId 1`] = `
<Pluggable
components={
Object {
"PopoverSection1": Array [
Object {
"component": [Function],
},
],
}
}
pluggableName="PopoverSection1"
theme={Object {}}
>
<PluggableErrorBoundary
key="PopoverSection1undefined"
>
<ProfilePopoverPlugin
theme={Object {}}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;
exports[`plugins/Pluggable should match snapshot with valid pluggableId 1`] = `
<Pluggable
components={
Object {
"PopoverSection1": Array [
Object {
"component": [Function],
"id": "pluggableId",
},
],
}
}
pluggableId="pluggableId"
pluggableName="PopoverSection1"
theme={Object {}}
>
<PluggableErrorBoundary
key="PopoverSection1pluggableId"
>
<ProfilePopoverPlugin
theme={Object {}}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;

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

@@ -0,0 +1,660 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`plugins/Pluggable should match snapshot with extended component 1`] = `
<Pluggable
components={
Object {
"AppBar": Array [],
"CallButton": Array [],
"ChannelHeaderButton": Array [],
"CodeBlockAction": Array [],
"CreateBoardFromTemplate": Array [],
"DesktopNotificationHooks": Array [],
"FilePreview": Array [],
"FilesWillUploadHook": Array [],
"LinkTooltip": Array [],
"MainMenu": Array [],
"MobileChannelHeaderButton": Array [],
"NeedsTeamComponent": Array [],
"NewMessagesSeparatorAction": Array [],
"PopoverSection1": Array [
Object {
"component": [Function],
"id": "",
"pluginId": "",
},
],
"PostAction": Array [],
"PostDropdownMenu": Array [],
"PostEditorAction": Array [],
"Product": Array [],
"RightHandSidebarComponent": Array [],
"UserGuideDropdownItem": Array [],
}
}
pluggableName="PopoverSection1"
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
>
<PluggableErrorBoundary
key="PopoverSection1"
pluginId=""
>
<ProfilePopoverPlugin
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;
exports[`plugins/Pluggable should match snapshot with extended component with pluggableName 1`] = `
<Pluggable
components={
Object {
"AppBar": Array [],
"CallButton": Array [],
"ChannelHeaderButton": Array [],
"CodeBlockAction": Array [],
"CreateBoardFromTemplate": Array [],
"DesktopNotificationHooks": Array [],
"FilePreview": Array [],
"FilesWillUploadHook": Array [],
"LinkTooltip": Array [],
"MainMenu": Array [],
"MobileChannelHeaderButton": Array [],
"NeedsTeamComponent": Array [],
"NewMessagesSeparatorAction": Array [],
"PopoverSection1": Array [
Object {
"component": [Function],
"id": "",
"pluginId": "",
},
],
"PostAction": Array [],
"PostDropdownMenu": Array [],
"PostEditorAction": Array [],
"Product": Array [],
"RightHandSidebarComponent": Array [],
"UserGuideDropdownItem": Array [],
}
}
pluggableName="PopoverSection1"
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
>
<PluggableErrorBoundary
key="PopoverSection1"
pluginId=""
>
<ProfilePopoverPlugin
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;
exports[`plugins/Pluggable should match snapshot with no extended component 1`] = `
<Pluggable
components={
Object {
"AppBar": Array [],
"CallButton": Array [],
"ChannelHeaderButton": Array [],
"CodeBlockAction": Array [],
"CreateBoardFromTemplate": Array [],
"DesktopNotificationHooks": Array [],
"FilePreview": Array [],
"FilesWillUploadHook": Array [],
"LinkTooltip": Array [],
"MainMenu": Array [],
"MobileChannelHeaderButton": Array [],
"NeedsTeamComponent": Array [],
"NewMessagesSeparatorAction": Array [],
"PostAction": Array [],
"PostDropdownMenu": Array [],
"PostEditorAction": Array [],
"Product": Array [],
"RightHandSidebarComponent": Array [],
"UserGuideDropdownItem": Array [],
}
}
pluggableName=""
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
/>
`;
exports[`plugins/Pluggable should match snapshot with non-null pluggableId 1`] = `
<Pluggable
components={
Object {
"AppBar": Array [],
"CallButton": Array [],
"ChannelHeaderButton": Array [],
"CodeBlockAction": Array [],
"CreateBoardFromTemplate": Array [],
"DesktopNotificationHooks": Array [],
"FilePreview": Array [],
"FilesWillUploadHook": Array [],
"LinkTooltip": Array [],
"MainMenu": Array [],
"MobileChannelHeaderButton": Array [],
"NeedsTeamComponent": Array [],
"NewMessagesSeparatorAction": Array [],
"PopoverSection1": Array [
Object {
"component": [Function],
"id": "",
"pluginId": "",
},
],
"PostAction": Array [],
"PostDropdownMenu": Array [],
"PostEditorAction": Array [],
"Product": Array [],
"RightHandSidebarComponent": Array [],
"UserGuideDropdownItem": Array [],
}
}
pluggableId="pluggableId"
pluggableName="PopoverSection1"
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
/>
`;
exports[`plugins/Pluggable should match snapshot with null pluggableId 1`] = `
<Pluggable
components={
Object {
"AppBar": Array [],
"CallButton": Array [],
"ChannelHeaderButton": Array [],
"CodeBlockAction": Array [],
"CreateBoardFromTemplate": Array [],
"DesktopNotificationHooks": Array [],
"FilePreview": Array [],
"FilesWillUploadHook": Array [],
"LinkTooltip": Array [],
"MainMenu": Array [],
"MobileChannelHeaderButton": Array [],
"NeedsTeamComponent": Array [],
"NewMessagesSeparatorAction": Array [],
"PopoverSection1": Array [
Object {
"component": [Function],
"id": "",
"pluginId": "",
},
],
"PostAction": Array [],
"PostDropdownMenu": Array [],
"PostEditorAction": Array [],
"Product": Array [],
"RightHandSidebarComponent": Array [],
"UserGuideDropdownItem": Array [],
}
}
pluggableName="PopoverSection1"
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
>
<PluggableErrorBoundary
key="PopoverSection1"
pluginId=""
>
<ProfilePopoverPlugin
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;
exports[`plugins/Pluggable should match snapshot with valid pluggableId 1`] = `
<Pluggable
components={
Object {
"AppBar": Array [],
"CallButton": Array [],
"ChannelHeaderButton": Array [],
"CodeBlockAction": Array [],
"CreateBoardFromTemplate": Array [],
"DesktopNotificationHooks": Array [],
"FilePreview": Array [],
"FilesWillUploadHook": Array [],
"LinkTooltip": Array [],
"MainMenu": Array [],
"MobileChannelHeaderButton": Array [],
"NeedsTeamComponent": Array [],
"NewMessagesSeparatorAction": Array [],
"PopoverSection1": Array [
Object {
"component": [Function],
"id": "pluggableId",
"pluginId": "",
},
],
"PostAction": Array [],
"PostDropdownMenu": Array [],
"PostEditorAction": Array [],
"Product": Array [],
"RightHandSidebarComponent": Array [],
"UserGuideDropdownItem": Array [],
}
}
pluggableId="pluggableId"
pluggableName="PopoverSection1"
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
>
<PluggableErrorBoundary
key="PopoverSection1pluggableId"
pluginId=""
>
<ProfilePopoverPlugin
theme={
Object {
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
webSocketClient={
WebSocketClient {
"closeCallback": null,
"closeListeners": Set {},
"conn": null,
"connectFailCount": 0,
"connectionId": "",
"connectionUrl": null,
"errorCallback": null,
"errorListeners": Set {},
"eventCallback": null,
"firstConnectCallback": null,
"firstConnectListeners": Set {},
"messageListeners": Set {},
"missedEventCallback": null,
"missedMessageListeners": Set {},
"reconnectCallback": null,
"reconnectListeners": Set {},
"responseCallbacks": Object {},
"responseSequence": 1,
"serverSequence": 0,
}
}
>
<span
id="pluginId"
>
ProfilePopoverPlugin
</span>
</ProfilePopoverPlugin>
</PluggableErrorBoundary>
</Pluggable>
`;

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

@@ -3,6 +3,8 @@
import React from 'react';
import {Preferences} from 'mattermost-redux/constants';
import {mountWithIntl} from 'tests/helpers/intl-test-helper';
import Pluggable from './pluggable';
@@ -18,8 +20,28 @@ jest.mock('actions/views/profile_popover');
describe('plugins/Pluggable', () => {
const baseProps = {
pluggableName: '',
components: {},
theme: {},
components: {
Product: [],
CallButton: [],
PostDropdownMenu: [],
PostAction: [],
PostEditorAction: [],
CodeBlockAction: [],
NewMessagesSeparatorAction: [],
FilePreview: [],
MainMenu: [],
LinkTooltip: [],
RightHandSidebarComponent: [],
ChannelHeaderButton: [],
MobileChannelHeaderButton: [],
AppBar: [],
UserGuideDropdownItem: [],
FilesWillUploadHook: [],
NeedsTeamComponent: [],
CreateBoardFromTemplate: [],
DesktopNotificationHooks: [],
},
theme: Preferences.THEMES.denim,
};
test('should match snapshot with no extended component', () => {
@@ -37,7 +59,7 @@ describe('plugins/Pluggable', () => {
<Pluggable
{...baseProps}
pluggableName='PopoverSection1'
components={{PopoverSection1: [{component: ProfilePopoverPlugin}]}}
components={{...baseProps.components, PopoverSection1: [{id: '', pluginId: '', component: ProfilePopoverPlugin}]}}
/>,
);
@@ -51,7 +73,7 @@ describe('plugins/Pluggable', () => {
<Pluggable
{...baseProps}
pluggableName='PopoverSection1'
components={{PopoverSection1: [{component: ProfilePopoverPlugin}]}}
components={{...baseProps.components, PopoverSection1: [{id: '', pluginId: '', component: ProfilePopoverPlugin}]}}
/>,
);
@@ -64,7 +86,7 @@ describe('plugins/Pluggable', () => {
const wrapper = mountWithIntl(
<Pluggable
{...baseProps}
components={{PopoverSection1: [{component: ProfilePopoverPlugin}]}}
components={{...baseProps.components, PopoverSection1: [{id: '', pluginId: '', component: ProfilePopoverPlugin}]}}
/>,
);
@@ -85,9 +107,10 @@ describe('plugins/Pluggable', () => {
test('should match snapshot with non-null pluggableId', () => {
const wrapper = mountWithIntl(
<Pluggable
{...baseProps}
pluggableName='PopoverSection1'
pluggableId={'pluggableId'}
components={{PopoverSection1: [{component: ProfilePopoverPlugin}]}}
components={{...baseProps.components, PopoverSection1: [{id: '', pluginId: '', component: ProfilePopoverPlugin}]}}
/>,
);
@@ -100,7 +123,7 @@ describe('plugins/Pluggable', () => {
<Pluggable
{...baseProps}
pluggableName='PopoverSection1'
components={{PopoverSection1: [{component: ProfilePopoverPlugin}]}}
components={{...baseProps.components, PopoverSection1: [{id: '', pluginId: '', component: ProfilePopoverPlugin}]}}
/>,
);
@@ -114,7 +137,7 @@ describe('plugins/Pluggable', () => {
{...baseProps}
pluggableName='PopoverSection1'
pluggableId={'pluggableId'}
components={{PopoverSection1: [{id: 'pluggableId', component: ProfilePopoverPlugin}]}}
components={{...baseProps.components, PopoverSection1: [{id: 'pluggableId', pluginId: '', component: ProfilePopoverPlugin}]}}
/>,
);

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

@@ -28,7 +28,7 @@ import {
registerPluginReconnectHandler,
unregisterPluginReconnectHandler,
} from 'actions/websocket_actions.jsx';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {ActionTypes} from 'utils/constants';
import {reArg} from 'utils/func';

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

@@ -37,7 +37,32 @@ exports[`plugins/PostMessageView should match snapshot with extended post type 1
}
theme={
Object {
"id": "theme_id",
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
>
@@ -52,7 +77,32 @@ exports[`plugins/PostMessageView should match snapshot with extended post type 1
}
theme={
Object {
"id": "theme_id",
"awayIndicator": "#ffbc1f",
"buttonBg": "#1c58d9",
"buttonColor": "#ffffff",
"centerChannelBg": "#ffffff",
"centerChannelColor": "#3f4350",
"codeTheme": "github",
"dndIndicator": "#d24b4e",
"errorTextColor": "#d24b4e",
"linkColor": "#386fe5",
"mentionBg": "#ffffff",
"mentionBj": "#ffffff",
"mentionColor": "#1e325c",
"mentionHighlightBg": "#ffd470",
"mentionHighlightLink": "#1b1d22",
"newMessageSeparator": "#cc8f00",
"onlineIndicator": "#3db887",
"sidebarBg": "#1e325c",
"sidebarHeaderBg": "#192a4d",
"sidebarHeaderTextColor": "#ffffff",
"sidebarTeamBarBg": "#14213e",
"sidebarText": "#ffffff",
"sidebarTextActiveBorder": "#5d89ea",
"sidebarTextActiveColor": "#ffffff",
"sidebarTextHoverBg": "#28427b",
"sidebarUnreadText": "#ffffff",
"type": "Denim",
}
}
>

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

@@ -3,6 +3,8 @@
import React from 'react';
import type {UserProfile} from '@mattermost/types/users';
import MainMenu from 'components/main_menu/main_menu';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
@@ -15,7 +17,7 @@ describe('plugins/MainMenuActions', () => {
teamType: '',
teamDisplayName: 'some name',
teamName: 'somename',
currentUser: {id: 'someuserid', roles: 'system_user'},
currentUser: {id: 'someuserid', roles: 'system_user'} as UserProfile,
enableCommands: true,
enableCustomEmoji: true,
enableIncomingWebhooks: true,
@@ -27,7 +29,7 @@ describe('plugins/MainMenuActions', () => {
enablePluginMarketplace: true,
showDropdown: true,
onToggleDropdown: () => {}, //eslint-disable-line no-empty-function
pluginMenuItems: [{id: 'someplugin', text: 'some plugin text', action: pluginAction}],
pluginMenuItems: [{id: 'someplugin', pluginId: 'test', text: 'some plugin text', action: pluginAction}],
canCreateOrDeleteCustomEmoji: true,
canManageIntegrations: true,
moreTeamsToJoin: true,
@@ -54,6 +56,7 @@ describe('plugins/MainMenuActions', () => {
isFreeTrial: false,
teamsLimitReached: false,
usageDeltaTeams: -1,
mobile: false,
};
test('should match snapshot in web view', () => {

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

@@ -4,6 +4,8 @@
import {shallow, mount} from 'enzyme';
import React from 'react';
import {Preferences} from 'mattermost-redux/constants';
import PostMessageView from 'components/post_view/post_message_view/post_message_view';
class PostTypePlugin extends React.PureComponent {
@@ -13,7 +15,7 @@ class PostTypePlugin extends React.PureComponent {
}
describe('plugins/PostMessageView', () => {
const post = {type: 'testtype', message: 'this is some text', id: 'post_id'};
const post = {type: 'testtype', message: 'this is some text', id: 'post_id'} as any;
const pluginPostTypes = {
testtype: {component: PostTypePlugin},
};
@@ -24,7 +26,7 @@ describe('plugins/PostMessageView', () => {
currentUser: {username: 'username'},
team: {name: 'team_name'},
emojis: {name: 'smile'},
theme: {id: 'theme_id'},
theme: Preferences.THEMES.denim,
enableFormatting: true,
currentRelativeTeamUrl: 'team_url',
};

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

@@ -4,7 +4,7 @@
import {getRedirectChannelNameForTeam} from 'mattermost-redux/selectors/entities/channels';
import {getBasePath} from 'selectors/general';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {PreviousViewedTypes} from 'utils/constants';

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

@@ -10,6 +10,6 @@ const store = configureStore();
// Export the store to simplify debugging in production environments. This is not a supported API,
// and should not be relied upon by plugins.
window.store = store;
(window as any).store = store;
export default store;

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

@@ -3,6 +3,8 @@
// Based on https://stackoverflow.com/a/41434763
class LocalStorageMock {
store: {[key: string]: string};
constructor() {
this.store = {};
}
@@ -11,17 +13,19 @@ class LocalStorageMock {
this.store = {};
}
getItem(key) {
getItem(key: string): string | null {
return this.store[key] || null;
}
setItem(key, value) {
setItem(key: string, value: {toString: () => string}) {
this.store[key] = value.toString();
}
removeItem(key) {
removeItem(key: string) {
delete this.store[key];
}
}
global.localStorage = new LocalStorageMock();
(global as any).localStorage = new LocalStorageMock();
export {};

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

@@ -20,7 +20,7 @@ Object.defineProperty(window.navigator, 'userAgent', {
export function reset() {
set(initialUA);
}
export function set(ua) {
export function set(ua: string) {
currentUA = ua;
}
export function mockSafari() {

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

@@ -5,7 +5,7 @@ import marked from 'marked';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import type EmojiMap from 'utils/emoji_map';
import RemoveMarkdown from 'utils/markdown/remove_markdown';

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

@@ -7,13 +7,16 @@ import AtMention from 'components/at_mention';
import MarkdownImage from 'components/markdown_image';
import Constants from 'utils/constants';
import EmojiMap from 'utils/emoji_map';
import messageHtmlToComponent from 'utils/message_html_to_component';
import * as TextFormatting from 'utils/text_formatting';
const emptyEmojiMap = new EmojiMap(new Map());
describe('messageHtmlToComponent', () => {
test('plain text', () => {
const input = 'Hello, world!';
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html)).toMatchSnapshot();
});
@@ -29,7 +32,7 @@ F_m - 2 = F_0 F_1 \\dots F_{m-1}
\`\`\`
That was some latex!`;
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html)).toMatchSnapshot();
});
@@ -41,7 +44,7 @@ const myFunction = () => {
};
\`\`\`
`;
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html, {postId: 'randompostid'})).toMatchSnapshot();
});
@@ -51,28 +54,28 @@ const myFunction = () => {
<div>This is a html div</div>
\`\`\`
`;
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html, {postId: 'randompostid'})).toMatchSnapshot();
});
test('link without enabled tooltip plugins', () => {
const input = 'lorem ipsum www.dolor.com sit amet';
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html)).toMatchSnapshot();
});
test('link with enabled a tooltip plugin', () => {
const input = 'lorem ipsum www.dolor.com sit amet';
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html, {hasPluginTooltips: true})).toMatchSnapshot();
});
test('Inline markdown image', () => {
const options = {markdown: true};
const html = TextFormatting.formatText('![Mattermost](/images/icon.png) and a [link](link)', options);
const html = TextFormatting.formatText('![Mattermost](/images/icon.png) and a [link](link)', options, emptyEmojiMap);
const component = messageHtmlToComponent(html, {
hasPluginTooltips: false,
@@ -85,7 +88,7 @@ const myFunction = () => {
test('Inline markdown image where image is link', () => {
const options = {markdown: true};
const html = TextFormatting.formatText('[![Mattermost](images/icon.png)](images/icon.png)', options);
const html = TextFormatting.formatText('[![Mattermost](images/icon.png)](images/icon.png)', options, emptyEmojiMap);
const component = messageHtmlToComponent(html, {
hasPluginTooltips: false,
@@ -98,7 +101,7 @@ const myFunction = () => {
test('At mention', () => {
const options = {mentionHighlight: true, atMentions: true, mentionKeys: [{key: '@joram'}]};
let html = TextFormatting.formatText('@joram', options);
let html = TextFormatting.formatText('@joram', options, emptyEmojiMap);
let component = messageHtmlToComponent(html, {mentionHighlight: true});
expect(component).toMatchSnapshot();
@@ -106,7 +109,7 @@ const myFunction = () => {
options.mentionHighlight = false;
html = TextFormatting.formatText('@joram', options);
html = TextFormatting.formatText('@joram', options, emptyEmojiMap);
component = messageHtmlToComponent(html, {mentionHighlight: false});
expect(component).toMatchSnapshot();
@@ -114,8 +117,8 @@ const myFunction = () => {
});
test('At mention with group highlight disabled', () => {
const options = {mentionHighlight: true, atMentions: true, mentionKeys: [{key: '@joram'}]};
let html = TextFormatting.formatText('@developers', options);
const options: TextFormatting.TextFormattingOptions = {mentionHighlight: true, atMentions: true, mentionKeys: [{key: '@joram'}]};
let html = TextFormatting.formatText('@developers', options, emptyEmojiMap);
let component = messageHtmlToComponent(html, {disableGroupHighlight: false});
expect(component).toMatchSnapshot();
@@ -123,7 +126,7 @@ const myFunction = () => {
options.disableGroupHighlight = true;
html = TextFormatting.formatText('@developers', options);
html = TextFormatting.formatText('@developers', options, emptyEmojiMap);
component = messageHtmlToComponent(html, {disableGroupHighlight: true});
expect(component).toMatchSnapshot();
@@ -139,7 +142,7 @@ const myFunction = () => {
\`\`\`
text after typescript block`;
const html = TextFormatting.formatText(input);
const html = TextFormatting.formatText(input, {}, emptyEmojiMap);
expect(messageHtmlToComponent(html)).toMatchSnapshot();
});

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

@@ -15,6 +15,34 @@ import MarkdownImage from 'components/markdown_image';
import PostEmoji from 'components/post_emoji';
import PostEditedIndicator from 'components/post_view/post_edited_indicator';
export type Options = Partial<{
postId: string;
editedAt: number;
hasPluginTooltips: boolean;
mentions: boolean;
mentionHighlight: boolean;
disableGroupHighlight: boolean;
markdown: boolean;
latex: boolean;
inlinelatex: boolean;
postType: string;
imageProps: {[key: string]: any};
atSumOfMembersMentions: boolean;
userIds: string[];
imagesMetadata: any;
emoji: boolean;
messageMetadata: any;
images: boolean;
atPlanMentions: boolean;
channelId: string;
}>
type ProcessingInstruction = {
replaceChildren: boolean;
shouldProcessNode: (node: any) => boolean;
processNode: (node: any, children?: any, index?: number) => any;
}
/*
* Converts HTML to React components using html-to-react.
* The following options can be specified:
@@ -29,25 +57,25 @@ import PostEditedIndicator from 'components/post_view/post_edited_indicator';
* - hasPluginTooltips - If specified, the LinkTooltip component is placed inside links. Defaults to false.
* - channelId = If specified, to be passed along to ProfilePopover via AtMention
*/
export function messageHtmlToComponent(html, options = {}) {
export function messageHtmlToComponent(html: string, options: Options = {}) {
if (!html) {
return null;
}
const parser = new Parser();
const processNodeDefinitions = new ProcessNodeDefinitions(React);
const parser = new (Parser as any)();
const processNodeDefinitions = new (ProcessNodeDefinitions as any)();
function isValidNode() {
return true;
}
const processingInstructions = [
const processingInstructions: ProcessingInstruction[] = [
// Workaround to fix MM-14931
{
replaceChildren: false,
shouldProcessNode: (node) => node.type === 'tag' && node.name === 'input' && node.attribs.type === 'checkbox',
processNode: (node) => {
shouldProcessNode: (node: any) => node.type === 'tag' && node.name === 'input' && node.attribs.type === 'checkbox',
processNode: (node: any) => {
const attribs = node.attribs || {};
node.attribs.checked = Boolean(attribs.checked);
@@ -56,9 +84,9 @@ export function messageHtmlToComponent(html, options = {}) {
},
{
replaceChildren: false,
shouldProcessNode: (node) => node.type === 'tag' && node.name === 'span' && node.attribs['data-edited-post-id'] && node.attribs['data-edited-post-id'] === options.postId,
shouldProcessNode: (node: any) => node.type === 'tag' && node.name === 'span' && node.attribs['data-edited-post-id'] && node.attribs['data-edited-post-id'] === options.postId,
processNode: () => {
return options.postId && options.editedAt > 0 ? (
return options.postId && options.editedAt && options.editedAt > 0 ? (
<React.Fragment key={`edited-${options.postId}`}>
{' '}
<PostEditedIndicator
@@ -75,8 +103,8 @@ export function messageHtmlToComponent(html, options = {}) {
const hrefAttrib = 'href';
processingInstructions.push({
replaceChildren: true,
shouldProcessNode: (node) => node.type === 'tag' && node.name === 'a' && node.attribs[hrefAttrib],
processNode: (node, children) => {
shouldProcessNode: (node: any) => node.type === 'tag' && node.name === 'a' && node.attribs[hrefAttrib],
processNode: (node: any, children: any) => {
return (
<LinkTooltip
href={node.attribs[hrefAttrib]}
@@ -96,7 +124,7 @@ export function messageHtmlToComponent(html, options = {}) {
processingInstructions.push({
replaceChildren: true,
shouldProcessNode: (node) => node.attribs && node.attribs[mentionAttrib],
processNode: (node, children) => {
processNode: (node: any, children: any) => {
const mentionName = node.attribs[mentionAttrib];
const callAtMention = (
<AtMention
@@ -118,13 +146,13 @@ export function messageHtmlToComponent(html, options = {}) {
const mentionAttrib = 'data-sum-of-members-mention';
processingInstructions.push({
replaceChildren: true,
shouldProcessNode: (node) => node.attribs && node.attribs[mentionAttrib],
processNode: (node) => {
shouldProcessNode: (node: any) => node.attribs && node.attribs[mentionAttrib],
processNode: (node: any) => {
const mentionName = node.attribs[mentionAttrib];
const sumOfMembersMention = (
<AtSumOfMembersMention
postId={options.postId}
userIds={options.userIds}
postId={options.postId || ''}
userIds={options.userIds || []}
messageMetadata={options.messageMetadata}
text={mentionName}
/>);
@@ -137,8 +165,8 @@ export function messageHtmlToComponent(html, options = {}) {
const mentionAttrib = 'data-plan-mention';
processingInstructions.push({
replaceChildren: true,
shouldProcessNode: (node) => node.attribs && node.attribs[mentionAttrib],
processNode: (node) => {
shouldProcessNode: (node: any) => node.attribs && node.attribs[mentionAttrib],
processNode: (node: any) => {
const mentionName = node.attribs[mentionAttrib];
const sumOfMembersMention = (
<AtPlanMention
@@ -153,8 +181,8 @@ export function messageHtmlToComponent(html, options = {}) {
const emojiAttrib = 'data-emoticon';
processingInstructions.push({
replaceChildren: true,
shouldProcessNode: (node) => node.attribs && node.attribs[emojiAttrib],
processNode: (node) => {
shouldProcessNode: (node: any) => node.attribs && node.attribs[emojiAttrib],
processNode: (node: any) => {
const emojiName = node.attribs[emojiAttrib];
return <PostEmoji name={emojiName}/>;
@@ -164,14 +192,15 @@ export function messageHtmlToComponent(html, options = {}) {
if (!('images' in options) || options.images) {
processingInstructions.push({
shouldProcessNode: (node) => node.type === 'tag' && node.name === 'img',
processNode: (node) => {
replaceChildren: false,
shouldProcessNode: (node: any) => node.type === 'tag' && node.name === 'img',
processNode: (node: any) => {
const {
class: className,
...attribs
} = node.attribs;
const imageIsLink = (parentNode) => {
const imageIsLink = (parentNode: any) => {
if (parentNode &&
parentNode.type === 'tag' &&
parentNode.name === 'a'
@@ -198,8 +227,9 @@ export function messageHtmlToComponent(html, options = {}) {
if (!('latex' in options) || options.latex) {
processingInstructions.push({
shouldProcessNode: (node) => node.attribs && node.attribs['data-latex'],
processNode: (node) => {
replaceChildren: false,
shouldProcessNode: (node: any) => node.attribs && node.attribs['data-latex'],
processNode: (node: any) => {
return (
<LatexBlock
key={node.attribs['data-latex']}
@@ -212,8 +242,9 @@ export function messageHtmlToComponent(html, options = {}) {
if (!('inlinelatex' in options) || options.inlinelatex) {
processingInstructions.push({
replaceChildren: false,
shouldProcessNode: (node) => node.attribs && node.attribs['data-inline-latex'],
processNode: (node) => {
processNode: (node: any) => {
return (
<LatexInline content={node.attribs['data-inline-latex']}/>
);
@@ -223,8 +254,9 @@ export function messageHtmlToComponent(html, options = {}) {
if (!('markdown' in options) || options.markdown) {
processingInstructions.push({
replaceChildren: false,
shouldProcessNode: (node) => node.attribs && node.attribs['data-codeblock-code'],
processNode: (node) => {
processNode: (node: any) => {
return (
<CodeBlock
key={node.attribs['data-codeblock-code']}
@@ -238,8 +270,9 @@ export function messageHtmlToComponent(html, options = {}) {
}
processingInstructions.push({
replaceChildren: false,
shouldProcessNode: () => true,
processNode: processNodeDefinitions.processDefaultNode,
processNode: processNodeDefinitions.processDefaultNode as (node: any, children?: any, index?: number) => any,
});
return parser.parseWithInstructions(html, isValidNode, processingInstructions);

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

@@ -4,7 +4,7 @@
import emojiRegex from 'emoji-regex';
import {getEmojiMap} from 'selectors/emojis';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import EmojiMap from 'utils/emoji_map';
import LinkOnlyRenderer from 'utils/markdown/link_only_renderer';

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

@@ -7,7 +7,7 @@ import type {UserProfile} from '@mattermost/types/users';
import {GeneralTypes} from 'mattermost-redux/action_types';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import * as lineBreakHelpers from 'tests/helpers/line_break_helpers.js';
import * as ua from 'tests/helpers/user_agent_mocks';

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

@@ -51,7 +51,7 @@ import {displayUsername, isSystemAdmin} from 'mattermost-redux/utils/user_utils'
import {searchForTerm} from 'actions/post_actions';
import {addUserToTeam} from 'actions/team_actions';
import {getCurrentLocale, getTranslations} from 'selectors/i18n';
import store from 'stores/redux_store.jsx';
import store from 'stores/redux_store';
import {focusPost} from 'components/permalink_view/actions';
import type {TextboxElement} from 'components/textbox';

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

@@ -358,7 +358,7 @@ async function initializeModuleFederation() {
// Desktop specific code for remote module loading
moduleFederationPluginOptions.exposes = {
'./app': 'components/app',
'./store': 'stores/redux_store.jsx',
'./store': 'stores/redux_store',
'./styles': './src/sass/styles.scss',
'./registry': 'module_registry',
};

19
webapp/package-lock.json сгенерированный
Просмотреть файл

@@ -90,7 +90,7 @@
"highlight.js": "11.6.0",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",
"html-to-react": "1.5.0",
"html-to-react": "1.6.0",
"inobounce": "0.2.1",
"katex": "0.16.3",
"key-mirror": "1.0.1",
@@ -12421,13 +12421,16 @@
}
},
"node_modules/html-to-react": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.5.0.tgz",
"integrity": "sha512-tjihXBgaJZRRYzmkrJZ/Qf9jFayilFYcb+sJxXXE2BVLk2XsNrGeuNCVvhXmvREULZb9dz6NFTBC96DTR/lQCQ==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.6.0.tgz",
"integrity": "sha512-W7HvCu2fipgz3F7fpEtIt2Ty6XcqFGQXOorR4+HQAk72y9mTtUH3BmJ43BEvXQHO+bt//z1Hbfe6JzojpSC/9w==",
"dependencies": {
"domhandler": "^5.0",
"htmlparser2": "^8.0",
"lodash.camelcase": "^4.3.0"
},
"peerDependencies": {
"react": "^0.13.0 || ^0.14.0 || >=15"
}
},
"node_modules/html-webpack-plugin": {
@@ -33070,9 +33073,9 @@
"dev": true
},
"html-to-react": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.5.0.tgz",
"integrity": "sha512-tjihXBgaJZRRYzmkrJZ/Qf9jFayilFYcb+sJxXXE2BVLk2XsNrGeuNCVvhXmvREULZb9dz6NFTBC96DTR/lQCQ==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.6.0.tgz",
"integrity": "sha512-W7HvCu2fipgz3F7fpEtIt2Ty6XcqFGQXOorR4+HQAk72y9mTtUH3BmJ43BEvXQHO+bt//z1Hbfe6JzojpSC/9w==",
"requires": {
"domhandler": "^5.0",
"htmlparser2": "^8.0",
@@ -35677,7 +35680,7 @@
"highlight.js": "11.6.0",
"history": "4.10.1",
"hoist-non-react-statics": "3.3.2",
"html-to-react": "1.5.0",
"html-to-react": "1.6.0",
"html-webpack-plugin": "5.5.0",
"identity-obj-proxy": "3.0.0",
"image-webpack-loader": "8.1.0",