diff --git a/Jenkinsfile b/Jenkinsfile
deleted file mode 100644
index 457f39a49..000000000
--- a/Jenkinsfile
+++ /dev/null
@@ -1,14 +0,0 @@
-pipeline {
- agent any
-
- stages {
- stage('Test') {
- steps {
- echo 'assets/base/config.json'
- sh 'cat assets/base/config.json'
- sh 'touch .podinstall'
- sh 'make test || exit 1'
- }
- }
- }
-}
\ No newline at end of file
diff --git a/NOTICE.txt b/NOTICE.txt
index 71e2f1ff3..7137b79f1 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -183,38 +183,218 @@ SOFTWARE.
---
-## analytics-react-native
+## rudder-sdk-react-native
-This product contains 'analytics-react-native' by Javier Alvarez.
+This product contains 'rudder-sdk-react-native' by Rudder Labs
-A React Native client for [Segment](https://segment.com) — The hassle-free way to integrate analytics into any application.
+Rudder is an open-source Segment alternative written in Go, built for the enterprise.
* HOMEPAGE:
- * https://github.com/neiker/analytics-react-native
+ * https://github.com/rudderlabs/rudder-sdk-react-native
-* LICENSE: MIT
+* LICENSE: Apache-2.0
-MIT License
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
-Copyright (c) 2016 Javier Alvarez
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+ 1. Definitions.
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright 2019 Rudderlabs
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
---
diff --git a/android/build.gradle b/android/build.gradle
index 9b1f3ad02..2076b9e7f 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -63,5 +63,8 @@ allprojects {
maven {
url "https://www.jitpack.io"
}
+ maven {
+ url ("https://dl.bintray.com/rudderstack/rudderstack")
+ }
}
}
diff --git a/app/actions/views/root.js b/app/actions/views/root.js
index 8825fdb33..d63d72f91 100644
--- a/app/actions/views/root.js
+++ b/app/actions/views/root.js
@@ -3,6 +3,8 @@
import {batchActions} from 'redux-batched-actions';
+import {NavigationTypes, ViewTypes} from '@constants';
+import {recordTime} from '@init/analytics.ts';
import {ChannelTypes, GeneralTypes, TeamTypes} from '@mm-redux/action_types';
import {fetchMyChannelsAndMembers} from '@mm-redux/actions/channels';
import {getDataRetentionPolicy} from '@mm-redux/actions/general';
@@ -11,12 +13,9 @@ import {getMyTeams, getMyTeamMembers} from '@mm-redux/actions/teams';
import {Client4} from '@mm-redux/client';
import {General} from '@mm-redux/constants';
import EventEmitter from '@mm-redux/utils/event_emitter';
-
-import {NavigationTypes, ViewTypes} from '@constants';
import EphemeralStore from '@store/ephemeral_store';
import initialState from '@store/initial_state';
import {getStateForReset} from '@store/utils';
-import {recordTime} from '@utils/segment';
import {markChannelViewedAndRead} from './channel';
diff --git a/app/components/error_list/error_list.js b/app/components/error_list/error_list.js
index ec3edc524..4e1377d1b 100644
--- a/app/components/error_list/error_list.js
+++ b/app/components/error_list/error_list.js
@@ -10,9 +10,11 @@ import {
TouchableOpacity,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
-import FormattedText from 'app/components/formatted_text';
+
+import Config from '@assets/config.json';
+import FormattedText from '@components/formatted_text';
+
import GeneralError from './general_error';
-import Config from 'assets/config.json';
const {width: deviceWidth} = Dimensions.get('window');
diff --git a/app/components/file_attachment_list/file_attachment_icon.js b/app/components/file_attachment_list/file_attachment_icon.js
index 8b9c2db4d..e54d393e7 100644
--- a/app/components/file_attachment_list/file_attachment_icon.js
+++ b/app/components/file_attachment_list/file_attachment_icon.js
@@ -9,22 +9,20 @@ import {
StyleSheet,
} from 'react-native';
+import audioIcon from '@assets/images/icons/audio.png';
+import codeIcon from '@assets/images/icons/code.png';
+import excelIcon from '@assets/images/icons/excel.png';
+import genericIcon from '@assets/images/icons/generic.png';
+import imageIcon from '@assets/images/icons/image.png';
+import patchIcon from '@assets/images/icons/patch.png';
+import pdfIcon from '@assets/images/icons/pdf.png';
+import pptIcon from '@assets/images/icons/ppt.png';
+import textIcon from '@assets/images/icons/text.png';
+import videoIcon from '@assets/images/icons/video.png';
+import wordIcon from '@assets/images/icons/word.png';
+import {ATTACHMENT_ICON_HEIGHT, ATTACHMENT_ICON_WIDTH} from '@constants/attachment';
import * as Utils from '@mm-redux/utils/file_utils';
-
-import audioIcon from 'assets/images/icons/audio.png';
-import codeIcon from 'assets/images/icons/code.png';
-import excelIcon from 'assets/images/icons/excel.png';
-import genericIcon from 'assets/images/icons/generic.png';
-import imageIcon from 'assets/images/icons/image.png';
-import patchIcon from 'assets/images/icons/patch.png';
-import pdfIcon from 'assets/images/icons/pdf.png';
-import pptIcon from 'assets/images/icons/ppt.png';
-import textIcon from 'assets/images/icons/text.png';
-import videoIcon from 'assets/images/icons/video.png';
-import wordIcon from 'assets/images/icons/word.png';
-
-import {ATTACHMENT_ICON_HEIGHT, ATTACHMENT_ICON_WIDTH} from 'app/constants/attachment';
-import {changeOpacity} from 'app/utils/theme';
+import {changeOpacity} from '@utils/theme';
const ICON_PATH_FROM_FILE_TYPE = {
audio: audioIcon,
diff --git a/app/components/file_attachment_list/file_attachment_image.js b/app/components/file_attachment_list/file_attachment_image.js
index 9deccbbed..511a6588e 100644
--- a/app/components/file_attachment_list/file_attachment_image.js
+++ b/app/components/file_attachment_list/file_attachment_image.js
@@ -9,14 +9,12 @@ import {
} from 'react-native';
import FastImage from 'react-native-fast-image';
-import {Client4} from '@mm-redux/client';
-
+import brokenImageIcon from '@assets/images/icons/brokenimage.png';
import ProgressiveImage from '@components/progressive_image';
+import {Client4} from '@mm-redux/client';
import {isGif} from '@utils/file';
import {changeOpacity} from '@utils/theme';
-import brokenImageIcon from 'assets/images/icons/brokenimage.png';
-
const SMALL_IMAGE_MAX_HEIGHT = 48;
const SMALL_IMAGE_MAX_WIDTH = 48;
diff --git a/app/components/markdown/markdown_image/markdown_image.js b/app/components/markdown/markdown_image/markdown_image.js
index 71859a21f..d646a30c0 100644
--- a/app/components/markdown/markdown_image/markdown_image.js
+++ b/app/components/markdown/markdown_image/markdown_image.js
@@ -15,6 +15,7 @@ import {
} from 'react-native';
import FastImage from 'react-native-fast-image';
+import brokenImageIcon from '@assets/images/icons/brokenimage.png';
import ImageViewPort from '@components/image_viewport';
import ProgressiveImage from '@components/progressive_image';
import FormattedText from '@components/formatted_text';
@@ -26,7 +27,6 @@ import {calculateDimensions, getViewPortWidth, isGifTooLarge, previewImageAtInde
import {normalizeProtocol} from '@utils/url';
import mattermostManaged from 'app/mattermost_managed';
-import brokenImageIcon from 'assets/images/icons/brokenimage.png';
const ANDROID_MAX_HEIGHT = 4096;
const ANDROID_MAX_WIDTH = 4096;
diff --git a/app/components/markdown/markdown_link/markdown_link.js b/app/components/markdown/markdown_link/markdown_link.js
index 122c18e3f..6e1640d4b 100644
--- a/app/components/markdown/markdown_link/markdown_link.js
+++ b/app/components/markdown/markdown_link/markdown_link.js
@@ -7,17 +7,17 @@ import {Alert, Clipboard, Linking, Text} from 'react-native';
import urlParse from 'url-parse';
import {intlShape} from 'react-intl';
-import CustomPropTypes from 'app/constants/custom_prop_types';
-import {DeepLinkTypes} from 'app/constants';
-import {getCurrentServerUrl} from 'app/init/credentials';
-import mattermostManaged from 'app/mattermost_managed';
-import BottomSheet from 'app/utils/bottom_sheet';
-import {preventDoubleTap} from 'app/utils/tap';
-import {matchDeepLink, normalizeProtocol} from 'app/utils/url';
-import {alertErrorWithFallback} from 'app/utils/general';
-import {t} from 'app/utils/i18n';
+import Config from '@assets/config';
+import {DeepLinkTypes} from '@constants';
+import CustomPropTypes from '@constants/custom_prop_types';
+import {getCurrentServerUrl} from '@init/credentials';
+import BottomSheet from '@utils/bottom_sheet';
+import {alertErrorWithFallback} from '@utils/general';
+import {t} from '@utils/i18n';
+import {preventDoubleTap} from '@utils/tap';
+import {matchDeepLink, normalizeProtocol} from '@utils/url';
-import Config from 'assets/config';
+import mattermostManaged from 'app/mattermost_managed';
export default class MarkdownLink extends PureComponent {
static propTypes = {
diff --git a/app/components/post_body_additional_content/post_body_additional_content.js b/app/components/post_body_additional_content/post_body_additional_content.js
index fd25bc920..699aa9c09 100644
--- a/app/components/post_body_additional_content/post_body_additional_content.js
+++ b/app/components/post_body_additional_content/post_body_additional_content.js
@@ -411,7 +411,7 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
type={'opacity'}
>
diff --git a/app/components/post_draft/quick_actions/input_quick_action/index.js b/app/components/post_draft/quick_actions/input_quick_action/index.js
index d75a48bcc..184d0170a 100644
--- a/app/components/post_draft/quick_actions/input_quick_action/index.js
+++ b/app/components/post_draft/quick_actions/input_quick_action/index.js
@@ -59,7 +59,7 @@ export default class InputQuickAction extends PureComponent {
return (
);
diff --git a/app/components/post_header/post_pre_header.js b/app/components/post_header/post_pre_header.js
index 1b9edcf5a..cde747105 100644
--- a/app/components/post_header/post_pre_header.js
+++ b/app/components/post_header/post_pre_header.js
@@ -5,12 +5,11 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Image, View} from 'react-native';
-import FormattedText from 'app/components/formatted_text';
-import {t} from 'app/utils/i18n';
-import {makeStyleSheetFromTheme} from 'app/utils/theme';
-
-import flagIcon from 'assets/images/post_header/flag.png';
-import pinIcon from 'assets/images/post_header/pin.png';
+import flagIcon from '@assets/images/post_header/flag.png';
+import pinIcon from '@assets/images/post_header/pin.png';
+import FormattedText from '@components/formatted_text';
+import {t} from '@utils/i18n';
+import {makeStyleSheetFromTheme} from '@utils/theme';
export default class PostPreHeader extends PureComponent {
static propTypes = {
diff --git a/app/components/post_profile_picture/post_profile_picture.js b/app/components/post_profile_picture/post_profile_picture.js
index 7f7e95b08..6745cbcf1 100644
--- a/app/components/post_profile_picture/post_profile_picture.js
+++ b/app/components/post_profile_picture/post_profile_picture.js
@@ -6,12 +6,12 @@ import PropTypes from 'prop-types';
import {Platform, StyleSheet, View} from 'react-native';
import FastImage from 'react-native-fast-image';
-import AppIcon from 'app/components/app_icon';
-import ProfilePicture from 'app/components/profile_picture';
-import TouchableWithFeedback from 'app/components/touchable_with_feedback';
-import {emptyFunction} from 'app/utils/general';
-import webhookIcon from 'assets/images/icons/webhook.jpg';
-import {ViewTypes} from 'app/constants';
+import webhookIcon from '@assets/images/icons/webhook.jpg';
+import AppIcon from '@components/app_icon';
+import ProfilePicture from '@components/profile_picture';
+import TouchableWithFeedback from '@components/touchable_with_feedback';
+import {ViewTypes} from '@constants';
+import {emptyFunction} from '@utils/general';
export default class PostProfilePicture extends PureComponent {
static propTypes = {
diff --git a/app/components/profile_picture/profile_picture.js b/app/components/profile_picture/profile_picture.js
index 883e6ef01..7399e725f 100644
--- a/app/components/profile_picture/profile_picture.js
+++ b/app/components/profile_picture/profile_picture.js
@@ -7,12 +7,10 @@ import {Platform, View} from 'react-native';
import FastImage from 'react-native-fast-image';
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
+import placeholder from '@assets/images/profile.jpg';
+import UserStatus from '@components/user_status';
import {Client4} from '@mm-redux/client';
-
-import UserStatus from 'app/components/user_status';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-
-import placeholder from 'assets/images/profile.jpg';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
const STATUS_BUFFER = Platform.select({
ios: 3,
diff --git a/app/components/progressive_image/progressive_image.js b/app/components/progressive_image/progressive_image.js
index d74385c05..c4a05dc02 100644
--- a/app/components/progressive_image/progressive_image.js
+++ b/app/components/progressive_image/progressive_image.js
@@ -6,10 +6,9 @@ import PropTypes from 'prop-types';
import {Animated, ImageBackground, View, StyleSheet} from 'react-native';
import FastImage from 'react-native-fast-image';
-import CustomPropTypes from 'app/constants/custom_prop_types';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-
-import thumb from 'assets/images/thumb.png';
+import thumb from '@assets/images/thumb.png';
+import CustomPropTypes from '@constants/custom_prop_types';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
const AnimatedImageBackground = Animated.createAnimatedComponent(ImageBackground);
const AnimatedFastImage = Animated.createAnimatedComponent(FastImage);
diff --git a/app/components/reaction_picker/reaction_picker.js b/app/components/reaction_picker/reaction_picker.js
index e61003f66..56319a4c4 100644
--- a/app/components/reaction_picker/reaction_picker.js
+++ b/app/components/reaction_picker/reaction_picker.js
@@ -9,9 +9,7 @@ import {
TouchableWithoutFeedback,
} from 'react-native';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import addReactionIcon from 'assets/images/icons/reaction.png';
-import ReactionButton from './reaction_button';
+import addReactionIcon from '@assets/images/icons/reaction.png';
import {
REACTION_PICKER_HEIGHT,
DEFAULT_EMOJIS,
@@ -20,7 +18,10 @@ import {
LARGE_CONTAINER_SIZE,
SMALL_ICON_SIZE,
LARGE_ICON_SIZE,
-} from 'app/constants/reaction_picker';
+} from '@constants/reaction_picker';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
+
+import ReactionButton from './reaction_button';
export default class ReactionPicker extends PureComponent {
static propTypes = {
diff --git a/app/components/reactions/reactions.js b/app/components/reactions/reactions.js
index 5406cac1a..99aad4a6f 100644
--- a/app/components/reactions/reactions.js
+++ b/app/components/reactions/reactions.js
@@ -10,12 +10,11 @@ import {
import {intlShape} from 'react-intl';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
-import TouchableWithFeedback from 'app/components/touchable_with_feedback';
-import {preventDoubleTap} from 'app/utils/tap';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {showModal, showModalOverCurrentContext} from 'app/actions/navigation';
-
-import addReactionIcon from 'assets/images/icons/reaction.png';
+import {showModal, showModalOverCurrentContext} from '@actions/navigation';
+import addReactionIcon from '@assets/images/icons/reaction.png';
+import TouchableWithFeedback from '@components/touchable_with_feedback';
+import {preventDoubleTap} from '@utils/tap';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import Reaction from './reaction';
diff --git a/app/components/sidebars/main/channels_list/filtered_list/index.js b/app/components/sidebars/main/channels_list/filtered_list/index.js
index 938ec8f0e..02a6811dd 100644
--- a/app/components/sidebars/main/channels_list/filtered_list/index.js
+++ b/app/components/sidebars/main/channels_list/filtered_list/index.js
@@ -5,6 +5,7 @@ import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {createSelector} from 'reselect';
+import Config from '@assets/config';
import {searchChannels} from '@mm-redux/actions/channels';
import {getProfilesInTeam, searchProfiles} from '@mm-redux/actions/users';
import {makeGroupMessageVisibleIfNecessary} from '@mm-redux/actions/preferences';
@@ -20,8 +21,7 @@ import {getConfig} from '@mm-redux/selectors/entities/general';
import {getCurrentTeam} from '@mm-redux/selectors/entities/teams';
import {getCurrentUserId, getProfilesInCurrentTeam, getUsers, getUserIdsInChannels, getUserStatuses} from '@mm-redux/selectors/entities/users';
import {getDirectShowPreferences, getTeammateNameDisplaySetting, getTheme} from '@mm-redux/selectors/entities/preferences';
-import {isLandscape} from 'app/selectors/device';
-import Config from 'assets/config';
+import {isLandscape} from '@selectors/device';
import FilteredList from './filtered_list';
diff --git a/app/components/vector_icon.js b/app/components/vector_icon.js
index 935820b55..23d57414c 100644
--- a/app/components/vector_icon.js
+++ b/app/components/vector_icon.js
@@ -11,7 +11,7 @@ import FoundationIcon from 'react-native-vector-icons/Foundation';
import IonIcon from 'react-native-vector-icons/Ionicons';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
-import icoMoonConfig from 'assets/mattermost-fonts.json';
+import icoMoonConfig from '@assets/mattermost-fonts.json';
const Mattermost = createIconSetFromIcoMoon(
icoMoonConfig,
diff --git a/app/components/video_controls.js b/app/components/video_controls.js
index 61ed42017..5474d560e 100644
--- a/app/components/video_controls.js
+++ b/app/components/video_controls.js
@@ -18,10 +18,10 @@ import {
import FastImage from 'react-native-fast-image';
import Slider from 'react-native-slider';
-import fullscreenImage from 'assets/images/video_player/fullscreen.png';
-import pauseImage from 'assets/images/video_player/pause.png';
-import playImage from 'assets/images/video_player/play.png';
-import replayImage from 'assets/images/video_player/replay.png';
+import fullscreenImage from '@assets/images/video_player/fullscreen.png';
+import pauseImage from '@assets/images/video_player/pause.png';
+import playImage from '@assets/images/video_player/play.png';
+import replayImage from '@assets/images/video_player/replay.png';
export const PLAYER_STATE = {
PLAYING: 0,
diff --git a/app/i18n/index.js b/app/i18n/index.js
index 2dadac003..2de7582b0 100644
--- a/app/i18n/index.js
+++ b/app/i18n/index.js
@@ -6,7 +6,7 @@ import {addLocaleData} from 'react-intl';
import enLocaleData from 'react-intl/locale-data/en';
import moment from 'moment';
-import en from 'assets/i18n/en.json';
+import en from '@assets/i18n/en.json';
export const DEFAULT_LOCALE = 'en';
@@ -19,77 +19,77 @@ function loadTranslation(locale) {
let momentData;
switch (locale) {
case 'de':
- translations = require('assets/i18n/de.json');
+ translations = require('@assets/i18n/de.json');
localeData = require('react-intl/locale-data/de');
momentData = require('moment/locale/de');
break;
case 'es':
- translations = require('assets/i18n/es.json');
+ translations = require('@assets/i18n/es.json');
localeData = require('react-intl/locale-data/es');
momentData = require('moment/locale/es');
break;
case 'fr':
- translations = require('assets/i18n/fr.json');
+ translations = require('@assets/i18n/fr.json');
localeData = require('react-intl/locale-data/fr');
momentData = require('moment/locale/fr');
break;
case 'it':
- translations = require('assets/i18n/it.json');
+ translations = require('@assets/i18n/it.json');
localeData = require('react-intl/locale-data/it');
momentData = require('moment/locale/it');
break;
case 'ja':
- translations = require('assets/i18n/ja.json');
+ translations = require('@assets/i18n/ja.json');
localeData = require('react-intl/locale-data/ja');
momentData = require('moment/locale/ja');
break;
case 'ko':
- translations = require('assets/i18n/ko.json');
+ translations = require('@assets/i18n/ko.json');
localeData = require('react-intl/locale-data/ko');
momentData = require('moment/locale/ko');
break;
case 'nl':
- translations = require('assets/i18n/nl.json');
+ translations = require('@assets/i18n/nl.json');
localeData = require('react-intl/locale-data/nl');
momentData = require('moment/locale/nl');
break;
case 'pl':
- translations = require('assets/i18n/pl.json');
+ translations = require('@assets/i18n/pl.json');
localeData = require('react-intl/locale-data/pl');
momentData = require('moment/locale/pl');
break;
case 'pt-BR':
- translations = require('assets/i18n/pt-BR.json');
+ translations = require('@assets/i18n/pt-BR.json');
localeData = require('react-intl/locale-data/pt');
momentData = require('moment/locale/pt-br');
break;
case 'ro':
- translations = require('assets/i18n/ro.json');
+ translations = require('@assets/i18n/ro.json');
localeData = require('react-intl/locale-data/ro');
momentData = require('moment/locale/ro');
break;
case 'ru':
- translations = require('assets/i18n/ru.json');
+ translations = require('@assets/i18n/ru.json');
localeData = require('react-intl/locale-data/ru');
momentData = require('moment/locale/ru');
break;
case 'tr':
- translations = require('assets/i18n/tr.json');
+ translations = require('@assets/i18n/tr.json');
localeData = require('react-intl/locale-data/tr');
momentData = require('moment/locale/tr');
break;
case 'uk':
- translations = require('assets/i18n/uk.json');
+ translations = require('@assets/i18n/uk.json');
localeData = require('react-intl/locale-data/uk');
momentData = require('moment/locale/uk');
break;
case 'zh-CN':
- translations = require('assets/i18n/zh-CN.json');
+ translations = require('@assets/i18n/zh-CN.json');
localeData = require('react-intl/locale-data/zh');
momentData = require('moment/locale/zh-cn');
break;
case 'zh-TW':
- translations = require('assets/i18n/zh-TW.json');
+ translations = require('@assets/i18n/zh-TW.json');
localeData = require('react-intl/locale-data/zh');
momentData = require('moment/locale/zh-tw');
break;
diff --git a/app/init/analytics.ts b/app/init/analytics.ts
new file mode 100644
index 000000000..666d21a80
--- /dev/null
+++ b/app/init/analytics.ts
@@ -0,0 +1,84 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import DeviceInfo from 'react-native-device-info';
+import {Dimensions} from 'react-native';
+
+import LocalConfig from '@assets/config.json';
+import {Config} from '@mm-redux/types/config';
+import tracker from '@utils/time_tracker';
+
+type RudderClient = {
+ setup(key: string, options: any): Promise;
+ track(event: string, properties: Record | undefined, options?: Record): void;
+ identify(userId: string, traits: Record, options?: Record): Promise;
+ screen(name: string, properties: Record | undefined, options?: Record): void;
+ reset(): Promise;
+}
+
+let diagnosticId: string | undefined;
+export let analytics: RudderClient | null = null;
+export let context: any;
+
+export async function init(config: Config) {
+ if (!analytics) {
+ analytics = require('@rudderstack/rudder-sdk-react-native').default;
+ }
+
+ if (analytics) {
+ const {height, width} = Dimensions.get('window');
+ diagnosticId = config.DiagnosticId;
+
+ if (diagnosticId) {
+ await analytics.setup(LocalConfig.RudderApiKey, {
+ dataPlaneUrl: 'https://pdat.matterlytics.com',
+ recordScreenViews: true,
+ flushQueueSize: 20,
+ });
+
+ context = {
+ app: {
+ version: DeviceInfo.getVersion(),
+ build: DeviceInfo.getBuildNumber(),
+ },
+ device: {
+ dimensions: {
+ height,
+ width,
+ },
+ isTablet: DeviceInfo.isTablet(),
+ os: DeviceInfo.getSystemVersion(),
+ },
+ ip: '0.0.0.0',
+ server: config.Version,
+ };
+
+ analytics.identify(
+ diagnosticId,
+ context,
+ );
+ } else {
+ analytics.reset();
+ }
+ }
+
+ return analytics;
+}
+
+export function recordTime(screenName: string, category: string, userId: string) {
+ if (analytics) {
+ const track: Record = tracker;
+ const startTime: number = track[category];
+ track[category] = 0;
+ analytics.screen(
+ screenName, {
+ userId: diagnosticId,
+ context,
+ properties: {
+ actual_user_id: userId,
+ time: Date.now() - startTime,
+ },
+ },
+ );
+ }
+}
diff --git a/app/init/emm_provider.js b/app/init/emm_provider.js
index 89df193bc..e6f1bad5c 100644
--- a/app/init/emm_provider.js
+++ b/app/init/emm_provider.js
@@ -4,6 +4,7 @@
import {Alert, Platform} from 'react-native';
import {setServerUrl} from '@actions/views/select_server';
+import LocalConfig from '@assets/config';
import {getTranslations} from '@i18n';
import {getCurrentLocale} from '@selectors/i18n';
import Store from '@store/store';
@@ -14,8 +15,6 @@ import mattermostManaged from 'app/mattermost_managed';
import {getAppCredentials} from './credentials';
-import LocalConfig from 'assets/config';
-
class EMMProvider {
constructor() {
this.enabled = false;
diff --git a/app/init/fetch.js b/app/init/fetch.js
index 0ea1180e5..cf7b53633 100644
--- a/app/init/fetch.js
+++ b/app/init/fetch.js
@@ -6,16 +6,15 @@ import DeviceInfo from 'react-native-device-info';
import RNFetchBlob from 'rn-fetch-blob';
import urlParse from 'url-parse';
+import LocalConfig from '@assets/config';
import {Client4} from '@mm-redux/client';
import {ClientError, HEADER_X_VERSION_ID} from '@mm-redux/client/client4';
import EventEmitter from '@mm-redux/utils/event_emitter';
import {General} from '@mm-redux/constants';
+import {t} from '@utils/i18n';
import mattermostBucket from 'app/mattermost_bucket';
import mattermostManaged from 'app/mattermost_managed';
-import LocalConfig from 'assets/config';
-
-import {t} from 'app/utils/i18n';
/* eslint-disable no-throw-literal */
diff --git a/app/init/global_event_handler.js b/app/init/global_event_handler.js
index f02ec4109..9d9a07925 100644
--- a/app/init/global_event_handler.js
+++ b/app/init/global_event_handler.js
@@ -13,6 +13,7 @@ import {autoUpdateTimezone} from '@mm-redux/actions/timezone';
import {close as closeWebSocket} from '@actions/websocket';
import {Client4} from '@mm-redux/client';
import {General} from '@mm-redux/constants';
+import {getConfig} from '@mm-redux/selectors/entities/general';
import {getCurrentChannelId} from '@mm-redux/selectors/entities/channels';
import {getCurrentUserId, getUser} from '@mm-redux/selectors/entities/users';
import {isTimezoneEnabled} from '@mm-redux/selectors/entities/timezone';
@@ -23,6 +24,7 @@ import {selectDefaultChannel} from '@actions/views/channel';
import {showOverlay} from '@actions/navigation';
import {loadConfigAndLicense, setDeepLinkURL, startDataCleanup} from '@actions/views/root';
import {loadMe, logout} from '@actions/views/user';
+import LocalConfig from '@assets/config';
import {NavigationTypes, ViewTypes} from '@constants';
import {getTranslations, resetMomentLocale} from '@i18n';
import PushNotifications from 'app/push_notifications';
@@ -35,7 +37,6 @@ import {getDeviceTimezoneAsync} from '@utils/timezone';
import mattermostBucket from 'app/mattermost_bucket';
import mattermostManaged from 'app/mattermost_managed';
-import LocalConfig from 'assets/config';
import {getAppCredentials, removeAppCredentials} from './credentials';
import emmProvider from './emm_provider';
@@ -43,6 +44,8 @@ import emmProvider from './emm_provider';
const {StatusBarManager} = NativeModules;
const PROMPT_IN_APP_PIN_CODE_AFTER = 5 * 1000;
+let analytics;
+
class GlobalEventHandler {
constructor() {
this.pushNotificationListener = false;
@@ -112,14 +115,16 @@ class GlobalEventHandler {
mattermostManaged.addEventListener('managedConfigDidChange', this.onManagedConfigurationChange);
};
- configureAnalytics = (config) => {
- const initAnalytics = require('app/utils/segment').init;
+ configureAnalytics = async () => {
+ const state = Store.redux.getState();
+ const config = getConfig(state);
+ const initAnalytics = require('./analytics').init;
- if (!__DEV__ && config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && LocalConfig.SegmentApiKey) {
- initAnalytics(config);
- } else {
- global.analytics = null;
+ if (config && config.DiagnosticsEnabled === 'true' && config.DiagnosticId && LocalConfig.RudderApiKey) {
+ analytics = await initAnalytics(config);
}
+
+ return analytics;
};
onAppStateChange = (appState) => {
@@ -158,6 +163,11 @@ class GlobalEventHandler {
Store.redux.dispatch(closeWebSocket(false));
Store.redux.dispatch(setServerVersion(''));
await this.resetState();
+
+ if (analytics) {
+ await analytics.reset();
+ }
+
removeAppCredentials();
deleteFileCache();
resetMomentLocale();
@@ -235,7 +245,7 @@ class GlobalEventHandler {
}
};
- onServerVersionChanged = async (serverVersion) => {
+ onServerVersionChanged = (serverVersion) => {
const {dispatch, getState} = Store.redux;
const state = getState();
const match = serverVersion && serverVersion.match(/^[0-9]*.[0-9]*.[0-9]*(-[a-zA-Z0-9.-]*)?/g);
@@ -256,8 +266,7 @@ class GlobalEventHandler {
);
} else if (state.entities.users && state.entities.users.currentUserId) {
dispatch(setServerVersion(serverVersion));
- const data = await dispatch(loadConfigAndLicense());
- this.configureAnalytics(data.config);
+ dispatch(loadConfigAndLicense());
}
}
};
diff --git a/app/init/global_event_handler.test.js b/app/init/global_event_handler.test.js
index 898661778..07e0bbcb1 100644
--- a/app/init/global_event_handler.test.js
+++ b/app/init/global_event_handler.test.js
@@ -6,14 +6,14 @@ import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import semver from 'semver/preload';
-import PushNotification from 'app/push_notifications';
-import mattermostBucket from 'app/mattermost_bucket';
+import {MinServerVersion} from '@assets/config';
import * as I18n from '@i18n';
import EventEmitter from '@mm-redux/utils/event_emitter';
import Store from '@store/store';
import intitialState from '@store/initial_state';
-import {MinServerVersion} from 'assets/config';
+import PushNotification from 'app/push_notifications';
+import mattermostBucket from 'app/mattermost_bucket';
import GlobalEventHandler from './global_event_handler';
@@ -183,7 +183,6 @@ describe('GlobalEventHandler', () => {
expect(dispatch).toHaveBeenCalledTimes(2);
expect(dispatch).toHaveBeenCalledWith('setServerVersion');
expect(dispatch).toHaveBeenCalledWith('loadConfigAndLicense');
- expect(configureAnalytics).toHaveBeenCalledTimes(1);
});
it('should dispatch on gte min server version with currentUserId', async () => {
@@ -193,13 +192,11 @@ describe('GlobalEventHandler', () => {
expect(dispatch).toHaveBeenCalledTimes(2);
expect(dispatch).toHaveBeenCalledWith('setServerVersion');
expect(dispatch).toHaveBeenCalledWith('loadConfigAndLicense');
- expect(configureAnalytics).toHaveBeenCalledTimes(1);
version = semver.coerce(minVersion.major + 1).version;
await GlobalEventHandler.onServerVersionChanged(version);
expect(alert).not.toHaveBeenCalled();
expect(dispatch).toHaveBeenCalledTimes(4);
- expect(configureAnalytics).toHaveBeenCalledTimes(2);
});
it('should alert on lt min server version', async () => {
diff --git a/app/mattermost.js b/app/mattermost.js
index c44d42f06..7600309d9 100644
--- a/app/mattermost.js
+++ b/app/mattermost.js
@@ -62,6 +62,7 @@ const launchApp = (credentials) => {
const valid = validatePreviousVersion(previousVersion);
if (valid) {
store.dispatch(loadMe());
+ await globalEventHandler.configureAnalytics();
resetToChannel({skipMetrics: true});
} else {
const error = new Error(`Previous app version "${previousVersion}" is invalid.`);
diff --git a/app/mm-redux/client/client4.ts b/app/mm-redux/client/client4.ts
index e10e81ed3..41cc64b73 100644
--- a/app/mm-redux/client/client4.ts
+++ b/app/mm-redux/client/client4.ts
@@ -1,13 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
+import {analytics, context} from '@init/analytics.ts';
import {buildQueryString, isMinimumServerVersion} from '@mm-redux/utils/helpers';
import {cleanUrlForLogging} from '@mm-redux/utils/sentry';
-import {General} from '../constants';
-
import {isSystemAdmin} from '@mm-redux/utils/user_utils';
-
-import fetch from './fetch_etag';
import {UserProfile, UserStatus} from '@mm-redux/types/users';
import {Team} from '@mm-redux/types/teams';
import {Channel, ChannelModerationPatch} from '@mm-redux/types/channels';
@@ -23,6 +20,9 @@ import {Config} from '@mm-redux/types/config';
import {Bot, BotPatch} from '@mm-redux/types/bots';
import {SyncablePatch} from '@mm-redux/types/groups';
+import fetch from './fetch_etag';
+import {General} from '../constants';
+
const FormData = require('form-data');
const HEADER_AUTH = 'Authorization';
const HEADER_BEARER = 'BEARER';
@@ -3078,6 +3078,10 @@ export default class Client4 {
};
trackEvent(category: string, event: string, props?: any) {
+ if (!analytics) {
+ return;
+ }
+
// Temporary change to allow only certain events to reduce data rate - see MM-13062
// All events in 'admin' category are allowed, since they are low-volume
if (category !== 'admin' && ![
@@ -3116,31 +3120,11 @@ export default class Client4 {
user_actual_id: this.userId,
}, props);
const options = {
- context: {
- ip: '0.0.0.0',
- },
- page: {
- path: '',
- referrer: '',
- search: '',
- title: '',
- url: '',
- },
+ context,
anonymousId: '00000000000000000000000000',
};
- const globalAny: any = global;
- if (globalAny && globalAny.window && globalAny.window.analytics && globalAny.window.analytics.initialized) {
- globalAny.window.analytics.track('event', properties, options);
- } else if (globalAny && globalAny.analytics) {
- if (globalAny.analytics_context) {
- options.context = globalAny.analytics_context;
- }
- globalAny.analytics.track(Object.assign({
- event: 'event',
- userId: this.diagnosticId,
- }, {properties}, options));
- }
+ analytics.track(event, properties, options);
}
}
diff --git a/app/mm-redux/utils/i18n_utils.test.js b/app/mm-redux/utils/i18n_utils.test.js
index cb133a863..3fbae6b2b 100644
--- a/app/mm-redux/utils/i18n_utils.test.js
+++ b/app/mm-redux/utils/i18n_utils.test.js
@@ -4,7 +4,7 @@
import assert from 'assert';
import {setLocalizeFunction, localizeMessage} from '@mm-redux/utils/i18n_utils';
-const en = require('assets/i18n/en.json');
+const en = require('@assets/i18n/en.json');
const [testKey, testValue] = Object.entries(en)[0];
describe('i18n utils', () => {
diff --git a/app/reducers/views/select_server.js b/app/reducers/views/select_server.js
index ea9fb04f4..04233d981 100644
--- a/app/reducers/views/select_server.js
+++ b/app/reducers/views/select_server.js
@@ -3,7 +3,7 @@
import {combineReducers} from 'redux';
-import Config from 'assets/config.json';
+import Config from '@assets/config.json';
import {ViewTypes} from 'app/constants';
diff --git a/app/screens/about/about.js b/app/screens/about/about.js
index 67482c698..dbfbdd79a 100644
--- a/app/screens/about/about.js
+++ b/app/screens/about/about.js
@@ -12,13 +12,13 @@ import {
} from 'react-native';
import DeviceInfo from 'react-native-device-info';
-import FormattedText from 'app/components/formatted_text';
-import StatusBar from 'app/components/status_bar';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
-import AppIcon from 'app/components/app_icon';
-import Config from 'assets/config';
-import AboutLinks from 'app/constants/about_links';
+import Config from '@assets/config';
+import AppIcon from '@components/app_icon';
+import FormattedText from '@components/formatted_text';
+import {paddingHorizontal as padding} from '@components/safe_area_view/iphone_x_spacing';
+import StatusBar from '@components/status_bar';
+import AboutLinks from '@constants/about_links';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
const MATTERMOST_BUNDLE_IDS = ['com.mattermost.rnbeta', 'com.mattermost.rn'];
diff --git a/app/screens/channel/channel.android.js b/app/screens/channel/channel.android.js
index 6b492eb1c..1ae28fd5d 100644
--- a/app/screens/channel/channel.android.js
+++ b/app/screens/channel/channel.android.js
@@ -5,6 +5,7 @@ import React from 'react';
import {StyleSheet, View} from 'react-native';
import {openMainSideMenu, openSettingsSideMenu} from '@actions/navigation';
+import LocalConfig from '@assets/config';
import KeyboardLayout from '@components/layout/keyboard_layout';
import InteractiveDialogController from '@components/interactive_dialog_controller';
import NetworkIndicator from '@components/network_indicator';
@@ -12,8 +13,6 @@ import PostDraft from '@components/post_draft';
import {NavigationTypes} from '@constants';
import EventEmitter from '@mm-redux/utils/event_emitter';
-import LocalConfig from 'assets/config';
-
import ChannelNavBar from './channel_nav_bar';
import ChannelPostList from './channel_post_list';
diff --git a/app/screens/channel/channel.ios.js b/app/screens/channel/channel.ios.js
index f0e84747b..c871096eb 100644
--- a/app/screens/channel/channel.ios.js
+++ b/app/screens/channel/channel.ios.js
@@ -5,6 +5,7 @@ import React from 'react';
import {View} from 'react-native';
import {KeyboardTrackingView} from 'react-native-keyboard-tracking-view';
+import LocalConfig from '@assets/config';
import Autocomplete, {AUTOCOMPLETE_MAX_HEIGHT} from '@components/autocomplete';
import InteractiveDialogController from '@components/interactive_dialog_controller';
import NetworkIndicator from '@components/network_indicator';
@@ -16,8 +17,6 @@ import StatusBar from '@components/status_bar';
import {ACCESSORIES_CONTAINER_NATIVE_ID, CHANNEL_POST_TEXTBOX_CURSOR_CHANGE, CHANNEL_POST_TEXTBOX_VALUE_CHANGE} from '@constants/post_draft';
import {makeStyleSheetFromTheme} from '@utils/theme';
-import LocalConfig from 'assets/config';
-
import ChannelBase, {ClientUpgradeListener} from './channel_base';
import ChannelNavBar from './channel_nav_bar';
import ChannelPostList from './channel_post_list';
diff --git a/app/screens/channel/channel_base.js b/app/screens/channel/channel_base.js
index 6fef6a586..50d15f860 100644
--- a/app/screens/channel/channel_base.js
+++ b/app/screens/channel/channel_base.js
@@ -11,20 +11,19 @@ import {
} from 'react-native';
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
+import {showModal, showModalOverCurrentContext} from '@actions/navigation';
+import LocalConfig from '@assets/config';
+import SafeAreaView from '@components/safe_area_view';
+import EmptyToolbar from '@components/start/empty_toolbar';
+import {NavigationTypes} from '@constants';
import EventEmitter from '@mm-redux/utils/event_emitter';
+import EphemeralStore from '@store/ephemeral_store';
+import {preventDoubleTap} from '@utils/tap';
+import {setNavigatorStyles} from '@utils/theme';
+import tracker from '@utils/time_tracker';
-import {showModal, showModalOverCurrentContext} from 'app/actions/navigation';
-import SafeAreaView from 'app/components/safe_area_view';
-import EmptyToolbar from 'app/components/start/empty_toolbar';
-import {NavigationTypes} from 'app/constants';
import PushNotifications from 'app/push_notifications';
-import EphemeralStore from 'app/store/ephemeral_store';
import telemetry from 'app/telemetry';
-import {preventDoubleTap} from 'app/utils/tap';
-import {setNavigatorStyles} from 'app/utils/theme';
-import tracker from 'app/utils/time_tracker';
-
-import LocalConfig from 'assets/config';
export let ClientUpgradeListener;
diff --git a/app/screens/channel_info/channel_info.js b/app/screens/channel_info/channel_info.js
index 91b6f8528..9829799e9 100644
--- a/app/screens/channel_info/channel_info.js
+++ b/app/screens/channel_info/channel_info.js
@@ -11,16 +11,14 @@ import {
} from 'react-native';
import {Navigation} from 'react-native-navigation';
+import {dismissModal, goToScreen, showModalOverCurrentContext} from '@actions/navigation';
+import pinIcon from '@assets/images/channel_info/pin.png';
+import StatusBar from '@components/status_bar';
import {General, Users} from '@mm-redux/constants';
-
-import StatusBar from 'app/components/status_bar';
-import {preventDoubleTap} from 'app/utils/tap';
-import {alertErrorWithFallback} from 'app/utils/general';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {t} from 'app/utils/i18n';
-import {dismissModal, goToScreen, showModalOverCurrentContext} from 'app/actions/navigation';
-
-import pinIcon from 'assets/images/channel_info/pin.png';
+import {alertErrorWithFallback} from '@utils/general';
+import {t} from '@utils/i18n';
+import {preventDoubleTap} from '@utils/tap';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import ChannelInfoHeader from './channel_info_header';
import ChannelInfoRow from './channel_info_row';
diff --git a/app/screens/channel_info/channel_info.test.js b/app/screens/channel_info/channel_info.test.js
index be326b699..846a5cfc0 100644
--- a/app/screens/channel_info/channel_info.test.js
+++ b/app/screens/channel_info/channel_info.test.js
@@ -3,19 +3,18 @@
import React from 'react';
import {shallow} from 'enzyme';
+import * as NavigationActions from '@actions/navigation';
import Preferences from '@mm-redux/constants/preferences';
import {General} from '@mm-redux/constants';
-import * as NavigationActions from 'app/actions/navigation';
-
import ChannelInfo from './channel_info';
// ChannelInfoRow expects to receive the pinIcon as a number
-jest.mock('assets/images/channel_info/pin.png', () => {
+jest.mock('@assets/images/channel_info/pin.png', () => {
return 1;
});
-jest.mock('app/utils/theme', () => {
+jest.mock('@utils/theme', () => {
const original = require.requireActual('app/utils/theme');
return {
...original,
diff --git a/app/screens/client_upgrade/client_upgrade.js b/app/screens/client_upgrade/client_upgrade.js
index 581caea68..f9ebe2e98 100644
--- a/app/screens/client_upgrade/client_upgrade.js
+++ b/app/screens/client_upgrade/client_upgrade.js
@@ -14,13 +14,13 @@ import {
} from 'react-native';
import {intlShape} from 'react-intl';
-import FormattedText from 'app/components/formatted_text';
-import StatusBar from 'app/components/status_bar';
-import {UpgradeTypes} from 'app/constants';
-import logo from 'assets/images/logo.png';
-import {checkUpgradeType, isUpgradeAvailable} from 'app/utils/client_upgrade';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {popTopScreen, dismissModal} from 'app/actions/navigation';
+import {popTopScreen, dismissModal} from '@actions/navigation';
+import logo from '@assets/images/logo.png';
+import FormattedText from '@components/formatted_text';
+import StatusBar from '@components/status_bar';
+import {UpgradeTypes} from '@constants';
+import {checkUpgradeType, isUpgradeAvailable} from '@utils/client_upgrade';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
export default class ClientUpgrade extends PureComponent {
static propTypes = {
diff --git a/app/screens/forgot_password/forgot_password.js b/app/screens/forgot_password/forgot_password.js
index bcc372bab..b9ef2f697 100644
--- a/app/screens/forgot_password/forgot_password.js
+++ b/app/screens/forgot_password/forgot_password.js
@@ -15,16 +15,14 @@ import {
View,
} from 'react-native';
+import ErrorText from '@components/error_text';
+import FormattedText from '@components/formatted_text';
+import StatusBar from '@components/status_bar';
import {isEmail} from '@mm-redux/utils/helpers';
+import {changeOpacity} from '@utils/theme';
import {GlobalStyles} from 'app/styles';
-import ErrorText from 'app/components/error_text';
-import FormattedText from 'app/components/formatted_text';
-import StatusBar from 'app/components/status_bar';
-
-import {changeOpacity} from 'app/utils/theme';
-
export default class ForgotPassword extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
@@ -156,7 +154,7 @@ export default class ForgotPassword extends PureComponent {
>
{displayError}
{passwordFormView}
diff --git a/app/screens/login/login.js b/app/screens/login/login.js
index 2e3dbd800..dfba4fb77 100644
--- a/app/screens/login/login.js
+++ b/app/screens/login/login.js
@@ -19,19 +19,19 @@ import {
import Button from 'react-native-button';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
-import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
-import ErrorText from 'app/components/error_text';
-import FormattedText from 'app/components/formatted_text';
-import StatusBar from 'app/components/status_bar';
-import {resetToChannel, goToScreen} from 'app/actions/navigation';
-import mattermostManaged from 'app/mattermost_managed';
-import {preventDoubleTap} from 'app/utils/tap';
-import tracker from 'app/utils/time_tracker';
-import {t} from 'app/utils/i18n';
-import {setMfaPreflightDone, getMfaPreflightDone} from 'app/utils/security';
-import {changeOpacity} from 'app/utils/theme';
-import {GlobalStyles} from 'app/styles';
+import {resetToChannel, goToScreen} from '@actions/navigation';
+import ErrorText from '@components/error_text';
+import FormattedText from '@components/formatted_text';
+import {paddingHorizontal as padding} from '@components/safe_area_view/iphone_x_spacing';
+import StatusBar from '@components/status_bar';
+import {t} from '@utils/i18n';
+import {setMfaPreflightDone, getMfaPreflightDone} from '@utils/security';
+import {preventDoubleTap} from '@utils/tap';
+import {changeOpacity} from '@utils/theme';
+import tracker from '@utils/time_tracker';
+import mattermostManaged from 'app/mattermost_managed';
+import {GlobalStyles} from 'app/styles';
import telemetry from 'app/telemetry';
export const mfaExpectedErrors = ['mfa.validate_token.authenticate.app_error', 'ent.mfa.validate_token.authenticate.app_error'];
@@ -388,7 +388,7 @@ export default class Login extends PureComponent {
enableOnAndroid={true}
>
diff --git a/app/screens/login_options/login_options.js b/app/screens/login_options/login_options.js
index 2c3ee77a7..b95b120e8 100644
--- a/app/screens/login_options/login_options.js
+++ b/app/screens/login_options/login_options.js
@@ -13,17 +13,17 @@ import {
} from 'react-native';
import Button from 'react-native-button';
-import FormattedText from 'app/components/formatted_text';
-import StatusBar from 'app/components/status_bar';
-import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
-import {GlobalStyles} from 'app/styles';
-import {preventDoubleTap} from 'app/utils/tap';
-import {ViewTypes} from 'app/constants';
-import {goToScreen} from 'app/actions/navigation';
+import {goToScreen} from '@actions/navigation';
+import LocalConfig from '@assets/config';
+import gitlab from '@assets/images/gitlab.png';
+import logo from '@assets/images/logo.png';
+import FormattedText from '@components/formatted_text';
+import StatusBar from '@components/status_bar';
+import {paddingHorizontal as padding} from '@components/safe_area_view/iphone_x_spacing';
+import {ViewTypes} from '@constants';
+import {preventDoubleTap} from '@utils/tap';
-import LocalConfig from 'assets/config';
-import gitlab from 'assets/images/gitlab.png';
-import logo from 'assets/images/logo.png';
+import {GlobalStyles} from 'app/styles';
export default class LoginOptions extends PureComponent {
static propTypes = {
diff --git a/app/screens/mfa/mfa.js b/app/screens/mfa/mfa.js
index c10359416..0f14c1379 100644
--- a/app/screens/mfa/mfa.js
+++ b/app/screens/mfa/mfa.js
@@ -15,15 +15,16 @@ import {
} from 'react-native';
import Button from 'react-native-button';
-import ErrorText from 'app/components/error_text';
-import FormattedText from 'app/components/formatted_text';
-import StatusBar from 'app/components/status_bar';
-import TextInputWithLocalizedPlaceholder from 'app/components/text_input_with_localized_placeholder';
+import {popTopScreen} from '@actions/navigation';
+import ErrorText from '@components/error_text';
+import FormattedText from '@components/formatted_text';
+import StatusBar from '@components/status_bar';
+import TextInputWithLocalizedPlaceholder from '@components/text_input_with_localized_placeholder';
+import {t} from '@utils/i18n';
+import {preventDoubleTap} from '@utils/tap';
+import {setMfaPreflightDone} from '@utils/security';
+
import {GlobalStyles} from 'app/styles';
-import {preventDoubleTap} from 'app/utils/tap';
-import {t} from 'app/utils/i18n';
-import {setMfaPreflightDone} from 'app/utils/security';
-import {popTopScreen} from 'app/actions/navigation';
export default class Mfa extends PureComponent {
static propTypes = {
@@ -140,7 +141,7 @@ export default class Mfa extends PureComponent {
{
+ handleLoginOptions = async (props = this.props) => {
const {formatMessage} = this.context.intl;
const {config, license} = props;
const samlEnabled = config.EnableSaml === 'true' && license.IsLicensed === 'true' && license.SAML === 'true';
@@ -252,6 +250,7 @@ export default class SelectServer extends PureComponent {
}
this.props.actions.resetPing();
+ await globalEventHandler.configureAnalytics();
if (Platform.OS === 'ios') {
if (config.ExperimentalClientSideCertEnable === 'true' && config.ExperimentalClientSideCertCheck === 'primary') {
@@ -477,7 +476,7 @@ export default class SelectServer extends PureComponent {
>
diff --git a/app/screens/settings/advanced_settings/advanced_settings.js b/app/screens/settings/advanced_settings/advanced_settings.js
index c6ded2e5f..df21d52d9 100644
--- a/app/screens/settings/advanced_settings/advanced_settings.js
+++ b/app/screens/settings/advanced_settings/advanced_settings.js
@@ -14,17 +14,15 @@ import {
} from 'react-native';
import * as Sentry from '@sentry/react-native';
+import {dismissAllModals} from '@actions/navigation';
+import Config from '@assets/config';
+import StatusBar from '@components/status_bar';
import {getFormattedFileSize} from '@mm-redux/utils/file_utils';
-
-import SettingsItem from 'app/screens/settings/settings_item';
-import StatusBar from 'app/components/status_bar';
-import {t} from 'app/utils/i18n';
-import {deleteFileCache, getFileCacheSize} from 'app/utils/file';
-import {preventDoubleTap} from 'app/utils/tap';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {dismissAllModals} from 'app/actions/navigation';
-
-import Config from 'assets/config';
+import SettingsItem from '@screens/settings/settings_item';
+import {t} from '@utils/i18n';
+import {deleteFileCache, getFileCacheSize} from '@utils/file';
+import {preventDoubleTap} from '@utils/tap';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
class AdvancedSettings extends Component {
static propTypes = {
diff --git a/app/screens/settings/general/settings.js b/app/screens/settings/general/settings.js
index a94022765..a9cccf1a5 100644
--- a/app/screens/settings/general/settings.js
+++ b/app/screens/settings/general/settings.js
@@ -13,15 +13,14 @@ import {
import DeviceInfo from 'react-native-device-info';
import {Navigation} from 'react-native-navigation';
-import SettingsItem from 'app/screens/settings/settings_item';
-import StatusBar from 'app/components/status_bar';
-import {preventDoubleTap} from 'app/utils/tap';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {isValidUrl} from 'app/utils/url';
-import {t} from 'app/utils/i18n';
-import {goToScreen, dismissModal} from 'app/actions/navigation';
-
-import LocalConfig from 'assets/config';
+import {goToScreen, dismissModal} from '@actions/navigation';
+import LocalConfig from '@assets/config';
+import StatusBar from '@components/status_bar';
+import SettingsItem from '@screens/settings/settings_item';
+import {t} from '@utils/i18n';
+import {preventDoubleTap} from '@utils/tap';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
+import {isValidUrl} from '@utils/url';
class Settings extends PureComponent {
static propTypes = {
diff --git a/app/screens/settings/theme/theme.js b/app/screens/settings/theme/theme.js
index 946af24b9..092fcd943 100644
--- a/app/screens/settings/theme/theme.js
+++ b/app/screens/settings/theme/theme.js
@@ -8,19 +8,19 @@ import {intlShape} from 'react-intl';
import Preferences from '@mm-redux/constants/preferences';
-import StatusBar from 'app/components/status_bar';
-import Section from 'app/screens/settings/section';
-import SectionItem from 'app/screens/settings/section_item';
-import FormattedText from 'app/components/formatted_text';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
+import FormattedText from '@components/formatted_text';
+import StatusBar from '@components/status_bar';
+import Section from '@screens/settings/section';
+import SectionItem from '@screens/settings/section_item';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import ThemeTile from './theme_tile';
const thumbnailImages = {
- default: require('assets/images/themes/mattermost.png'),
- organization: require('assets/images/themes/organization.png'),
- mattermostDark: require('assets/images/themes/mattermost_dark.png'),
- windows10: require('assets/images/themes/windows_dark.png'),
+ default: require('@assets/images/themes/mattermost.png'),
+ organization: require('@assets/images/themes/organization.png'),
+ mattermostDark: require('@assets/images/themes/mattermost_dark.png'),
+ windows10: require('@assets/images/themes/windows_dark.png'),
};
export default class Theme extends React.PureComponent {
diff --git a/app/screens/settings/theme/theme_tile.js b/app/screens/settings/theme/theme_tile.js
index 01b146e9a..2d50449ae 100644
--- a/app/screens/settings/theme/theme_tile.js
+++ b/app/screens/settings/theme/theme_tile.js
@@ -10,9 +10,9 @@ import {
View,
} from 'react-native';
-import {makeStyleSheetFromTheme} from 'app/utils/theme';
+import {makeStyleSheetFromTheme} from '@utils/theme';
-const checkmark = require('assets/images/themes/check.png');
+const checkmark = require('@assets/images/themes/check.png');
const tilePadding = 8;
diff --git a/app/screens/user_profile/user_profile.js b/app/screens/user_profile/user_profile.js
index e74062ec1..02ca131d4 100644
--- a/app/screens/user_profile/user_profile.js
+++ b/app/screens/user_profile/user_profile.js
@@ -12,30 +12,27 @@ import {
import {intlShape} from 'react-intl';
import {Navigation} from 'react-native-navigation';
-import {displayUsername} from '@mm-redux/utils/user_utils';
-import {getUserCurrentTimezone} from '@mm-redux/utils/timezone_utils';
-
-import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
-import ProfilePicture from 'app/components/profile_picture';
-import FormattedText from 'app/components/formatted_text';
-import FormattedTime from 'app/components/formatted_time';
-import StatusBar from 'app/components/status_bar';
-import {BotTag, GuestTag} from 'app/components/tag';
-
-import {alertErrorWithFallback} from 'app/utils/general';
-import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
-import {t} from 'app/utils/i18n';
-import {isGuest} from 'app/utils/users';
-
import {
goToScreen,
popToRoot,
dismissModal,
setButtons,
-} from 'app/actions/navigation';
+} from '@actions/navigation';
+import Config from '@assets/config';
+import FormattedTime from '@components/formatted_time';
+import ProfilePicture from '@components/profile_picture';
+import FormattedText from '@components/formatted_text';
+import {paddingHorizontal as padding} from '@components/safe_area_view/iphone_x_spacing';
+import StatusBar from '@components/status_bar';
+import {BotTag, GuestTag} from '@components/tag';
+import {displayUsername} from '@mm-redux/utils/user_utils';
+import {getUserCurrentTimezone} from '@mm-redux/utils/timezone_utils';
+import {alertErrorWithFallback} from '@utils/general';
+import {t} from '@utils/i18n';
+import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
+import {isGuest} from '@utils/users';
import UserProfileRow from './user_profile_row';
-import Config from 'assets/config';
export default class UserProfile extends PureComponent {
static propTypes = {
diff --git a/app/selectors/client_upgrade.js b/app/selectors/client_upgrade.js
index bbd39620d..bfb0f2295 100644
--- a/app/selectors/client_upgrade.js
+++ b/app/selectors/client_upgrade.js
@@ -4,10 +4,9 @@ import {createSelector} from 'reselect';
import {Platform} from 'react-native';
import DeviceInfo from 'react-native-device-info';
+import LocalConfig from '@assets/config';
import {getConfig} from '@mm-redux/selectors/entities/general';
-import LocalConfig from 'assets/config';
-
const getClientUpgrade = createSelector(
getConfig,
(config) => {
diff --git a/app/store/initial_state.js b/app/store/initial_state.js
index 41d16827a..00a716ccb 100644
--- a/app/store/initial_state.js
+++ b/app/store/initial_state.js
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import Config from 'assets/config.json';
+import Config from '@assets/config.json';
const state = {
app: {
diff --git a/app/telemetry/telemetry.android.js b/app/telemetry/telemetry.android.js
index 81ae31134..9f5808237 100644
--- a/app/telemetry/telemetry.android.js
+++ b/app/telemetry/telemetry.android.js
@@ -1,8 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import LocalConfig from 'assets/config'; // eslint-disable-line
-
+import LocalConfig from '@assets/config';
import Store from '@store/store';
import {
diff --git a/app/telemetry/telemetry_utils.js b/app/telemetry/telemetry_utils.js
index 553c934b0..88b3b2d38 100644
--- a/app/telemetry/telemetry_utils.js
+++ b/app/telemetry/telemetry_utils.js
@@ -4,7 +4,7 @@
import {Dimensions} from 'react-native';
import DeviceInfo from 'react-native-device-info';
-import LocalConfig from 'assets/config';
+import LocalConfig from '@assets/config';
export function saveToTelemetryServer(data) {
const {
diff --git a/app/utils/client_upgrade.js b/app/utils/client_upgrade.js
index 52017933a..65c4dd297 100644
--- a/app/utils/client_upgrade.js
+++ b/app/utils/client_upgrade.js
@@ -2,9 +2,8 @@
// See LICENSE.txt for license information.
import semver from 'semver';
-import {UpgradeTypes} from 'app/constants';
-
-import LocalConfig from 'assets/config';
+import LocalConfig from '@assets/config';
+import {UpgradeTypes} from '@constants';
export function checkUpgradeType(currentVersion, minVersion, latestVersion, logError) {
let upgradeType = UpgradeTypes.NO_UPGRADE;
diff --git a/app/utils/segment.js b/app/utils/segment.js
deleted file mode 100644
index 2542faa6f..000000000
--- a/app/utils/segment.js
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-import DeviceInfo from 'react-native-device-info';
-import {Dimensions} from 'react-native';
-
-import Config from 'assets/config';
-
-import tracker from './time_tracker';
-
-let diagnosticId;
-let Analytics;
-
-export function init(config) {
- if (!global.analytics) {
- if (!Analytics) {
- Analytics = require('analytics-react-native').default;
- }
- diagnosticId = config.DiagnosticId;
- const {height, width} = Dimensions.get('window');
- global.analytics = new Analytics(Config.SegmentApiKey, {
- flushAt: 20,
- flushInterval: 10000,
- });
- global.analytics_context = {
- app: {
- version: DeviceInfo.getVersion(),
- build: DeviceInfo.getBuildNumber(),
- },
- device: {
- dimensions: {
- height,
- width,
- },
- isTablet: DeviceInfo.isTablet(),
- os: DeviceInfo.getSystemVersion(),
- },
- ip: '0.0.0.0',
- server: config.Version,
- };
-
- global.analytics.identify({
- userId: diagnosticId,
- context: global.analytics_context,
- page: {
- path: '',
- referrer: '',
- search: '',
- title: '',
- url: '',
- },
- anonymousId: '00000000000000000000000000',
- });
- }
-}
-
-export function recordTime(screenName, category, userId) {
- if (global.analytics) {
- const startTime = tracker[category];
- tracker[category] = 0;
- global.analytics.screen({
- userId: diagnosticId,
- name: screenName,
- context: global.analytics_context,
- properties: {
- actual_user_id: userId,
- time: Date.now() - startTime,
- },
- });
- }
-}
diff --git a/app/utils/sentry/index.js b/app/utils/sentry/index.js
index 0086d5b52..645812dbc 100644
--- a/app/utils/sentry/index.js
+++ b/app/utils/sentry/index.js
@@ -2,8 +2,8 @@
// See LICENSE.txt for license information.
import {Platform} from 'react-native';
-import Config from 'assets/config';
+import Config from '@assets/config';
import {Client4} from '@mm-redux/client';
import {getConfig} from '@mm-redux/selectors/entities/general';
import {getCurrentUser} from '@mm-redux/selectors/entities/users';
diff --git a/assets/base/config.json b/assets/base/config.json
index ff134a642..d465a5ac2 100644
--- a/assets/base/config.json
+++ b/assets/base/config.json
@@ -10,7 +10,7 @@
"AboutEnterpriseURL": "http://about.mattermost.com/",
"PlatformNoticeURL": "https://about.mattermost.com/platform-notice-txt/",
"MobileNoticeURL": "https://about.mattermost.com/mobile-notice-txt/",
- "SegmentApiKey": "",
+ "RudderApiKey": "",
"HideEmailLoginExperimental": false,
"HideGitLabLoginExperimental": false,
diff --git a/babel.config.js b/babel.config.js
index 3ae18fa24..1a0d77bb2 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -12,7 +12,7 @@ module.exports = {
['module-resolver', {
root: ['.'],
alias: {
- assets: './dist/assets',
+ '@assets': './dist/assets',
'@actions': './app/actions',
'@components': './app/components',
'@constants': './app/constants',
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index 8ad72e049..05a864e54 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -154,8 +154,8 @@ lane :configure do
json = load_config_json('../dist/assets/config.json')
# Set the Segment API Key
- unless ENV['SEGMENT_API_KEY'].nil? || ENV['SEGMENT_API_KEY'].empty?
- json['SegmentApiKey'] = ENV['SEGMENT_API_KEY']
+ unless ENV['RUDDER_API_KEY'].nil? || ENV['RUDDER_API_KEY'].empty?
+ json['RudderApiKey'] = ENV['RUDDER_API_KEY']
end
# Configure Sentry if enabled
diff --git a/index.js b/index.js
index 89b2d352a..e255ea41d 100644
--- a/index.js
+++ b/index.js
@@ -5,11 +5,9 @@ import 'react-native/Libraries/Core/InitializeCore';
import {DeviceEventEmitter, Platform, Text} from 'react-native';
import 'react-native-gesture-handler';
-import LocalConfig from 'assets/config';
-
-import telemetry from 'app/telemetry';
-
+import LocalConfig from '@assets/config';
import 'app/mattermost';
+import telemetry from 'app/telemetry';
if (Platform.OS === 'android') {
require('harmony-reflect');
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index d6da1aa67..87494b7d2 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -34,7 +34,7 @@ PODS:
- libwebp/webp (1.1.0)
- MMKV (1.1.0):
- MMKVCore (~> 1.1.0)
- - MMKVCore (1.1.0)
+ - MMKVCore (1.1.1)
- Permission-Camera (2.0.10):
- RNPermissions
- Permission-PhotoLibrary (2.0.10):
@@ -322,6 +322,9 @@ PODS:
- React
- RNReactNativeHapticFeedback (1.9.0):
- React
+ - RNRudderSdk (1.0.0):
+ - React
+ - Rudder (= 1.0.3-beta-4)
- RNSentry (1.3.6):
- React
- Sentry (~> 4.4.0)
@@ -329,9 +332,10 @@ PODS:
- React
- RNVectorIcons (6.6.0):
- React
- - SDWebImage (5.6.1):
- - SDWebImage/Core (= 5.6.1)
- - SDWebImage/Core (5.6.1)
+ - Rudder (1.0.3-beta.4)
+ - SDWebImage (5.8.0):
+ - SDWebImage/Core (= 5.8.0)
+ - SDWebImage/Core (5.8.0)
- SDWebImageWebPCoder (0.4.1):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.5)
@@ -401,6 +405,7 @@ DEPENDENCIES:
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReactNativeDocViewer (from `../node_modules/react-native-doc-viewer`)
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
+ - "RNRudderSdk (from `../node_modules/@rudderstack/rudder-sdk-react-native/ios`)"
- "RNSentry (from `../node_modules/@sentry/react-native`)"
- RNSVG (from `../node_modules/react-native-svg`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
@@ -414,6 +419,7 @@ SPEC REPOS:
- libwebp
- MMKV
- MMKVCore
+ - Rudder
- SDWebImage
- SDWebImageWebPCoder
- Sentry
@@ -530,6 +536,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-doc-viewer"
RNReactNativeHapticFeedback:
:path: "../node_modules/react-native-haptic-feedback"
+ RNRudderSdk:
+ :path: "../node_modules/@rudderstack/rudder-sdk-react-native/ios"
RNSentry:
:path: "../node_modules/@sentry/react-native"
RNSVG:
@@ -550,7 +558,7 @@ SPEC CHECKSUMS:
jail-monkey: d7c5048b2336f22ee9c9e0efa145f1f917338ea9
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
MMKV: 7bb6c30f9ff2ea45bc2398c86e66dd1cb63cfe20
- MMKVCore: f455d4bf01bb5257511c1062fdbc3d7ebdec216b
+ MMKVCore: 2748bf702287a814a6c514d054033e41e07f5c0f
Permission-Camera: 8f0e5decca5f28f70f28a8dc31f012c9bad40ad8
Permission-PhotoLibrary: b209bf23b784c9e1409a57d81c6d11ab1d3079c1
RCTRequired: cec6a34b3ac8a9915c37e7e4ad3aa74726ce4035
@@ -598,10 +606,12 @@ SPEC CHECKSUMS:
RNPermissions: 8afd37dbc1be65748363c6a90caffd1806567651
RNReactNativeDocViewer: 571c6ac38483531b8fb521d02a6ba54652ed10a7
RNReactNativeHapticFeedback: 2566b468cc8d0e7bb2f84b23adc0f4614594d071
+ RNRudderSdk: 3abdcc4b145b3db6571827b0fc7af4e75a96af13
RNSentry: d892cbdee165cc6159d71e2a7954efdb8a361918
RNSVG: 7e16ddfc6e00d5aa69c9eb83e699bcce5dcb85d4
RNVectorIcons: 0bb4def82230be1333ddaeee9fcba45f0b288ed4
- SDWebImage: 7edb9c3ea661e77a66661f7f044de8c1b55d1120
+ Rudder: 358a71278045a608ae4b081b37a465ffb65c129d
+ SDWebImage: 84000f962cbfa70c07f19d2234cbfcf5d779b5dc
SDWebImageWebPCoder: 36f8f47bd9879a8aea6044765c1351120fd8e3a8
Sentry: 14bdd673870e8cf64932b149fad5bbbf39a9b390
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
diff --git a/package-lock.json b/package-lock.json
index 2fc51b9be..f18859e24 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5039,6 +5039,25 @@
}
}
},
+ "@rudderstack/rudder-sdk-react-native": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-0.1.2.tgz",
+ "integrity": "sha512-k7KMnRpNvk0DDu83sIJLKCuOWTmPn0c9qAbhQ0d91NU6QADG2466oYf8yobmLi29au0r5HAnK0M9kIEYKY+Y+g==",
+ "requires": {
+ "@babel/runtime": "^7.7.7",
+ "@types/react-native": "^0.62.2"
+ },
+ "dependencies": {
+ "@types/react-native": {
+ "version": "0.62.7",
+ "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.7.tgz",
+ "integrity": "sha512-FGFEt9GcFVl//XxWmxkeBxAx0YnzyEhJpR8hOJrjfaFKZm0KjHzzyCmCksBAP2qHSTrcJCiBkIvYCX/kGiOgww==",
+ "requires": {
+ "@types/react": "*"
+ }
+ }
+ }
+ },
"@sentry/browser": {
"version": "5.15.4",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.15.4.tgz",
@@ -5756,15 +5775,6 @@
"uri-js": "^4.2.2"
}
},
- "analytics-react-native": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/analytics-react-native/-/analytics-react-native-1.2.0.tgz",
- "integrity": "sha512-ppgJZjnsXMS5YMnYNEXm4LMxpoq08ghkz8l0wX+ECTKICkmP8t+KqKSy0sxCzbrltUyDEJLHOfOkeBr8Ieo7CA==",
- "requires": {
- "base-64": "0.1.0",
- "type-of": "2.0.1"
- }
- },
"anser": {
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/anser/-/anser-1.4.9.tgz",
@@ -22258,11 +22268,6 @@
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
},
- "type-of": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/type-of/-/type-of-2.0.1.tgz",
- "integrity": "sha1-5yoXQYllaOn2KDeNgW1pEvfyOXI="
- },
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
diff --git a/package.json b/package.json
index e0f76f50e..b6019e890 100644
--- a/package.json
+++ b/package.json
@@ -11,8 +11,8 @@
"@react-native-community/async-storage": "1.8.1",
"@react-native-community/cameraroll": "1.5.2",
"@react-native-community/netinfo": "4.4.0",
+ "@rudderstack/rudder-sdk-react-native": "0.1.2",
"@sentry/react-native": "1.3.6",
- "analytics-react-native": "1.2.0",
"commonmark": "github:mattermost/commonmark.js#f6ab98dede6ce4b4e7adea140ac77249bfb2d6ce",
"commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#3a2ac19cab725ad28b170fdc1d397dddedcf87eb",
"core-js": "3.6.4",
diff --git a/packager/moduleNames.js b/packager/moduleNames.js
index bb903d67f..1f67d784b 100644
--- a/packager/moduleNames.js
+++ b/packager/moduleNames.js
@@ -23,6 +23,7 @@ module.exports = [
'app/constants/view.js',
'app/constants/websocket.ts',
'app/i18n/index.js',
+ 'app/init/analytics.ts',
'app/init/credentials.js',
'app/init/device.js',
'app/init/emm_provider.js',
@@ -183,7 +184,6 @@ module.exports = [
'app/utils/preferences.js',
'app/utils/push_notifications.js',
'app/utils/security.js',
- 'app/utils/segment.js',
'app/utils/sentry/index.js',
'app/utils/time_tracker.js',
'app/utils/timezone.js',
diff --git a/packager/modulePaths.js b/packager/modulePaths.js
index bc5e3ec92..2ce82a1ed 100644
--- a/packager/modulePaths.js
+++ b/packager/modulePaths.js
@@ -23,6 +23,7 @@ module.exports = [
'./node_modules/app/constants/view.js',
'./node_modules/app/constants/websocket.ts',
'./node_modules/app/i18n/index.js',
+ './node_modules/app/init/analytics.ts',
'./node_modules/app/init/credentials.js',
'./node_modules/app/init/device.js',
'./node_modules/app/init/emm_provider.js',
@@ -183,7 +184,6 @@ module.exports = [
'./node_modules/app/utils/preferences.js',
'./node_modules/app/utils/push_notifications.js',
'./node_modules/app/utils/security.js',
- './node_modules/app/utils/segment.js',
'./node_modules/app/utils/sentry/index.js',
'./node_modules/app/utils/time_tracker.js',
'./node_modules/app/utils/timezone.js',
diff --git a/test/test_helper.js b/test/test_helper.js
index 334e709e5..32ec9ab4b 100644
--- a/test/test_helper.js
+++ b/test/test_helper.js
@@ -4,10 +4,8 @@
import assert from 'assert';
import nock from 'nock';
-import Config from 'assets/config.json';
-
+import Config from '@assets/config.json';
import Client from '@mm-redux/client/client4';
-
import {DEFAULT_LOCALE} from '@mm-redux/constants/general';
import {generateId} from '@mm-redux/utils/helpers';
diff --git a/tsconfig.json b/tsconfig.json
index efb2824c2..3a4cd9a29 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -29,12 +29,15 @@
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
+ "resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"@actions/*": ["app/actions/*"],
+ "@assets/*": ["dist/assets/*"],
"@constants/*": ["app/constants/*"],
"@constants": ["app/constants/index"],
"@i18n": ["app/i18n/index"],
+ "@init/*": ["app/init/*"],
"@mm-redux/*": ["app/mm-redux/*"],
"@selectors/*": ["app/selectors/*"],
"@store/*": ["app/store"],