mirror of
https://github.com/mattermost/mattermost.git
synced 2026-05-28 04:35:04 -04:00
[MM-53702] Remove Downgrade Team Selection modal and all accompanying logic (#24059)
* Remove Downgrade Team Selection modal and all accompanying logic * fix linter * Fix i18n * Final pipeline fixes
This commit is contained in:
parent
9322f71f94
commit
0b564005cf
13 changed files with 9 additions and 955 deletions
|
|
@ -42,7 +42,6 @@ func (api *API) InitTeam() {
|
|||
api.BaseRoutes.Team.Handle("", api.APISessionRequired(getTeam)).Methods("GET")
|
||||
api.BaseRoutes.Team.Handle("", api.APISessionRequired(updateTeam)).Methods("PUT")
|
||||
api.BaseRoutes.Team.Handle("", api.APISessionRequired(deleteTeam)).Methods("DELETE")
|
||||
api.BaseRoutes.Team.Handle("/except", api.APISessionRequired(softDeleteTeamsExcept)).Methods("DELETE")
|
||||
api.BaseRoutes.Team.Handle("/patch", api.APISessionRequired(patchTeam)).Methods("PUT")
|
||||
api.BaseRoutes.Team.Handle("/restore", api.APISessionRequired(restoreTeam)).Methods("POST")
|
||||
api.BaseRoutes.Team.Handle("/privacy", api.APISessionRequired(updateTeamPrivacy)).Methods("PUT")
|
||||
|
|
@ -464,25 +463,6 @@ func deleteTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func softDeleteTeamsExcept(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequireTeamId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), c.Params.TeamId, model.PermissionManageTeam) {
|
||||
c.SetPermissionError(model.PermissionManageTeam)
|
||||
return
|
||||
}
|
||||
|
||||
err := c.App.SoftDeleteAllTeamsExcept(c.Params.TeamId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func getTeamsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequireUserId()
|
||||
if c.Err != nil {
|
||||
|
|
|
|||
|
|
@ -1096,7 +1096,6 @@ type AppIface interface {
|
|||
SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppError
|
||||
SetTeamIconFromMultiPartFile(teamID string, file multipart.File) *model.AppError
|
||||
SlackImport(c *request.Context, fileData multipart.File, fileSize int64, teamID string) (*model.AppError, *bytes.Buffer)
|
||||
SoftDeleteAllTeamsExcept(teamID string) *model.AppError
|
||||
SoftDeleteTeam(teamID string) *model.AppError
|
||||
Srv() *Server
|
||||
SubmitInteractiveDialog(c *request.Context, request model.SubmitDialogRequest) (*model.SubmitDialogResponse, *model.AppError)
|
||||
|
|
|
|||
|
|
@ -16652,28 +16652,6 @@ func (a *OpenTracingAppLayer) SlackImport(c *request.Context, fileData multipart
|
|||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) SoftDeleteAllTeamsExcept(teamID string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SoftDeleteAllTeamsExcept")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store().SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store().SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.SoftDeleteAllTeamsExcept(teamID)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) SoftDeleteTeam(teamID string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SoftDeleteTeam")
|
||||
|
|
|
|||
|
|
@ -133,33 +133,6 @@ func (a *App) AdjustTeamsFromProductLimits(teamLimits *model.TeamsLimits) *model
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *App) SoftDeleteAllTeamsExcept(teamID string) *model.AppError {
|
||||
teams, appErr := a.GetAllTeams()
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
if teams == nil {
|
||||
return nil
|
||||
}
|
||||
cloudLimitsArchived := true
|
||||
patch := &model.TeamPatch{CloudLimitsArchived: &cloudLimitsArchived}
|
||||
for _, team := range teams {
|
||||
if team.Id != teamID {
|
||||
_, err := a.PatchTeam(team.Id, patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = a.SoftDeleteTeam(team.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) CreateTeam(c request.CTX, team *model.Team) (*model.Team, *model.AppError) {
|
||||
rteam, err := a.ch.srv.teamService.CreateTeam(team)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -469,41 +469,6 @@ func TestAddUserToTeamByTeamId(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestSoftDeleteAllTeamsExcept(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
teams := []*model.Team{
|
||||
{
|
||||
DisplayName: "team-1",
|
||||
Name: "team-1",
|
||||
Email: "foo@foo.com",
|
||||
Type: model.TeamOpen,
|
||||
},
|
||||
}
|
||||
teamId := ""
|
||||
for _, create := range teams {
|
||||
team, err := th.App.CreateTeam(th.Context, create)
|
||||
require.Nil(t, err)
|
||||
teamId = team.Id
|
||||
}
|
||||
|
||||
err := th.App.SoftDeleteAllTeamsExcept(teamId)
|
||||
assert.Nil(t, err)
|
||||
allTeams, err := th.App.GetAllTeams()
|
||||
require.Nil(t, err)
|
||||
for _, team := range allTeams {
|
||||
if team.Id == teamId {
|
||||
require.Equal(t, int64(0), team.DeleteAt)
|
||||
require.Equal(t, false, team.CloudLimitsArchived)
|
||||
} else {
|
||||
require.NotEqual(t, int64(0), team.DeleteAt)
|
||||
require.Equal(t, true, team.CloudLimitsArchived)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAdjustTeamsFromProductLimits(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
|
|
|||
|
|
@ -20,9 +20,6 @@ import PaymentSuccessStandardSvg from 'components/common/svg_images_components/p
|
|||
import PaymentFailedSvg from 'components/common/svg_images_components/payment_failed_svg';
|
||||
import IconMessage from 'components/purchase_modal/icon_message';
|
||||
import ProgressBar, {ProcessState} from 'components/icon_message_with_progress_bar';
|
||||
import {
|
||||
archiveAllTeamsExcept,
|
||||
} from 'mattermost-redux/actions/teams';
|
||||
import {DispatchFunc} from 'mattermost-redux/types/actions';
|
||||
|
||||
type Props = RouteComponentProps & {
|
||||
|
|
@ -55,10 +52,6 @@ function CloudSubscribeWithLoad(props: Props) {
|
|||
|
||||
const handleSubscribe = async () => {
|
||||
const start = new Date();
|
||||
if (props.teamToKeep) {
|
||||
await dispatch(archiveAllTeamsExcept(props.teamToKeep.id));
|
||||
}
|
||||
|
||||
const result = await dispatch(subscribeCloudSubscription(
|
||||
props.selectedProduct?.id as string, undefined, 0, props.downgradeFeedback,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import {DispatchFunc} from 'mattermost-redux/types/actions';
|
|||
import {deprecateCloudFree} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import {Feedback} from '@mattermost/types/cloud';
|
||||
import useGetUsage from 'components/common/hooks/useGetUsage';
|
||||
import useGetLimits from 'components/common/hooks/useGetLimits';
|
||||
import SuccessModal from 'components/cloud_subscribe_result_modal/success';
|
||||
import ErrorModal from 'components/cloud_subscribe_result_modal/error';
|
||||
|
|
@ -41,7 +40,6 @@ import useOpenSalesLink from 'components/common/hooks/useOpenSalesLink';
|
|||
import {useOpenCloudZendeskSupportForm} from 'components/common/hooks/useOpenZendeskForm';
|
||||
import ExternalLink from 'components/external_link';
|
||||
|
||||
import DowngradeTeamRemovalModal from './downgrade_team_removal_modal';
|
||||
import ContactSalesCTA from './contact_sales_cta';
|
||||
import StarterDisclaimerCTA from './starter_disclaimer_cta';
|
||||
import StartTrialCaution from './start_trial_caution';
|
||||
|
|
@ -60,7 +58,6 @@ type ContentProps = {
|
|||
function Content(props: ContentProps) {
|
||||
const {formatMessage, formatNumber} = useIntl();
|
||||
const dispatch = useDispatch<DispatchFunc>();
|
||||
const usage = useGetUsage();
|
||||
const [limits] = useGetLimits();
|
||||
const openPricingModalBackAction = useOpenPricingModal();
|
||||
|
||||
|
|
@ -379,29 +376,15 @@ function Content(props: ContentProps) {
|
|||
if (!starterProduct) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage.teams.active > 1) {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalId: ModalIdentifiers.CLOUD_DOWNGRADE_CHOOSE_TEAM,
|
||||
dialogType: DowngradeTeamRemovalModal,
|
||||
dialogProps: {
|
||||
product_id: starterProduct?.id,
|
||||
starterProduct,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalId: ModalIdentifiers.FEEDBACK,
|
||||
dialogType: DowngradeFeedbackModal,
|
||||
dialogProps: {
|
||||
onSubmit: handleClickDowngrade,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
dispatch(
|
||||
openModal({
|
||||
modalId: ModalIdentifiers.FEEDBACK,
|
||||
dialogType: DowngradeFeedbackModal,
|
||||
dialogProps: {
|
||||
onSubmit: handleClickDowngrade,
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
text: freeTierText,
|
||||
disabled: isStarter || isEnterprise || !isAdmin,
|
||||
|
|
|
|||
|
|
@ -1,165 +0,0 @@
|
|||
|
||||
@import 'utils/variables';
|
||||
|
||||
.modal-backdrop.downgrade-modal-backdrop {
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
.DowngradeTeamRemovalModal {
|
||||
z-index: 1051;
|
||||
|
||||
.modal {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 600px;
|
||||
height: 404px;
|
||||
border: none;
|
||||
margin: auto;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
|
||||
.modal-content {
|
||||
border: none;
|
||||
background-color: var(--center-channel-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: $elevation-6;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
height: 77px;
|
||||
min-height: 77px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.DowngradeTeamRemovalModal__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 22px 32px;
|
||||
border: none;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// beat regular modal-header in specificity
|
||||
&.modal-header {
|
||||
background-color: var(--center-channel-bg);
|
||||
color: var(--center-channel-color);
|
||||
}
|
||||
|
||||
.icon-close {
|
||||
padding: 0;
|
||||
border: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background: none;
|
||||
color: rgb(var(--center-channel-color-rgb), 0.56);
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
outline: inherit;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: rgb(var(--center-channel-color-rgb), 0.56);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 26px 32px;
|
||||
padding-top: 0;
|
||||
border: none;
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
.DowngradeTeamRemovalModal__body {
|
||||
.DowngradeTeamRemovalModal__selectionSection {
|
||||
.radio {
|
||||
margin-bottom: 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.DropDown__menu {
|
||||
max-height: 124px;
|
||||
}
|
||||
|
||||
.DropDown__menu-list {
|
||||
max-height: 124px;
|
||||
}
|
||||
|
||||
.DropDown__value-container {
|
||||
padding-left: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cta {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.warning {
|
||||
display: flex;
|
||||
height: 16px;
|
||||
align-items: center;
|
||||
margin-top: 19px;
|
||||
margin-bottom: 35px;
|
||||
color: var(--sys-error-text);
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
|
||||
.icon.icon-alert-outline {
|
||||
height: 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon.icon-alert-outline::before {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.DowngradeTeamRemovalModal__buttons {
|
||||
border: none;
|
||||
float: right;
|
||||
|
||||
.btn.btn-light {
|
||||
padding: 12px 20px;
|
||||
background: rgba(var(--denim-button-bg-rgb), 0.08);
|
||||
border-radius: 4px;
|
||||
color: var(--sys-denim-button-bg);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.btn.btn-primary {
|
||||
padding: 12px 20px;
|
||||
margin-left: 8px;
|
||||
background: var(--sys-denim-button-bg);
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,365 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import * as redux from 'react-redux';
|
||||
|
||||
import {renderWithIntl, screen} from 'tests/react_testing_utils';
|
||||
import mockStore from 'tests/test_store';
|
||||
|
||||
import {CloudProducts} from 'utils/constants';
|
||||
import {FileSizes} from 'utils/file_utils';
|
||||
|
||||
import DowngradeTeamRemovalModal from './';
|
||||
|
||||
describe('components/pricing_modal/downgrade_team_removal_modal', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(redux, 'useDispatch').mockImplementation(
|
||||
jest.fn(() => jest.fn()),
|
||||
);
|
||||
});
|
||||
|
||||
const state = {
|
||||
entities: {
|
||||
users: {
|
||||
currentUserId: 'user1',
|
||||
profiles: {
|
||||
user1: {
|
||||
id: 'user1',
|
||||
roles: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
usage: {
|
||||
files: {
|
||||
totalStorage: 0,
|
||||
totalStorageLoaded: true,
|
||||
},
|
||||
messages: {
|
||||
history: 0,
|
||||
historyLoaded: true,
|
||||
},
|
||||
boards: {
|
||||
cards: 0,
|
||||
cardsLoaded: true,
|
||||
},
|
||||
integrations: {
|
||||
enabled: 3,
|
||||
enabledLoaded: true,
|
||||
},
|
||||
teams: {
|
||||
active: 4,
|
||||
cloudArchived: 0,
|
||||
teamsLoaded: true,
|
||||
},
|
||||
},
|
||||
teams: {
|
||||
currentTeamId: 'frggfw9objyz5e6ma7ibpx6jda',
|
||||
teams: {
|
||||
frggfw9objyz5e6ma7ibpx6jda: {
|
||||
id: 'frggfw9objyz5e6ma7ibpx6jda',
|
||||
create_at: 1654097827977,
|
||||
update_at: 1654783962398,
|
||||
delete_at: 0,
|
||||
display_name: 'Team 4',
|
||||
name: 'team-4',
|
||||
description: '',
|
||||
email: 'test@example.com',
|
||||
type: 'O',
|
||||
company_name: '',
|
||||
allowed_domains: '',
|
||||
invite_id: 'jagqnrb5ubb78grwebzckmpxxa',
|
||||
allow_open_invite: false,
|
||||
scheme_id: null,
|
||||
group_constrained: null,
|
||||
policy_id: null,
|
||||
cloud_limits_archived: false,
|
||||
},
|
||||
ypbsfrr583yc9futzyghpmhc6r: {
|
||||
id: 'ypbsfrr583yc9futzyghpmhc6r',
|
||||
create_at: 1652892296690,
|
||||
update_at: 1654784021789,
|
||||
delete_at: 0,
|
||||
display_name: 'team 3',
|
||||
name: 'team-3',
|
||||
description: '',
|
||||
email: 'test@example.com',
|
||||
type: 'O',
|
||||
company_name: '',
|
||||
allowed_domains: '',
|
||||
invite_id: 'cfqgw4utbpfjucjqjaddg6mxmo',
|
||||
allow_open_invite: false,
|
||||
scheme_id: null,
|
||||
group_constrained: false,
|
||||
policy_id: null,
|
||||
cloud_limits_archived: false,
|
||||
},
|
||||
p6kpct39xigtpxfk739dwu9eny: {
|
||||
id: 'p6kpct39xigtpxfk739dwu9eny',
|
||||
create_at: 1652891664653,
|
||||
update_at: 1654784021776,
|
||||
delete_at: 0,
|
||||
display_name: 'second team',
|
||||
name: 'second-team',
|
||||
description: '',
|
||||
email: 'test@example.com',
|
||||
type: 'O',
|
||||
company_name: '',
|
||||
allowed_domains: '',
|
||||
invite_id: 'yefar6zmoiya8dsw59oiw9xwac',
|
||||
allow_open_invite: false,
|
||||
scheme_id: null,
|
||||
group_constrained: false,
|
||||
policy_id: null,
|
||||
cloud_limits_archived: false,
|
||||
},
|
||||
qet86xzhwpbim841jwyfh3fgwe: {
|
||||
id: 'qet86xzhwpbim841jwyfh3fgwe',
|
||||
create_at: 1652891651309,
|
||||
update_at: 1654784021766,
|
||||
delete_at: 0,
|
||||
display_name: 'first team',
|
||||
name: 'first-team',
|
||||
description: '',
|
||||
email: 'test@example.com',
|
||||
type: 'O',
|
||||
company_name: '',
|
||||
allowed_domains: '',
|
||||
invite_id: '3qm66p1ub3n17rbi7f315wqsdy',
|
||||
allow_open_invite: false,
|
||||
scheme_id: null,
|
||||
group_constrained: false,
|
||||
policy_id: null,
|
||||
cloud_limits_archived: false,
|
||||
},
|
||||
},
|
||||
myMembers: {
|
||||
frggfw9objyz5e6ma7ibpx6jda: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'frggfw9objyz5e6ma7ibpx6jda',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
ypbsfrr583yc9futzyghpmhc6r: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'ypbsfrr583yc9futzyghpmhc6r',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
p6kpct39xigtpxfk739dwu9eny: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'p6kpct39xigtpxfk739dwu9eny',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
qet86xzhwpbim841jwyfh3fgwe: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'qet86xzhwpbim841jwyfh3fgwe',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
isw1dyt5ijnozg8frzjb1uongr: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'isw1dyt5ijnozg8frzjb1uongr',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
m1niyeo5n3fc9kb41dthno6xgy: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'm1niyeo5n3fc9kb41dthno6xgy',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
'51ifbyhn6b8s7es7nbu5faezhc': {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: '51ifbyhn6b8s7es7nbu5faezhc',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
n8h6tsdfipn79eho3k1dj69jba: {
|
||||
mention_count: 0,
|
||||
msg_count: 0,
|
||||
mention_count_root: 0,
|
||||
msg_count_root: 0,
|
||||
team_id: 'n8h6tsdfipn79eho3k1dj69jba',
|
||||
user_id: 'jp1dthppbfri5d46impk1ndk8a',
|
||||
roles: 'team_user team_admin',
|
||||
delete_at: 0,
|
||||
scheme_guest: false,
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
explicit_roles: '',
|
||||
},
|
||||
},
|
||||
membersInTeam: {},
|
||||
stats: {},
|
||||
groupsAssociatedToTeam: {},
|
||||
totalCount: 0,
|
||||
},
|
||||
admin: {},
|
||||
general: {
|
||||
license: {
|
||||
IsLicensed: 'true',
|
||||
Cloud: 'true',
|
||||
},
|
||||
credentials: {
|
||||
url: 'http://example.com',
|
||||
},
|
||||
},
|
||||
cloud: {
|
||||
subscription: {
|
||||
is_free_trial: 'false',
|
||||
trial_end_at: 0,
|
||||
product_id: 'prod_free',
|
||||
},
|
||||
limits: {
|
||||
limitsLoaded: true,
|
||||
limits: {
|
||||
integrations: {
|
||||
enabled: 5,
|
||||
},
|
||||
messages: {
|
||||
history: 10000,
|
||||
},
|
||||
files: {
|
||||
total_storage: FileSizes.Gigabyte,
|
||||
},
|
||||
teams: {
|
||||
active: 1,
|
||||
},
|
||||
boards: {
|
||||
cards: 500,
|
||||
views: 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
products: {
|
||||
prod_free: {
|
||||
id: 'prod_free',
|
||||
name: 'Cloud Free',
|
||||
sku: CloudProducts.STARTER,
|
||||
price_per_seat: 0,
|
||||
product_family: 'cloud',
|
||||
description: '',
|
||||
add_ons: [],
|
||||
billing_scheme: 'flat_fee',
|
||||
recurring_interval: 'month',
|
||||
cross_sells_to: '',
|
||||
},
|
||||
prod_enterprise: {
|
||||
id: 'prod_enterprise',
|
||||
name: 'Cloud Enterprise',
|
||||
sku: CloudProducts.ENTERPRISE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
views: {
|
||||
modals: {
|
||||
modalState: {
|
||||
cloud_downgrade_choose_team: {
|
||||
open: 'true',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
test('renders modal', () => {
|
||||
const store = mockStore(state);
|
||||
renderWithIntl(
|
||||
<redux.Provider store={store}>
|
||||
<DowngradeTeamRemovalModal
|
||||
product_id={'prod_free'}
|
||||
starterProduct={state.entities.cloud.products.prod_free}
|
||||
/>
|
||||
</redux.Provider>,
|
||||
);
|
||||
expect(screen.getByText('Confirm Plan Downgrade')).toBeInTheDocument();
|
||||
expect(screen.getByText('Which team would you like to continue using?')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders dropdown with 4+ teams', () => {
|
||||
const store = mockStore(state);
|
||||
renderWithIntl(
|
||||
<redux.Provider store={store}>
|
||||
<DowngradeTeamRemovalModal
|
||||
product_id={'prod_free'}
|
||||
starterProduct={state.entities.cloud.products.prod_free}
|
||||
/>
|
||||
</redux.Provider>,
|
||||
);
|
||||
expect(screen.getByTestId('deleteTeamDropdownInput')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('renders radio buttons with fewer than 4 teams', () => {
|
||||
const newState = {...state};
|
||||
newState.entities.usage.teams.active = 2;
|
||||
const store = mockStore(state);
|
||||
renderWithIntl(
|
||||
<redux.Provider store={store}>
|
||||
<DowngradeTeamRemovalModal
|
||||
product_id={'prod_free'}
|
||||
starterProduct={state.entities.cloud.products.prod_free}
|
||||
/>
|
||||
</redux.Provider>,
|
||||
);
|
||||
expect(screen.getByTestId('deleteTeamRadioGroup')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import {isEmpty} from 'lodash';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {Feedback, Product} from '@mattermost/types/cloud';
|
||||
import {t} from 'utils/i18n';
|
||||
import RadioButtonGroup from 'components/common/radio_group';
|
||||
import DropdownInput, {ValueType} from 'components/dropdown_input';
|
||||
import CloudSubscribeWithLoadingModal from 'components/cloud_subscribe_with_loading_modal';
|
||||
import useGetUsage from 'components/common/hooks/useGetUsage';
|
||||
import DowngradeFeedback from 'components/feedback_modal/downgrade_feedback';
|
||||
import {getTeams} from 'mattermost-redux/actions/teams';
|
||||
import {getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {closeModal, openModal} from 'actions/views/modals';
|
||||
import {ModalIdentifiers} from 'utils/constants';
|
||||
import {isModalOpen} from 'selectors/views/modals';
|
||||
import {GlobalState} from 'types/store';
|
||||
|
||||
import {fallbackStarterLimits, asGBString} from 'utils/limits';
|
||||
|
||||
import './downgrade_team_removal_modal.scss';
|
||||
|
||||
type Props = {
|
||||
product_id: string;
|
||||
starterProduct: Product | null | undefined;
|
||||
};
|
||||
|
||||
function DowngradeTeamRemovalModal(props: Props) {
|
||||
const dispatch = useDispatch();
|
||||
const [radioValue, setRadioValue] = useState('');
|
||||
const [dropdownValue, setDropdownValue] = useState<ValueType | undefined>();
|
||||
|
||||
const intl = useIntl();
|
||||
const isCloudDowngradeChooseTeamModalOpen = useSelector(
|
||||
(state: GlobalState) =>
|
||||
isModalOpen(state, ModalIdentifiers.CLOUD_DOWNGRADE_CHOOSE_TEAM),
|
||||
);
|
||||
|
||||
const teams = useSelector(getActiveTeamsList);
|
||||
useEffect(() => {
|
||||
if (!teams) {
|
||||
dispatch(getTeams(0, 10000));
|
||||
}
|
||||
}, [teams]);
|
||||
const usage = useGetUsage();
|
||||
|
||||
const onHide = () => {
|
||||
dispatch(closeModal(ModalIdentifiers.CLOUD_DOWNGRADE_CHOOSE_TEAM));
|
||||
};
|
||||
|
||||
const onConfirmDowngrade = async () => {
|
||||
dispatch(closeModal(ModalIdentifiers.CLOUD_DOWNGRADE_CHOOSE_TEAM));
|
||||
dispatch(closeModal(ModalIdentifiers.PRICING_MODAL));
|
||||
dispatch(openModal({
|
||||
modalId: ModalIdentifiers.FEEDBACK,
|
||||
dialogType: DowngradeFeedback,
|
||||
dialogProps: {
|
||||
onSubmit: downgrade,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const downgrade = (downgradeFeedback: Feedback) => {
|
||||
const teamToKeep = getSelectedTeam();
|
||||
dispatch(openModal({
|
||||
modalId: ModalIdentifiers.CLOUD_SUBSCRIBE_WITH_LOADING_MODAL,
|
||||
dialogType: CloudSubscribeWithLoadingModal,
|
||||
dialogProps: {
|
||||
onBack: () => {
|
||||
dispatch(
|
||||
closeModal(
|
||||
ModalIdentifiers.CLOUD_SUBSCRIBE_WITH_LOADING_MODAL,
|
||||
),
|
||||
);
|
||||
dispatch(
|
||||
openModal({
|
||||
modalId:
|
||||
ModalIdentifiers.CLOUD_DOWNGRADE_CHOOSE_TEAM,
|
||||
dialogType: DowngradeTeamRemovalModal,
|
||||
dialogProps: {
|
||||
product_id: props.starterProduct?.id || '',
|
||||
starterProduct: props.starterProduct,
|
||||
},
|
||||
}),
|
||||
);
|
||||
},
|
||||
teamToKeep,
|
||||
selectedProduct: props.starterProduct,
|
||||
downgradeFeedback,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const getSelectedTeam = () => {
|
||||
let teamIdToKeep = '';
|
||||
if (radioValue && !dropdownValue) {
|
||||
teamIdToKeep = radioValue;
|
||||
} else {
|
||||
teamIdToKeep = dropdownValue?.value || '';
|
||||
}
|
||||
return teams.find((team: Team) => team.id === teamIdToKeep);
|
||||
};
|
||||
|
||||
const selectionSection = (teamsList: Team[]) => {
|
||||
if (usage.teams.active < 4) {
|
||||
return (
|
||||
<RadioButtonGroup
|
||||
id='deleteTeamRadioGroup'
|
||||
testId='deleteTeamRadioGroup'
|
||||
values={teamsList.map((team) => {
|
||||
return {
|
||||
value: team.id,
|
||||
key: team.display_name,
|
||||
testId: team.id,
|
||||
};
|
||||
})}
|
||||
value={radioValue}
|
||||
onChange={(e) => setRadioValue(e.target.value)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownInput
|
||||
testId='deleteTeamDropdownInput'
|
||||
onChange={setDropdownValue}
|
||||
legend={intl.formatMessage({
|
||||
id: t('admin.channel_settings.channel_list.teamHeader'),
|
||||
defaultMessage: 'Team',
|
||||
})}
|
||||
placeholder={intl.formatMessage({
|
||||
id: t('downgrade_plan_modal.selectTeam'),
|
||||
defaultMessage: 'Select team',
|
||||
})}
|
||||
value={dropdownValue}
|
||||
options={teamsList.map((team) => {
|
||||
return {
|
||||
label: team.display_name,
|
||||
value: team.id,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className='DowngradeTeamRemovalModal'
|
||||
show={isCloudDowngradeChooseTeamModalOpen}
|
||||
backdropClassName={'downgrade-modal-backdrop'}
|
||||
id='downgradeTeamRemovalModal'
|
||||
onExited={onHide}
|
||||
data-testid='downgradeTeamRemovalModal'
|
||||
dialogClassName='a11y__modal'
|
||||
onHide={onHide}
|
||||
role='dialog'
|
||||
aria-modal='true'
|
||||
aria-labelledby='downgradeTeamRemovalModalTitle'
|
||||
>
|
||||
<>
|
||||
<Modal.Header className='DowngradeTeamRemovalModal__header'>
|
||||
<FormattedMessage
|
||||
id='downgrade_plan_modal.title'
|
||||
defaultMessage='Confirm Plan Downgrade'
|
||||
/>
|
||||
<button
|
||||
id='closeIcon'
|
||||
className='icon icon-close'
|
||||
aria-label='Close'
|
||||
title='Close'
|
||||
onClick={onHide}
|
||||
/>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<div className='DowngradeTeamRemovalModal__body'>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='downgrade_plan_modal.subtitle'
|
||||
defaultMessage='{planName} is restricted to {teams} team, {messages} messages, and {storage} file storage. <strong>If you downgrade, some data will be archived</strong>. Archived data can be accessible when you upgrade back'
|
||||
values={{
|
||||
strong: (msg: React.ReactNode) => (
|
||||
<strong>{msg}</strong>
|
||||
),
|
||||
planName: props.starterProduct?.name,
|
||||
messages: intl.formatNumber(
|
||||
fallbackStarterLimits.messages.
|
||||
history,
|
||||
),
|
||||
storage: asGBString(
|
||||
fallbackStarterLimits.files.
|
||||
totalStorage,
|
||||
intl.formatNumber,
|
||||
),
|
||||
teams: fallbackStarterLimits.teams.
|
||||
active,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='cta'>
|
||||
<FormattedMessage
|
||||
id='downgrade_plan_modal.whichTeamToUse'
|
||||
defaultMessage='Which team would you like to continue using?'
|
||||
/>
|
||||
</div>
|
||||
<div className='DowngradeTeamRemovalModal__selectionSection'>
|
||||
{selectionSection(teams)}
|
||||
</div>
|
||||
<div className='warning'>
|
||||
<i className='icon icon-alert-outline'/>
|
||||
<span className='warning-text'>
|
||||
<FormattedMessage
|
||||
id='downgrade_plan_modal.alert'
|
||||
defaultMessage='The unselected teams will be automatically archived in the system console, but not deleted'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='DowngradeTeamRemovalModal__buttons'>
|
||||
<button
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
closeModal(
|
||||
ModalIdentifiers.CLOUD_DOWNGRADE_CHOOSE_TEAM,
|
||||
),
|
||||
)
|
||||
}
|
||||
className='btn btn-light'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='admin.team_channel_settings.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
disabled={
|
||||
isEmpty(radioValue) &&
|
||||
isEmpty(dropdownValue)
|
||||
}
|
||||
onClick={onConfirmDowngrade}
|
||||
className='btn btn-primary'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='downgrade_plan_modal.confirmDowngrade'
|
||||
defaultMessage='Confirm Downgrade'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
</>
|
||||
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DowngradeTeamRemovalModal;
|
||||
|
|
@ -3299,12 +3299,6 @@
|
|||
"dnd_custom_time_picker_modal.defaultMsg": "Disable notifications until",
|
||||
"dnd_custom_time_picker_modal.submitButton": "Disable Notifications",
|
||||
"dnd_custom_time_picker_modal.time": "Time",
|
||||
"downgrade_plan_modal.alert": "The unselected teams will be automatically archived in the system console, but not deleted",
|
||||
"downgrade_plan_modal.confirmDowngrade": "Confirm Downgrade",
|
||||
"downgrade_plan_modal.selectTeam": "Select team",
|
||||
"downgrade_plan_modal.subtitle": "{planName} is restricted to {teams} team, {messages} messages, and {storage} file storage. <strong>If you downgrade, some data will be archived</strong>. Archived data can be accessible when you upgrade back.",
|
||||
"downgrade_plan_modal.title": "Confirm Plan Downgrade",
|
||||
"downgrade_plan_modal.whichTeamToUse": "Which team would you like to continue using?",
|
||||
"drafts.actions.delete": "Delete draft",
|
||||
"drafts.actions.edit": "Edit draft",
|
||||
"drafts.actions.send": "Send draft",
|
||||
|
|
|
|||
|
|
@ -297,18 +297,6 @@ export function unarchiveTeam(teamId: string): ActionFunc {
|
|||
};
|
||||
}
|
||||
|
||||
export function archiveAllTeamsExcept(teamId: string) {
|
||||
return async () => {
|
||||
try {
|
||||
await Client4.archiveAllTeamsExcept(teamId);
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
|
||||
return {data: true};
|
||||
};
|
||||
}
|
||||
|
||||
export function updateTeam(team: Team): ActionFunc {
|
||||
return bindClientFunc({
|
||||
clientFunc: Client4.updateTeam,
|
||||
|
|
|
|||
|
|
@ -1172,13 +1172,6 @@ export default class Client4 {
|
|||
);
|
||||
}
|
||||
|
||||
archiveAllTeamsExcept = (teamId: string) => {
|
||||
return this.doFetch<StatusOK>(
|
||||
`${this.getTeamRoute(teamId)}/except`,
|
||||
{method: 'delete'},
|
||||
);
|
||||
}
|
||||
|
||||
updateTeam = (team: Team) => {
|
||||
this.trackEvent('api', 'api_teams_update_name', {team_id: team.id});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue