[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:
Nick Misasi 2023-07-19 09:35:14 -04:00 committed by GitHub
parent 9322f71f94
commit 0b564005cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 9 additions and 955 deletions

View file

@ -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 {

View file

@ -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)

View file

@ -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")

View file

@ -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 {

View file

@ -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()

View file

@ -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,
));

View file

@ -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,

View file

@ -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;
}
}
}

View file

@ -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();
});
});

View file

@ -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;

View file

@ -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",

View file

@ -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,

View file

@ -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});