mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-29 02:28:16 +08:00
Migrate most remaining files to TypeScript (#36954)
* Migrate actions/emoji_actions to TS * Migrate i18n/i18n to TS * Migrate selectors/admin_console and selectors/admin_console.test to TS * Migrate actions/views/cookie to TS * Migrate actions/views/group to TS * Migrate actions/admin_actions to TS * Migrate actions/telemetry_actions, actions/announcement_bar, actions/notice, actions/search, and actions/system to TS * Migrate actions/views/mfa to TS * Migrate actions/views/posts and actions/views/textbox to TS * Migrate suggestion_box/index to TS * Rename create_selector files to TS files * Migrate create_selector files to TS * Move langmap out of channels and change it to an ES Module * Revert accidentally committed changes to authorize.test.tsx * Remove unused recomputations and resetRecomputations from createSelector * Fix lint * Merge ESLint changes
This commit is contained in:
@@ -69,7 +69,7 @@ var TDefault TranslateFunc = func(translationID string, args ...any) string {
|
||||
var locales = make(map[string]string)
|
||||
|
||||
// supportedLocales is a hard-coded list of locales considered ready for production use. It must
|
||||
// be kept in sync with ../../../../webapp/channels/src/i18n/i18n.jsx.
|
||||
// be kept in sync with ../../../../webapp/channels/src/i18n/i18n.ts.
|
||||
var supportedLocales = []string{
|
||||
"de",
|
||||
"en",
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import * as Actions from 'actions/admin_actions.jsx';
|
||||
import configureStore from 'store';
|
||||
|
||||
import * as Actions from './admin_actions';
|
||||
|
||||
describe('Actions.Admin', () => {
|
||||
let store;
|
||||
beforeEach(async () => {
|
||||
|
||||
+124
-67
@@ -1,6 +1,13 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {ClusterInfo} from '@mattermost/types/admin';
|
||||
import type {StatusOK} from '@mattermost/types/client4';
|
||||
import type {AdminConfig, AllowedIPRange, FetchIPResponse, RequestLicenseBody} from '@mattermost/types/config';
|
||||
import type {Job, JobTypeBase} from '@mattermost/types/jobs';
|
||||
import type {SamlCertificateStatus, SamlMetadataResponse} from '@mattermost/types/saml';
|
||||
import type {AuthChangeResponse, UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import * as AdminActions from 'mattermost-redux/actions/admin';
|
||||
import {bindClientFunc} from 'mattermost-redux/actions/helpers';
|
||||
import {createJob} from 'mattermost-redux/actions/jobs';
|
||||
@@ -15,9 +22,15 @@ import store from 'stores/redux_store';
|
||||
|
||||
import {ActionTypes, JobTypes} from 'utils/constants';
|
||||
|
||||
import type {ThunkActionFunc} from 'types/store';
|
||||
import type {AdminConsolePluginComponent} from 'types/store/plugins';
|
||||
|
||||
const dispatch = store.dispatch;
|
||||
|
||||
export async function reloadConfig(success, error) {
|
||||
type SuccessCallback<T = StatusOK> = ((data: T) => void) | null | undefined;
|
||||
type ErrorCallback = ((error: Error & {id: string; server_error_id: string}) => void) | null | undefined;
|
||||
|
||||
export async function reloadConfig(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.reloadConfig());
|
||||
if (data && success) {
|
||||
dispatch(AdminActions.getConfig());
|
||||
@@ -28,7 +41,7 @@ export async function reloadConfig(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function adminResetMfa(userId, success, error) {
|
||||
export async function adminResetMfa(userId: string, success: SuccessCallback<boolean>, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(UserActions.updateUserMfa(userId, false));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -37,7 +50,7 @@ export async function adminResetMfa(userId, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getClusterStatus(success, error) {
|
||||
export async function getClusterStatus(success: SuccessCallback<ClusterInfo[]>, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.getClusterStatus());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -46,7 +59,7 @@ export async function getClusterStatus(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function ldapTest(success, error) {
|
||||
export async function ldapTest(success: SuccessCallback, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testLdap());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -55,7 +68,7 @@ export async function ldapTest(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function ldapTestConnection(success, error, settings) {
|
||||
export async function ldapTestConnection(success: SuccessCallback, error: ErrorCallback, settings: any) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testLdapConnection(settings));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -64,7 +77,7 @@ export async function ldapTestConnection(success, error, settings) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function ldapTestFilters(success, error, settings) {
|
||||
export async function ldapTestFilters(success: SuccessCallback, error: ErrorCallback, settings: any) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testLdapFilters(settings));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -73,7 +86,7 @@ export async function ldapTestFilters(success, error, settings) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function ldapTestAttributes(success, error, settings) {
|
||||
export async function ldapTestAttributes(success: SuccessCallback, error: ErrorCallback, settings: any) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testLdapAttributes(settings));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -82,7 +95,7 @@ export async function ldapTestAttributes(success, error, settings) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function ldapTestGroupAttributes(success, error, settings) {
|
||||
export async function ldapTestGroupAttributes(success: SuccessCallback, error: ErrorCallback, settings: any) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testLdapGroupAttributes(settings));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -91,7 +104,7 @@ export async function ldapTestGroupAttributes(success, error, settings) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function invalidateAllCaches(success, error) {
|
||||
export async function invalidateAllCaches(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.invalidateCaches());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -100,7 +113,7 @@ export async function invalidateAllCaches(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function recycleDatabaseConnection(success, error) {
|
||||
export async function recycleDatabaseConnection(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.recycleDatabase());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -109,7 +122,7 @@ export async function recycleDatabaseConnection(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function adminResetEmail(user, success, error) {
|
||||
export async function adminResetEmail(user: UserProfile, success: SuccessCallback<UserProfile>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(UserActions.patchUser(user));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -118,7 +131,7 @@ export async function adminResetEmail(user, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function samlCertificateStatus(success, error) {
|
||||
export async function samlCertificateStatus(success: SuccessCallback<SamlCertificateStatus>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.getSamlCertificateStatus());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -127,7 +140,7 @@ export async function samlCertificateStatus(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getIPFilters(success, error) {
|
||||
export async function getIPFilters(success: SuccessCallback<AllowedIPRange[]>, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.getIPFilters());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -136,7 +149,7 @@ export async function getIPFilters(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCurrentIP(success, error) {
|
||||
export async function getCurrentIP(success: SuccessCallback<FetchIPResponse>, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.getCurrentIP());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -145,7 +158,7 @@ export async function getCurrentIP(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function applyIPFilters(ipList, success, error) {
|
||||
export async function applyIPFilters(ipList: AllowedIPRange[], success: SuccessCallback<AllowedIPRange[]>, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.applyIPFilters(ipList));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -154,29 +167,47 @@ export async function applyIPFilters(ipList, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | null} clientId
|
||||
* @returns {ActionResult<OAuthApp>}
|
||||
*/
|
||||
export function getOAuthAppInfo(clientId) {
|
||||
export function getOAuthAppInfo(clientId: string) {
|
||||
return bindClientFunc({
|
||||
clientFunc: Client4.getOAuthAppInfo,
|
||||
params: [clientId],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*}
|
||||
* @returns {ActionResult<{redirect: string}>}
|
||||
*/
|
||||
export function allowOAuth2({responseType, clientId, redirectUri, state, scope, resource, codeChallenge, codeChallengeMethod}) {
|
||||
export function allowOAuth2({
|
||||
responseType,
|
||||
clientId,
|
||||
redirectUri,
|
||||
state,
|
||||
scope,
|
||||
resource,
|
||||
codeChallenge,
|
||||
codeChallengeMethod,
|
||||
}: {
|
||||
responseType: string | null;
|
||||
clientId: string | null;
|
||||
redirectUri: string | null;
|
||||
state: string | null;
|
||||
scope: string | null;
|
||||
resource?: string | null;
|
||||
codeChallenge?: string | null;
|
||||
codeChallengeMethod?: string | null;
|
||||
}) {
|
||||
return bindClientFunc({
|
||||
clientFunc: Client4.authorizeOAuthApp,
|
||||
params: [responseType, clientId, redirectUri, state, scope, resource, codeChallenge, codeChallengeMethod],
|
||||
});
|
||||
}
|
||||
|
||||
export async function emailToLdap(loginId, password, token, ldapId, ldapPassword, success, error) {
|
||||
export async function emailToLdap(
|
||||
loginId: string,
|
||||
password: string,
|
||||
token: string | undefined,
|
||||
ldapId: string,
|
||||
ldapPassword: string,
|
||||
success: SuccessCallback<AuthChangeResponse>,
|
||||
error: ErrorCallback,
|
||||
) {
|
||||
const {data, error: err} = await dispatch(UserActions.switchEmailToLdap(loginId, password, ldapId, ldapPassword, token));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -185,7 +216,14 @@ export async function emailToLdap(loginId, password, token, ldapId, ldapPassword
|
||||
}
|
||||
}
|
||||
|
||||
export async function emailToOAuth(loginId, password, token, newType, success, error) {
|
||||
export async function emailToOAuth(
|
||||
loginId: string,
|
||||
password: string,
|
||||
token: string | undefined,
|
||||
newType: string,
|
||||
success: SuccessCallback<AuthChangeResponse>,
|
||||
error: ErrorCallback,
|
||||
) {
|
||||
const {data, error: err} = await dispatch(UserActions.switchEmailToOAuth(newType, loginId, password, token));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -194,7 +232,13 @@ export async function emailToOAuth(loginId, password, token, newType, success, e
|
||||
}
|
||||
}
|
||||
|
||||
export async function oauthToEmail(currentService, email, password, success, error) {
|
||||
export async function oauthToEmail(
|
||||
currentService: string,
|
||||
email: string,
|
||||
password: string,
|
||||
success: SuccessCallback<AuthChangeResponse>,
|
||||
error: ErrorCallback,
|
||||
) {
|
||||
const {data, error: err} = await dispatch(UserActions.switchOAuthToEmail(currentService, email, password));
|
||||
if (data) {
|
||||
if (data.follow_link) {
|
||||
@@ -208,7 +252,7 @@ export async function oauthToEmail(currentService, email, password, success, err
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadBrandImage(brandImage, success, error) {
|
||||
export async function uploadBrandImage(brandImage: File, success: SuccessCallback<StatusOK>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadBrandImage(brandImage));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -217,7 +261,7 @@ export async function uploadBrandImage(brandImage, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteBrandImage(success, error) {
|
||||
export async function deleteBrandImage(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.deleteBrandImage());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -226,7 +270,7 @@ export async function deleteBrandImage(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadPublicSamlCertificate(file, success, error) {
|
||||
export async function uploadPublicSamlCertificate(file: File, success: SuccessCallback<string>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadPublicSamlCertificate(file));
|
||||
if (data && success) {
|
||||
success('saml-public.crt');
|
||||
@@ -235,7 +279,7 @@ export async function uploadPublicSamlCertificate(file, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadPrivateSamlCertificate(file, success, error) {
|
||||
export async function uploadPrivateSamlCertificate(file: File, success: SuccessCallback<string>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadPrivateSamlCertificate(file));
|
||||
if (data && success) {
|
||||
success('saml-private.key');
|
||||
@@ -244,7 +288,7 @@ export async function uploadPrivateSamlCertificate(file, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadPublicLdapCertificate(file, success, error) {
|
||||
export async function uploadPublicLdapCertificate(file: File, success: SuccessCallback<string>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadPublicLdapCertificate(file));
|
||||
if (data && success) {
|
||||
success('ldap-public.crt');
|
||||
@@ -252,7 +296,7 @@ export async function uploadPublicLdapCertificate(file, success, error) {
|
||||
error({id: err.server_error_id, ...err});
|
||||
}
|
||||
}
|
||||
export async function uploadPrivateLdapCertificate(file, success, error) {
|
||||
export async function uploadPrivateLdapCertificate(file: File, success: SuccessCallback<string>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadPrivateLdapCertificate(file));
|
||||
if (data && success) {
|
||||
success('ldap-private.key');
|
||||
@@ -261,7 +305,7 @@ export async function uploadPrivateLdapCertificate(file, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadIdpSamlCertificate(file, success, error) {
|
||||
export async function uploadIdpSamlCertificate(file: File, success: SuccessCallback<string>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadIdpSamlCertificate(file));
|
||||
if (data && success) {
|
||||
success('saml-idp.crt');
|
||||
@@ -270,7 +314,7 @@ export async function uploadIdpSamlCertificate(file, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadAuditCertificate(fileData, success, error) {
|
||||
export async function uploadAuditCertificate(fileData: File, success: SuccessCallback<string>, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.uploadAuditCertificate(fileData));
|
||||
if (data && success) {
|
||||
success('audit.crt');
|
||||
@@ -279,7 +323,7 @@ export async function uploadAuditCertificate(fileData, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeAuditCertificate(success, error) {
|
||||
export async function removeAuditCertificate(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.removeAuditCertificate());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -288,7 +332,7 @@ export async function removeAuditCertificate(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removePublicSamlCertificate(success, error) {
|
||||
export async function removePublicSamlCertificate(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.removePublicSamlCertificate());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -297,7 +341,7 @@ export async function removePublicSamlCertificate(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removePrivateSamlCertificate(success, error) {
|
||||
export async function removePrivateSamlCertificate(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.removePrivateSamlCertificate());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -306,7 +350,7 @@ export async function removePrivateSamlCertificate(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removePublicLdapCertificate(success, error) {
|
||||
export async function removePublicLdapCertificate(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.removePublicLdapCertificate());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -315,7 +359,7 @@ export async function removePublicLdapCertificate(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removePrivateLdapCertificate(success, error) {
|
||||
export async function removePrivateLdapCertificate(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.removePrivateLdapCertificate());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -324,7 +368,7 @@ export async function removePrivateLdapCertificate(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeIdpSamlCertificate(success, error) {
|
||||
export async function removeIdpSamlCertificate(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.removeIdpSamlCertificate());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -333,7 +377,7 @@ export async function removeIdpSamlCertificate(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStandardAnalytics(teamId) {
|
||||
export async function getStandardAnalytics(teamId?: string) {
|
||||
await dispatch(AdminActions.getStandardAnalytics(teamId));
|
||||
}
|
||||
|
||||
@@ -341,23 +385,23 @@ export async function refreshServerLimits() {
|
||||
await dispatch(getServerLimitsAction());
|
||||
}
|
||||
|
||||
export async function getAdvancedAnalytics(teamId) {
|
||||
export async function getAdvancedAnalytics(teamId?: string) {
|
||||
await dispatch(AdminActions.getAdvancedAnalytics(teamId));
|
||||
}
|
||||
|
||||
export async function getBotPostsPerDayAnalytics(teamId) {
|
||||
export async function getBotPostsPerDayAnalytics(teamId?: string) {
|
||||
await dispatch(AdminActions.getBotPostsPerDayAnalytics(teamId));
|
||||
}
|
||||
|
||||
export async function getPostsPerDayAnalytics(teamId) {
|
||||
export async function getPostsPerDayAnalytics(teamId?: string) {
|
||||
await dispatch(AdminActions.getPostsPerDayAnalytics(teamId));
|
||||
}
|
||||
|
||||
export async function getUsersPerDayAnalytics(teamId) {
|
||||
export async function getUsersPerDayAnalytics(teamId?: string) {
|
||||
await dispatch(AdminActions.getUsersPerDayAnalytics(teamId));
|
||||
}
|
||||
|
||||
export async function elasticsearchTest(config, success, error) {
|
||||
export async function elasticsearchTest(config: AdminConfig, success: SuccessCallback, error?: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testElasticsearch(config));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -366,7 +410,7 @@ export async function elasticsearchTest(config, success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function testFileStoreConnection(success, error) {
|
||||
export async function testFileStoreConnection(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testFileStoreConnection());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -375,7 +419,7 @@ export async function testFileStoreConnection(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function elasticsearchPurgeIndexes(success, error, indexes) {
|
||||
export async function elasticsearchPurgeIndexes(success: SuccessCallback, error: ErrorCallback, indexes?: string[]) {
|
||||
const {data, error: err} = await dispatch(AdminActions.purgeElasticsearchIndexes(indexes));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -384,7 +428,7 @@ export async function elasticsearchPurgeIndexes(success, error, indexes) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function jobCreate(success, error, job) {
|
||||
export async function jobCreate(success: SuccessCallback<Job>, error: ErrorCallback, job: JobTypeBase & {data?: any}) {
|
||||
const {data, error: err} = await dispatch(createJob(job));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -393,7 +437,7 @@ export async function jobCreate(success, error, job) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function rebuildChannelsIndex(success, error) {
|
||||
export async function rebuildChannelsIndex(success: SuccessCallback<void>, error: ErrorCallback) {
|
||||
await elasticsearchPurgeIndexes(undefined, error, ['channels']);
|
||||
const job = {
|
||||
type: JobTypes.ELASTICSEARCH_POST_INDEXING,
|
||||
@@ -406,17 +450,17 @@ export async function rebuildChannelsIndex(success, error) {
|
||||
},
|
||||
};
|
||||
await jobCreate(undefined, error, job);
|
||||
success();
|
||||
success?.();
|
||||
}
|
||||
|
||||
export function setNavigationBlocked(blocked) {
|
||||
export function setNavigationBlocked(blocked: boolean) {
|
||||
return {
|
||||
type: ActionTypes.SET_NAVIGATION_BLOCKED,
|
||||
blocked,
|
||||
};
|
||||
}
|
||||
|
||||
export function deferNavigation(onNavigationConfirmed) {
|
||||
export function deferNavigation(onNavigationConfirmed: () => void) {
|
||||
return {
|
||||
type: ActionTypes.DEFER_NAVIGATION,
|
||||
onNavigationConfirmed,
|
||||
@@ -429,7 +473,7 @@ export function cancelNavigation() {
|
||||
};
|
||||
}
|
||||
|
||||
export function confirmNavigation() {
|
||||
export function confirmNavigation(): ThunkActionFunc<void> {
|
||||
// have to rename these because of lint no-shadow
|
||||
return (thunkDispatch, thunkGetState) => {
|
||||
const callback = getOnNavigationConfirmed(thunkGetState());
|
||||
@@ -444,7 +488,7 @@ export function confirmNavigation() {
|
||||
};
|
||||
}
|
||||
|
||||
export async function invalidateAllEmailInvites(success, error) {
|
||||
export async function invalidateAllEmailInvites(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(TeamActions.invalidateAllEmailInvites());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -453,7 +497,7 @@ export async function invalidateAllEmailInvites(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function testSmtp(success, error) {
|
||||
export async function testSmtp(success: SuccessCallback, error: ErrorCallback) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testEmail());
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -462,7 +506,7 @@ export async function testSmtp(success, error) {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerAdminConsolePlugin(pluginId, reducer) {
|
||||
export function registerAdminConsolePlugin(pluginId: string, reducer: unknown): ThunkActionFunc<void> {
|
||||
return (storeDispatch) => {
|
||||
storeDispatch({
|
||||
type: ActionTypes.RECEIVED_ADMIN_CONSOLE_REDUCER,
|
||||
@@ -474,7 +518,7 @@ export function registerAdminConsolePlugin(pluginId, reducer) {
|
||||
};
|
||||
}
|
||||
|
||||
export function unregisterAdminConsolePlugin(pluginId) {
|
||||
export function unregisterAdminConsolePlugin(pluginId: string): ThunkActionFunc<void> {
|
||||
return (storeDispatch) => {
|
||||
storeDispatch({
|
||||
type: ActionTypes.REMOVED_ADMIN_CONSOLE_REDUCER,
|
||||
@@ -485,7 +529,7 @@ export function unregisterAdminConsolePlugin(pluginId) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function testSiteURL(success, error, siteURL) {
|
||||
export async function testSiteURL(success: SuccessCallback, error: ErrorCallback, siteURL: string) {
|
||||
const {data, error: err} = await dispatch(AdminActions.testSiteURL(siteURL));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -494,7 +538,12 @@ export async function testSiteURL(success, error, siteURL) {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerAdminConsoleCustomSetting(pluginId, key, component, {showTitle}) {
|
||||
export function registerAdminConsoleCustomSetting(
|
||||
pluginId: string,
|
||||
key: string,
|
||||
component: React.Component,
|
||||
{showTitle}: AdminConsolePluginComponent['options'],
|
||||
): ThunkActionFunc<void> {
|
||||
return (storeDispatch) => {
|
||||
storeDispatch({
|
||||
type: ActionTypes.RECEIVED_ADMIN_CONSOLE_CUSTOM_COMPONENT,
|
||||
@@ -508,7 +557,11 @@ export function registerAdminConsoleCustomSetting(pluginId, key, component, {sho
|
||||
};
|
||||
}
|
||||
|
||||
export function registerAdminConsoleCustomSection(pluginId, key, component) {
|
||||
export function registerAdminConsoleCustomSection(
|
||||
pluginId: string,
|
||||
key: string,
|
||||
component: React.Component,
|
||||
): ThunkActionFunc<void> {
|
||||
return (storeDispatch) => {
|
||||
storeDispatch({
|
||||
type: ActionTypes.RECEIVED_ADMIN_CONSOLE_CUSTOM_SECTION,
|
||||
@@ -521,7 +574,11 @@ export function registerAdminConsoleCustomSection(pluginId, key, component) {
|
||||
};
|
||||
}
|
||||
|
||||
export async function getSamlMetadataFromIdp(success, error, samlMetadataURL) {
|
||||
export async function getSamlMetadataFromIdp(
|
||||
success: SuccessCallback<SamlMetadataResponse>,
|
||||
error: ErrorCallback,
|
||||
samlMetadataURL: string,
|
||||
) {
|
||||
const {data, error: err} = await dispatch(AdminActions.getSamlMetadataFromIdp(samlMetadataURL));
|
||||
if (data && success) {
|
||||
success(data);
|
||||
@@ -530,7 +587,7 @@ export async function getSamlMetadataFromIdp(success, error, samlMetadataURL) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function setSamlIdpCertificateFromMetadata(success, error, certData) {
|
||||
export async function setSamlIdpCertificateFromMetadata(success: SuccessCallback<string>, error: ErrorCallback, certData: string) {
|
||||
const {data, error: err} = await dispatch(AdminActions.setSamlIdpCertificateFromMetadata(certData));
|
||||
if (data && success) {
|
||||
success('saml-idp.crt');
|
||||
@@ -571,14 +628,14 @@ export function restartServer() {
|
||||
};
|
||||
}
|
||||
|
||||
export function ping(getServerStatus, deviceId) {
|
||||
export function ping(getServerStatus?: boolean, deviceId?: string) {
|
||||
return async () => {
|
||||
const data = await Client4.ping(getServerStatus, deviceId);
|
||||
return data;
|
||||
};
|
||||
}
|
||||
|
||||
export function requestTrialLicense(requestLicenseBody) {
|
||||
export function requestTrialLicense(requestLicenseBody: RequestLicenseBody) {
|
||||
return async () => {
|
||||
try {
|
||||
const response = await Client4.requestTrialLicense(requestLicenseBody);
|
||||
+29
-28
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {Post} from '@mattermost/types/posts';
|
||||
import type {IDMappedObjects} from '@mattermost/types/utilities';
|
||||
|
||||
import * as EmojiActions from 'mattermost-redux/actions/emojis';
|
||||
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||
import {Preferences as ReduxPreferences} from 'mattermost-redux/constants';
|
||||
@@ -16,8 +19,10 @@ import LocalStorageStore from 'stores/local_storage_store';
|
||||
import Constants, {ActionTypes, Preferences} from 'utils/constants';
|
||||
import {EmojiIndicesByAlias} from 'utils/emoji';
|
||||
|
||||
export function loadRecentlyUsedCustomEmojis() {
|
||||
return (dispatch, getState) => {
|
||||
import type {ActionFunc, ActionFuncAsync} from 'types/store';
|
||||
|
||||
export function loadRecentlyUsedCustomEmojis(): ActionFuncAsync {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
|
||||
if (!getCustomEmojisEnabled(state)) {
|
||||
@@ -31,17 +36,13 @@ export function loadRecentlyUsedCustomEmojis() {
|
||||
}
|
||||
|
||||
export function incrementEmojiPickerPage() {
|
||||
return async (dispatch) => {
|
||||
dispatch({
|
||||
type: ActionTypes.INCREMENT_EMOJI_PICKER_PAGE,
|
||||
});
|
||||
|
||||
return {data: true};
|
||||
return {
|
||||
type: ActionTypes.INCREMENT_EMOJI_PICKER_PAGE,
|
||||
};
|
||||
}
|
||||
|
||||
export function setUserSkinTone(skin) {
|
||||
return async (dispatch, getState) => {
|
||||
export function setUserSkinTone(skin: string): ActionFuncAsync {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const skinTonePreference = [{
|
||||
@@ -50,17 +51,17 @@ export function setUserSkinTone(skin) {
|
||||
category: Preferences.CATEGORY_EMOJI,
|
||||
value: skin,
|
||||
}];
|
||||
dispatch(savePreferences(currentUserId, skinTonePreference));
|
||||
return dispatch(savePreferences(currentUserId, skinTonePreference));
|
||||
};
|
||||
}
|
||||
|
||||
export function addRecentEmoji(alias) {
|
||||
export function addRecentEmoji(alias: string) {
|
||||
return addRecentEmojis([alias]);
|
||||
}
|
||||
|
||||
export const MAXIMUM_RECENT_EMOJI = 27;
|
||||
|
||||
export function addRecentEmojis(aliases) {
|
||||
export function addRecentEmojis(aliases: string[]): ActionFunc {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
@@ -107,9 +108,9 @@ export function addRecentEmojis(aliases) {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomEmojisForCustomStatusesByUserIds(userIds) {
|
||||
export function loadCustomEmojisForCustomStatusesByUserIds(userIds: Set<string> | string[]): ActionFuncAsync {
|
||||
const getCustomStatus = makeGetCustomStatus();
|
||||
return (dispatch, getState) => {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const customEmojiEnabled = isCustomEmojiEnabled(state);
|
||||
const customStatusEnabled = isCustomStatusEnabled(state);
|
||||
@@ -117,7 +118,7 @@ export function loadCustomEmojisForCustomStatusesByUserIds(userIds) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const emojisToLoad = new Set();
|
||||
const emojisToLoad = new Set<string>();
|
||||
|
||||
userIds.forEach((userId) => {
|
||||
const customStatus = getCustomStatus(state, userId);
|
||||
@@ -132,8 +133,8 @@ export function loadCustomEmojisForCustomStatusesByUserIds(userIds) {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomEmojisForRecentCustomStatuses() {
|
||||
return (dispatch, getState) => {
|
||||
export function loadCustomEmojisForRecentCustomStatuses(): ActionFuncAsync {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const customEmojiEnabled = isCustomEmojiEnabled(state);
|
||||
const customStatusEnabled = isCustomStatusEnabled(state);
|
||||
@@ -147,7 +148,7 @@ export function loadCustomEmojisForRecentCustomStatuses() {
|
||||
}
|
||||
|
||||
const recentCustomStatuses = JSON.parse(recentCustomStatusesValue);
|
||||
const emojisToLoad = new Set();
|
||||
const emojisToLoad = new Set<string>();
|
||||
|
||||
for (const customStatus of recentCustomStatuses) {
|
||||
if (!customStatus || !customStatus.emoji) {
|
||||
@@ -161,8 +162,8 @@ export function loadCustomEmojisForRecentCustomStatuses() {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomEmojisIfNeeded(emojis) {
|
||||
return (dispatch, getState) => {
|
||||
export function loadCustomEmojisIfNeeded(emojis: string[]): ActionFuncAsync {
|
||||
return async (dispatch, getState) => {
|
||||
if (!emojis || emojis.length === 0) {
|
||||
return {data: false};
|
||||
}
|
||||
@@ -176,7 +177,7 @@ export function loadCustomEmojisIfNeeded(emojis) {
|
||||
const systemEmojis = EmojiIndicesByAlias;
|
||||
const customEmojisByName = selectCustomEmojisByName(state);
|
||||
const nonExistentCustomEmoji = state.entities.emojis.nonExistentEmoji;
|
||||
const emojisToLoad = [];
|
||||
const emojisToLoad: string[] = [];
|
||||
|
||||
emojis.forEach((emoji) => {
|
||||
if (!emoji) {
|
||||
@@ -205,13 +206,13 @@ export function loadCustomEmojisIfNeeded(emojis) {
|
||||
};
|
||||
}
|
||||
|
||||
export function loadCustomStatusEmojisForPostList(posts) {
|
||||
return (dispatch) => {
|
||||
if (!posts || posts.length === 0) {
|
||||
export function loadCustomStatusEmojisForPostList(posts: IDMappedObjects<Post>): ActionFuncAsync {
|
||||
return async (dispatch) => {
|
||||
if (!posts || Object.keys(posts).length === 0) {
|
||||
return {data: false};
|
||||
}
|
||||
|
||||
const userIds = new Set();
|
||||
const userIds = new Set<string>();
|
||||
Object.keys(posts).forEach((postId) => {
|
||||
const post = posts[postId];
|
||||
if (post.user_id) {
|
||||
@@ -222,7 +223,7 @@ export function loadCustomStatusEmojisForPostList(posts) {
|
||||
};
|
||||
}
|
||||
|
||||
export function migrateRecentEmojis() {
|
||||
export function migrateRecentEmojis(): ActionFuncAsync {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
@@ -230,7 +231,7 @@ export function migrateRecentEmojis() {
|
||||
if (recentEmojisFromPreference.length === 0) {
|
||||
const recentEmojisFromLocalStorage = LocalStorageStore.getRecentEmojis(currentUserId);
|
||||
if (recentEmojisFromLocalStorage) {
|
||||
const parsedRecentEmojisFromLocalStorage = JSON.parse(recentEmojisFromLocalStorage);
|
||||
const parsedRecentEmojisFromLocalStorage = JSON.parse(recentEmojisFromLocalStorage) as string[];
|
||||
const toSetRecentEmojiData = parsedRecentEmojisFromLocalStorage.map((emojiName) => ({name: emojiName, usageCount: 1}));
|
||||
if (toSetRecentEmojiData.length > 0) {
|
||||
dispatch(savePreferences(currentUserId, [{category: Constants.Preferences.RECENT_EMOJIS, name: currentUserId, user_id: currentUserId, value: JSON.stringify(toSetRecentEmojiData)}]));
|
||||
+4
-6
@@ -7,15 +7,13 @@ const HEADER_X_PAGE_LOAD_CONTEXT = 'X-Page-Load-Context';
|
||||
|
||||
/**
|
||||
* Takes an array of string names of performance markers and invokes
|
||||
* performance.clearMarkers on each.
|
||||
* @param {array} names of markers to clear
|
||||
*
|
||||
* performance.clearMarkers on each. *
|
||||
*/
|
||||
export function clearMarks(names) {
|
||||
export function clearMarks(names: string[]) {
|
||||
names.forEach((name) => performance.clearMarks(name));
|
||||
}
|
||||
|
||||
export function mark(name) {
|
||||
export function mark(name: string) {
|
||||
performance.mark(name);
|
||||
}
|
||||
|
||||
@@ -25,7 +23,7 @@ export function mark(name) {
|
||||
* The setTimeout approach is a "best effort" approach that will produce false positives.
|
||||
* A more accurate approach will result in more obtrusive code, which would add risk and maintenance cost.
|
||||
*/
|
||||
export const temporarilySetPageLoadContext = (pageLoadContext) => {
|
||||
export const temporarilySetPageLoadContext = (pageLoadContext: string) => {
|
||||
Client4.setHeader(HEADER_X_PAGE_LOAD_CONTEXT, pageLoadContext);
|
||||
setTimeout(() => {
|
||||
Client4.removeHeader(HEADER_X_PAGE_LOAD_CONTEXT);
|
||||
@@ -345,7 +345,7 @@ export async function loadProfilesForGM() {
|
||||
const currentUserId = Selectors.getCurrentUserId(state);
|
||||
const collapsedThreads = isCollapsedThreadsEnabled(state);
|
||||
|
||||
const userIdsForLoadingCustomEmojis = new Set();
|
||||
const userIdsForLoadingCustomEmojis = new Set<string>();
|
||||
const channelUsersToLoad: string[] = [];
|
||||
for (const channel of getGMsForLoading(state)) {
|
||||
const userIds = userIdsInChannels[channel.id] || new Set();
|
||||
|
||||
+10
-1
@@ -1,13 +1,22 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {GroupSearchParams} from '@mattermost/types/groups';
|
||||
|
||||
import {searchGroups} from 'mattermost-redux/actions/groups';
|
||||
import Permissions from 'mattermost-redux/constants/permissions';
|
||||
import {searchAssociatedGroupsForReferenceLocal} from 'mattermost-redux/selectors/entities/groups';
|
||||
import {isCustomGroupsEnabled} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
||||
|
||||
export function searchAssociatedGroupsForReference(prefix, teamId, channelId, opts = {}) {
|
||||
import type {ActionFuncAsync} from 'types/store';
|
||||
|
||||
export function searchAssociatedGroupsForReference(
|
||||
prefix: string,
|
||||
teamId: string,
|
||||
channelId: string,
|
||||
opts: Omit<GroupSearchParams, 'q'> = {},
|
||||
): ActionFuncAsync {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
if (!haveIChannelPermission(state,
|
||||
@@ -5,13 +5,13 @@ jest.mock('mattermost-redux/actions/users');
|
||||
|
||||
import * as UserActions from 'mattermost-redux/actions/users';
|
||||
|
||||
import configureStore from 'tests/test_store';
|
||||
|
||||
import {
|
||||
activateMfa,
|
||||
deactivateMfa,
|
||||
generateMfaSecret,
|
||||
} from 'actions/views/mfa';
|
||||
|
||||
import configureStore from 'tests/test_store';
|
||||
} from './mfa';
|
||||
|
||||
describe('actions/views/mfa', () => {
|
||||
describe('activateMfa', () => {
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {MfaSecret} from '@mattermost/types/mfa';
|
||||
|
||||
import * as UserActions from 'mattermost-redux/actions/users';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
export function activateMfa(code) {
|
||||
import type {ActionFuncAsync} from 'types/store';
|
||||
|
||||
export function activateMfa(code: string): ActionFuncAsync {
|
||||
return (dispatch, getState) => {
|
||||
const currentUserId = getCurrentUserId(getState());
|
||||
|
||||
@@ -12,7 +16,7 @@ export function activateMfa(code) {
|
||||
};
|
||||
}
|
||||
|
||||
export function deactivateMfa() {
|
||||
export function deactivateMfa(): ActionFuncAsync {
|
||||
return (dispatch, getState) => {
|
||||
const currentUserId = getCurrentUserId(getState());
|
||||
|
||||
@@ -20,7 +24,7 @@ export function deactivateMfa() {
|
||||
};
|
||||
}
|
||||
|
||||
export function generateMfaSecret() {
|
||||
export function generateMfaSecret(): ActionFuncAsync<MfaSecret> {
|
||||
return (dispatch, getState) => {
|
||||
const currentUserId = getCurrentUserId(getState());
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ActionTypes} from 'utils/constants';
|
||||
|
||||
export function dismissNotice(type) {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: ActionTypes.DISMISS_NOTICE,
|
||||
data: type,
|
||||
});
|
||||
|
||||
return {data: true};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ActionTypes} from 'utils/constants';
|
||||
|
||||
export function dismissNotice(type: string) {
|
||||
return {
|
||||
type: ActionTypes.DISMISS_NOTICE,
|
||||
data: type,
|
||||
};
|
||||
}
|
||||
+24
-8
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {Channel} from '@mattermost/types/channels';
|
||||
import type {Post, PostMetadata} from '@mattermost/types/posts';
|
||||
|
||||
import {logError} from 'mattermost-redux/actions/errors';
|
||||
import * as PostActions from 'mattermost-redux/actions/posts';
|
||||
import {Permissions} from 'mattermost-redux/constants';
|
||||
@@ -18,22 +21,24 @@ import {containsAtChannel, groupsMentionedInText} from 'utils/post_utils';
|
||||
import {getSiteURL} from 'utils/url';
|
||||
import {getTimestamp} from 'utils/utils';
|
||||
|
||||
import type {ActionFuncAsync} from 'types/store';
|
||||
|
||||
import {runMessageWillBePostedHooks} from '../hooks';
|
||||
|
||||
export function editPost(post) {
|
||||
export function editPost(post: Post): ActionFuncAsync<Post> {
|
||||
return async (dispatch) => {
|
||||
const result = await dispatch(PostActions.editPost(post));
|
||||
|
||||
// Send to error bar if it's an edit post error about time limit.
|
||||
if (result.error && result.error.server_error_id === 'api.post.update_post.permissions_time_limit.app_error') {
|
||||
dispatch(logError({type: AnnouncementBarTypes.ANNOUNCEMENT, message: result.error.message}, true));
|
||||
dispatch(logError({type: AnnouncementBarTypes.ANNOUNCEMENT, message: result.error.message}));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export function forwardPost(post, channel, message = '') {
|
||||
export function forwardPost(post: Post, channel: Channel, message = ''): ActionFuncAsync<PostActions.CreatePostReturnType> {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const channelId = channel.id;
|
||||
@@ -41,6 +46,10 @@ export function forwardPost(post, channel, message = '') {
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const currentTeam = getCurrentTeam(state);
|
||||
|
||||
if (!currentTeam) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const relativePermaLink = getPermalinkURL(state, currentTeam.id, post.id);
|
||||
const permaLink = `${getSiteURL()}${relativePermaLink}`;
|
||||
|
||||
@@ -51,7 +60,7 @@ export function forwardPost(post, channel, message = '') {
|
||||
const useCustomGroupMentions = isCustomGroupsEnabled(state) && haveICurrentChannelPermission(state, Permissions.USE_GROUP_MENTIONS);
|
||||
const groupsWithAllowReference = useLDAPGroupMentions || useCustomGroupMentions ? getAssociatedGroupsForReferenceByMention(state, currentTeam.id, channelId) : null;
|
||||
|
||||
let newPost = {};
|
||||
let newPost = {} as Post;
|
||||
|
||||
newPost.channel_id = channelId;
|
||||
|
||||
@@ -62,7 +71,7 @@ export function forwardPost(post, channel, message = '') {
|
||||
newPost.pending_post_id = `${userId}:${time}`;
|
||||
newPost.user_id = userId;
|
||||
newPost.create_at = time;
|
||||
newPost.metadata = {};
|
||||
newPost.metadata = {} as PostMetadata;
|
||||
newPost.props = {};
|
||||
|
||||
if (!useChannelMentions && containsAtChannel(newPost.message, {checkAllMentions: true})) {
|
||||
@@ -76,16 +85,23 @@ export function forwardPost(post, channel, message = '') {
|
||||
const hookResult = await dispatch(runMessageWillBePostedHooks(newPost));
|
||||
|
||||
if (hookResult.error) {
|
||||
return hookResult;
|
||||
return hookResult as PostActions.CreatePostReturnType;
|
||||
}
|
||||
|
||||
newPost = hookResult.data;
|
||||
newPost = hookResult.data!;
|
||||
|
||||
return dispatch(PostActions.createPost(newPost, []));
|
||||
};
|
||||
}
|
||||
|
||||
export function selectAttachmentMenuAction(postId, actionId, cookie, dataSource, text, value) {
|
||||
export function selectAttachmentMenuAction(
|
||||
postId: string,
|
||||
actionId: string,
|
||||
cookie: string,
|
||||
dataSource: string | undefined,
|
||||
text: string,
|
||||
value: string,
|
||||
): ActionFuncAsync {
|
||||
return async (dispatch) => {
|
||||
dispatch({
|
||||
type: ActionTypes.SELECT_ATTACHMENT_MENU_ACTION,
|
||||
+11
-9
@@ -3,63 +3,65 @@
|
||||
|
||||
import {SearchTypes} from 'utils/constants';
|
||||
|
||||
export function setModalSearchTerm(term) {
|
||||
import type {ChannelListSearchFilters, ModalFilters, UserGridSearchFilters} from 'types/store/views';
|
||||
|
||||
export function setModalSearchTerm(term: string) {
|
||||
return {
|
||||
type: SearchTypes.SET_MODAL_SEARCH,
|
||||
data: term,
|
||||
};
|
||||
}
|
||||
|
||||
export function setPopoverSearchTerm(term) {
|
||||
export function setPopoverSearchTerm(term: string) {
|
||||
return {
|
||||
type: SearchTypes.SET_POPOVER_SEARCH,
|
||||
data: term,
|
||||
};
|
||||
}
|
||||
|
||||
export function setChannelMembersRhsSearchTerm(term) {
|
||||
export function setChannelMembersRhsSearchTerm(term: string) {
|
||||
return {
|
||||
type: SearchTypes.SET_CHANNEL_MEMBERS_RHS_SEARCH,
|
||||
data: term,
|
||||
};
|
||||
}
|
||||
|
||||
export function setModalFilters(filters = {}) {
|
||||
export function setModalFilters(filters: ModalFilters = {}) {
|
||||
return {
|
||||
type: SearchTypes.SET_MODAL_FILTERS,
|
||||
data: filters,
|
||||
};
|
||||
}
|
||||
|
||||
export function setUserGridSearch(term) {
|
||||
export function setUserGridSearch(term: string) {
|
||||
return {
|
||||
type: SearchTypes.SET_USER_GRID_SEARCH,
|
||||
data: term,
|
||||
};
|
||||
}
|
||||
|
||||
export function setUserGridFilters(filters = {}) {
|
||||
export function setUserGridFilters(filters: UserGridSearchFilters = {}) {
|
||||
return {
|
||||
type: SearchTypes.SET_USER_GRID_FILTERS,
|
||||
data: filters,
|
||||
};
|
||||
}
|
||||
|
||||
export function setTeamListSearch(term) {
|
||||
export function setTeamListSearch(term: string) {
|
||||
return {
|
||||
type: SearchTypes.SET_TEAM_LIST_SEARCH,
|
||||
data: term,
|
||||
};
|
||||
}
|
||||
|
||||
export function setChannelListSearch(term) {
|
||||
export function setChannelListSearch(term: string) {
|
||||
return {
|
||||
type: SearchTypes.SET_CHANNEL_LIST_SEARCH,
|
||||
data: term,
|
||||
};
|
||||
}
|
||||
|
||||
export function setChannelListFilters(filters = {}) {
|
||||
export function setChannelListFilters(filters: ChannelListSearchFilters = {}) {
|
||||
return {
|
||||
type: SearchTypes.SET_CHANNEL_LIST_FILTERS,
|
||||
data: filters,
|
||||
+4
-8
@@ -4,17 +4,13 @@
|
||||
import {ActionTypes} from 'utils/constants';
|
||||
|
||||
export function incrementWsErrorCount() {
|
||||
return async (dispatch) => {
|
||||
dispatch({
|
||||
type: ActionTypes.INCREMENT_WS_ERROR_COUNT,
|
||||
});
|
||||
return {
|
||||
type: ActionTypes.INCREMENT_WS_ERROR_COUNT,
|
||||
};
|
||||
}
|
||||
|
||||
export function resetWsErrorCount() {
|
||||
return async (dispatch) => {
|
||||
dispatch({
|
||||
type: ActionTypes.RESET_WS_ERROR_COUNT,
|
||||
});
|
||||
return {
|
||||
type: ActionTypes.RESET_WS_ERROR_COUNT,
|
||||
};
|
||||
}
|
||||
+5
-5
@@ -3,35 +3,35 @@
|
||||
|
||||
import {ActionTypes} from 'utils/constants';
|
||||
|
||||
export function setShowPreviewOnCreateComment(showPreview) {
|
||||
export function setShowPreviewOnCreateComment(showPreview: boolean) {
|
||||
return {
|
||||
type: ActionTypes.SET_SHOW_PREVIEW_ON_CREATE_COMMENT,
|
||||
showPreview,
|
||||
};
|
||||
}
|
||||
|
||||
export function setShowPreviewOnCreatePost(showPreview) {
|
||||
export function setShowPreviewOnCreatePost(showPreview: boolean) {
|
||||
return {
|
||||
type: ActionTypes.SET_SHOW_PREVIEW_ON_CREATE_POST,
|
||||
showPreview,
|
||||
};
|
||||
}
|
||||
|
||||
export function setShowPreviewOnEditChannelHeaderModal(showPreview) {
|
||||
export function setShowPreviewOnEditChannelHeaderModal(showPreview: boolean) {
|
||||
return {
|
||||
type: ActionTypes.SET_SHOW_PREVIEW_ON_EDIT_CHANNEL_HEADER_MODAL,
|
||||
showPreview,
|
||||
};
|
||||
}
|
||||
|
||||
export function setShowPreviewOnChannelSettingsHeaderModal(showPreview) {
|
||||
export function setShowPreviewOnChannelSettingsHeaderModal(showPreview: boolean) {
|
||||
return {
|
||||
type: ActionTypes.SET_SHOW_PREVIEW_ON_CHANNEL_SETTINGS_HEADER_MODAL,
|
||||
showPreview,
|
||||
};
|
||||
}
|
||||
|
||||
export function setShowPreviewOnChannelSettingsPurposeModal(showPreview) {
|
||||
export function setShowPreviewOnChannelSettingsPurposeModal(showPreview: boolean) {
|
||||
return {
|
||||
type: ActionTypes.SET_SHOW_PREVIEW_ON_CHANNEL_SETTINGS_PURPOSE_MODAL,
|
||||
showPreview,
|
||||
@@ -9,7 +9,7 @@ import {getAccessControlPolicy as fetchPolicy, createAccessControlPolicy as crea
|
||||
import {createJob} from 'mattermost-redux/actions/jobs';
|
||||
import {getAccessControlSettings, getAccessControlPolicy as getPolicy} from 'mattermost-redux/selectors/entities/access_control';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import type {Dispatch} from 'redux';
|
||||
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getMyTeams} from 'mattermost-redux/selectors/entities/teams';
|
||||
|
||||
import {deferNavigation} from 'actions/admin_actions.jsx';
|
||||
import {deferNavigation} from 'actions/admin_actions';
|
||||
import {getCurrentLocale} from 'selectors/i18n';
|
||||
import {getNavigationBlocked} from 'selectors/views/admin';
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import {buttonClassNames} from '@mattermost/shared/components/button';
|
||||
|
||||
import {getCloudCustomer, updateCloudCustomer, updateCloudCustomerAddress} from 'mattermost-redux/actions/cloud';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import BlockableLink from 'components/admin_console/blockable_link';
|
||||
import CountrySelector from 'components/payment_form/country_selector';
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ import {WithTooltip} from '@mattermost/shared/components/tooltip';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import {uploadBrandImage, deleteBrandImage} from 'actions/admin_actions.jsx';
|
||||
import {uploadBrandImage, deleteBrandImage} from 'actions/admin_actions';
|
||||
|
||||
import SettingSet from 'components/admin_console/setting_set';
|
||||
import useDidUpdate from 'components/common/hooks/useDidUpdate';
|
||||
@@ -57,7 +57,7 @@ const BrandImageSetting = ({
|
||||
const imageRef = useRef<HTMLImageElement>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [brandImage, setBrandImage] = useState<Blob | undefined>();
|
||||
const [brandImage, setBrandImage] = useState<File | undefined>();
|
||||
const [shouldDeleteBrandImage, setShouldDeleteBrandImage] = useState(false);
|
||||
const [brandImageExists, setBrandImageExists] = useState(false);
|
||||
const [brandImageTimestamp, setBrandImageTimestamp] = useState(Date.now());
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {MouseEvent} from 'react';
|
||||
|
||||
import type {ClusterInfo} from '@mattermost/types/admin';
|
||||
|
||||
import {getClusterStatus} from 'actions/admin_actions.jsx';
|
||||
import {getClusterStatus} from 'actions/admin_actions';
|
||||
|
||||
import ClusterTable from './cluster_table';
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import {defineMessage} from 'react-intl';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import type {PluginRedux, PluginSetting, PluginSettingSection} from '@mattermost/types/plugins';
|
||||
import type {GlobalState} from '@mattermost/types/store';
|
||||
|
||||
import {createSelector} from 'mattermost-redux/selectors/create_selector';
|
||||
import {appsFeatureFlagEnabled} from 'mattermost-redux/selectors/entities/apps';
|
||||
@@ -18,6 +17,7 @@ import {getAdminConsoleCustomComponents, getAdminConsoleCustomSections} from 'se
|
||||
import {appsPluginID} from 'utils/apps';
|
||||
import {Constants} from 'utils/constants';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
import type {AdminConsolePluginComponent, AdminConsolePluginCustomSection} from 'types/store/plugins';
|
||||
|
||||
import CustomPluginSettings from './custom_plugin_settings';
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import {
|
||||
import {getDataRetentionCustomPolicy} from 'mattermost-redux/selectors/entities/admin';
|
||||
import {getTeamsInPolicy} from 'mattermost-redux/selectors/entities/teams';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import {
|
||||
import {getEnvironmentConfig} from 'mattermost-redux/selectors/entities/admin';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import DatabaseSettings from 'components/admin_console/database_settings';
|
||||
|
||||
import {renderWithContext} from 'tests/react_testing_utils';
|
||||
|
||||
jest.mock('actions/admin_actions.jsx', () => {
|
||||
jest.mock('actions/admin_actions', () => {
|
||||
const pingFn = () => {
|
||||
return jest.fn(() => {
|
||||
return {ActiveSearchBackend: 'none'};
|
||||
|
||||
@@ -9,7 +9,7 @@ import ElasticSearchSettings from 'components/admin_console/elasticsearch_settin
|
||||
|
||||
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
|
||||
|
||||
jest.mock('actions/admin_actions.jsx', () => {
|
||||
jest.mock('actions/admin_actions', () => {
|
||||
return {
|
||||
elasticsearchPurgeIndexes: jest.fn(),
|
||||
rebuildChannelsIndex: jest.fn(),
|
||||
|
||||
@@ -8,7 +8,7 @@ import {FormattedMessage, defineMessage, defineMessages} from 'react-intl';
|
||||
import type {AdminConfig} from '@mattermost/types/config';
|
||||
import type {Job, JobType} from '@mattermost/types/jobs';
|
||||
|
||||
import {elasticsearchPurgeIndexes, elasticsearchTest, rebuildChannelsIndex} from 'actions/admin_actions.jsx';
|
||||
import {elasticsearchPurgeIndexes, elasticsearchTest, rebuildChannelsIndex} from 'actions/admin_actions';
|
||||
|
||||
import ExternalLink from 'components/external_link';
|
||||
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
|
||||
|
||||
@@ -16,7 +16,7 @@ import {getRoles} from 'mattermost-redux/selectors/entities/roles';
|
||||
import {getTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {isCurrentUserSystemAdmin, currentUserHasAnAdminRole, getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {setNavigationBlocked, deferNavigation, cancelNavigation, confirmNavigation} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked, deferNavigation, cancelNavigation, confirmNavigation} from 'actions/admin_actions';
|
||||
import {setAdminConsoleUsersManagementTableProperties} from 'actions/views/admin';
|
||||
import {selectLhsItem} from 'actions/views/lhs';
|
||||
import {getAdminDefinition, getConsoleAccess} from 'selectors/admin_console';
|
||||
|
||||
-1
@@ -48,7 +48,6 @@ describe('components/admin_console/license_settings/LicenseSettings', () => {
|
||||
removeLicense: jest.fn(),
|
||||
upgradeToE0: jest.fn(),
|
||||
ping: jest.fn(),
|
||||
requestTrialLicense: jest.fn(),
|
||||
restartServer: jest.fn(),
|
||||
getPrevTrialLicense: jest.fn(),
|
||||
upgradeToE0Status: jest.fn().mockImplementation(() => Promise.resolve({percentage: 0, error: null})),
|
||||
|
||||
@@ -55,7 +55,6 @@ type Props = {
|
||||
isAllowedToUpgradeToEnterprise: () => Promise<ActionResult>;
|
||||
restartServer: () => Promise<StatusOK>;
|
||||
ping: () => Promise<{status: string}>;
|
||||
requestTrialLicense: (users: number, termsAccepted: boolean, receiveEmailsAccepted: boolean, featureName: string) => Promise<ActionResult>;
|
||||
openModal: <P>(modalData: ModalData<P>) => void;
|
||||
getServerLimits: () => Promise<ActionResult<ServerLimits, ServerError>>;
|
||||
getFilteredUsersStats: (filters: GetFilteredUsersStatsOpts) => Promise<{
|
||||
|
||||
@@ -20,7 +20,7 @@ import useGetAgentsBridgeEnabled from 'components/common/hooks/useGetAgentsBridg
|
||||
import Toggle from 'components/toggle';
|
||||
import BetaTag from 'components/widgets/tag/beta_tag';
|
||||
|
||||
import * as I18n from 'i18n/i18n.jsx';
|
||||
import * as I18n from 'i18n/i18n';
|
||||
|
||||
import AgentsSettings from './agents_settings';
|
||||
import AutoTranslationInfo from './auto_translation_info';
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from 'components/admin_console/system_properties/controls';
|
||||
import ExternalLink from 'components/external_link';
|
||||
|
||||
import * as I18n from 'i18n/i18n.jsx';
|
||||
import * as I18n from 'i18n/i18n';
|
||||
|
||||
import type {SystemConsoleCustomSettingsComponentProps} from '../schema_admin_settings';
|
||||
import type {SearchableStrings} from '../types';
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import {getAccessControlPolicy as fetchPolicy, createAccessControlPolicy as crea
|
||||
import {getAccessControlSettings, getAccessControlPolicy as getPolicy} from 'mattermost-redux/selectors/entities/access_control';
|
||||
import {getFeatureFlagValue} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import {loadRolesIfNeeded, editRole} from 'mattermost-redux/actions/roles';
|
||||
import {getLicense, getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getRoles} from 'mattermost-redux/selectors/entities/roles';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import PermissionSystemSchemeSettings from './permission_system_scheme_settings';
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import AdminSectionPanel from 'components/widgets/admin_console/admin_section_pa
|
||||
import WarningIcon from 'components/widgets/icons/fa_warning_icon';
|
||||
import BetaTag from 'components/widgets/tag/beta_tag';
|
||||
|
||||
import * as I18n from 'i18n/i18n.jsx';
|
||||
import * as I18n from 'i18n/i18n';
|
||||
import Constants from 'utils/constants';
|
||||
import {mappingValueFromRoles, rolesFromMapping} from 'utils/policy_roles_adapter';
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {updateUserRoles} from 'mattermost-redux/actions/users';
|
||||
import {getLicense} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getRolesById} from 'mattermost-redux/selectors/entities/roles';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {updateUserActive, updateUserAuth, getUser, patchUser, updateUserMfa, get
|
||||
import {getConfig, getCustomProfileAttributes, getLicense, isCustomProfileAttributesEnabled} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {setNavigationBlocked} from 'actions/admin_actions.jsx';
|
||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||
import {openModal} from 'actions/views/modals';
|
||||
import {getShowLockedManageUserSettings, getShowManageUserSettings} from 'selectors/admin_console';
|
||||
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ const siteURLCheck = async (config: Partial<AdminConfig>, formatMessage: ReturnT
|
||||
const onError = () => {
|
||||
status = ItemStatus.ERROR;
|
||||
};
|
||||
await testSiteURL(onSuccess, onError, config.ServiceSettings?.SiteURL);
|
||||
await testSiteURL(onSuccess, onError, config.ServiceSettings?.SiteURL ?? '');
|
||||
};
|
||||
|
||||
await testURL();
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ const search = async (
|
||||
check = ItemStatus.OK;
|
||||
}
|
||||
};
|
||||
await elasticsearchTest(config, onSuccess);
|
||||
await elasticsearchTest(config as AdminConfig, onSuccess);
|
||||
return check;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {useCallback, useMemo, useRef, useState} from 'react';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
|
||||
import type {ServerError} from '@mattermost/types/errors';
|
||||
import type {Post} from '@mattermost/types/posts';
|
||||
import type {SchedulingInfo} from '@mattermost/types/schedule_post';
|
||||
|
||||
import {FileTypes} from 'mattermost-redux/action_types';
|
||||
@@ -198,7 +199,9 @@ const useSubmit = (
|
||||
try {
|
||||
let response;
|
||||
if (isInEditMode) {
|
||||
response = await dispatch(editPost(submittingDraft));
|
||||
// The types of Post and PostDraft are mostly interchangeable, but our typing doesn't make it easy to
|
||||
// mix them without assertions like this
|
||||
response = await dispatch(editPost(submittingDraft as unknown as Post));
|
||||
handleFileChange(submittingDraft);
|
||||
} else {
|
||||
response = await dispatch(onSubmit(submittingDraft, options, schedulingInfo));
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {ServerLimits} from '@mattermost/types/limits';
|
||||
|
||||
import {getFormattedFileSize} from 'mattermost-redux/utils/file_utils';
|
||||
|
||||
import * as AdminActions from 'actions/admin_actions.jsx';
|
||||
import * as AdminActions from 'actions/admin_actions';
|
||||
|
||||
import UserSeatAlertBanner from 'components/admin_console/license_settings/user_seat_alert_banner';
|
||||
import ActivatedUserCard from 'components/analytics/activated_users_card';
|
||||
|
||||
@@ -10,27 +10,20 @@ import type {OAuthApp} from '@mattermost/types/integrations';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
import type {allowOAuth2} from 'actions/admin_actions';
|
||||
|
||||
import FormError from 'components/form_error';
|
||||
|
||||
import icon50 from 'images/icon50x50.png';
|
||||
import {getHistory} from 'utils/browser_history';
|
||||
|
||||
export type Params = {
|
||||
responseType: string | null;
|
||||
clientId: string | null;
|
||||
redirectUri: string | null;
|
||||
state: string | null;
|
||||
scope: string | null;
|
||||
resource: string | null;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
location: {
|
||||
search: string;
|
||||
};
|
||||
actions: {
|
||||
getOAuthAppInfo: (clientId: string | null) => Promise<ActionResult<OAuthApp>>;
|
||||
allowOAuth2: (params: Params) => Promise<ActionResult<{redirect: string}>>;
|
||||
getOAuthAppInfo: (clientId: string) => Promise<ActionResult<OAuthApp>>;
|
||||
allowOAuth2: (...params: Parameters<typeof allowOAuth2>) => Promise<ActionResult<{redirect: string}>>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -53,7 +46,7 @@ export default class Authorize extends React.PureComponent<Props, State> {
|
||||
blocker.parentNode.removeChild(blocker);
|
||||
}
|
||||
const clientId = (new URLSearchParams(this.props.location.search)).get('client_id');
|
||||
if (clientId && !((/^[a-z0-9]+$/).test(clientId))) {
|
||||
if (!clientId || !((/^[a-z0-9]+$/).test(clientId))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import type {Dispatch} from 'redux';
|
||||
|
||||
import {allowOAuth2, getOAuthAppInfo} from 'actions/admin_actions.jsx';
|
||||
import {allowOAuth2, getOAuthAppInfo} from 'actions/admin_actions';
|
||||
|
||||
import Authorize from './authorize';
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export type Props = {
|
||||
loadStatusesForProfilesList: (users: UserProfile[]) => void;
|
||||
searchProfiles: (term: string, options: any) => Promise<ActionResult>;
|
||||
closeModal: (modalId: string) => void;
|
||||
searchAssociatedGroupsForReference: (prefix: string, teamId: string, channelId: string | undefined, opts: GroupSearchParams) => Promise<ActionResult>;
|
||||
searchAssociatedGroupsForReference: (prefix: string, teamId: string, channelId: string, opts: GroupSearchParams) => Promise<ActionResult>;
|
||||
getTeamMembersByIds: (teamId: string, userIds: string[]) => Promise<ActionResult>;
|
||||
};
|
||||
};
|
||||
@@ -229,9 +229,7 @@ const ChannelInviteModalComponent = (props: Props) => {
|
||||
let users: UserProfileValue[];
|
||||
if (isPolicyEnforcedPrivate) {
|
||||
const sourceList =
|
||||
term.trim().length > 0 ?
|
||||
(privateAbacSearchHits ?? []) :
|
||||
abacFilteredUsers;
|
||||
term.trim().length > 0 ? (privateAbacSearchHits ?? []) : abacFilteredUsers;
|
||||
users = filterOutDeletedAndExcludedAndNotInTeamUsers(sourceList, excludedAndNotInTeamUserIds);
|
||||
} else {
|
||||
// Non-ABAC or advisory (public policy): full team list.
|
||||
@@ -422,16 +420,14 @@ const ChannelInviteModalComponent = (props: Props) => {
|
||||
// getOptions() reads from. Routing through Redux here would
|
||||
// populate profilesNotInCurrentChannel which getOptions ignores
|
||||
// on the strict-gate path, leaving subsequent pages invisible.
|
||||
const fetchPage = isPolicyEnforcedPrivate ?
|
||||
fetchAbacUsers(page + 1, USERS_PER_PAGE, cursorId) :
|
||||
props.actions.getProfilesNotInChannel(
|
||||
props.channel.team_id,
|
||||
props.channel.id,
|
||||
props.channel.group_constrained,
|
||||
page + 1,
|
||||
USERS_PER_PAGE,
|
||||
cursorId,
|
||||
);
|
||||
const fetchPage = isPolicyEnforcedPrivate ? fetchAbacUsers(page + 1, USERS_PER_PAGE, cursorId) : props.actions.getProfilesNotInChannel(
|
||||
props.channel.team_id,
|
||||
props.channel.id,
|
||||
props.channel.group_constrained,
|
||||
page + 1,
|
||||
USERS_PER_PAGE,
|
||||
cursorId,
|
||||
);
|
||||
|
||||
fetchPage.then((result) => {
|
||||
// Store the cursor for the next page (ID of the last user)
|
||||
|
||||
@@ -63,8 +63,8 @@ export default class ClaimController extends React.PureComponent<Props> {
|
||||
path={`${this.props.match.url}/oauth_to_email`}
|
||||
render={() => (
|
||||
<OAuthToEmail
|
||||
currentType={currentType}
|
||||
email={email}
|
||||
currentType={currentType || ''}
|
||||
email={email || ''}
|
||||
siteName={this.props.siteName}
|
||||
passwordConfig={this.props.passwordConfig}
|
||||
/>
|
||||
@@ -74,7 +74,7 @@ export default class ClaimController extends React.PureComponent<Props> {
|
||||
path={`${this.props.match.url}/email_to_oauth`}
|
||||
render={() => (
|
||||
<EmailToOAuth
|
||||
newType={newType}
|
||||
newType={newType || ''}
|
||||
email={email || ''}
|
||||
siteName={this.props.siteName}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Button} from '@mattermost/shared/components/button';
|
||||
import type {AuthChangeResponse} from '@mattermost/types/users';
|
||||
|
||||
import {emailToLdap} from 'actions/admin_actions.jsx';
|
||||
import {emailToLdap} from 'actions/admin_actions';
|
||||
|
||||
import LoginMfa from 'components/login/login_mfa';
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {Button} from '@mattermost/shared/components/button';
|
||||
import type {AuthChangeResponse} from '@mattermost/types/users';
|
||||
|
||||
import {emailToOAuth} from 'actions/admin_actions.jsx';
|
||||
import {emailToOAuth} from 'actions/admin_actions';
|
||||
|
||||
import LoginMfa from 'components/login/login_mfa';
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {SubmitOptions} from './email_to_ldap';
|
||||
import ErrorLabel from './error_label';
|
||||
|
||||
type Props = {
|
||||
newType: string | null;
|
||||
newType: string;
|
||||
email: string;
|
||||
siteName?: string;
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {AuthChangeResponse} from '@mattermost/types/users';
|
||||
|
||||
import type {PasswordConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import {oauthToEmail} from 'actions/admin_actions.jsx';
|
||||
import {oauthToEmail} from 'actions/admin_actions';
|
||||
|
||||
import Constants from 'utils/constants';
|
||||
import {isValidPassword} from 'utils/password';
|
||||
@@ -19,8 +19,8 @@ import {toTitleCase} from 'utils/utils';
|
||||
import ErrorLabel from './error_label';
|
||||
|
||||
type Props = {
|
||||
currentType: string | null;
|
||||
email: string | null;
|
||||
currentType: string;
|
||||
email: string;
|
||||
siteName?: string;
|
||||
passwordConfig?: PasswordConfig;
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ import './style.scss';
|
||||
|
||||
export type Actions = {
|
||||
addMessageIntoHistory: (message: string) => void;
|
||||
editPost: (input: Partial<Post>) => Promise<Post>;
|
||||
editPost: (input: Post) => Promise<ActionResult<Post>>;
|
||||
setDraft: (name: string, value: PostDraft | null) => void;
|
||||
unsetEditingPost: () => void;
|
||||
scrollPostListToBottom: () => void;
|
||||
|
||||
@@ -5,8 +5,11 @@ import React from 'react';
|
||||
import {defineMessage, FormattedMessage} from 'react-intl';
|
||||
|
||||
import {Button} from '@mattermost/shared/components/button';
|
||||
import type {MfaSecret} from '@mattermost/types/mfa';
|
||||
import type {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
import LocalizedPlaceholderInput from 'components/localized_placeholder_input';
|
||||
|
||||
type Props = {
|
||||
@@ -14,21 +17,11 @@ type Props = {
|
||||
siteName?: string;
|
||||
enforceMultifactorAuthentication: boolean;
|
||||
actions: {
|
||||
activateMfa: (code: string) => Promise<{
|
||||
error?: {
|
||||
server_error_id: string;
|
||||
message: string;
|
||||
};
|
||||
}>;
|
||||
generateMfaSecret: () => Promise<{
|
||||
data: {
|
||||
secret: string;
|
||||
qr_code: string;
|
||||
};
|
||||
error?: {
|
||||
message: string;
|
||||
};
|
||||
}>;
|
||||
activateMfa: (code: string) => Promise<ActionResult<unknown, {
|
||||
server_error_id: string;
|
||||
message: string;
|
||||
}>>;
|
||||
generateMfaSecret: () => Promise<ActionResult<MfaSecret>>;
|
||||
};
|
||||
history: {
|
||||
push(path: string): void;
|
||||
@@ -73,8 +66,8 @@ export default class Setup extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
this.setState({
|
||||
secret: data.secret,
|
||||
qrCode: data.qr_code,
|
||||
secret: data!.secret,
|
||||
qrCode: data!.qr_code,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ export type Props = {
|
||||
isEmbedVisible?: boolean;
|
||||
toggleEmbedVisibility: () => void;
|
||||
actions: {
|
||||
editPost: (post: {id: string; props: Record<string, any>}) => void;
|
||||
editPost: (post: Post) => void;
|
||||
};
|
||||
isInPermalink?: boolean;
|
||||
imageCollapsed?: boolean;
|
||||
@@ -115,7 +115,7 @@ const PostAttachmentOpenGraph = ({openGraphData, post, actions, link, isInPermal
|
||||
props,
|
||||
};
|
||||
|
||||
return actions.editPost(patchedPost);
|
||||
return actions.editPost(patchedPost as Post);
|
||||
};
|
||||
|
||||
const safeLink = makeUrlSafe(openGraphData?.url || link);
|
||||
|
||||
@@ -27,7 +27,7 @@ jest.mock('components/loading_screen', () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('actions/telemetry_actions.jsx', () => ({
|
||||
jest.mock('actions/telemetry_actions', () => ({
|
||||
clearMarks: jest.fn(),
|
||||
mark: jest.fn(),
|
||||
}));
|
||||
|
||||
@@ -6,7 +6,7 @@ import React from 'react';
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
import type {updateNewMessagesAtInChannel} from 'actions/global_actions';
|
||||
import {clearMarks, mark} from 'actions/telemetry_actions.jsx';
|
||||
import {clearMarks, mark} from 'actions/telemetry_actions';
|
||||
import type {LoadPostsParameters, LoadPostsReturnValue, CanLoadMorePosts} from 'actions/views/channel';
|
||||
|
||||
import LoadingScreen from 'components/loading_screen';
|
||||
|
||||
@@ -12,7 +12,7 @@ import {setSystemEmojis} from 'mattermost-redux/actions/emojis';
|
||||
import {setUrl} from 'mattermost-redux/actions/general';
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import {temporarilySetPageLoadContext} from 'actions/telemetry_actions.jsx';
|
||||
import {temporarilySetPageLoadContext} from 'actions/telemetry_actions';
|
||||
import BrowserStore from 'stores/browser_store';
|
||||
|
||||
import {makeAsyncComponent, makeAsyncPluggableComponent} from 'components/async_load';
|
||||
|
||||
@@ -91,7 +91,7 @@ function StartTrialFormModal(props: Props): JSX.Element | null {
|
||||
const [name, setName] = useState('');
|
||||
const [email, setEmail] = useState(currentUser.email);
|
||||
const [companyName, setCompanyName] = useState('');
|
||||
const [orgSize, setOrgSize] = useState<OrgSize | undefined>();
|
||||
const [orgSize, setOrgSize] = useState<OrgSize | ''>('');
|
||||
const [country, setCountry] = useState('');
|
||||
const [businessEmailError, setBusinessEmailError] = useState<CustomMessageInputType | undefined>(undefined);
|
||||
const {formatMessage} = useIntl();
|
||||
@@ -213,8 +213,8 @@ function StartTrialFormModal(props: Props): JSX.Element | null {
|
||||
};
|
||||
|
||||
const getOrgSizeDropdownValue = () => {
|
||||
if (typeof orgSize === 'undefined') {
|
||||
return orgSize;
|
||||
if (!orgSize) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
value: orgSize,
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ export type Props = {
|
||||
autocompleteUsersInChannel: (prefix: string) => Promise<ActionResult>;
|
||||
useChannelMentions: boolean;
|
||||
autocompleteGroups: Group[] | null;
|
||||
searchAssociatedGroupsForReference: (prefix: string) => Promise<{data: Group[]}>;
|
||||
searchAssociatedGroupsForReference: (prefix: string) => Promise<ActionResult<Group[]>>;
|
||||
priorityProfiles: UserProfile[] | undefined;
|
||||
defaultAgent?: Agent;
|
||||
};
|
||||
@@ -71,7 +71,7 @@ export default class AtMentionProvider extends Provider {
|
||||
public autocompleteUsersInChannel: (prefix: string) => Promise<ActionResult>;
|
||||
public useChannelMentions: boolean;
|
||||
public autocompleteGroups: Group[] | null;
|
||||
public searchAssociatedGroupsForReference: (prefix: string) => Promise<{data: Group[]}>;
|
||||
public searchAssociatedGroupsForReference: (prefix: string) => Promise<ActionResult<Group[]>>;
|
||||
public priorityProfiles: UserProfile[] | undefined;
|
||||
public defaultAgent?: Agent;
|
||||
|
||||
|
||||
+2
-2
@@ -2,13 +2,13 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {bindActionCreators, type Dispatch} from 'redux';
|
||||
|
||||
import {addMessageIntoHistory} from 'mattermost-redux/actions/posts';
|
||||
|
||||
import SuggestionBox from './suggestion_box';
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
function mapDispatchToProps(dispatch: Dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
addMessageIntoHistory,
|
||||
@@ -64,7 +64,7 @@ export type Props = {
|
||||
actions: {
|
||||
autocompleteUsersInChannel: (prefix: string, channelId: string) => Promise<ActionResult>;
|
||||
autocompleteChannels: (term: string, success: (channels: Channel[]) => void, error: () => void) => Promise<ActionResult>;
|
||||
searchAssociatedGroupsForReference: (prefix: string, teamId: string, channelId: string | undefined) => Promise<{data: any}>;
|
||||
searchAssociatedGroupsForReference: (prefix: string, teamId: string, channelId: string) => Promise<ActionResult>;
|
||||
fetchAgents: () => Promise<ActionResult>;
|
||||
};
|
||||
useChannelMentions: boolean;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
import {getAllLanguages, getLanguageInfo, getLanguages, isLanguageAvailable, languages} from './i18n';
|
||||
|
||||
jest.mock('./imports', () => ({
|
||||
@@ -35,7 +37,7 @@ describe('i18n', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} as GlobalState;
|
||||
|
||||
// no experimental languages
|
||||
expect(getLanguages(state)).toBe(languages);
|
||||
@@ -82,7 +84,7 @@ describe('i18n', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} as GlobalState;
|
||||
|
||||
// no experimental languages
|
||||
expect(isLanguageAvailable(state, 'cc')).toBe(false);
|
||||
@@ -7,8 +7,17 @@
|
||||
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
import {langFiles, langIDs, langLabels} from './imports';
|
||||
|
||||
export interface Language {
|
||||
value: string;
|
||||
name: string;
|
||||
order: number;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// should match the values in server/public/shared/i18n/i18n.go
|
||||
export const languages = {
|
||||
de: {
|
||||
@@ -145,14 +154,14 @@ export const languages = {
|
||||
},
|
||||
};
|
||||
|
||||
export function getAllLanguages(includeExperimental) {
|
||||
export function getAllLanguages(includeExperimental = false): Record<string, Language> {
|
||||
if (includeExperimental) {
|
||||
let order = Object.keys(languages).length;
|
||||
return {
|
||||
...langIDs.reduce((out, id) => {
|
||||
...langIDs.reduce<Record<string, Language>>((out, id) => {
|
||||
out[id] = {
|
||||
value: id,
|
||||
name: langLabels[id] + ' (Experimental)',
|
||||
name: langLabels[id as keyof typeof langLabels] + ' (Experimental)',
|
||||
url: langFiles[id],
|
||||
order: order++,
|
||||
};
|
||||
@@ -164,32 +173,23 @@ export function getAllLanguages(includeExperimental) {
|
||||
return languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('types/store').GlobalState} state
|
||||
* @returns {Record<string, Language>}
|
||||
*/
|
||||
export function getLanguages(state) {
|
||||
export function getLanguages(state: GlobalState) {
|
||||
const config = getConfig(state);
|
||||
if (!config.AvailableLocales) {
|
||||
return getAllLanguages(config.EnableExperimentalLocales === 'true');
|
||||
}
|
||||
return config.AvailableLocales.split(',').reduce((result, l) => {
|
||||
if (languages[l]) {
|
||||
result[l] = languages[l];
|
||||
return config.AvailableLocales.split(',').reduce<Record<string, Language>>((result, l) => {
|
||||
if (Object.hasOwn(languages, l)) {
|
||||
result[l] = languages[l as keyof typeof languages];
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function getLanguageInfo(locale) {
|
||||
export function getLanguageInfo(locale: string) {
|
||||
return getAllLanguages(true)[locale];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('types/store').GlobalState} state
|
||||
* @param {string} locale
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isLanguageAvailable(state, locale) {
|
||||
export function isLanguageAvailable(state: GlobalState, locale: string) {
|
||||
return Boolean(getLanguages(state)[locale]);
|
||||
}
|
||||
@@ -68,12 +68,75 @@ import vi from './vi.json';
|
||||
import zhCN from './zh-CN.json';
|
||||
import zhTW from './zh-TW.json';
|
||||
|
||||
type TranslationsMap = {
|
||||
[id: string]: string,
|
||||
};
|
||||
|
||||
export const langIDs = ["am","ar","be","bg","bn","br","ca","cs","da","de","el","en-AU","es","et","eu","fa","fi","fil","fr","fy","gl","gu","he","hi","hr","hu","id","is","it","ja","ka","kk-Latn","kk","km","ko","la","lo","lt","lv","mk","ml","mn","nb-NO","ne","nl","pl","pr","pt-BR","pt","ro","ru","si","sl","sq","sr","sv","th","tr","uk","vi","zh-CN","zh-TW"];
|
||||
|
||||
export const langLabels = {"am":"አማርኛ","ar":"العربية","be":"Беларуская","bg":"Български","bn":"বাংলা","br":"Brezhoneg","ca":"Català","cs":"Čeština","da":"Dansk","de":"Deutsch","el":"Ελληνικά","en-AU":"English (Australia)","es":"Español","et":"eesti keel","eu":"Euskara","fa":"فارسی","fi":"Suomi","fil":"Filipino","fr":"Français","fy":"Frysk","gl":"Galego","gu":"ગુજરાતી","he":"עברית","hi":"हिन्दी","hr":"Hrvatski","hu":"Magyar","id":"Bahasa Indonesia","is":"Íslenska","it":"Italiano","ja":"日本語","ka":"ქართული","kk-Latn":"Қазақша","kk":"Қазақша","km":"ភាសាខ្មែរ","ko":"한국어","la":"Latin","lo":"ພາສາລາວ","lt":"Lietuvių","lv":"Latviešu","mk":"Македонски","ml":"മലയാളം","mn":"Монгол","nb-NO":"Norsk (bokmål)","ne":"नेपाली","nl":"Nederlands","pl":"Polski","pr":"pr","pt-BR":"Português (Brasil)","pt":"Português","ro":"Română","ru":"Русский","si":"සිංහල","sl":"Slovenščina","sq":"Shqip","sr":"Српски","sv":"Svenska","th":"ภาษาไทย","tr":"Türkçe","uk":"Українська","vi":"Tiếng Việt","zh-CN":"中文(中国大陆)","zh-TW":"中文(台灣)"};
|
||||
|
||||
export const langFiles: {[langID: string]: TranslationsMap} = {am,ar,be,bg,bn,br,ca,cs,da,de,el,'en-AU':enAU,es,et,eu,fa,fi,fil,fr,fy,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,'kk-Latn':kkLatn,kk,km,ko,la,lo,lt,lv,mk,ml,mn,'nb-NO':nbNO,ne,nl,pl,pr,'pt-BR':ptBR,pt,ro,ru,si,sl,sq,sr,sv,th,tr,uk,vi,'zh-CN':zhCN,'zh-TW':zhTW};
|
||||
// TypeScript thinks it's importing these language files' contents directly, but Webpack rewrites the above imports
|
||||
// to the URL the file for lazy loading. That's the reason for the ugly type assertions below.
|
||||
export const langFiles: {
|
||||
[langID: string]: string;
|
||||
} = {
|
||||
am: am as unknown as string,
|
||||
ar: ar as unknown as string,
|
||||
be: be as unknown as string,
|
||||
bg: bg as unknown as string,
|
||||
bn: bn as unknown as string,
|
||||
br: br as unknown as string,
|
||||
ca: ca as unknown as string,
|
||||
cs: cs as unknown as string,
|
||||
da: da as unknown as string,
|
||||
de: de as unknown as string,
|
||||
el: el as unknown as string,
|
||||
'en-AU': enAU as unknown as string,
|
||||
es: es as unknown as string,
|
||||
et: et as unknown as string,
|
||||
eu: eu as unknown as string,
|
||||
fa: fa as unknown as string,
|
||||
fi: fi as unknown as string,
|
||||
fil: fil as unknown as string,
|
||||
fr: fr as unknown as string,
|
||||
fy: fy as unknown as string,
|
||||
gl: gl as unknown as string,
|
||||
gu: gu as unknown as string,
|
||||
he: he as unknown as string,
|
||||
hi: hi as unknown as string,
|
||||
hr: hr as unknown as string,
|
||||
hu: hu as unknown as string,
|
||||
id: id as unknown as string,
|
||||
is: is as unknown as string,
|
||||
it: it as unknown as string,
|
||||
ja: ja as unknown as string,
|
||||
ka: ka as unknown as string,
|
||||
'kk-Latn': kkLatn as unknown as string,
|
||||
kk: kk as unknown as string,
|
||||
km: km as unknown as string,
|
||||
ko: ko as unknown as string,
|
||||
la: la as unknown as string,
|
||||
lo: lo as unknown as string,
|
||||
lt: lt as unknown as string,
|
||||
lv: lv as unknown as string,
|
||||
mk: mk as unknown as string,
|
||||
ml: ml as unknown as string,
|
||||
mn: mn as unknown as string,
|
||||
'nb-NO': nbNO as unknown as string,
|
||||
ne: ne as unknown as string,
|
||||
nl: nl as unknown as string,
|
||||
pl: pl as unknown as string,
|
||||
pr: pr as unknown as string,
|
||||
'pt-BR': ptBR as unknown as string,
|
||||
pt: pt as unknown as string,
|
||||
ro: ro as unknown as string,
|
||||
ru: ru as unknown as string,
|
||||
si: si as unknown as string,
|
||||
sl: sl as unknown as string,
|
||||
sq: sq as unknown as string,
|
||||
sr: sr as unknown as string,
|
||||
sv: sv as unknown as string,
|
||||
th: th as unknown as string,
|
||||
tr: tr as unknown as string,
|
||||
uk: uk as unknown as string,
|
||||
vi: vi as unknown as string,
|
||||
'zh-CN': zhCN as unknown as string,
|
||||
'zh-TW': zhTW as unknown as string
|
||||
};
|
||||
|
||||
@@ -1054,7 +1054,7 @@ export function updateUserRoles(userId: string, roles: string): ActionFuncAsync
|
||||
};
|
||||
}
|
||||
|
||||
export function updateUserMfa(userId: string, activate: boolean, code = ''): ActionFuncAsync {
|
||||
export function updateUserMfa(userId: string, activate: boolean, code = ''): ActionFuncAsync<boolean> {
|
||||
return async (dispatch, getState) => {
|
||||
try {
|
||||
await Client4.updateUserMfa(userId, activate, code);
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ export const RESOURCE_KEYS = {
|
||||
DEVELOPER: 'environment.developer',
|
||||
MOBILE_SECURITY: 'environment.mobile_security',
|
||||
},
|
||||
};
|
||||
} as const;
|
||||
|
||||
export const ResourceToSysConsolePermissionsTable: Record<string, string[]> = {
|
||||
[RESOURCE_KEYS.ABOUT.EDITION_AND_LICENSE]: [Permissions.SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE, Permissions.SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE],
|
||||
|
||||
-1106
File diff suppressed because it is too large
Load Diff
@@ -1,110 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
function defaultEqualityCheck(a, b) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
function areArgumentsShallowlyEqual(equalityCheck, prev, next) {
|
||||
if (prev === null || next === null || prev.length !== next.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
|
||||
const length = prev.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (!equalityCheck(prev[i], next[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
|
||||
let lastArgs = null
|
||||
let lastResult = null
|
||||
// we reference arguments instead of spreading them for performance reasons
|
||||
return function () {
|
||||
if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
|
||||
// apply arguments instead of spreading for performance.
|
||||
lastResult = func.apply(null, arguments)
|
||||
}
|
||||
|
||||
lastArgs = arguments
|
||||
return lastResult
|
||||
}
|
||||
}
|
||||
|
||||
function getDependencies(funcs) {
|
||||
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
|
||||
|
||||
if (!dependencies.every((dep) => typeof dep === 'function')) {
|
||||
const dependencyTypes = dependencies.map(
|
||||
(dep) => typeof dep,
|
||||
).join(', ');
|
||||
throw new Error(
|
||||
'Selector creators expect all input-selectors to be functions, ' +
|
||||
`instead received the following types: [${dependencyTypes}]`,
|
||||
);
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
export function createSelectorCreator(memoize, ...memoizeOptions) {
|
||||
return (name, ...funcs) => {
|
||||
const resultFunc = funcs.pop();
|
||||
const dependencies = getDependencies(funcs);
|
||||
|
||||
const memoizedResultFunc = memoize(
|
||||
function() {
|
||||
// apply arguments instead of spreading for performance.
|
||||
return resultFunc?.apply(null, arguments);
|
||||
},
|
||||
...memoizeOptions,
|
||||
);
|
||||
|
||||
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
|
||||
const selector = memoize(function() {
|
||||
const params = [];
|
||||
const length = dependencies.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
// apply arguments instead of spreading and mutate a local list of params for performance.
|
||||
params.push(dependencies[i].apply(null, arguments));
|
||||
}
|
||||
|
||||
// apply arguments instead of spreading for performance.
|
||||
return memoizedResultFunc.apply(null, params);
|
||||
});
|
||||
|
||||
selector.resultFunc = resultFunc;
|
||||
selector.dependencies = dependencies;
|
||||
|
||||
return selector;
|
||||
};
|
||||
}
|
||||
|
||||
export const createSelector = /* #__PURE__ */ createSelectorCreator(defaultMemoize);
|
||||
|
||||
export function createStructuredSelector(selectors, selectorCreator = createSelector) {
|
||||
if (typeof selectors !== 'object') {
|
||||
throw new Error(
|
||||
'createStructuredSelector expects first argument to be an object ' +
|
||||
`where each property is a selector, instead received a ${typeof selectors}`,
|
||||
);
|
||||
}
|
||||
const objectKeys = Object.keys(selectors);
|
||||
return selectorCreator(
|
||||
objectKeys.map((key) => selectors[key]),
|
||||
(...values) => {
|
||||
return values.reduce((composition, value, index) => {
|
||||
composition[objectKeys[index]] = value;
|
||||
return composition;
|
||||
}, {});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||
/* eslint-disable prefer-spread */
|
||||
/* eslint-disable prefer-rest-params */
|
||||
|
||||
import type {CreateSelector, EqualityCheck, ParametricSelector, Selector} from './types';
|
||||
|
||||
export type {
|
||||
Selector,
|
||||
OutputSelector,
|
||||
ParametricSelector,
|
||||
OutputParametricSelector,
|
||||
CreateSelector,
|
||||
} from './types';
|
||||
|
||||
function defaultEqualityCheck(a: any, b: any): boolean {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
function areArgumentsShallowlyEqual(equalityCheck: EqualityCheck, prev: IArguments | null, next: IArguments | null): boolean {
|
||||
if (prev === null || next === null || prev.length !== next.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
|
||||
const length = prev.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (!equalityCheck(prev[i], next[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function defaultMemoize<F extends Function>(func: F, equalityCheck: Function = defaultEqualityCheck): F {
|
||||
let lastArgs: IArguments | null = null;
|
||||
let lastResult: any = null;
|
||||
|
||||
// we reference arguments instead of spreading them for performance reasons
|
||||
return function memoized() {
|
||||
if (!areArgumentsShallowlyEqual(equalityCheck as EqualityCheck, lastArgs, arguments)) {
|
||||
// apply arguments instead of spreading for performance.
|
||||
lastResult = func.apply(null, arguments as any);
|
||||
}
|
||||
|
||||
lastArgs = arguments;
|
||||
return lastResult;
|
||||
} as unknown as F;
|
||||
}
|
||||
|
||||
function getDependencies(funcs: any[]): Function[] {
|
||||
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
|
||||
|
||||
if (!dependencies.every((dep: any) => typeof dep === 'function')) {
|
||||
const dependencyTypes = dependencies.map(
|
||||
(dep: any) => typeof dep,
|
||||
).join(', ');
|
||||
throw new Error(
|
||||
'Selector creators expect all input-selectors to be functions, ' +
|
||||
`instead received the following types: [${dependencyTypes}]`,
|
||||
);
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
export function createSelectorCreator(
|
||||
memoize: <F extends Function>(func: F, measure: Function) => F,
|
||||
): typeof createSelector;
|
||||
|
||||
export function createSelectorCreator<O1>(
|
||||
memoize: <F extends Function>(func: F, measure: Function,
|
||||
option1: O1) => F,
|
||||
option1: O1,
|
||||
): typeof createSelector;
|
||||
|
||||
export function createSelectorCreator<O1, O2>(
|
||||
memoize: <F extends Function>(func: F, measure: Function,
|
||||
option1: O1,
|
||||
option2: O2) => F,
|
||||
option1: O1,
|
||||
option2: O2,
|
||||
): typeof createSelector;
|
||||
|
||||
export function createSelectorCreator<O1, O2, O3>(
|
||||
memoize: <F extends Function>(func: F, measure: Function,
|
||||
option1: O1,
|
||||
option2: O2,
|
||||
option3: O3,
|
||||
...rest: any[]) => F,
|
||||
option1: O1,
|
||||
option2: O2,
|
||||
option3: O3,
|
||||
...rest: any[]
|
||||
): typeof createSelector;
|
||||
|
||||
export function createSelectorCreator(memoize: any, ...memoizeOptions: any[]): typeof createSelector {
|
||||
return ((_name: string, ...funcs: any[]) => {
|
||||
const resultFunc = funcs.pop();
|
||||
const dependencies = getDependencies(funcs);
|
||||
|
||||
const memoizedResultFunc = memoize(
|
||||
function resultFuncMemoized() {
|
||||
// apply arguments instead of spreading for performance.
|
||||
return resultFunc?.apply(null, arguments);
|
||||
},
|
||||
...memoizeOptions,
|
||||
);
|
||||
|
||||
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
|
||||
const selector = memoize(function selectorMemoized() {
|
||||
const params = [];
|
||||
const length = dependencies.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
// apply arguments instead of spreading and mutate a local list of params for performance.
|
||||
params.push(dependencies[i].apply(null, arguments));
|
||||
}
|
||||
|
||||
// apply arguments instead of spreading for performance.
|
||||
return memoizedResultFunc.apply(null, params);
|
||||
});
|
||||
|
||||
selector.resultFunc = resultFunc;
|
||||
selector.dependencies = dependencies;
|
||||
|
||||
return selector;
|
||||
});
|
||||
}
|
||||
|
||||
export const createSelector: CreateSelector = /* #__PURE__ */ createSelectorCreator(defaultMemoize);
|
||||
|
||||
export function createStructuredSelector<S, T>(
|
||||
selectors: {[K in keyof T]: Selector<S, T[K]>},
|
||||
selectorCreator?: typeof createSelector,
|
||||
): Selector<S, T>;
|
||||
|
||||
export function createStructuredSelector<S, P, T>(
|
||||
selectors: {[K in keyof T]: ParametricSelector<S, P, T[K]>},
|
||||
selectorCreator?: typeof createSelector,
|
||||
): ParametricSelector<S, P, T>;
|
||||
|
||||
export function createStructuredSelector(selectors: any, selectorCreator: any = createSelector): any {
|
||||
if (typeof selectors !== 'object') {
|
||||
throw new Error(
|
||||
'createStructuredSelector expects first argument to be an object ' +
|
||||
`where each property is a selector, instead received a ${typeof selectors}`,
|
||||
);
|
||||
}
|
||||
const objectKeys = Object.keys(selectors);
|
||||
return selectorCreator(
|
||||
objectKeys.map((key) => selectors[key]),
|
||||
(...values: any[]) => {
|
||||
return values.reduce((composition: any, value: any, index: number) => {
|
||||
composition[objectKeys[index]] = value;
|
||||
return composition;
|
||||
}, {});
|
||||
},
|
||||
);
|
||||
}
|
||||
+1062
File diff suppressed because it is too large
Load Diff
-3
@@ -221,9 +221,6 @@ describe('getDefaultReportAProblemMailtoLink', () => {
|
||||
mockIsDesktopApp.mockReturnValue(true);
|
||||
mockGetDesktopVersion.mockReturnValue('5.10.0');
|
||||
|
||||
// Reset selector cache so it re-runs with updated mocks
|
||||
getDefaultReportAProblemMailtoLink.resetRecomputations?.();
|
||||
|
||||
const stateWithDifferentUser = {
|
||||
...baseState,
|
||||
entities: {
|
||||
|
||||
+32
-15
@@ -1,14 +1,21 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getAdminDefinition} from 'selectors/admin_console.jsx';
|
||||
|
||||
import AdminDefinition from 'components/admin_console/admin_definition';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
import {getAdminDefinition} from './admin_console';
|
||||
|
||||
type TestReducerState = {
|
||||
something?: string;
|
||||
otherThing?: string;
|
||||
};
|
||||
|
||||
describe('Selectors.AdminConsole', () => {
|
||||
describe('get admin definitions', () => {
|
||||
it('should return the default admin definition if there is not plugins', () => {
|
||||
const state = {plugins: {adminConsoleReducers: {}}};
|
||||
const state = {plugins: {adminConsoleReducers: {}}} as GlobalState;
|
||||
expect(getAdminDefinition(state)).toEqual(AdminDefinition);
|
||||
});
|
||||
|
||||
@@ -17,7 +24,7 @@ describe('Selectors.AdminConsole', () => {
|
||||
plugins: {
|
||||
adminConsoleReducers: {clean: () => ({})},
|
||||
},
|
||||
});
|
||||
} as unknown as GlobalState);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
@@ -25,31 +32,41 @@ describe('Selectors.AdminConsole', () => {
|
||||
const result = getAdminDefinition({
|
||||
plugins: {
|
||||
adminConsoleReducers: {
|
||||
'add-something': (data) => {
|
||||
data.something = 'test';
|
||||
return data;
|
||||
'add-something': (data: TestReducerState) => {
|
||||
return {
|
||||
...data,
|
||||
something: 'test',
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} as unknown as GlobalState);
|
||||
expect(result.something).toEqual('test');
|
||||
});
|
||||
|
||||
it('should allow to use multiple plugins', () => {
|
||||
type TestReducerState = {
|
||||
something?: string;
|
||||
otherThing?: string;
|
||||
};
|
||||
const result = getAdminDefinition({
|
||||
plugins: {
|
||||
adminConsoleReducers: {
|
||||
'add-something': (data) => {
|
||||
data.something = 'test';
|
||||
return data;
|
||||
'add-something': (data: TestReducerState) => {
|
||||
return {
|
||||
...data,
|
||||
something: 'test',
|
||||
};
|
||||
},
|
||||
'add-other-thing': (data) => {
|
||||
data.otherThing = 'other-thing';
|
||||
return data;
|
||||
'add-other-thing': (data: TestReducerState) => {
|
||||
return {
|
||||
...data,
|
||||
otherThing: 'other-thing',
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} as unknown as GlobalState);
|
||||
expect(result.something).toEqual('test');
|
||||
expect(result.otherThing).toEqual('other-thing');
|
||||
});
|
||||
+18
-9
@@ -11,12 +11,14 @@ import {getMySystemPermissions, haveISystemPermission} from 'mattermost-redux/se
|
||||
|
||||
import AdminDefinition from 'components/admin_console/admin_definition';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
import {isEnterpriseLicense} from '../utils/license_utils';
|
||||
|
||||
export const getAdminDefinition = createSelector(
|
||||
'getAdminDefinition',
|
||||
() => AdminDefinition,
|
||||
(state) => state.plugins.adminConsoleReducers,
|
||||
(state: GlobalState) => state.plugins.adminConsoleReducers,
|
||||
(adminDefinition, reducers) => {
|
||||
let result = cloneDeep(AdminDefinition);
|
||||
for (const reducer of Object.values(reducers)) {
|
||||
@@ -26,10 +28,10 @@ export const getAdminDefinition = createSelector(
|
||||
},
|
||||
);
|
||||
|
||||
export const getAdminConsoleCustomComponents = (state, pluginId) =>
|
||||
export const getAdminConsoleCustomComponents = (state: GlobalState, pluginId: string) =>
|
||||
state.plugins.adminConsoleCustomComponents[pluginId] || {};
|
||||
|
||||
export const getAdminConsoleCustomSections = (state, pluginId) =>
|
||||
export const getAdminConsoleCustomSections = (state: GlobalState, pluginId: string) =>
|
||||
state.plugins.adminConsoleCustomSections[pluginId] || {};
|
||||
|
||||
export const getConsoleAccess = createSelector(
|
||||
@@ -37,22 +39,29 @@ export const getConsoleAccess = createSelector(
|
||||
getAdminDefinition,
|
||||
getMySystemPermissions,
|
||||
(adminDefinition, mySystemPermissions) => {
|
||||
const consoleAccess = {read: {}, write: {}};
|
||||
const addEntriesForKey = (entryKey) => {
|
||||
const consoleAccess: {
|
||||
read: Record<string, boolean>;
|
||||
write: Record<string, boolean>;
|
||||
} = {
|
||||
read: {},
|
||||
write: {},
|
||||
};
|
||||
const addEntriesForKey = (entryKey: string) => {
|
||||
const permissions = ResourceToSysConsolePermissionsTable[entryKey].filter((x) => mySystemPermissions.has(x));
|
||||
consoleAccess.read[entryKey] = permissions.length !== 0;
|
||||
consoleAccess.write[entryKey] = permissions.some((permission) => permission.startsWith('sysconsole_write_'));
|
||||
};
|
||||
const mapAccessValuesForKey = ([key]) => {
|
||||
if (typeof RESOURCE_KEYS[key.toUpperCase()] === 'object') {
|
||||
Object.values(RESOURCE_KEYS[key.toUpperCase()]).forEach((entry) => {
|
||||
const mapAccessValuesForKey = (key: string) => {
|
||||
const upperKey = key.toUpperCase() as keyof typeof RESOURCE_KEYS;
|
||||
if (upperKey in RESOURCE_KEYS && typeof RESOURCE_KEYS[upperKey] === 'object') {
|
||||
Object.values(RESOURCE_KEYS[upperKey]).forEach((entry) => {
|
||||
addEntriesForKey(entry);
|
||||
});
|
||||
} else {
|
||||
addEntriesForKey(key);
|
||||
}
|
||||
};
|
||||
Object.entries(adminDefinition).forEach(mapAccessValuesForKey);
|
||||
Object.keys(adminDefinition).forEach(mapAccessValuesForKey);
|
||||
return consoleAccess;
|
||||
},
|
||||
);
|
||||
@@ -20,6 +20,19 @@ export type ModalFilters = {
|
||||
team_roles?: string[];
|
||||
};
|
||||
|
||||
export type UserGridSearchFilters = {
|
||||
roles?: string[];
|
||||
channel_roles?: string[];
|
||||
team_roles?: string[];
|
||||
};
|
||||
|
||||
export type ChannelListSearchFilters = {
|
||||
public?: boolean;
|
||||
private?: boolean;
|
||||
deleted?: boolean;
|
||||
team_ids?: string[];
|
||||
};
|
||||
|
||||
export type AdminConsoleUserManagementTableProperties = {
|
||||
sortColumn: string;
|
||||
sortIsDescending: boolean;
|
||||
@@ -141,21 +154,12 @@ export type ViewsState = {
|
||||
modalFilters: ModalFilters;
|
||||
userGridSearch: {
|
||||
term: string;
|
||||
filters: {
|
||||
roles?: string[];
|
||||
channel_roles?: string[];
|
||||
team_roles?: string[];
|
||||
};
|
||||
filters: UserGridSearchFilters;
|
||||
};
|
||||
teamListSearch: string;
|
||||
channelListSearch: {
|
||||
term: string;
|
||||
filters: {
|
||||
public?: boolean;
|
||||
private?: boolean;
|
||||
deleted?: boolean;
|
||||
team_ids?: string[];
|
||||
};
|
||||
filters: ChannelListSearchFilters;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1247,7 +1247,16 @@ export default class Client4 {
|
||||
);
|
||||
};
|
||||
|
||||
authorizeOAuthApp = (responseType: string, clientId: string, redirectUri: string, state: string, scope: string, resource?: string, codeChallenge?: string, codeChallengeMethod?: string) => {
|
||||
authorizeOAuthApp = (
|
||||
responseType: string | null,
|
||||
clientId: string | null,
|
||||
redirectUri: string | null,
|
||||
state: string | null,
|
||||
scope: string | null,
|
||||
resource?: string | null,
|
||||
codeChallenge?: string | null,
|
||||
codeChallengeMethod?: string | null,
|
||||
) => {
|
||||
const body: any = {client_id: clientId, response_type: responseType, redirect_uri: redirectUri, state, scope};
|
||||
|
||||
// Include resource parameter if provided
|
||||
@@ -1263,7 +1272,7 @@ export default class Client4 {
|
||||
body.code_challenge_method = codeChallengeMethod;
|
||||
}
|
||||
|
||||
return this.doFetch<void>(
|
||||
return this.doFetch<{redirect: string}>(
|
||||
`${this.url}/oauth/authorize`,
|
||||
{method: 'post', body: JSON.stringify(body)},
|
||||
);
|
||||
@@ -2856,7 +2865,7 @@ export default class Client4 {
|
||||
|
||||
// General Routes
|
||||
|
||||
ping = (getServerStatus: boolean, deviceId?: string) => {
|
||||
ping = (getServerStatus?: boolean, deviceId?: string) => {
|
||||
return this.doFetch<{
|
||||
status: string;
|
||||
ActiveSearchBackend: string;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/node
|
||||
|
||||
import * as fs from 'fs';
|
||||
import langmap from '../channels/src/i18n/langmap.js';
|
||||
|
||||
import langmap from './langmap.mjs';
|
||||
|
||||
let lines = '';
|
||||
const langIDs = [];
|
||||
@@ -16,7 +17,7 @@ fs.readdirSync('./channels/src/i18n').forEach(file => {
|
||||
if (langID === 'en') {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
langIDs.push(langID);
|
||||
lines += `import ${langID.replace('-', '')} from './${file}';\n`;
|
||||
langFiles[langID] = langID.replace('-', '');
|
||||
@@ -38,25 +39,35 @@ fs.readdirSync('./channels/src/i18n').forEach(file => {
|
||||
});
|
||||
|
||||
lines += `
|
||||
type TranslationsMap = {
|
||||
[id: string]: string,
|
||||
};
|
||||
export const langIDs = ${JSON.stringify(langIDs)};
|
||||
|
||||
export const langLabels = ${JSON.stringify(langLabels)};
|
||||
`;
|
||||
lines += `\nexport const langIDs = ${JSON.stringify(langIDs)};\n`
|
||||
lines += `\nexport const langLabels = ${JSON.stringify(langLabels)};\n`
|
||||
|
||||
// To generate the file exports we need to do a bit more work to handle ids with dashes and also output a map of literals rather than strings.
|
||||
lines += '\nexport const langFiles: {[langID: string]: TranslationsMap} = {' + Object.keys(langFiles).reduce((out, id, idx) => {
|
||||
lines += `
|
||||
// TypeScript thinks it's importing these language files' contents directly, but Webpack rewrites the above imports
|
||||
// to the URL the file for lazy loading. That's the reason for the ugly type assertions below.
|
||||
export const langFiles: {
|
||||
[langID: string]: string;
|
||||
} = {
|
||||
` + Object.keys(langFiles).reduce((out, id, idx) => {
|
||||
out += ' ';
|
||||
|
||||
if (id.includes('-')) {
|
||||
out += `'${id}':${langFiles[id]}`;
|
||||
out += `'${id}': ${langFiles[id]}`;
|
||||
} else {
|
||||
out += `${langFiles[id]}`;
|
||||
out += `${id}: ${langFiles[id]}`;
|
||||
}
|
||||
|
||||
out += ' as unknown as string';
|
||||
|
||||
if (idx !== (langIDs.length - 1)) {
|
||||
out += ',';
|
||||
}
|
||||
|
||||
out += '\n';
|
||||
|
||||
return out;
|
||||
}, '') + '};';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
ach: {
|
||||
nativeName: 'Lwo',
|
||||
englishName: 'Acholi',
|
||||
Reference in New Issue
Block a user