diff --git a/app/components/channel_list/__snapshots__/index.test.tsx.snap b/app/components/channel_list/__snapshots__/index.test.tsx.snap index 49acd1e40..2aa41ca63 100644 --- a/app/components/channel_list/__snapshots__/index.test.tsx.snap +++ b/app/components/channel_list/__snapshots__/index.test.tsx.snap @@ -17,7 +17,7 @@ exports[`components/channel_list should render channels error 1`] = ` "maxWidth": "100%", "paddingLeft": 18, "paddingRight": 20, - "paddingVertical": 10, + "paddingTop": 10, } } > @@ -187,7 +187,7 @@ exports[`components/channel_list should render team error 1`] = ` "maxWidth": "100%", "paddingLeft": 18, "paddingRight": 20, - "paddingVertical": 10, + "paddingTop": 10, } } > diff --git a/app/components/channel_list/categories/body/channel/channel_list_item.tsx b/app/components/channel_list/categories/body/channel/channel_list_item.tsx index 1e458be25..230fc9fc2 100644 --- a/app/components/channel_list/categories/body/channel/channel_list_item.tsx +++ b/app/components/channel_list/categories/body/channel/channel_list_item.tsx @@ -65,7 +65,7 @@ type Props = { isActive: boolean; isOwnDirectMessage: boolean; isMuted: boolean; - myChannel: MyChannelModel; + myChannel?: MyChannelModel; collapsed: boolean; } @@ -76,7 +76,7 @@ const ChannelListItem = ({channel, isActive, isOwnDirectMessage, isMuted, myChan const serverUrl = useServerUrl(); // Make it brighter if it's not muted, and highlighted or has unreads - const bright = !isMuted && (isActive || myChannel.isUnread || myChannel.mentionsCount > 0); + const bright = !isMuted && (isActive || (myChannel && (myChannel.isUnread || myChannel.mentionsCount > 0))); const sharedValue = useSharedValue(collapsed && !bright); @@ -92,7 +92,11 @@ const ChannelListItem = ({channel, isActive, isOwnDirectMessage, isMuted, myChan }; }); - const switchChannels = () => switchToChannelById(serverUrl, myChannel.id); + const switchChannels = () => { + if (myChannel) { + switchToChannelById(serverUrl, myChannel.id); + } + }; const membersCount = useMemo(() => { if (channel.type === General.GM_CHANNEL) { return channel.displayName?.split(',').length; @@ -112,7 +116,7 @@ const ChannelListItem = ({channel, isActive, isOwnDirectMessage, isMuted, myChan displayName = formatMessage({id: 'channel_header.directchannel.you', defaultMessage: '{displayName} (you)'}, {displayName}); } - if (channel.deleteAt > 0 && !isActive) { + if ((channel.deleteAt > 0 && !isActive) || !myChannel) { return null; } diff --git a/app/components/channel_list/categories/body/channel/index.ts b/app/components/channel_list/categories/body/channel/index.ts index bfc4323d4..4aeca82c5 100644 --- a/app/components/channel_list/categories/body/channel/index.ts +++ b/app/components/channel_list/categories/body/channel/index.ts @@ -14,8 +14,6 @@ import {getUserIdFromChannelName} from '@utils/user'; import ChannelListItem from './channel_list_item'; import type {WithDatabaseArgs} from '@typings/database/database'; -import type ChannelModel from '@typings/database/models/servers/channel'; -import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; const enhance = withObservables(['channelId'], ({channelId, database}: {channelId: string} & WithDatabaseArgs) => { const myChannel = observeMyChannel(database, channelId); @@ -37,16 +35,16 @@ const enhance = withObservables(['channelId'], ({channelId, database}: {channelI return { isOwnDirectMessage, isMuted: settings.pipe( - switchMap((s: MyChannelSettingsModel) => of$(s.notifyProps?.mark_unread === 'mention')), + switchMap((s) => of$(s?.notifyProps?.mark_unread === 'mention')), ), myChannel, channel: channel.pipe( - switchMap((c: ChannelModel) => of$({ - deleteAt: c.deleteAt, - displayName: c.displayName, - name: c.name, - shared: c.shared, - type: c.type, + switchMap((c) => of$({ + deleteAt: c?.deleteAt || 0, + displayName: c?.displayName || '', + name: c?.name || '', + shared: c?.shared || false, + type: c?.type || '', })), ), }; diff --git a/app/components/channel_list/categories/categories.tsx b/app/components/channel_list/categories/categories.tsx index 5718fd42b..c63d8189d 100644 --- a/app/components/channel_list/categories/categories.tsx +++ b/app/components/channel_list/categories/categories.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback} from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; import {useIntl} from 'react-intl'; import {FlatList, StyleSheet} from 'react-native'; @@ -9,12 +9,13 @@ import CategoryBody from './body'; import LoadCategoriesError from './error'; import CategoryHeader from './header'; -import type {CategoryModel} from '@database/models/server'; +import type CategoryModel from '@typings/database/models/servers/category'; type Props = { categories: CategoryModel[]; currentChannelId: string; currentUserId: string; + currentTeamId: string; } const styles = StyleSheet.create({ @@ -25,8 +26,9 @@ const styles = StyleSheet.create({ const extractKey = (item: CategoryModel) => item.id; -const Categories = ({categories, currentChannelId, currentUserId}: Props) => { +const Categories = ({categories, currentChannelId, currentUserId, currentTeamId}: Props) => { const intl = useIntl(); + const listRef = useRef(null); const renderCategory = useCallback((data: {item: CategoryModel}) => { return ( @@ -42,6 +44,10 @@ const Categories = ({categories, currentChannelId, currentUserId}: Props) => { ); }, [categories, currentChannelId, intl.locale]); + useEffect(() => { + listRef.current?.scrollToOffset({animated: false, offset: 0}); + }, [currentTeamId]); + // Sort Categories categories.sort((a, b) => a.sortOrder - b.sortOrder); @@ -52,6 +58,7 @@ const Categories = ({categories, currentChannelId, currentUserId}: Props) => { return ( ({ backgroundColor: theme.sidebarBg, paddingLeft: 18, paddingRight: 20, - paddingVertical: 10, + paddingTop: 10, }, })); diff --git a/app/components/post_list/index.tsx b/app/components/post_list/index.tsx index 1bdb0355f..46095bbe2 100644 --- a/app/components/post_list/index.tsx +++ b/app/components/post_list/index.tsx @@ -235,6 +235,7 @@ const PostList = ({ ); } @@ -312,11 +313,11 @@ const PostList = ({ ); }, [currentTimezone, highlightPinnedOrSaved, isTimezoneEnabled, orderedPosts, shouldRenderReplyButton, theme]); - const scrollToIndex = useCallback((index: number, animated = true) => { + const scrollToIndex = useCallback((index: number, animated = true, applyOffset = true) => { listRef.current?.scrollToIndex({ animated, index, - viewOffset: 0, + viewOffset: applyOffset ? Platform.select({ios: -45, default: 0}) : 0, viewPosition: 1, // 0 is at bottom }); }, []); diff --git a/app/components/post_list/more_messages/more_messages.tsx b/app/components/post_list/more_messages/more_messages.tsx index 14cbf4b26..80f3c914f 100644 --- a/app/components/post_list/more_messages/more_messages.tsx +++ b/app/components/post_list/more_messages/more_messages.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {ActivityIndicator, DeviceEventEmitter, View, ViewToken} from 'react-native'; +import {ActivityIndicator, DeviceEventEmitter, Platform, View, ViewToken} from 'react-native'; import Animated, {interpolate, useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated'; import {resetMessageCount} from '@actions/local/channel'; @@ -23,14 +23,14 @@ type Props = { posts: Array; registerScrollEndIndexListener: (fn: (endIndex: number) => void) => () => void; registerViewableItemsListener: (fn: (viewableItems: ViewToken[]) => void) => () => void; - scrollToIndex: (index: number, animated?: boolean) => void; + scrollToIndex: (index: number, animated?: boolean, applyOffset?: boolean) => void; unreadCount: number; theme: Theme; testID: string; } const HIDDEN_TOP = -60; -const SHOWN_TOP = 0; +const SHOWN_TOP = Platform.select({ios: 40, default: 0}); const MIN_INPUT = 0; const MAX_INPUT = 1; @@ -103,6 +103,7 @@ const MoreMessages = ({ const serverUrl = useServerUrl(); const pressed = useRef(false); const resetting = useRef(false); + const initialScroll = useRef(false); const [loading, setLoading] = useState(false); const [remaining, setRemaining] = useState(0); const underlayColor = useMemo(() => `hsl(${hexToHue(theme.buttonBg)}, 50%, 38%)`, [theme]); @@ -149,13 +150,14 @@ const MoreMessages = ({ const lastViewableIndex = viewableItems.filter((v) => v.isViewable)[viewableItems.length - 1]?.index || 0; const nextViewableIndex = lastViewableIndex + 1; - if (viewableItems[0].index === 0 && nextViewableIndex > newMessageLineIndex) { + if (viewableItems[0].index === 0 && nextViewableIndex > newMessageLineIndex && !initialScroll.current) { // Auto scroll if the first post is viewable and // * the new message line is viewable OR // * the new message line will be the first next viewable item - scrollToIndex(newMessageLineIndex, true); + scrollToIndex(newMessageLineIndex, true, false); resetCount(); top.value = 0; + initialScroll.current = true; return; } @@ -212,6 +214,7 @@ const MoreMessages = ({ useEffect(() => { resetting.current = false; + initialScroll.current = false; }, [channelId]); return ( diff --git a/app/components/post_list/post/post.tsx b/app/components/post_list/post/post.tsx index 7bbe460fb..b13b096a8 100644 --- a/app/components/post_list/post/post.tsx +++ b/app/components/post_list/post/post.tsx @@ -91,6 +91,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { flexDirection: 'column', }, rightColumnPadding: {paddingBottom: 3}, + touchableContainer: {marginHorizontal: -20, paddingHorizontal: 20}, }; }); @@ -274,6 +275,7 @@ const Post = ({ onPress={handlePress} onLongPress={showPostOptions} underlayColor={changeOpacity(theme.centerChannelColor, 0.1)} + style={styles.touchableContainer} > <> ; }; const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { @@ -55,7 +56,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }; }); -const ThreadOverview = ({isSaved, repliesCount, rootPost, testID}: Props) => { +const ThreadOverview = ({isSaved, repliesCount, rootPost, style, testID}: Props) => { const theme = useTheme(); const styles = getStyleSheet(theme); @@ -85,14 +86,15 @@ const ThreadOverview = ({isSaved, repliesCount, rootPost, testID}: Props) => { }), [rootPost]); const containerStyle = useMemo(() => { - const style = [styles.container]; + const container = [styles.container]; if (repliesCount === 0) { - style.push({ + container.push({ borderBottomWidth: 0, }); } - return style; - }, [repliesCount]); + container.push(style); + return container; + }, [repliesCount, style]); return ( class extends superclass { const emojis: CustomEmoji[] = []; const files: FileInfo[] = []; - const metadatas: Metadata[] = []; const postsReactions: ReactionsPerPost[] = []; const pendingPostsToDelete: Post[] = []; const postsInThread: Record = {}; @@ -193,12 +192,6 @@ const PostHandler = (superclass: any) => class extends superclass { batch.push(...postFiles); } - if (metadatas.length) { - // calls handler for postMetadata ( embeds and images ) - const postMetadata = await this.handlePostMetadata({metadatas, prepareRecordsOnly: true}); - batch.push(...postMetadata); - } - if (emojis.length) { const postEmojis = await this.handleCustomEmojis({emojis, prepareRecordsOnly: true}); batch.push(...postEmojis); diff --git a/app/database/operator/server_data_operator/transformers/channel.ts b/app/database/operator/server_data_operator/transformers/channel.ts index bc4c4becd..4e4bd466a 100644 --- a/app/database/operator/server_data_operator/transformers/channel.ts +++ b/app/database/operator/server_data_operator/transformers/channel.ts @@ -49,7 +49,7 @@ export const transformChannelRecord = ({action, database, value}: TransformerArg const rawMembers = raw.display_name.split(',').length; const recordMembers = record?.displayName.split(',').length || rawMembers; - if (recordMembers < rawMembers) { + if (recordMembers < rawMembers && record.displayName) { displayName = record.displayName; } else { displayName = raw.display_name; diff --git a/app/screens/channel/intro/direct_channel/direct_channel.tsx b/app/screens/channel/intro/direct_channel/direct_channel.tsx deleted file mode 100644 index 98c9140ad..000000000 --- a/app/screens/channel/intro/direct_channel/direct_channel.tsx +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useEffect, useMemo} from 'react'; -import {Text, View} from 'react-native'; - -import {fetchProfilesInChannel} from '@actions/remote/user'; -import FormattedText from '@components/formatted_text'; -import {BotTag} from '@components/tag'; -import {General} from '@constants'; -import {useServerUrl} from '@context/server'; -import {makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; - -import IntroOptions from '../options'; - -import Group from './group'; -import Member from './member'; - -import type ChannelModel from '@typings/database/models/servers/channel'; -import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; - -type Props = { - channel: ChannelModel; - currentUserId: string; - isBot: boolean; - members?: ChannelMembershipModel[]; - theme: Theme; -} - -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - botContainer: { - alignSelf: 'flex-end', - bottom: 7.5, - height: 20, - marginBottom: 0, - marginLeft: 4, - paddingVertical: 0, - }, - botText: { - fontSize: 14, - lineHeight: 20, - }, - container: { - alignItems: 'center', - }, - message: { - color: theme.centerChannelColor, - marginTop: 16, - textAlign: 'center', - ...typography('Body', 200, 'Regular'), - }, - profilesContainer: { - justifyContent: 'center', - alignItems: 'center', - }, - title: { - color: theme.centerChannelColor, - marginTop: 16, - textAlign: 'center', - ...typography('Heading', 700, 'SemiBold'), - }, - titleGroup: { - ...typography('Heading', 600, 'SemiBold'), - }, -})); - -const DirectChannel = ({channel, currentUserId, isBot, members, theme}: Props) => { - const serverUrl = useServerUrl(); - const styles = getStyleSheet(theme); - - useEffect(() => { - const channelMembers = members?.filter((m) => m.userId !== currentUserId); - if (!channelMembers?.length) { - fetchProfilesInChannel(serverUrl, channel.id, currentUserId, false); - } - }, []); - - const message = useMemo(() => { - if (channel.type === General.DM_CHANNEL) { - return ( - - ); - } - return ( - - ); - }, [channel.displayName, theme]); - - const profiles = useMemo(() => { - const channelMembers = members?.filter((m) => m.userId !== currentUserId); - if (!channelMembers?.length) { - return null; - } - - if (channel.type === General.DM_CHANNEL) { - return ( - - ); - } - - return ( - cm.userId)} - /> - ); - }, [members, theme]); - - return ( - - - {profiles} - - - - {channel.displayName} - - {isBot && - - } - - {message} - - - ); -}; - -export default DirectChannel; diff --git a/app/screens/channel/intro/direct_channel/group/group.tsx b/app/screens/channel/intro/direct_channel/group/group.tsx deleted file mode 100644 index cb37ac563..000000000 --- a/app/screens/channel/intro/direct_channel/group/group.tsx +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {chunk} from 'lodash'; -import React from 'react'; -import {View} from 'react-native'; -import FastImage from 'react-native-fast-image'; - -import {useServerUrl} from '@context/server'; -import NetworkManager from '@init/network_manager'; -import {makeStyleSheetFromTheme} from '@utils/theme'; - -import type {Client} from '@client/rest'; -import type UserModel from '@typings/database/models/servers/user'; - -type Props = { - theme: Theme; - users: UserModel[]; -} - -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - container: { - alignItems: 'center', - flexDirection: 'row', - marginBottom: 12, - }, - profile: { - borderColor: theme.centerChannelBg, - borderRadius: 36, - borderWidth: 2, - height: 72, - width: 72, - }, -})); - -const Group = ({theme, users}: Props) => { - const serverUrl = useServerUrl(); - const styles = getStyleSheet(theme); - - let client: Client | undefined; - - try { - client = NetworkManager.getClient(serverUrl); - } catch { - return null; - } - - const rows = chunk(users, 5); - const groups = rows.map((c, k) => { - const group = c.map((u, i) => { - const pictureUrl = client!.getProfilePictureUrl(u.id, u.lastPictureUpdate); - return ( - - ); - }); - - return ( - - {group} - - ); - }); - - return ( - <> - {groups} - - ); -}; - -export default Group; diff --git a/app/screens/channel/intro/direct_channel/group/index.ts b/app/screens/channel/intro/direct_channel/group/index.ts deleted file mode 100644 index dcb4f124a..000000000 --- a/app/screens/channel/intro/direct_channel/group/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; -import withObservables from '@nozbe/with-observables'; - -import {queryUsersById} from '@queries/servers/user'; - -import Group from './group'; - -import type {WithDatabaseArgs} from '@typings/database/database'; - -const enhanced = withObservables([], ({userIds, database}: {userIds: string[]} & WithDatabaseArgs) => ({ - users: queryUsersById(database, userIds).observeWithColumns(['last_picture_update']), -})); - -export default withDatabase(enhanced(Group)); diff --git a/app/screens/channel/intro/direct_channel/index.ts b/app/screens/channel/intro/direct_channel/index.ts deleted file mode 100644 index 6c30d0fe4..000000000 --- a/app/screens/channel/intro/direct_channel/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; -import withObservables from '@nozbe/with-observables'; -import {of as of$} from 'rxjs'; -import {switchMap} from 'rxjs/operators'; - -import {General} from '@constants'; -import {observeCurrentUserId} from '@queries/servers/system'; -import {observeUser} from '@queries/servers/user'; -import {getUserIdFromChannelName} from '@utils/user'; - -import DirectChannel from './direct_channel'; - -import type {WithDatabaseArgs} from '@typings/database/database'; -import type ChannelModel from '@typings/database/models/servers/channel'; -import type UserModel from '@typings/database/models/servers/user'; - -const observeIsBot = (user: UserModel | undefined) => of$(Boolean(user?.isBot)); - -const enhanced = withObservables([], ({channel, database}: {channel: ChannelModel} & WithDatabaseArgs) => { - const currentUserId = observeCurrentUserId(database); - const members = channel.members.observe(); - let isBot = of$(false); - - if (channel.type === General.DM_CHANNEL) { - isBot = currentUserId.pipe( - switchMap((userId) => { - const otherUserId = getUserIdFromChannelName(userId, channel.name); - return observeUser(database, otherUserId).pipe( - switchMap(observeIsBot), - ); - }), - ); - } - - return { - currentUserId, - isBot, - members, - }; -}); - -export default withDatabase(enhanced(DirectChannel)); diff --git a/app/screens/channel/intro/direct_channel/member/index.ts b/app/screens/channel/intro/direct_channel/member/index.ts deleted file mode 100644 index 2e1577dcb..000000000 --- a/app/screens/channel/intro/direct_channel/member/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; -import withObservables from '@nozbe/with-observables'; - -import Member from './member'; - -import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; - -const enhanced = withObservables([], ({member}: {member: ChannelMembershipModel}) => ({ - user: member.memberUser.observe(), -})); - -export default withDatabase(enhanced(Member)); diff --git a/app/screens/channel/intro/direct_channel/member/member.tsx b/app/screens/channel/intro/direct_channel/member/member.tsx deleted file mode 100644 index 24b1d5515..000000000 --- a/app/screens/channel/intro/direct_channel/member/member.tsx +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useCallback} from 'react'; -import {useIntl} from 'react-intl'; -import {StyleProp, StyleSheet, ViewStyle} from 'react-native'; - -import CompassIcon from '@components/compass_icon'; -import ProfilePicture from '@components/profile_picture'; -import TouchableWithFeedback from '@components/touchable_with_feedback'; -import {Screens} from '@constants'; -import {showModal} from '@screens/navigation'; - -import type UserModel from '@typings/database/models/servers/user'; - -type Props = { - containerStyle?: StyleProp; - size?: number; - showStatus?: boolean; - theme: Theme; - user: UserModel; -} - -const styles = StyleSheet.create({ - profile: { - height: 67, - marginBottom: 12, - marginRight: 12, - }, -}); - -const Member = ({containerStyle, size = 72, showStatus = true, theme, user}: Props) => { - const intl = useIntl(); - const onPress = useCallback(() => { - const screen = Screens.USER_PROFILE; - const title = intl.formatMessage({id: 'mobile.routes.user_profile', defaultMessage: 'Profile'}); - const passProps = { - userId: user.id, - }; - - const closeButton = CompassIcon.getImageSourceSync('close', 24, theme.sidebarHeaderTextColor); - - const options = { - topBar: { - leftButtons: [{ - id: 'close-user-profile', - icon: closeButton, - testID: 'close.settings.button', - }], - }, - }; - - showModal(screen, title, passProps, options); - }, [theme]); - - return ( - - - - ); -}; - -export default Member; diff --git a/app/screens/channel/intro/illustration/private.tsx b/app/screens/channel/intro/illustration/private.tsx deleted file mode 100644 index 00b0e6401..000000000 --- a/app/screens/channel/intro/illustration/private.tsx +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import * as React from 'react'; -import Svg, { - G, - Path, - Ellipse, - Mask, - Defs, - Pattern, - Use, - Image, - LinearGradient, - Stop, - ClipPath, -} from 'react-native-svg'; - -type Props = { - theme: Theme; -}; - -const PrivateChannelIllustration = ({theme}: Props) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -); - -export default PrivateChannelIllustration; diff --git a/app/screens/channel/intro/illustration/public.tsx b/app/screens/channel/intro/illustration/public.tsx deleted file mode 100644 index 7d9265e2a..000000000 --- a/app/screens/channel/intro/illustration/public.tsx +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import * as React from 'react'; -import Svg, { - G, - Path, - Mask, - Ellipse, - Defs, - Pattern, - Use, - Image, - LinearGradient, - Stop, - ClipPath, -} from 'react-native-svg'; - -type Props = { - theme: Theme; -}; - -const PublicChannelIllustration = ({theme}: Props) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -); - -export default PublicChannelIllustration; diff --git a/app/screens/channel/intro/index.ts b/app/screens/channel/intro/index.ts deleted file mode 100644 index 1a81754c0..000000000 --- a/app/screens/channel/intro/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; -import withObservables from '@nozbe/with-observables'; -import {combineLatest} from 'rxjs'; -import {switchMap} from 'rxjs/operators'; - -import {observeChannel, observeMyChannel} from '@queries/servers/channel'; -import {queryRolesByNames} from '@queries/servers/role'; -import {observeCurrentUser} from '@queries/servers/user'; - -import Intro from './intro'; - -import type {WithDatabaseArgs} from '@typings/database/database'; - -const enhanced = withObservables(['channelId'], ({channelId, database}: {channelId: string} & WithDatabaseArgs) => { - const channel = observeChannel(database, channelId); - const myChannel = observeMyChannel(database, channelId); - const me = observeCurrentUser(database); - - const roles = combineLatest([me, myChannel]).pipe( - switchMap(([user, member]) => { - const userRoles = user?.roles.split(' '); - const memberRoles = member?.roles.split(' '); - const combinedRoles = []; - if (userRoles) { - combinedRoles.push(...userRoles); - } - if (memberRoles) { - combinedRoles.push(...memberRoles); - } - return queryRolesByNames(database, combinedRoles).observe(); - }), - ); - - return { - channel, - roles, - }; -}); - -export default withDatabase(enhanced(Intro)); diff --git a/app/screens/channel/intro/intro.tsx b/app/screens/channel/intro/intro.tsx deleted file mode 100644 index bb50706a4..000000000 --- a/app/screens/channel/intro/intro.tsx +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useMemo} from 'react'; -import {ActivityIndicator, Platform, StyleSheet, View} from 'react-native'; - -import {General} from '@constants'; -import {useTheme} from '@context/theme'; - -import DirectChannel from './direct_channel'; -import PublicOrPrivateChannel from './public_or_private_channel'; -import TownSquare from './townsquare'; - -import type ChannelModel from '@typings/database/models/servers/channel'; -import type RoleModel from '@typings/database/models/servers/role'; - -type Props = { - channel: ChannelModel; - loading?: boolean; - roles: RoleModel[]; -} - -const styles = StyleSheet.create({ - container: { - marginVertical: 12, - overflow: 'hidden', - ...Platform.select({ - android: { - scaleY: -1, - }, - }), - }, -}); - -const Intro = ({channel, loading = false, roles}: Props) => { - const theme = useTheme(); - const element = useMemo(() => { - if (channel.type === General.OPEN_CHANNEL && channel.name === General.DEFAULT_CHANNEL) { - return ( - - ); - } - - switch (channel.type) { - case General.OPEN_CHANNEL: - case General.PRIVATE_CHANNEL: - return ( - - ); - default: - return ( - - ); - } - }, [channel, roles, theme]); - - if (loading) { - return ( - - ); - } - - return ( - - {element} - - ); -}; - -export default Intro; diff --git a/app/screens/channel/intro/options/favorite/favorite.tsx b/app/screens/channel/intro/options/favorite/favorite.tsx deleted file mode 100644 index 7c6bcdd6d..000000000 --- a/app/screens/channel/intro/options/favorite/favorite.tsx +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useCallback} from 'react'; -import {useIntl} from 'react-intl'; - -import {saveFavoriteChannel} from '@actions/remote/preference'; -import {useServerUrl} from '@context/server'; - -import OptionItem from '../item'; - -type Props = { - channelId: string; - isFavorite: boolean; - theme: Theme; -} - -const IntroFavorite = ({channelId, isFavorite, theme}: Props) => { - const {formatMessage} = useIntl(); - const serverUrl = useServerUrl(); - - const toggleFavorite = useCallback(() => { - saveFavoriteChannel(serverUrl, channelId, !isFavorite); - }, [channelId, isFavorite]); - - return ( - - ); -}; - -export default IntroFavorite; diff --git a/app/screens/channel/intro/options/favorite/index.ts b/app/screens/channel/intro/options/favorite/index.ts deleted file mode 100644 index 6b54aaacb..000000000 --- a/app/screens/channel/intro/options/favorite/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; -import withObservables from '@nozbe/with-observables'; -import {of as of$} from 'rxjs'; -import {switchMap} from 'rxjs/operators'; - -import {Preferences} from '@constants'; -import {queryPreferencesByCategoryAndName} from '@queries/servers/preference'; - -import FavoriteItem from './favorite'; - -import type {WithDatabaseArgs} from '@typings/database/database'; - -const enhanced = withObservables([], ({channelId, database}: {channelId: string} & WithDatabaseArgs) => ({ - isFavorite: queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_FAVORITE_CHANNEL, channelId).observeWithColumns(['value']).pipe( - switchMap((prefs) => { - return prefs.length ? of$(prefs[0].value === 'true') : of$(false); - }), - ), -})); - -export default withDatabase(enhanced(FavoriteItem)); diff --git a/app/screens/channel/intro/options/index.tsx b/app/screens/channel/intro/options/index.tsx deleted file mode 100644 index 774791f61..000000000 --- a/app/screens/channel/intro/options/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useCallback} from 'react'; -import {useIntl} from 'react-intl'; -import {StyleSheet, View} from 'react-native'; - -import {Screens} from '@constants'; -import {showModal} from '@screens/navigation'; - -import IntroFavorite from './favorite'; -import OptionItem from './item'; - -type Props = { - channelId: string; - header?: boolean; - favorite?: boolean; - people?: boolean; - theme: Theme; -} - -const styles = StyleSheet.create({ - container: { - justifyContent: 'center', - flexDirection: 'row', - marginBottom: 8, - marginTop: 28, - width: '100%', - }, -}); - -const IntroOptions = ({channelId, header, favorite, people, theme}: Props) => { - const {formatMessage} = useIntl(); - - const onAddPeople = useCallback(() => { - const title = formatMessage({id: 'intro.add_people', defaultMessage: 'Add People'}); - showModal(Screens.CHANNEL_ADD_PEOPLE, title, {channelId}); - }, []); - - const onSetHeader = useCallback(() => { - const title = formatMessage({id: 'screens.channel_edit', defaultMessage: 'Edit Channel'}); - showModal(Screens.CHANNEL_EDIT, title, {channelId}); - }, []); - - const onDetails = useCallback(() => { - const title = formatMessage({id: 'screens.channel_details', defaultMessage: 'Channel Details'}); - showModal(Screens.CHANNEL_DETAILS, title, {channelId}); - }, []); - - return ( - - {people && - - } - {header && - - } - {favorite && - - } - - - ); -}; - -export default IntroOptions; diff --git a/app/screens/channel/intro/options/item.tsx b/app/screens/channel/intro/options/item.tsx deleted file mode 100644 index 041dc90bc..000000000 --- a/app/screens/channel/intro/options/item.tsx +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useCallback} from 'react'; -import {Pressable, PressableStateCallbackType, Text} from 'react-native'; - -import CompassIcon from '@components/compass_icon'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; - -type Props = { - applyMargin?: boolean; - color?: string; - iconName: string; - label: string; - onPress: () => void; - theme: Theme; -} - -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - container: { - alignItems: 'center', - backgroundColor: changeOpacity(theme.centerChannelColor, 0.04), - borderRadius: 4, - height: 70, - justifyContent: 'center', - paddingHorizontal: 16, - paddingVertical: 12, - width: 112, - }, - containerPressed: { - backgroundColor: changeOpacity(theme.buttonBg, 0.08), - }, - label: { - marginTop: 6, - ...typography('Body', 50, 'SemiBold'), - }, - margin: { - marginRight: 8, - }, -})); - -const IntroItem = ({applyMargin, color, iconName, label, onPress, theme}: Props) => { - const styles = getStyleSheet(theme); - const pressedStyle = useCallback(({pressed}: PressableStateCallbackType) => { - const style = [styles.container]; - if (pressed) { - style.push(styles.containerPressed); - } - - if (applyMargin) { - style.push(styles.margin); - } - - return style; - }, [applyMargin, theme]); - - const renderPressableChildren = ({pressed}: PressableStateCallbackType) => { - let pressedColor = color || changeOpacity(theme.centerChannelColor, 0.56); - if (pressed) { - pressedColor = theme.linkColor; - } - - return ( - <> - - - {label} - - - ); - }; - - return ( - - {renderPressableChildren} - - ); -}; - -export default IntroItem; diff --git a/app/screens/channel/intro/public_or_private_channel/index.ts b/app/screens/channel/intro/public_or_private_channel/index.ts deleted file mode 100644 index afe46e31e..000000000 --- a/app/screens/channel/intro/public_or_private_channel/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; -import withObservables from '@nozbe/with-observables'; -import {combineLatest, of as of$} from 'rxjs'; -import {map} from 'rxjs/operators'; - -import {Preferences} from '@constants'; -import {getTeammateNameDisplaySetting} from '@helpers/api/preference'; -import {queryPreferencesByCategoryAndName} from '@queries/servers/preference'; -import {observeConfig, observeLicense} from '@queries/servers/system'; -import {observeCurrentUser} from '@queries/servers/user'; -import {displayUsername} from '@utils/user'; - -import PublicOrPrivateChannel from './public_or_private_channel'; - -import type {WithDatabaseArgs} from '@typings/database/database'; -import type ChannelModel from '@typings/database/models/servers/channel'; -import type UserModel from '@typings/database/models/servers/user'; - -const enhanced = withObservables([], ({channel, database}: {channel: ChannelModel} & WithDatabaseArgs) => { - let creator; - if (channel.creatorId) { - const config = observeConfig(database); - const license = observeLicense(database); - const preferences = queryPreferencesByCategoryAndName(database, Preferences.CATEGORY_DISPLAY_SETTINGS).observe(); - const me = observeCurrentUser(database); - - const profile = channel.creator.observe(); - const teammateNameDisplay = combineLatest([preferences, config, license]).pipe( - map(([prefs, cfg, lcs]) => getTeammateNameDisplaySetting(prefs, cfg, lcs)), - ); - creator = combineLatest([profile, teammateNameDisplay, me]).pipe( - map(([user, displaySetting, currentUser]) => (user ? displayUsername(user as UserModel, currentUser?.locale, displaySetting, true) : '')), - ); - } else { - creator = of$(undefined); - } - - return { - creator, - }; -}); - -export default withDatabase(enhanced(PublicOrPrivateChannel)); diff --git a/app/screens/channel/intro/public_or_private_channel/public_or_private_channel.tsx b/app/screens/channel/intro/public_or_private_channel/public_or_private_channel.tsx deleted file mode 100644 index e6558fa5c..000000000 --- a/app/screens/channel/intro/public_or_private_channel/public_or_private_channel.tsx +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React, {useEffect, useMemo} from 'react'; -import {useIntl} from 'react-intl'; -import {Text, View} from 'react-native'; - -import {fetchChannelCreator} from '@actions/remote/channel'; -import CompassIcon from '@components/compass_icon'; -import {General, Permissions} from '@constants'; -import {useServerUrl} from '@context/server'; -import {t} from '@i18n'; -import {hasPermission} from '@utils/role'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; - -import PrivateChannel from '../illustration/private'; -import PublicChannel from '../illustration/public'; -import IntroOptions from '../options'; - -import type ChannelModel from '@typings/database/models/servers/channel'; -import type RoleModel from '@typings/database/models/servers/role'; - -type Props = { - channel: ChannelModel; - creator?: string; - roles: RoleModel[]; - theme: Theme; -} - -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - container: { - alignItems: 'center', - }, - created: { - color: changeOpacity(theme.centerChannelColor, 0.64), - ...typography('Body', 50, 'Regular'), - }, - icon: { - marginRight: 5, - }, - message: { - color: theme.centerChannelColor, - marginTop: 16, - textAlign: 'center', - ...typography('Body', 200, 'Regular'), - }, - title: { - color: theme.centerChannelColor, - marginTop: 16, - marginBottom: 8, - ...typography('Heading', 700, 'SemiBold'), - }, -})); - -const PublicOrPrivateChannel = ({channel, creator, roles, theme}: Props) => { - const intl = useIntl(); - const serverUrl = useServerUrl(); - const styles = getStyleSheet(theme); - const illustration = useMemo(() => { - if (channel.type === General.OPEN_CHANNEL) { - return ; - } - - return ; - }, [channel.type, theme]); - - useEffect(() => { - if (!creator && channel.creatorId) { - fetchChannelCreator(serverUrl, channel.id); - } - }, []); - - const canManagePeople = useMemo(() => { - const permission = channel.type === General.OPEN_CHANNEL ? Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS : Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS; - return hasPermission(roles, permission, false); - }, [channel.type, roles]); - - const canSetHeader = useMemo(() => { - const permission = channel.type === General.OPEN_CHANNEL ? Permissions.MANAGE_PUBLIC_CHANNEL_PROPERTIES : Permissions.MANAGE_PRIVATE_CHANNEL_PROPERTIES; - return hasPermission(roles, permission, false); - }, [channel.type, roles]); - - const createdBy = useMemo(() => { - const id = channel.type === General.OPEN_CHANNEL ? t('intro.public_channel') : t('intro.private_channel'); - const defaultMessage = channel.type === General.OPEN_CHANNEL ? 'Public Channel' : 'Private Channel'; - const channelType = `${intl.formatMessage({id, defaultMessage})} `; - - const date = intl.formatDate(channel.createAt, { - year: 'numeric', - month: 'long', - day: 'numeric', - }); - const by = intl.formatMessage({id: 'intro.created_by', defaultMessage: 'created by {creator} on {date}.'}, { - creator, - date, - }); - - return `${channelType} ${by}`; - }, [channel.type, creator, theme]); - - const message = useMemo(() => { - const id = channel.type === General.OPEN_CHANNEL ? t('intro.welcome.public') : t('intro.welcome.private'); - const msg = channel.type === General.OPEN_CHANNEL ? 'Add some more team members to the channel or start a conversation below.' : 'Only invited members can see messages posted in this private channel.'; - const mainMessage = intl.formatMessage({ - id: 'intro.welcome', - defaultMessage: 'Welcome to {displayName} channel.', - }, {displayName: channel.displayName}); - - const suffix = intl.formatMessage({id, defaultMessage: msg}); - - return `${mainMessage} ${suffix}`; - }, [channel.displayName, channel.type, theme]); - - return ( - - {illustration} - - {channel.displayName} - - - - - {createdBy} - - - - {message} - - - - ); -}; - -export default PublicOrPrivateChannel; diff --git a/app/screens/channel/intro/townsquare/index.tsx b/app/screens/channel/intro/townsquare/index.tsx deleted file mode 100644 index 04fb5ab04..000000000 --- a/app/screens/channel/intro/townsquare/index.tsx +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import React from 'react'; -import {Text, View} from 'react-native'; - -import FormattedText from '@components/formatted_text'; -import {Permissions} from '@constants'; -import {hasPermission} from '@utils/role'; -import {makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; - -import PublicChannel from '../illustration/public'; -import IntroOptions from '../options'; - -import type RoleModel from '@typings/database/models/servers/role'; - -type Props = { - channelId: string; - displayName: string; - roles: RoleModel[]; - theme: Theme; -} - -const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ - container: { - alignItems: 'center', - }, - message: { - color: theme.centerChannelColor, - marginTop: 16, - textAlign: 'center', - ...typography('Body', 200, 'Regular'), - width: '100%', - }, - title: { - color: theme.centerChannelColor, - marginTop: 16, - ...typography('Heading', 700, 'SemiBold'), - }, -})); - -const TownSquare = ({channelId, displayName, roles, theme}: Props) => { - const styles = getStyleSheet(theme); - return ( - - - - {displayName} - - - - - ); -}; - -export default TownSquare; diff --git a/app/screens/thread/thread_post_list/thread_post_list.tsx b/app/screens/thread/thread_post_list/thread_post_list.tsx index 183203fe3..0d2a6ca4f 100644 --- a/app/screens/thread/thread_post_list/thread_post_list.tsx +++ b/app/screens/thread/thread_post_list/thread_post_list.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {useMemo} from 'react'; -import {StyleSheet} from 'react-native'; +import {StyleSheet, View} from 'react-native'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import PostList from '@components/post_list'; @@ -25,8 +25,9 @@ type Props = { const edges: Edge[] = ['bottom']; const styles = StyleSheet.create({ - container: {marginTop: 20}, + container: {marginTop: 10}, flex: {flex: 1}, + footer: {height: 20}, }); const ThreadPostList = ({ @@ -54,6 +55,7 @@ const ThreadPostList = ({ shouldShowJoinLeaveMessages={false} showMoreMessages={false} showNewMessageLine={false} + footer={} testID='thread.post_list' /> ); diff --git a/package-lock.json b/package-lock.json index 6a0df0afc..22456fc9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "requires": true, "packages": { "": { - "name": "mattermost-mobile", "version": "2.0.0", "hasInstallScript": true, "license": "Apache 2.0", @@ -4262,7 +4261,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, @@ -4304,7 +4303,7 @@ "chalk": "^4.1.2", "lodash": "^4.17.15", "mime": "^2.4.1", - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.0", "open": "^6.2.0", "semver": "^6.3.0", "shell-quote": "1.6.1" @@ -4606,7 +4605,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, @@ -4883,6 +4882,7 @@ "version": "0.1.11", "resolved": "https://registry.npmjs.org/@react-native-community/masked-view/-/masked-view-0.1.11.tgz", "integrity": "sha512-rQfMIGSR/1r/SyN87+VD8xHHzDYeHaJq6elOSCAD+0iLagXkSI2pfA0LmSXP21uw5i3em7GkkRjfJ8wpqWXZNw==", + "deprecated": "Repository was moved to @react-native-masked-view/masked-view", "peerDependencies": { "react": ">=16.0", "react-native": ">=0.57" @@ -5037,7 +5037,7 @@ "dependencies": { "https-proxy-agent": "^5.0.0", "mkdirp": "^0.5.5", - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.0", "npmlog": "^4.1.2", "progress": "^2.0.3", "proxy-from-env": "^1.1.0" @@ -8644,7 +8644,6 @@ "node_modules/commonmark-react-renderer": { "version": "4.3.5", "resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#4e52e1725c0ef5b1e2ecfe9883220ec36c2eb67d", - "license": "MIT", "dependencies": { "lodash.assign": "^4.2.0", "lodash.isplainobject": "^4.0.6", @@ -8833,7 +8832,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", - "deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js." + "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js." }, "node_modules/core-js-compat": { "version": "3.20.3", @@ -13444,7 +13443,7 @@ "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", "dev": true, "dependencies": { - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.1", "whatwg-fetch": "^3.4.1" } }, @@ -16560,7 +16559,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, @@ -17599,9 +17598,8 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" }, "node_modules/mississippi": { "version": "3.0.0", @@ -17667,11 +17665,13 @@ "node_modules/mmjstool/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/mmjstool/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { "node": ">=8" @@ -17680,6 +17680,7 @@ "node_modules/mmjstool/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", @@ -17693,6 +17694,7 @@ "node_modules/mmjstool/node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "engines": { "node": ">=10" @@ -17701,6 +17703,7 @@ "node_modules/mmjstool/node_modules/yargs": { "version": "17.3.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "dev": true, "dependencies": { "cliui": "^7.0.2", @@ -17718,6 +17721,7 @@ "node_modules/mmjstool/node_modules/yargs-parser": { "version": "21.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", "dev": true, "engines": { "node": ">=12" @@ -18204,11 +18208,20 @@ "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dependencies": { "whatwg-url": "^5.0.0" }, "engines": { "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/node-fetch/node_modules/tr46": { @@ -19129,9 +19142,9 @@ } }, "node_modules/plist": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", - "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", "dependencies": { "base64-js": "^1.5.1", "xmlbuilder": "^9.0.7" @@ -20233,7 +20246,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "dependencies": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }, @@ -21666,6 +21679,7 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", "dependencies": { "atob": "^2.1.2", "decode-uri-component": "^0.2.0", @@ -21694,7 +21708,8 @@ "node_modules/source-map-url": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated" }, "node_modules/split-on-first": { "version": "1.1.0", @@ -23503,7 +23518,7 @@ "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", "dev": true, "optional": true, "peer": true, @@ -27223,7 +27238,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "requires": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" } @@ -27658,7 +27673,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "requires": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" } @@ -27696,7 +27711,7 @@ "chalk": "^4.1.2", "lodash": "^4.17.15", "mime": "^2.4.1", - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.0", "open": "^6.2.0", "semver": "^6.3.0", "shell-quote": "1.6.1" @@ -28055,7 +28070,7 @@ "requires": { "https-proxy-agent": "^5.0.0", "mkdirp": "^0.5.5", - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.0", "npmlog": "^4.1.2", "progress": "^2.0.3", "proxy-from-env": "^1.1.0" @@ -34584,7 +34599,7 @@ "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", "dev": true, "requires": { - "node-fetch": "^2.6.7", + "node-fetch": "^2.6.1", "whatwg-fetch": "^3.4.1" } }, @@ -37326,7 +37341,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "requires": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" } @@ -37887,9 +37902,8 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" }, "mississippi": { "version": "3.0.0", @@ -37943,16 +37957,19 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", @@ -37963,11 +37980,13 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yargs": { "version": "17.3.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", + "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -37982,6 +38001,7 @@ "yargs-parser": { "version": "21.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", "dev": true } } @@ -38361,6 +38381,7 @@ "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" }, @@ -39076,9 +39097,9 @@ } }, "plist": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", - "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA==", "requires": { "base64-js": "^1.5.1", "xmlbuilder": "^9.0.7" @@ -39551,7 +39572,7 @@ "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", "requires": { "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.1", + "ansi-regex": "^5.0.0", "ansi-styles": "^4.0.0", "react-is": "^17.0.1" }