mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
MM-61032: Add default_team_id to accept invite flow (#28841)
* add default_team_id to accept invite api * add team selector to accept invite flow UI * e2e * lint/i18n
This commit is contained in:
parent
5a923e0b94
commit
fcded9559c
@ -277,6 +277,7 @@
|
|||||||
required:
|
required:
|
||||||
- invite
|
- invite
|
||||||
- name
|
- name
|
||||||
|
- default_team_id
|
||||||
- password
|
- password
|
||||||
properties:
|
properties:
|
||||||
invite:
|
invite:
|
||||||
@ -285,6 +286,8 @@
|
|||||||
type: string
|
type: string
|
||||||
display_name:
|
display_name:
|
||||||
type: string
|
type: string
|
||||||
|
default_team_id:
|
||||||
|
type: string
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
description: The password to decrypt the invite code.
|
description: The password to decrypt the invite code.
|
||||||
|
@ -84,6 +84,9 @@ describe('Connected Workspaces', () => {
|
|||||||
cy.findByText('Accept a secure connection from another server');
|
cy.findByText('Accept a secure connection from another server');
|
||||||
cy.findByText('Enter the encrypted invitation code shared to you by the admin of the server you are connecting with.');
|
cy.findByText('Enter the encrypted invitation code shared to you by the admin of the server you are connecting with.');
|
||||||
|
|
||||||
|
// * Verify accept disabled
|
||||||
|
cy.uiGetButton('Accept').should('be.disabled');
|
||||||
|
|
||||||
// # Enter org name
|
// # Enter org name
|
||||||
cy.findByRole('textbox', {name: 'Organization name'}).type(orgDisplayName);
|
cy.findByRole('textbox', {name: 'Organization name'}).type(orgDisplayName);
|
||||||
|
|
||||||
@ -93,6 +96,13 @@ describe('Connected Workspaces', () => {
|
|||||||
// # Enter bad password
|
// # Enter bad password
|
||||||
cy.findByRole('textbox', {name: 'Password'}).type('123abc');
|
cy.findByRole('textbox', {name: 'Password'}).type('123abc');
|
||||||
|
|
||||||
|
// * Verify accept still disabled
|
||||||
|
cy.uiGetButton('Accept').should('be.disabled');
|
||||||
|
|
||||||
|
// # Select team
|
||||||
|
cy.findByTestId('destination-team-input').click().
|
||||||
|
findByRole('textbox').type(`${testTeam2.display_name}{enter}`);
|
||||||
|
|
||||||
// # Try accept
|
// # Try accept
|
||||||
cy.uiGetButton('Accept').click();
|
cy.uiGetButton('Accept').click();
|
||||||
|
|
||||||
|
@ -464,6 +464,16 @@ func remoteClusterAcceptInvite(c *Context, w http.ResponseWriter, r *http.Reques
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rcAcceptInvite.DefaultTeamId == "" {
|
||||||
|
c.SetInvalidParam("remoteCluster.default_team_id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, teamErr := c.App.GetTeam(rcAcceptInvite.DefaultTeamId); teamErr != nil {
|
||||||
|
c.SetInvalidParamWithErr("remoteCluster.default_team_id", teamErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
audit.AddEventParameter(auditRec, "name", rcAcceptInvite.Name)
|
audit.AddEventParameter(auditRec, "name", rcAcceptInvite.Name)
|
||||||
audit.AddEventParameter(auditRec, "display_name", rcAcceptInvite.DisplayName)
|
audit.AddEventParameter(auditRec, "display_name", rcAcceptInvite.DisplayName)
|
||||||
|
|
||||||
@ -485,7 +495,7 @@ func remoteClusterAcceptInvite(c *Context, w http.ResponseWriter, r *http.Reques
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, aErr := rcs.AcceptInvitation(invite, rcAcceptInvite.Name, rcAcceptInvite.DisplayName, c.AppContext.Session().UserId, url)
|
rc, aErr := rcs.AcceptInvitation(invite, rcAcceptInvite.Name, rcAcceptInvite.DisplayName, c.AppContext.Session().UserId, url, rcAcceptInvite.DefaultTeamId)
|
||||||
if aErr != nil {
|
if aErr != nil {
|
||||||
c.Err = model.NewAppError("remoteClusterAcceptInvite", "api.remote_cluster.accept_invitation_error", nil, "", http.StatusInternalServerError).Wrap(aErr)
|
c.Err = model.NewAppError("remoteClusterAcceptInvite", "api.remote_cluster.accept_invitation_error", nil, "", http.StatusInternalServerError).Wrap(aErr)
|
||||||
if appErr, ok := aErr.(*model.AppError); ok {
|
if appErr, ok := aErr.(*model.AppError); ok {
|
||||||
|
@ -295,9 +295,10 @@ func TestCreateRemoteCluster(t *testing.T) {
|
|||||||
|
|
||||||
func TestRemoteClusterAcceptinvite(t *testing.T) {
|
func TestRemoteClusterAcceptinvite(t *testing.T) {
|
||||||
rcAcceptInvite := &model.RemoteClusterAcceptInvite{
|
rcAcceptInvite := &model.RemoteClusterAcceptInvite{
|
||||||
Name: "remotecluster",
|
Name: "remotecluster",
|
||||||
Invite: "myinvitecode",
|
Invite: "myinvitecode",
|
||||||
Password: "mysupersecret",
|
Password: "mysupersecret",
|
||||||
|
DefaultTeamId: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("Should not work if the remote cluster service is not enabled", func(t *testing.T) {
|
t.Run("Should not work if the remote cluster service is not enabled", func(t *testing.T) {
|
||||||
@ -313,6 +314,8 @@ func TestRemoteClusterAcceptinvite(t *testing.T) {
|
|||||||
th := setupForSharedChannels(t).InitBasic()
|
th := setupForSharedChannels(t).InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
|
rcAcceptInvite.DefaultTeamId = th.BasicTeam.Id
|
||||||
|
|
||||||
remoteId := model.NewId()
|
remoteId := model.NewId()
|
||||||
invite := &model.RemoteClusterInvite{
|
invite := &model.RemoteClusterInvite{
|
||||||
RemoteId: remoteId,
|
RemoteId: remoteId,
|
||||||
@ -335,7 +338,7 @@ func TestRemoteClusterAcceptinvite(t *testing.T) {
|
|||||||
|
|
||||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL = "http://localhost:8065" })
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SiteURL = "http://localhost:8065" })
|
||||||
|
|
||||||
t.Run("should fail if the parameters are not valid", func(t *testing.T) {
|
t.Run("should fail if the name parameter is not valid", func(t *testing.T) {
|
||||||
rcAcceptInvite.Name = ""
|
rcAcceptInvite.Name = ""
|
||||||
defer func() { rcAcceptInvite.Name = "remotecluster" }()
|
defer func() { rcAcceptInvite.Name = "remotecluster" }()
|
||||||
|
|
||||||
@ -345,6 +348,26 @@ func TestRemoteClusterAcceptinvite(t *testing.T) {
|
|||||||
require.Empty(t, rc)
|
require.Empty(t, rc)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("should fail if the default team parameter is empty", func(t *testing.T) {
|
||||||
|
rcAcceptInvite.DefaultTeamId = ""
|
||||||
|
defer func() { rcAcceptInvite.DefaultTeamId = th.BasicTeam.Id }()
|
||||||
|
|
||||||
|
rc, resp, err := th.SystemAdminClient.RemoteClusterAcceptInvite(context.Background(), rcAcceptInvite)
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Empty(t, rc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should fail if the default team provided doesn't exist", func(t *testing.T) {
|
||||||
|
rcAcceptInvite.DefaultTeamId = model.NewId()
|
||||||
|
defer func() { rcAcceptInvite.DefaultTeamId = th.BasicTeam.Id }()
|
||||||
|
|
||||||
|
rc, resp, err := th.SystemAdminClient.RemoteClusterAcceptInvite(context.Background(), rcAcceptInvite)
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Empty(t, rc)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("should fail with the correct status code if the invite returns an app error", func(t *testing.T) {
|
t.Run("should fail with the correct status code if the invite returns an app error", func(t *testing.T) {
|
||||||
rcAcceptInvite.Invite = "malformedinvite"
|
rcAcceptInvite.Invite = "malformedinvite"
|
||||||
// reset the invite after
|
// reset the invite after
|
||||||
|
@ -190,7 +190,7 @@ func (rp *RemoteProvider) doAccept(a *app.App, args *model.CommandArgs, margs ma
|
|||||||
return responsef(args.T("api.command_remote.site_url_not_set"))
|
return responsef(args.T("api.command_remote.site_url_not_set"))
|
||||||
}
|
}
|
||||||
|
|
||||||
rc, err := rcs.AcceptInvitation(invite, name, displayname, args.UserId, url)
|
rc, err := rcs.AcceptInvitation(invite, name, displayname, args.UserId, url, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return responsef(args.T("api.command_remote.accept_invitation.error", map[string]any{"Error": err.Error()}))
|
return responsef(args.T("api.command_remote.accept_invitation.error", map[string]any{"Error": err.Error()}))
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// AcceptInvitation is called when accepting an invitation to connect with a remote cluster.
|
// AcceptInvitation is called when accepting an invitation to connect with a remote cluster.
|
||||||
func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name string, displayName, creatorId string, siteURL string) (*model.RemoteCluster, error) {
|
func (rcs *Service) AcceptInvitation(invite *model.RemoteClusterInvite, name string, displayName string, creatorId string, siteURL string, defaultTeamId string) (*model.RemoteCluster, error) {
|
||||||
rc := &model.RemoteCluster{
|
rc := &model.RemoteCluster{
|
||||||
RemoteId: invite.RemoteId,
|
RemoteId: invite.RemoteId,
|
||||||
Name: name,
|
Name: name,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
Token: model.NewId(),
|
DefaultTeamId: defaultTeamId,
|
||||||
RemoteToken: invite.Token,
|
Token: model.NewId(),
|
||||||
SiteURL: invite.SiteURL,
|
RemoteToken: invite.Token,
|
||||||
CreatorId: creatorId,
|
SiteURL: invite.SiteURL,
|
||||||
|
CreatorId: creatorId,
|
||||||
}
|
}
|
||||||
|
|
||||||
rcSaved, err := rcs.server.GetStore().RemoteCluster().Save(rc)
|
rcSaved, err := rcs.server.GetStore().RemoteCluster().Save(rc)
|
||||||
|
@ -68,7 +68,7 @@ type RemoteClusterServiceIFace interface {
|
|||||||
SendMsg(ctx context.Context, msg model.RemoteClusterMsg, rc *model.RemoteCluster, f SendMsgResultFunc) error
|
SendMsg(ctx context.Context, msg model.RemoteClusterMsg, rc *model.RemoteCluster, f SendMsgResultFunc) error
|
||||||
SendFile(ctx context.Context, us *model.UploadSession, fi *model.FileInfo, rc *model.RemoteCluster, rp ReaderProvider, f SendFileResultFunc) error
|
SendFile(ctx context.Context, us *model.UploadSession, fi *model.FileInfo, rc *model.RemoteCluster, rp ReaderProvider, f SendFileResultFunc) error
|
||||||
SendProfileImage(ctx context.Context, userID string, rc *model.RemoteCluster, provider ProfileImageProvider, f SendProfileImageResultFunc) error
|
SendProfileImage(ctx context.Context, userID string, rc *model.RemoteCluster, provider ProfileImageProvider, f SendProfileImageResultFunc) error
|
||||||
AcceptInvitation(invite *model.RemoteClusterInvite, name string, displayName string, creatorId string, siteURL string) (*model.RemoteCluster, error)
|
AcceptInvitation(invite *model.RemoteClusterInvite, name string, displayName string, creatorId string, siteURL string, defaultTeamId string) (*model.RemoteCluster, error)
|
||||||
ReceiveIncomingMsg(rc *model.RemoteCluster, msg model.RemoteClusterMsg) Response
|
ReceiveIncomingMsg(rc *model.RemoteCluster, msg model.RemoteClusterMsg) Response
|
||||||
ReceiveInviteConfirmation(invite model.RemoteClusterInvite) (*model.RemoteCluster, error)
|
ReceiveInviteConfirmation(invite model.RemoteClusterInvite) (*model.RemoteCluster, error)
|
||||||
PingNow(rc *model.RemoteCluster)
|
PingNow(rc *model.RemoteCluster)
|
||||||
|
@ -462,10 +462,11 @@ func (rci *RemoteClusterInvite) Decrypt(encrypted []byte, password string) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RemoteClusterAcceptInvite struct {
|
type RemoteClusterAcceptInvite struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
DisplayName string `json:"display_name"`
|
DisplayName string `json:"display_name"`
|
||||||
Invite string `json:"invite"`
|
DefaultTeamId string `json:"default_team_id"`
|
||||||
Password string `json:"password"`
|
Invite string `json:"invite"`
|
||||||
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteClusterQueryFilter provides filter criteria for RemoteClusterStore.GetAll
|
// RemoteClusterQueryFilter provides filter criteria for RemoteClusterStore.GetAll
|
||||||
|
@ -156,6 +156,14 @@ export const ModalFieldsetWrapper = styled.div`
|
|||||||
background: none !important;
|
background: none !important;
|
||||||
height: 34px !important;
|
height: 34px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Input_container {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DropdownInput.Input_container {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ModalLegend = styled.legend`
|
const ModalLegend = styled.legend`
|
||||||
|
@ -116,7 +116,7 @@ export const useRemoteClusterAcceptInvite = () => {
|
|||||||
modalId: ModalIdentifiers.SECURE_CONNECTION_ACCEPT_INVITE,
|
modalId: ModalIdentifiers.SECURE_CONNECTION_ACCEPT_INVITE,
|
||||||
dialogType: SecureConnectionAcceptInviteModal,
|
dialogType: SecureConnectionAcceptInviteModal,
|
||||||
dialogProps: {
|
dialogProps: {
|
||||||
onConfirm: async (acceptInvite: PartialExcept<RemoteClusterAcceptInvite, 'display_name' | 'invite' | 'password'>) => {
|
onConfirm: async (acceptInvite: PartialExcept<RemoteClusterAcceptInvite, 'display_name' | 'default_team_id' | 'invite' | 'password'>) => {
|
||||||
try {
|
try {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
const rc = await Client4.acceptInviteRemoteCluster({
|
const rc = await Client4.acceptInviteRemoteCluster({
|
||||||
|
@ -13,12 +13,13 @@ import LoadingScreen from 'components/loading_screen';
|
|||||||
import Input from 'components/widgets/inputs/input/input';
|
import Input from 'components/widgets/inputs/input/input';
|
||||||
|
|
||||||
import {ModalFieldset, ModalParagraph} from '../controls';
|
import {ModalFieldset, ModalParagraph} from '../controls';
|
||||||
import {isErrorState, isPendingState} from '../utils';
|
import TeamSelector from '../team_selector';
|
||||||
|
import {isErrorState, isPendingState, useTeamOptions} from '../utils';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
creating?: boolean;
|
creating?: boolean;
|
||||||
password?: string;
|
password?: string;
|
||||||
onConfirm: (accept: PartialExcept<RemoteClusterAcceptInvite, 'display_name' | 'invite' | 'password'>) => Promise<RemoteCluster>;
|
onConfirm: (accept: PartialExcept<RemoteClusterAcceptInvite, 'display_name' | 'default_team_id' | 'invite' | 'password'>) => Promise<RemoteCluster>;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
onExited: () => void;
|
onExited: () => void;
|
||||||
onHide: () => void;
|
onHide: () => void;
|
||||||
@ -34,12 +35,16 @@ function SecureConnectionAcceptInviteModal({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const {formatMessage} = useIntl();
|
const {formatMessage} = useIntl();
|
||||||
const [displayName, setDisplayName] = useState('');
|
const [displayName, setDisplayName] = useState('');
|
||||||
|
const [defaultTeamId, setDefaultTeamId] = useState('');
|
||||||
const [inviteCode, setInviteCode] = useState('');
|
const [inviteCode, setInviteCode] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [saving, setSaving] = useState<boolean | ClientError>(false);
|
const [saving, setSaving] = useState<boolean | ClientError>(false);
|
||||||
|
|
||||||
|
const teamsById = useTeamOptions();
|
||||||
|
|
||||||
const need = {
|
const need = {
|
||||||
displayName: !displayName,
|
displayName: !displayName,
|
||||||
|
defaultTeamId: !defaultTeamId,
|
||||||
inviteCode: !inviteCode,
|
inviteCode: !inviteCode,
|
||||||
password: !password,
|
password: !password,
|
||||||
};
|
};
|
||||||
@ -50,7 +55,12 @@ function SecureConnectionAcceptInviteModal({
|
|||||||
setSaving(true);
|
setSaving(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await onConfirm({display_name: displayName, invite: inviteCode, password});
|
await onConfirm({
|
||||||
|
display_name: displayName,
|
||||||
|
default_team_id: defaultTeamId,
|
||||||
|
invite: inviteCode,
|
||||||
|
password,
|
||||||
|
});
|
||||||
setSaving(false);
|
setSaving(false);
|
||||||
onHide();
|
onHide();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -90,6 +100,7 @@ function SecureConnectionAcceptInviteModal({
|
|||||||
modalHeaderText={title}
|
modalHeaderText={title}
|
||||||
onExited={onExited}
|
onExited={onExited}
|
||||||
compassDesign={true}
|
compassDesign={true}
|
||||||
|
bodyOverflowVisible={true}
|
||||||
autoCloseOnConfirmButton={false}
|
autoCloseOnConfirmButton={false}
|
||||||
errorText={isErrorState(saving) && (
|
errorText={isErrorState(saving) && (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@ -120,6 +131,23 @@ function SecureConnectionAcceptInviteModal({
|
|||||||
onChange={handleDisplayNameChange}
|
onChange={handleDisplayNameChange}
|
||||||
data-testid='display-name'
|
data-testid='display-name'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormattedMessage
|
||||||
|
id={'admin.secure_connections.accept_invite.select_team'}
|
||||||
|
defaultMessage={'Please select the destination team where channels will be placed.'}
|
||||||
|
tagName={ModalParagraph}
|
||||||
|
/>
|
||||||
|
<TeamSelector
|
||||||
|
testId='destination-team-input'
|
||||||
|
value={defaultTeamId}
|
||||||
|
teamsById={teamsById}
|
||||||
|
onChange={setDefaultTeamId}
|
||||||
|
legend={formatMessage({
|
||||||
|
id: 'admin.secure_connections.accept_invite.select_team.legend',
|
||||||
|
defaultMessage: 'Select a team',
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id={'admin.secure_connections.accept_invite.prompt_invite_password'}
|
id={'admin.secure_connections.accept_invite.prompt_invite_password'}
|
||||||
defaultMessage={'Enter the encrypted invitation code shared to you by the admin of the server you are connecting with.'}
|
defaultMessage={'Enter the encrypted invitation code shared to you by the admin of the server you are connecting with.'}
|
||||||
|
@ -12,11 +12,8 @@ import styled from 'styled-components';
|
|||||||
|
|
||||||
import {GlobeIcon, LockIcon, PlusIcon, ArchiveOutlineIcon} from '@mattermost/compass-icons/components';
|
import {GlobeIcon, LockIcon, PlusIcon, ArchiveOutlineIcon} from '@mattermost/compass-icons/components';
|
||||||
import {isRemoteClusterPatch, type RemoteCluster} from '@mattermost/types/remote_clusters';
|
import {isRemoteClusterPatch, type RemoteCluster} from '@mattermost/types/remote_clusters';
|
||||||
import type {Team} from '@mattermost/types/teams';
|
|
||||||
import type {IDMappedObjects} from '@mattermost/types/utilities';
|
|
||||||
|
|
||||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
|
|
||||||
|
|
||||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||||
|
|
||||||
@ -47,7 +44,7 @@ import {
|
|||||||
import {useRemoteClusterCreate, useSharedChannelsAdd, useSharedChannelsRemove} from './modals/modal_utils';
|
import {useRemoteClusterCreate, useSharedChannelsAdd, useSharedChannelsRemove} from './modals/modal_utils';
|
||||||
import TeamSelector from './team_selector';
|
import TeamSelector from './team_selector';
|
||||||
import type {SharedChannelRemoteRow} from './utils';
|
import type {SharedChannelRemoteRow} from './utils';
|
||||||
import {getEditLocation, isConfirmed, isErrorState, isPendingState, useRemoteClusterEdit, useSharedChannelRemoteRows} from './utils';
|
import {getEditLocation, isConfirmed, isErrorState, isPendingState, useRemoteClusterEdit, useSharedChannelRemoteRows, useTeamOptions} from './utils';
|
||||||
|
|
||||||
import {AdminConsoleListTable} from '../list_table';
|
import {AdminConsoleListTable} from '../list_table';
|
||||||
import SaveChangesPanel from '../team_channel_settings/save_changes_panel';
|
import SaveChangesPanel from '../team_channel_settings/save_changes_panel';
|
||||||
@ -73,6 +70,8 @@ export default function SecureConnectionDetail(props: Props) {
|
|||||||
|
|
||||||
const {promptCreate, saving: creating} = useRemoteClusterCreate();
|
const {promptCreate, saving: creating} = useRemoteClusterCreate();
|
||||||
|
|
||||||
|
const teamsById = useTeamOptions();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// keep history cache up to date
|
// keep history cache up to date
|
||||||
history.replace({...location, state: currentRemoteCluster});
|
history.replace({...location, state: currentRemoteCluster});
|
||||||
@ -87,8 +86,6 @@ export default function SecureConnectionDetail(props: Props) {
|
|||||||
applyPatch({display_name: value});
|
applyPatch({display_name: value});
|
||||||
};
|
};
|
||||||
|
|
||||||
const teams = useSelector(getActiveTeamsList);
|
|
||||||
const teamsById = useMemo(() => teams.reduce<IDMappedObjects<Team>>((teams, team) => ({...teams, [team.id]: team}), {}), [teams]);
|
|
||||||
const handleTeamChange = (teamId: string) => {
|
const handleTeamChange = (teamId: string) => {
|
||||||
applyPatch({default_team_id: teamId});
|
applyPatch({default_team_id: teamId});
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@ export type Props = {
|
|||||||
teamsById: IDMappedObjects<Team>;
|
teamsById: IDMappedObjects<Team>;
|
||||||
onChange: (teamId: string) => void;
|
onChange: (teamId: string) => void;
|
||||||
testId: string;
|
testId: string;
|
||||||
|
legend?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TeamSelector = (props: Props): JSX.Element => {
|
const TeamSelector = (props: Props): JSX.Element => {
|
||||||
@ -40,6 +41,7 @@ const TeamSelector = (props: Props): JSX.Element => {
|
|||||||
value={value ? {label: value.display_name, value: value.id} : undefined}
|
value={value ? {label: value.display_name, value: value.id} : undefined}
|
||||||
options={teamValues}
|
options={teamValues}
|
||||||
name='team_selector'
|
name='team_selector'
|
||||||
|
legend={props.legend}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
import type {LocationDescriptor} from 'history';
|
import type {LocationDescriptor} from 'history';
|
||||||
import {DateTime, Interval} from 'luxon';
|
import {DateTime, Interval} from 'luxon';
|
||||||
import {useCallback, useEffect, useState} from 'react';
|
import {useCallback, useEffect, useMemo, useState} from 'react';
|
||||||
import {useDispatch} from 'react-redux';
|
import {useDispatch, useSelector} from 'react-redux';
|
||||||
|
|
||||||
import type {ClientError} from '@mattermost/client';
|
import type {ClientError} from '@mattermost/client';
|
||||||
import type {Channel} from '@mattermost/types/channels';
|
import type {Channel} from '@mattermost/types/channels';
|
||||||
@ -17,7 +17,7 @@ import {ChannelTypes} from 'mattermost-redux/action_types';
|
|||||||
import {getChannel as fetchChannel} from 'mattermost-redux/actions/channels';
|
import {getChannel as fetchChannel} from 'mattermost-redux/actions/channels';
|
||||||
import {Client4} from 'mattermost-redux/client';
|
import {Client4} from 'mattermost-redux/client';
|
||||||
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
import {getChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||||
import {getTeam} from 'mattermost-redux/selectors/entities/teams';
|
import {getActiveTeamsList, getTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import type {ActionFuncAsync} from 'mattermost-redux/types/actions';
|
import type {ActionFuncAsync} from 'mattermost-redux/types/actions';
|
||||||
|
|
||||||
import type {GlobalState} from 'types/store';
|
import type {GlobalState} from 'types/store';
|
||||||
@ -228,6 +228,12 @@ export const useSharedChannelRemoteRows = (remoteId: string, opts: {filter: 'hom
|
|||||||
return [sharedChannelRemotes, {loading, error, fetch}] as const;
|
return [sharedChannelRemotes, {loading, error, fetch}] as const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useTeamOptions = () => {
|
||||||
|
const teams = useSelector(getActiveTeamsList);
|
||||||
|
const teamsById = useMemo(() => teams.reduce<IDMappedObjects<Team>>((teams, team) => ({...teams, [team.id]: team}), {}), [teams]);
|
||||||
|
return teamsById;
|
||||||
|
};
|
||||||
|
|
||||||
export const getEditLocation = (rc: RemoteCluster): LocationDescriptor<RemoteCluster> => {
|
export const getEditLocation = (rc: RemoteCluster): LocationDescriptor<RemoteCluster> => {
|
||||||
return {pathname: `/admin_console/environment/secure_connections/${rc.remote_id}`, state: rc};
|
return {pathname: `/admin_console/environment/secure_connections/${rc.remote_id}`, state: rc};
|
||||||
};
|
};
|
||||||
|
@ -2222,6 +2222,8 @@
|
|||||||
"admin.secure_connections.accept_invite.prompt": "Accept a secure connection from another server",
|
"admin.secure_connections.accept_invite.prompt": "Accept a secure connection from another server",
|
||||||
"admin.secure_connections.accept_invite.prompt_invite_password": "Enter the encrypted invitation code shared to you by the admin of the server you are connecting with.",
|
"admin.secure_connections.accept_invite.prompt_invite_password": "Enter the encrypted invitation code shared to you by the admin of the server you are connecting with.",
|
||||||
"admin.secure_connections.accept_invite.saving_changes_error": "There was an error while accepting the invite.",
|
"admin.secure_connections.accept_invite.saving_changes_error": "There was an error while accepting the invite.",
|
||||||
|
"admin.secure_connections.accept_invite.select_team": "Please select the destination team where channels will be placed.",
|
||||||
|
"admin.secure_connections.accept_invite.select_team.legend": "Select a team",
|
||||||
"admin.secure_connections.accept_invite.share_title": "Accept a connection invite",
|
"admin.secure_connections.accept_invite.share_title": "Accept a connection invite",
|
||||||
"admin.secure_connections.confirm.delete.button": "Yes, delete",
|
"admin.secure_connections.confirm.delete.button": "Yes, delete",
|
||||||
"admin.secure_connections.confirm.delete.text": "Are you sure you want to delete the secure connection <strong>{displayName}</strong>?",
|
"admin.secure_connections.confirm.delete.text": "Are you sure you want to delete the secure connection <strong>{displayName}</strong>?",
|
||||||
|
@ -11,6 +11,7 @@ export type RemoteClusterInvite = {
|
|||||||
export type RemoteClusterAcceptInvite = {
|
export type RemoteClusterAcceptInvite = {
|
||||||
name: string;
|
name: string;
|
||||||
display_name: string;
|
display_name: string;
|
||||||
|
default_team_id: string;
|
||||||
invite: string;
|
invite: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user