MM-61297 - remove unused code (#29354)
* MM-61297 - remove unused code * remove unused code for install plugin in backend * fix translations
Этот коммит содержится в:
@@ -117,7 +117,7 @@ func (a *App) SendNotifyAdminPosts(c request.CTX, workspaceName string, currentS
|
||||
return nil
|
||||
}
|
||||
|
||||
userBasedPaidFeatureData, userBasedPluginData := a.groupNotifyAdminByUser(data)
|
||||
userBasedPaidFeatureData := a.groupNotifyAdminByUser(data)
|
||||
featureBasedData := a.groupNotifyAdminByPaidFeature(data)
|
||||
pluginBasedData := a.groupNotifyAdminByPlugin(data)
|
||||
|
||||
@@ -125,41 +125,12 @@ func (a *App) SendNotifyAdminPosts(c request.CTX, workspaceName string, currentS
|
||||
if len(userBasedPaidFeatureData) > 0 && len(featureBasedData) > 0 {
|
||||
a.upgradePlanAdminNotifyPost(c, workspaceName, userBasedPaidFeatureData, featureBasedData, systemBot, admin, trial)
|
||||
}
|
||||
|
||||
if len(userBasedPluginData) > 0 {
|
||||
a.pluginInstallAdminNotifyPost(c, userBasedPluginData, pluginBasedData, systemBot, admin)
|
||||
}
|
||||
}
|
||||
|
||||
a.FinishSendAdminNotifyPost(c, trial, now, pluginBasedData)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) pluginInstallAdminNotifyPost(c request.CTX, userBasedData map[string][]*model.NotifyAdminData, pluginBasedPluginData map[string][]*model.NotifyAdminData, systemBot *model.Bot, admin *model.User) {
|
||||
props := make(model.StringInterface)
|
||||
|
||||
channel, appErr := a.GetOrCreateDirectChannel(c, systemBot.UserId, admin.Id)
|
||||
if appErr != nil {
|
||||
c.Logger().Warn("Error getting direct channel", mlog.Err(appErr))
|
||||
return
|
||||
}
|
||||
|
||||
post := &model.Post{
|
||||
UserId: systemBot.UserId,
|
||||
ChannelId: channel.Id,
|
||||
Type: fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), // webapp will have to create renderer for this custom post type
|
||||
}
|
||||
|
||||
props["requested_plugins_by_plugin_ids"] = pluginBasedPluginData
|
||||
props["requested_plugins_by_user_ids"] = userBasedData
|
||||
post.SetProps(props)
|
||||
|
||||
_, appErr = a.CreatePost(c, post, channel, model.CreatePostFlags{SetOnline: true})
|
||||
if appErr != nil {
|
||||
c.Logger().Warn("Error creating post", mlog.Err(appErr))
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) upgradePlanAdminNotifyPost(c request.CTX, workspaceName string, userBasedData map[string][]*model.NotifyAdminData, featureBasedData map[model.MattermostFeature][]*model.NotifyAdminData, systemBot *model.Bot, admin *model.User, trial bool) {
|
||||
props := make(model.StringInterface)
|
||||
T := i18n.GetUserTranslations(admin.Locale)
|
||||
@@ -276,17 +247,12 @@ func (a *App) FinishSendAdminNotifyPost(rctx request.CTX, trial bool, now int64,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) groupNotifyAdminByUser(data []*model.NotifyAdminData) (map[string][]*model.NotifyAdminData, map[string][]*model.NotifyAdminData) {
|
||||
func (a *App) groupNotifyAdminByUser(data []*model.NotifyAdminData) map[string][]*model.NotifyAdminData {
|
||||
userBasedPaidFeatureData := make(map[string][]*model.NotifyAdminData)
|
||||
userBasedPluginData := make(map[string][]*model.NotifyAdminData)
|
||||
for _, d := range data {
|
||||
if strings.HasPrefix(string(d.RequiredFeature), string(model.PluginFeature)) {
|
||||
userBasedPluginData[d.UserId] = append(userBasedPluginData[d.UserId], d)
|
||||
} else {
|
||||
userBasedPaidFeatureData[d.UserId] = append(userBasedPaidFeatureData[d.UserId], d)
|
||||
}
|
||||
userBasedPaidFeatureData[d.UserId] = append(userBasedPaidFeatureData[d.UserId], d)
|
||||
}
|
||||
return userBasedPaidFeatureData, userBasedPluginData
|
||||
return userBasedPaidFeatureData
|
||||
}
|
||||
|
||||
func (a *App) groupNotifyAdminByPaidFeature(data []*model.NotifyAdminData) map[model.MattermostFeature][]*model.NotifyAdminData {
|
||||
|
||||
@@ -14,8 +14,6 @@ import (
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
)
|
||||
|
||||
const PluginIDGithub = "github"
|
||||
|
||||
func Test_SendNotifyAdminPosts(t *testing.T) {
|
||||
t.Run("no error sending non trial upgrade post when no notifications are available", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
@@ -137,119 +135,6 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
|
||||
require.Equal(t, "1 member of the test workspace has requested starting the Enterprise trial for access to: ", post.Message)
|
||||
})
|
||||
|
||||
t.Run("successfully send install plugin notification", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
// some notifications
|
||||
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
|
||||
UserId: th.BasicUser.Id,
|
||||
RequiredPlan: PluginIDGithub,
|
||||
RequiredFeature: model.PluginFeature,
|
||||
Trial: false,
|
||||
})
|
||||
require.Nil(t, appErr)
|
||||
|
||||
appErr = th.App.SendNotifyAdminPosts(th.Context, "", "", false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
bot, appErr := th.App.GetSystemBot(th.Context)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
var channel *model.Channel
|
||||
var err error
|
||||
var timeout = 5 * time.Second
|
||||
begin := time.Now()
|
||||
|
||||
for {
|
||||
if time.Since(begin) > timeout {
|
||||
break
|
||||
}
|
||||
channel, err = th.App.Srv().Store().Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
|
||||
if err == nil && channel != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
|
||||
postList, err := th.App.Srv().Store().Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false, map[string]bool{})
|
||||
require.NoError(t, err)
|
||||
|
||||
post := postList.Posts[postList.Order[0]]
|
||||
|
||||
require.Equal(t, fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), post.Type)
|
||||
require.Equal(t, bot.UserId, post.UserId)
|
||||
})
|
||||
|
||||
t.Run("persist notify admin data after sending the install plugin notification", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
// some notifications
|
||||
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
|
||||
UserId: th.BasicUser.Id,
|
||||
RequiredPlan: PluginIDGithub,
|
||||
RequiredFeature: model.PluginFeature,
|
||||
Trial: false,
|
||||
})
|
||||
require.Nil(t, appErr)
|
||||
|
||||
appErr = th.App.SendNotifyAdminPosts(th.Context, "", "", false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
bot, appErr := th.App.GetSystemBot(th.Context)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
var channel *model.Channel
|
||||
var err error
|
||||
var timeout = 5 * time.Second
|
||||
begin := time.Now()
|
||||
|
||||
for {
|
||||
if time.Since(begin) > timeout {
|
||||
break
|
||||
}
|
||||
channel, err = th.App.Srv().Store().Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
|
||||
if err == nil && channel != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
|
||||
postList, err := th.App.Srv().Store().Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false, map[string]bool{})
|
||||
require.NoError(t, err)
|
||||
|
||||
post := postList.Posts[postList.Order[0]]
|
||||
|
||||
require.Equal(t, fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), post.Type)
|
||||
require.Equal(t, bot.UserId, post.UserId)
|
||||
|
||||
data, err := th.App.Srv().Store().NotifyAdmin().GetDataByUserIdAndFeature(th.BasicUser.Id, model.PluginFeature)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(data), 1)
|
||||
})
|
||||
|
||||
t.Run("error sending more than one notification to the same user and for the same plugin", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
err := th.App.SaveAdminNotification(th.BasicUser.Id, &model.NotifyAdminToUpgradeRequest{
|
||||
RequiredPlan: PluginIDGithub,
|
||||
RequiredFeature: model.PluginFeature,
|
||||
TrialNotification: false,
|
||||
})
|
||||
|
||||
require.Nil(t, err)
|
||||
|
||||
err = th.App.SaveAdminNotification(th.BasicUser.Id, &model.NotifyAdminToUpgradeRequest{
|
||||
RequiredPlan: PluginIDGithub,
|
||||
RequiredFeature: model.PluginFeature,
|
||||
TrialNotification: false,
|
||||
})
|
||||
|
||||
require.Equal(t, err.Error(), "app.SaveAdminNotification: Already notified admin")
|
||||
})
|
||||
|
||||
t.Run("error when trying to send upgrade post before end of cool off period", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
@@ -370,67 +255,4 @@ func Test_SendNotifyAdminPosts(t *testing.T) {
|
||||
require.Equal(t, bot.UserId, post.UserId)
|
||||
require.Equal(t, "1 member of the test workspace has requested a workspace upgrade for: ", post.Message) // expect only one member's notification even though 2 were added
|
||||
})
|
||||
|
||||
t.Run("correctly send upgrade and install plugin post with the correct user request", func(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
os.Setenv("MM_NOTIFY_ADMIN_COOL_OFF_DAYS", "0")
|
||||
defer os.Unsetenv("MM_NOTIFY_ADMIN_COOL_OFF_DAYS")
|
||||
|
||||
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))
|
||||
|
||||
// some notifications
|
||||
_, appErr := th.App.SaveAdminNotifyData(&model.NotifyAdminData{
|
||||
UserId: th.BasicUser.Id,
|
||||
RequiredPlan: model.LicenseShortSkuProfessional,
|
||||
RequiredFeature: model.PaidFeatureGuestAccounts,
|
||||
Trial: false,
|
||||
})
|
||||
require.Nil(t, appErr)
|
||||
appErr = th.App.SendNotifyAdminPosts(th.Context, "test", "", false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// some notifications
|
||||
_, appErr = th.App.SaveAdminNotifyData(&model.NotifyAdminData{
|
||||
UserId: th.BasicUser.Id,
|
||||
RequiredPlan: PluginIDGithub,
|
||||
RequiredFeature: model.PluginFeature,
|
||||
Trial: false,
|
||||
})
|
||||
require.Nil(t, appErr)
|
||||
appErr = th.App.SendNotifyAdminPosts(th.Context, "test", "", false)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
bot, appErr := th.App.GetSystemBot(th.Context)
|
||||
require.Nil(t, appErr)
|
||||
|
||||
var channel *model.Channel
|
||||
var err error
|
||||
var timeout = 5 * time.Second
|
||||
begin := time.Now()
|
||||
|
||||
for {
|
||||
if time.Since(begin) > timeout {
|
||||
break
|
||||
}
|
||||
channel, err = th.App.Srv().Store().Channel().GetByName("", model.GetDMNameFromIds(bot.UserId, th.SystemAdminUser.Id), false)
|
||||
if err == nil && channel != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
require.NoError(t, err, "Expected message to have been sent within %d seconds", timeout)
|
||||
postList, err := th.App.Srv().Store().Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 2}, false, map[string]bool{})
|
||||
require.NoError(t, err)
|
||||
|
||||
installPluginPost := postList.Posts[postList.Order[0]]
|
||||
require.Equal(t, fmt.Sprintf("%spl_notification", model.PostCustomTypePrefix), installPluginPost.Type)
|
||||
require.Equal(t, bot.UserId, installPluginPost.UserId)
|
||||
|
||||
upgradePost := postList.Posts[postList.Order[1]]
|
||||
require.Equal(t, fmt.Sprintf("%sup_notification", model.PostCustomTypePrefix), upgradePost.Type)
|
||||
require.Equal(t, bot.UserId, upgradePost.UserId)
|
||||
require.Equal(t, "1 member of the test workspace has requested a workspace upgrade for: ", upgradePost.Message)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import {isCustomPostProps, type CustomPostProps} from '.';
|
||||
|
||||
describe('isCustomPostProps', () => {
|
||||
it('no content', () => {
|
||||
const props: CustomPostProps = {
|
||||
requested_plugins_by_plugin_ids: {},
|
||||
requested_plugins_by_user_ids: {},
|
||||
};
|
||||
expect(isCustomPostProps(props)).toBe(true);
|
||||
});
|
||||
|
||||
it('content but no elements', () => {
|
||||
const props: CustomPostProps = {
|
||||
requested_plugins_by_plugin_ids: {'some id': []},
|
||||
requested_plugins_by_user_ids: {'some id': []},
|
||||
};
|
||||
expect(isCustomPostProps(props)).toBe(true);
|
||||
});
|
||||
|
||||
it('content with elements', () => {
|
||||
const props: CustomPostProps = {
|
||||
requested_plugins_by_plugin_ids: {'some id': [{
|
||||
user_id: '123',
|
||||
}]},
|
||||
requested_plugins_by_user_ids: {'some id': [{
|
||||
user_id: '123',
|
||||
}]},
|
||||
};
|
||||
expect(isCustomPostProps(props)).toBe(true);
|
||||
});
|
||||
|
||||
it('all values are required', () => {
|
||||
const baseProp: CustomPostProps = {
|
||||
requested_plugins_by_plugin_ids: {},
|
||||
requested_plugins_by_user_ids: {},
|
||||
};
|
||||
|
||||
expect(isCustomPostProps(baseProp)).toBe(true);
|
||||
|
||||
for (const key of Object.keys(baseProp)) {
|
||||
const wrongProp: Partial<CustomPostProps> = {...baseProp};
|
||||
delete wrongProp[key as keyof CustomPostProps];
|
||||
expect(isCustomPostProps(wrongProp)).toBe(false);
|
||||
}
|
||||
|
||||
const wrongProp: DeepPartial<CustomPostProps> = {
|
||||
requested_plugins_by_plugin_ids: {'some id': [{}]},
|
||||
requested_plugins_by_user_ids: {'some id': []},
|
||||
};
|
||||
expect(isCustomPostProps(wrongProp)).toBe(false);
|
||||
});
|
||||
|
||||
it('common false cases', () => {
|
||||
expect(isCustomPostProps('')).toBe(false);
|
||||
expect(isCustomPostProps(undefined)).toBe(false);
|
||||
expect(isCustomPostProps(true)).toBe(false);
|
||||
expect(isCustomPostProps(1)).toBe(false);
|
||||
expect(isCustomPostProps([])).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,342 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import uniqWith from 'lodash/uniqWith';
|
||||
import React, {useEffect, useMemo} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {useSelector, useDispatch} from 'react-redux';
|
||||
import {Link} from 'react-router-dom';
|
||||
|
||||
import type {MarketplacePlugin} from '@mattermost/types/marketplace';
|
||||
import type {Post} from '@mattermost/types/posts';
|
||||
import {isArrayOf, isRecordOf} from '@mattermost/types/utilities';
|
||||
|
||||
import {getMissingProfilesByIds} from 'mattermost-redux/actions/users';
|
||||
import {getUsers} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {fetchListing, installPlugin} from 'actions/marketplace';
|
||||
import {getError, getInstalledListing, getInstalling, getPlugins} from 'selectors/views/marketplace';
|
||||
|
||||
import Markdown from 'components/markdown';
|
||||
import MarketplaceModal from 'components/plugin_marketplace/marketplace_modal';
|
||||
import ToggleModalButton from 'components/toggle_modal_button';
|
||||
|
||||
import {ModalIdentifiers} from 'utils/constants';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
// We only define the props used in this component for
|
||||
// clarity. If more props are needed in the future,
|
||||
// feel free to add them.
|
||||
type PluginRequest = {
|
||||
user_id: string;
|
||||
}
|
||||
|
||||
function isPluginRequest(v: unknown): v is PluginRequest {
|
||||
if (typeof v !== 'object' || v === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const request = v as PluginRequest;
|
||||
|
||||
if (typeof request.user_id !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
type RequestedPlugins = Record<string, PluginRequest[]>
|
||||
|
||||
export type CustomPostProps = {
|
||||
requested_plugins_by_plugin_ids: RequestedPlugins;
|
||||
requested_plugins_by_user_ids: RequestedPlugins;
|
||||
}
|
||||
|
||||
export function isCustomPostProps(v: unknown): v is CustomPostProps {
|
||||
if (typeof v !== 'object' || !v) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const props = v as CustomPostProps;
|
||||
|
||||
if (!isRecordOf(props.requested_plugins_by_plugin_ids, (e) => isArrayOf(e, isPluginRequest))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isRecordOf(props.requested_plugins_by_user_ids, (e) => isArrayOf(e, isPluginRequest))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const usersListStyle = {
|
||||
margin: '20px 0',
|
||||
};
|
||||
|
||||
const InstallLink = (props: {pluginId: string; pluginName: string}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
return (
|
||||
<Link
|
||||
to='#'
|
||||
onClick={() => dispatch(installPlugin(props.pluginId))}
|
||||
style={{color: 'var(--denim-button-bg)', fontWeight: '600'}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='marketplace_modal.list.install.plugin'
|
||||
defaultMessage={'Install {plugin}'}
|
||||
values={{
|
||||
plugin: props.pluginName,
|
||||
}}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const ConfigureLink = (props: {pluginId: string; pluginName: string}) => {
|
||||
return (
|
||||
<>
|
||||
<FormattedMessage
|
||||
id='postypes.custom_open_plugin_install_post_rendered.plugins_installed'
|
||||
defaultMessage={`${props.pluginName} is now installed.`}
|
||||
values={{
|
||||
pluginName: props.pluginName,
|
||||
}}
|
||||
/>
|
||||
{' '}
|
||||
<Link
|
||||
to={'/admin_console/plugins/plugin_' + props.pluginId}
|
||||
style={{color: 'var(--denim-button-bg)', fontWeight: '600'}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='marketplace_modal.list.configure.plugin'
|
||||
defaultMessage={'Configure {plugin}'}
|
||||
values={{
|
||||
plugin: props.pluginName,
|
||||
}}
|
||||
/>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const InstallAndConfigureLink = (props: {pluginId: string; pluginName: string}) => {
|
||||
const installedListing = useSelector(getInstalledListing) as MarketplacePlugin[];
|
||||
const error = useSelector((state: GlobalState) => getError(state, props.pluginId));
|
||||
|
||||
const isInstalled = installedListing.some((plugin) => plugin.manifest.id === props.pluginId);
|
||||
const installing = useSelector((state: GlobalState) => getInstalling(state, props.pluginId));
|
||||
if (installing) {
|
||||
return (
|
||||
<span style={{fontStyle: 'italic', color: 'var(--online-indicator)', fontWeight: '600'}}>
|
||||
<FormattedMessage
|
||||
id='marketplace_modal.installing'
|
||||
defaultMessage='Installing...'
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
} else if (!isInstalled && !error) {
|
||||
return (
|
||||
<InstallLink
|
||||
pluginId={props.pluginId}
|
||||
pluginName={props.pluginName}
|
||||
/>);
|
||||
} else if (isInstalled && !error) {
|
||||
return (
|
||||
<ConfigureLink
|
||||
pluginId={props.pluginId}
|
||||
pluginName={props.pluginName}
|
||||
/>);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default function OpenPluginInstallPost(props: {post: Post}) {
|
||||
const customMessageBody = [];
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const {formatMessage, formatList} = useIntl();
|
||||
|
||||
const postProps = isCustomPostProps(props.post.props) ? props.post.props : undefined;
|
||||
const requestedPluginsByPluginIds = postProps?.requested_plugins_by_plugin_ids;
|
||||
const requestedPluginsByUserIds = postProps?.requested_plugins_by_user_ids;
|
||||
|
||||
const userProfiles = useSelector(getUsers);
|
||||
const marketplacePlugins: MarketplacePlugin[] = useSelector(getPlugins);
|
||||
const marketplacePluginsNamesById = useMemo(() => {
|
||||
return marketplacePlugins.reduce<Record<string, string>>((acc, v) => {
|
||||
acc[v.manifest.id] = v.manifest.name;
|
||||
return acc;
|
||||
}, {});
|
||||
}, [marketplacePlugins]);
|
||||
|
||||
const getUserIdsForUsersThatRequestedFeature = (requests: PluginRequest[]): string[] => requests.map((request: PluginRequest) => request.user_id);
|
||||
|
||||
useEffect(() => {
|
||||
if (!marketplacePlugins.length) {
|
||||
dispatch(fetchListing());
|
||||
}
|
||||
}, [dispatch, marketplacePlugins.length]);
|
||||
|
||||
useEffect(() => {
|
||||
// process the plugins once the marketplace plugins are fetched and the plugins are available from the props
|
||||
if (requestedPluginsByPluginIds && marketplacePlugins.length) {
|
||||
for (const pluginId of Object.keys(requestedPluginsByPluginIds)) {
|
||||
dispatch(getMissingProfilesByIds(getUserIdsForUsersThatRequestedFeature(requestedPluginsByPluginIds[pluginId])));
|
||||
}
|
||||
}
|
||||
}, [dispatch, marketplacePlugins, requestedPluginsByPluginIds]);
|
||||
|
||||
const createUsernameMessage = (requests: PluginRequest[]) => {
|
||||
if (requests.length >= 5) {
|
||||
return formatMessage({
|
||||
id: 'postypes.custom_open_pricing_modal_post_renderer.members',
|
||||
defaultMessage: '{members} members',
|
||||
}, {members: requests.length});
|
||||
}
|
||||
|
||||
let usernameMessage;
|
||||
const users = getUserNamesForUsersThatRequestedFeature(requests);
|
||||
|
||||
if (users.length === 1) {
|
||||
usernameMessage = users[0];
|
||||
} else {
|
||||
const lastUser = users.splice(-1, 1)[0];
|
||||
users.push(formatMessage({id: 'postypes.custom_open_pricing_modal_post_renderer.and', defaultMessage: 'and'}) + ' ' + lastUser);
|
||||
usernameMessage = users.join(', ').replace(/,([^,]*)$/, '$1');
|
||||
}
|
||||
|
||||
return usernameMessage;
|
||||
};
|
||||
const getUserNamesForUsersThatRequestedFeature = (requests: PluginRequest[]): string[] => {
|
||||
const userNames = requests.map((req: PluginRequest) => {
|
||||
return getUserNameForUser(req.user_id);
|
||||
});
|
||||
return userNames;
|
||||
};
|
||||
|
||||
const getUserNameForUser = (userId: string) => {
|
||||
const unknownName = formatMessage({id: 'postypes.custom_open_pricing_modal_post_renderer.unknown', defaultMessage: '@unknown'});
|
||||
const username = userProfiles[userId]?.username;
|
||||
return username ? '@' + username : unknownName;
|
||||
};
|
||||
|
||||
const markDownOptions = {
|
||||
atSumOfMembersMentions: true,
|
||||
atPlanMentions: true,
|
||||
markdown: false,
|
||||
};
|
||||
const pluginIds = Object.keys(requestedPluginsByPluginIds || {});
|
||||
if (pluginIds.length && requestedPluginsByUserIds && requestedPluginsByPluginIds) {
|
||||
let post;
|
||||
const messageBuilder: string[] = [];
|
||||
const userIds = Object.keys(requestedPluginsByUserIds);
|
||||
if (userIds.length === 1 && pluginIds.length === 1) {
|
||||
const pluginName = marketplacePluginsNamesById[pluginIds[0]];
|
||||
messageBuilder.push('@' + userProfiles[userIds[0]]?.username);
|
||||
messageBuilder.push(' ' + formatMessage({id: 'postypes.custom_open_plugin_install_post_rendered.plugin_request', defaultMessage: 'requested installing the {pluginRequests} app.'}, {pluginRequests: pluginName}));
|
||||
|
||||
const instructions = (
|
||||
<FormattedMessage
|
||||
id='postypes.custom_open_plugin_install_post_rendered.plugin_instructions'
|
||||
defaultMessage='<pluginApp></pluginApp> or visit <marketplaceLink>Marketplace</marketplaceLink> to view all plugins.'
|
||||
values={{
|
||||
marketplaceLink: (text: string) => (
|
||||
<ToggleModalButton
|
||||
id='marketplaceModal'
|
||||
className='color--link'
|
||||
modalId={ModalIdentifiers.PLUGIN_MARKETPLACE}
|
||||
dialogType={MarketplaceModal}
|
||||
>
|
||||
{text}
|
||||
</ToggleModalButton>
|
||||
),
|
||||
pluginApp: () => (
|
||||
<InstallAndConfigureLink
|
||||
pluginId={pluginIds[0]}
|
||||
pluginName={pluginName}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>);
|
||||
|
||||
const message = formatList(messageBuilder, {style: 'narrow', type: 'unit'});
|
||||
post = (
|
||||
<>
|
||||
<Markdown
|
||||
postId={props.post.id}
|
||||
message={message}
|
||||
options={markDownOptions}
|
||||
userIds={getUserIdsForUsersThatRequestedFeature(requestedPluginsByUserIds[userIds[0]])}
|
||||
/>
|
||||
{' '}
|
||||
{instructions}
|
||||
</>);
|
||||
customMessageBody.push(post);
|
||||
} else {
|
||||
messageBuilder.push(formatMessage({id: 'postypes.custom_open_plugin_install_post_rendered.app_installation_request_text', defaultMessage: 'You’ve received the following app installation requests:'}));
|
||||
post = (
|
||||
<ul
|
||||
style={usersListStyle}
|
||||
key={pluginIds.join('')}
|
||||
>
|
||||
{pluginIds.map((pluginId) => {
|
||||
const plugins = requestedPluginsByPluginIds[pluginId];
|
||||
const pluginName = marketplacePluginsNamesById[pluginId];
|
||||
const uniqueUserRequestsForPlugins = uniqWith(plugins, (one, two) => one.user_id === two.user_id);
|
||||
const installRequests = [];
|
||||
installRequests.push(createUsernameMessage(uniqueUserRequestsForPlugins));
|
||||
installRequests.push(' ' + formatMessage({id: 'postypes.custom_open_plugin_install_post_rendered.plugin_request', defaultMessage: 'requested installing the {pluginRequests} app.'}, {pluginRequests: pluginName}));
|
||||
|
||||
return (
|
||||
<li key={pluginId}>
|
||||
<Markdown
|
||||
postId={props.post.id}
|
||||
message={installRequests.join('')}
|
||||
options={markDownOptions}
|
||||
userIds={getUserIdsForUsersThatRequestedFeature(requestedPluginsByUserIds[userIds[0]])}
|
||||
/>
|
||||
{' '}
|
||||
<InstallAndConfigureLink
|
||||
pluginId={pluginId}
|
||||
pluginName={pluginName}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
|
||||
const instructions = (
|
||||
<FormattedMessage
|
||||
id='postypes.custom_open_plugin_install_post_rendered.plugins_instructions'
|
||||
defaultMessage='Install the apps or visit <marketplaceLink>Marketplace</marketplaceLink> to view all plugins.'
|
||||
values={{
|
||||
marketplaceLink: (text: string) => (
|
||||
<ToggleModalButton
|
||||
id='marketplaceModal'
|
||||
className='color--link'
|
||||
modalId={ModalIdentifiers.PLUGIN_MARKETPLACE}
|
||||
dialogType={MarketplaceModal}
|
||||
dialogProps={{openedFrom: 'open_plugin_install_post'}}
|
||||
>
|
||||
{text}
|
||||
</ToggleModalButton>
|
||||
),
|
||||
}}
|
||||
/>);
|
||||
|
||||
customMessageBody.push(messageBuilder);
|
||||
customMessageBody.push(post);
|
||||
customMessageBody.push(instructions);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{customMessageBody}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import {measurePageLoadTelemetry, temporarilySetPageLoadContext, trackEvent, tra
|
||||
import BrowserStore from 'stores/browser_store';
|
||||
|
||||
import {makeAsyncComponent} from 'components/async_load';
|
||||
import OpenPluginInstallPost from 'components/custom_open_plugin_install_post_renderer';
|
||||
import GlobalHeader from 'components/global_header/global_header';
|
||||
import {HFRoute} from 'components/header_footer_route/header_footer_route';
|
||||
import {HFTRoute, LoggedInHFTRoute} from 'components/header_footer_template_route';
|
||||
@@ -360,9 +359,6 @@ export default class Root extends React.PureComponent<Props, State> {
|
||||
|
||||
this.initiateMeRequests();
|
||||
|
||||
// See figma design on issue https://mattermost.atlassian.net/browse/MM-43649
|
||||
this.props.actions.registerCustomPostRenderer('custom_pl_notification', OpenPluginInstallPost, 'plugin_install_post_message_renderer');
|
||||
|
||||
measurePageLoadTelemetry();
|
||||
trackSelectorMetrics();
|
||||
|
||||
|
||||
@@ -4281,9 +4281,7 @@
|
||||
"marketplace_modal.install_plugins": "Install plugins",
|
||||
"marketplace_modal.installing": "Installing...",
|
||||
"marketplace_modal.list.configure": "Configure",
|
||||
"marketplace_modal.list.configure.plugin": "Configure {plugin}",
|
||||
"marketplace_modal.list.install": "Install",
|
||||
"marketplace_modal.list.install.plugin": "Install {plugin}",
|
||||
"marketplace_modal.list.installed": "Installed",
|
||||
"marketplace_modal.list.try_again": "Try Again",
|
||||
"marketplace_modal.list.update": "Update",
|
||||
@@ -4723,14 +4721,7 @@
|
||||
"postlist.toast.searchHint": "Tip: Try {searchShortcut} to search this channel",
|
||||
"posts_view.loadMore": "Load More messages",
|
||||
"posts_view.newMsg": "New Messages",
|
||||
"postypes.custom_open_plugin_install_post_rendered.app_installation_request_text": "You’ve received the following app installation requests:",
|
||||
"postypes.custom_open_plugin_install_post_rendered.plugin_instructions": "<pluginApp></pluginApp> or visit <marketplaceLink>Marketplace</marketplaceLink> to view all plugins.",
|
||||
"postypes.custom_open_plugin_install_post_rendered.plugin_request": "requested installing the {pluginRequests} app.",
|
||||
"postypes.custom_open_plugin_install_post_rendered.plugins_instructions": "Install the apps or visit <marketplaceLink>Marketplace</marketplaceLink> to view all plugins.",
|
||||
"postypes.custom_open_pricing_modal_post_renderer.and": "and",
|
||||
"postypes.custom_open_pricing_modal_post_renderer.members": "{members} members",
|
||||
"postypes.custom_open_pricing_modal_post_renderer.membersThatRequested": "Members that requested ",
|
||||
"postypes.custom_open_pricing_modal_post_renderer.unknown": "@unknown",
|
||||
"pricing_modal.addons.dedicatedDB": "Dedicated database",
|
||||
"pricing_modal.addons.dedicatedDeployment": "Dedicated virtual secure cloud deployment (Cloud)",
|
||||
"pricing_modal.addons.dedicatedEncryption": "Dedicated encryption keys",
|
||||
|
||||
Ссылка в новой задаче
Block a user