From 190853225fe1b3ecd784f9f14b18f450c3990f62 Mon Sep 17 00:00:00 2001 From: Reinaldo Neto <47038980+reinaldonetof@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:11:26 -0300 Subject: [PATCH 1/4] [FIX] Create team crashing the app (#3248) Co-authored-by: Gerzon Z Co-authored-by: Gerzon Z Co-authored-by: Diego Mello --- app/sagas/createChannel.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/sagas/createChannel.js b/app/sagas/createChannel.js index a768916c8..9493d5405 100644 --- a/app/sagas/createChannel.js +++ b/app/sagas/createChannel.js @@ -41,10 +41,10 @@ const handleRequest = function* handleRequest({ data }) { encrypted } = data; logEvent(events.CT_CREATE, { - type, - readOnly, - broadcast, - encrypted + type: `${ type }`, + readOnly: `${ readOnly }`, + broadcast: `${ broadcast }`, + encrypted: `${ encrypted }` }); const result = yield call(createTeam, data); sub = { From 16fee2aa64fbd2bd358af312909e625da33e1da8 Mon Sep 17 00:00:00 2001 From: Reinaldo Neto <47038980+reinaldonetof@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:46:24 -0300 Subject: [PATCH 2/4] [IMPROVE] Convert Team to Channel (#3249) * [IMPROVE] Add convert team to a channel * Action to SelectListView and new words to i18n * Implemented the post and it's working with selected channels or not * Fixed the Convert Team Warning at english i18n and changed the function name * E2E test completed in sequence the convert/move teams * [IMPROVE] Add convert team to a channel * Action to SelectListView and new words to i18n * Implemented the post and it's working with selected channels or not * Fixed the Convert Team Warning at english i18n and changed the function name * rebase develop into this branch * [IMPROVE] Add convert team to a channel * Action to SelectListView and new words to i18n * Implemented the post and it's working with selected channels or not * Fixed the Convert Team Warning at english i18n and changed the function name * rebase develop into this branch Co-authored-by: Diego Mello --- app/i18n/locales/en.json | 8 +- app/i18n/locales/pt-BR.json | 3 +- app/lib/methods/getPermissions.js | 3 +- app/lib/rocketchat.js | 7 ++ app/utils/log/events.js | 2 + app/views/RoomActionsView/index.js | 103 +++++++++++++++++++++++++- e2e/tests/team/03-moveconvert.spec.js | 29 +++++++- 7 files changed, 146 insertions(+), 9 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 723b4dd9e..426aaa77a 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -756,7 +756,7 @@ "member-does-not-exist": "Member does not exist", "Convert": "Convert", "Convert_to_Team": "Convert to Team", - "Convert_to_Team_Warning": "This can't be undone. Once you convert a channel to a team, you can not turn it back to a channel.", + "Convert_to_Team_Warning": "You are converting this Channel to a Team. All Members will be kept.", "Move_to_Team": "Move to Team", "Move_Channel_Paragraph": "Moving a channel inside a team means that this channel will be added in the team’s context, however, all channel’s members, which are not members of the respective team, will still have access to this channel, but will not be added as team’s members. \n\nAll channel’s management will still be made by the owners of this channel.\n\nTeam’s members and even team’s owners, if not a member of this channel, can not have access to the channel’s content. \n\nPlease notice that the Team’s owner will be able remove members from the Channel.", "Move_to_Team_Warning": "After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?", @@ -765,5 +765,9 @@ "Load_Older": "Load Older", "Left_The_Room_Successfully": "Left the room successfully", "Deleted_The_Team_Successfully": "Team deleted successfully", - "Deleted_The_Room_Successfully": "Room deleted successfully" + "Deleted_The_Room_Successfully": "Room deleted successfully", + "Convert_to_Channel": "Convert to Channel", + "Converting_Team_To_Channel": "Converting Team to Channel", + "Select_Team_Channels_To_Delete": "Select the Team’s Channels you would like to delete, the ones you do not select will be moved to the Workspace. \n\nNotice that public Channels will be public and visible to everyone.", + "You_are_converting_the_team": "You are converting this Team to a Channel" } \ No newline at end of file diff --git a/app/i18n/locales/pt-BR.json b/app/i18n/locales/pt-BR.json index a56f169b8..aefd96106 100644 --- a/app/i18n/locales/pt-BR.json +++ b/app/i18n/locales/pt-BR.json @@ -669,5 +669,6 @@ "invalid-room": "Sala inválida", "Left_The_Room_Successfully": "Saiu da sala com sucesso", "Deleted_The_Team_Successfully": "Time deletado com sucesso", - "Deleted_The_Room_Successfully": "Sala deletada com sucesso" + "Deleted_The_Room_Successfully": "Sala deletada com sucesso", + "Convert_to_Channel": "Converter para um Canal" } \ No newline at end of file diff --git a/app/lib/methods/getPermissions.js b/app/lib/methods/getPermissions.js index 6e68f5c33..1c4c56b46 100644 --- a/app/lib/methods/getPermissions.js +++ b/app/lib/methods/getPermissions.js @@ -47,7 +47,8 @@ const PERMISSIONS = [ 'view-statistics', 'view-user-administration', 'view-all-teams', - 'view-all-team-channels' + 'view-all-team-channels', + 'convert-team' ]; export async function setPermissions() { diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 5b69b92ba..59ee94fc5 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -866,6 +866,13 @@ const RocketChat = { }; return this.sdk.post(type === 'c' ? 'channels.convertToTeam' : 'groups.convertToTeam', params); }, + convertTeamToChannel({ teamId, selected }) { + const params = { + teamId, + ...(selected.length && { roomsToRemove: selected }) + }; + return this.sdk.post('teams.convertToChannel', params); + }, joinRoom(roomId, joinCode, type) { // TODO: join code // RC 0.48.0 diff --git a/app/utils/log/events.js b/app/utils/log/events.js index a183735ba..2ab3f539b 100644 --- a/app/utils/log/events.js +++ b/app/utils/log/events.js @@ -259,6 +259,8 @@ export default { RA_LEAVE_TEAM_F: 'ra_leave_team_f', RA_CONVERT_TO_TEAM: 'ra_convert_to_team', RA_CONVERT_TO_TEAM_F: 'ra_convert_to_team_f', + RA_CONVERT_TEAM_TO_CHANNEL: 'ra_convert_team_to_channel', + RA_CONVERT_TEAM_TO_CHANNEL_F: 'ra_convert_team_to_channel_f', RA_MOVE_TO_TEAM: 'ra_move_to_team', RA_MOVE_TO_TEAM_F: 'ra_move_to_team_f', RA_SEARCH_TEAM: 'ra_search_team', diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 75c977a28..914a42913 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -67,7 +67,8 @@ class RoomActionsView extends React.Component { viewBroadcastMemberListPermission: PropTypes.array, transferLivechatGuestPermission: PropTypes.array, createTeamPermission: PropTypes.array, - addTeamChannelPermission: PropTypes.array + addTeamChannelPermission: PropTypes.array, + convertTeamPermission: PropTypes.array } constructor(props) { @@ -91,7 +92,8 @@ class RoomActionsView extends React.Component { canEdit: false, canToggleEncryption: false, canCreateTeam: false, - canAddChannelToTeam: false + canAddChannelToTeam: false, + canConvertTeam: false }; if (room && room.observe && room.rid) { this.roomObservable = room.observe(); @@ -142,9 +144,10 @@ class RoomActionsView extends React.Component { const canViewMembers = await this.canViewMembers(); const canCreateTeam = await this.canCreateTeam(); const canAddChannelToTeam = await this.canAddChannelToTeam(); + const canConvertTeam = await this.canConvertTeam(); this.setState({ - canAutoTranslate, canAddUser, canInviteUser, canEdit, canToggleEncryption, canViewMembers, canCreateTeam, canAddChannelToTeam + canAutoTranslate, canAddUser, canInviteUser, canEdit, canToggleEncryption, canViewMembers, canCreateTeam, canAddChannelToTeam, canConvertTeam }); // livechat permissions @@ -240,6 +243,16 @@ class RoomActionsView extends React.Component { return canAddChannelToTeam; } + canConvertTeam = async() => { + const { room } = this.state; + const { convertTeamPermission } = this.props; + const { rid } = room; + const permissions = await RocketChat.hasPermission([convertTeamPermission], rid); + + const canConvertTeam = permissions[0]; + return canConvertTeam; + } + canToggleEncryption = async() => { const { room } = this.state; const { toggleRoomE2EEncryptionPermission } = this.props; @@ -433,6 +446,59 @@ class RoomActionsView extends React.Component { }); } + convertTeamToChannel = async() => { + const { room } = this.state; + const { navigation } = this.props; + + try { + const result = await RocketChat.teamListRoomsOfUser({ teamId: room.teamId, userId: room.u._id }); + + if (result.rooms?.length) { + const teamChannels = result.rooms.map(r => ({ + rid: r._id, + name: r.name, + teamId: r.teamId + })); + navigation.navigate('SelectListView', { + title: 'Converting_Team_To_Channel', + data: teamChannels, + infoText: 'Select_Team_Channels_To_Delete', + nextAction: data => this.convertTeamToChannelConfirmation(data) + }); + } else { + this.convertTeamToChannelConfirmation(); + } + } catch (e) { + this.convertTeamToChannelConfirmation(); + } + } + + handleConvertTeamToChannel = async(selected) => { + logEvent(events.RA_CONVERT_TEAM_TO_CHANNEL); + try { + const { room } = this.state; + const { navigation } = this.props; + + const result = await RocketChat.convertTeamToChannel({ teamId: room.teamId, selected }); + + if (result.success) { + navigation.navigate('RoomView'); + } + } catch (e) { + logEvent(events.RA_CONVERT_TEAM_TO_CHANNEL_F); + log(e); + } + } + + convertTeamToChannelConfirmation = (selected = []) => { + showConfirmationAlert({ + title: I18n.t('Confirmation'), + message: I18n.t('You_are_converting_the_team'), + confirmationText: I18n.t('Convert'), + onPress: () => this.handleConvertTeamToChannel(selected) + }); + } + leaveTeam = async() => { const { room } = this.state; const { navigation, leaveRoom } = this.props; @@ -806,6 +872,32 @@ class RoomActionsView extends React.Component { ); } + teamToChannelActions = (t, room) => { + const { canEdit, canConvertTeam } = this.state; + const canConvertTeamToChannel = canEdit && canConvertTeam && !!room?.teamMain; + + return ( + <> + {['c', 'p'].includes(t) && canConvertTeamToChannel + ? ( + <> + this.onPressTouchable({ + event: this.convertTeamToChannel + })} + testID='room-actions-convert-channel-to-team' + left={() => } + showActionIndicator + /> + + + ) + : null} + + ); + } + render() { const { room, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate, canForwardGuest, canReturnQueue @@ -1007,7 +1099,9 @@ class RoomActionsView extends React.Component { ) : null} + { this.teamChannelActions(t, room) } + {this.teamToChannelActions(t, room)} {['l'].includes(t) && !this.isOmnichannelPreview ? ( @@ -1099,7 +1193,8 @@ const mapStateToProps = state => ({ viewBroadcastMemberListPermission: state.permissions['view-broadcast-member-list'], transferLivechatGuestPermission: state.permissions['transfer-livechat-guest'], createTeamPermission: state.permissions['create-team'], - addTeamChannelPermission: state.permissions['add-team-channel'] + addTeamChannelPermission: state.permissions['add-team-channel'], + convertTeamPermission: state.permissions['convert-team'] }); const mapDispatchToProps = dispatch => ({ diff --git a/e2e/tests/team/03-moveconvert.spec.js b/e2e/tests/team/03-moveconvert.spec.js index 7c071442b..754aafc09 100644 --- a/e2e/tests/team/03-moveconvert.spec.js +++ b/e2e/tests/team/03-moveconvert.spec.js @@ -51,7 +51,7 @@ describe('Move/Convert Team', () => { await element(by.id('room-actions-scrollview')).scrollTo('bottom'); await waitFor(element(by.id('room-actions-convert-to-team'))).toExist().withTimeout(2000); await element(by.id('room-actions-convert-to-team')).tap(); - await waitFor(element(by.label('This can\'t be undone. Once you convert a channel to a team, you can not turn it back to a channel.'))).toExist().withTimeout(2000); + await waitFor(element(by.label('You are converting this Channel to a Team. All Members will be kept.'))).toExist().withTimeout(2000); await element(by.text('Convert')).tap(); await waitFor(element(by.id('room-view'))).toExist().withTimeout(20000); await waitFor(element(by.id(`room-view-title-${ toBeConverted }`))).toExist().withTimeout(6000); @@ -84,5 +84,32 @@ describe('Move/Convert Team', () => { await element(by.text('Yes, move it!')).tap(); await waitFor(element(by.id('room-view-header-team-channels'))).toExist().withTimeout(10000); }); + + after(async() => { + await tapBack(); + await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000); + }); + }); + + describe('Convert Team to Channel and Delete toBeMoved channel within the Converted', () => { + it('should convert a team to a channel', async() => { + await navigateToRoomActions(toBeConverted); + await element(by.id('room-actions-scrollview')).scrollTo('bottom'); + await waitFor(element(by.id('room-actions-convert-channel-to-team'))).toExist().withTimeout(2000); + await element(by.id('room-actions-convert-channel-to-team')).tap(); + await sleep(2000); + await waitFor(element(by.id('select-list-view'))).toExist().withTimeout(2000); + await waitFor(element(by.id(`select-list-view-item-${ toBeMoved }`))).toExist().withTimeout(2000); + await element(by.id(`select-list-view-item-${ toBeMoved }`)).tap(); + await waitFor(element(by.id('select-list-view-submit'))).toExist().withTimeout(2000); + await element(by.id('select-list-view-submit')).tap(); + await waitFor(element(by.label('You are converting this Team to a Channel'))).toExist().withTimeout(2000); + await element(by.text('Convert')).tap(); + await waitFor(element(by.id('room-view'))).toExist().withTimeout(20000); + await waitFor(element(by.id(`room-view-title-${ toBeConverted }`))).toExist().withTimeout(6000); + await tapBack(); + await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000); + await waitFor(element(by.id(`rooms-list-view-item-${ toBeMoved }`))).toBeNotVisible().withTimeout(60000); + }); }); }); From c9d5bc37c48904c2cc81a6ad2ee5b0165448ef1c Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 12 Jul 2021 14:05:09 -0400 Subject: [PATCH 3/4] [IMPROVE] Set black as default dark theme (#3270) * Update default darkLevel * Minor tweak --- app/index.js | 2 +- app/share.js | 2 +- app/views/ThemeView.js | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/index.js b/app/index.js index 048323a5b..efcf1557e 100644 --- a/app/index.js +++ b/app/index.js @@ -75,7 +75,7 @@ export default class Root extends React.Component { theme: defaultTheme(), themePreferences: { currentTheme: supportSystemTheme() ? 'automatic' : 'light', - darkLevel: 'dark' + darkLevel: 'black' }, width, height, diff --git a/app/share.js b/app/share.js index bfe011264..dbf0bfbff 100644 --- a/app/share.js +++ b/app/share.js @@ -124,7 +124,7 @@ class Root extends React.Component { theme: defaultTheme(), themePreferences: { currentTheme: supportSystemTheme() ? 'automatic' : 'light', - darkLevel: 'dark' + darkLevel: 'black' }, root: '', width, diff --git a/app/views/ThemeView.js b/app/views/ThemeView.js index e62d7ca58..1152a920c 100644 --- a/app/views/ThemeView.js +++ b/app/views/ThemeView.js @@ -30,14 +30,14 @@ const THEMES = [ label: 'Dark', value: 'dark', group: THEME_GROUP - }, { - label: 'Dark', - value: 'dark', - group: DARK_GROUP }, { label: 'Black', value: 'black', group: DARK_GROUP + }, { + label: 'Dark', + value: 'dark', + group: DARK_GROUP } ]; From 4882ccd58831dac6671eaef2dbf9da6e3eac8777 Mon Sep 17 00:00:00 2001 From: Reinaldo Neto <47038980+reinaldonetof@users.noreply.github.com> Date: Mon, 12 Jul 2021 16:19:25 -0300 Subject: [PATCH 4/4] [IMPROVE] Make `system default` the default browser (#3265) * [FIX] use systemdefault: as the default browser, not inApp * Fix Co-authored-by: Diego Mello --- app/utils/openLink.js | 8 ++++---- app/views/DefaultBrowserView.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/utils/openLink.js b/app/utils/openLink.js index 36f72c0e2..703625497 100644 --- a/app/utils/openLink.js +++ b/app/utils/openLink.js @@ -39,16 +39,16 @@ const openLink = async(url, theme = 'light') => { try { const browser = await UserPreferences.getStringAsync(DEFAULT_BROWSER_KEY); - if (browser) { - const schemeUrl = appSchemeURL(url, browser.replace(':', '')); - await Linking.openURL(schemeUrl); - } else { + if (browser === 'inApp') { await WebBrowser.openBrowserAsync(url, { toolbarColor: themes[theme].headerBackground, controlsColor: themes[theme].headerTintColor, collapseToolbar: true, showTitle: true }); + } else { + const schemeUrl = appSchemeURL(url, browser.replace(':', '')); + await Linking.openURL(schemeUrl); } } catch { try { diff --git a/app/views/DefaultBrowserView.js b/app/views/DefaultBrowserView.js index 119ce9fa8..568802360 100644 --- a/app/views/DefaultBrowserView.js +++ b/app/views/DefaultBrowserView.js @@ -83,7 +83,7 @@ class DefaultBrowserView extends React.Component { isSelected = (value) => { const { browser } = this.state; - if (!browser && value === 'inApp') { + if (!browser && value === 'systemDefault:') { return true; } return browser === value; @@ -92,7 +92,7 @@ class DefaultBrowserView extends React.Component { changeDefaultBrowser = async(newBrowser) => { logEvent(events.DB_CHANGE_DEFAULT_BROWSER, { browser: newBrowser }); try { - const browser = newBrowser !== 'inApp' ? newBrowser : null; + const browser = newBrowser !== 'systemDefault:' ? newBrowser : null; await UserPreferences.setStringAsync(DEFAULT_BROWSER_KEY, browser); this.setState({ browser }); } catch {