diff --git a/.eslintrc.json b/.eslintrc.json index fa6d3dcd8f..47c6378d08 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,7 +8,8 @@ "parser": "@typescript-eslint/parser", "plugins": [ "@typescript-eslint", - "mattermost" + "mattermost", + "import" ], "settings": { "react": { @@ -58,7 +59,32 @@ "singleLine": { "beforeColon": false, "afterColon": true - }}] + }}], + "@typescript-eslint/member-delimiter-style": 2, + "import/order": [ + 2, + { + "groups": ["builtin", "external", "parent", "sibling", "index", "type"], + "newlines-between": "always", + "pathGroups": [ + { + "pattern": "{@(@actions|@app|@assets|@client|@components|@constants|@context|@database|@helpers|@hooks|@init|@queries|@screens|@selectors|@share|@store|@telemetry|@typings|@test|@utils)/**,@(@constants|@i18n|@notifications|@store|@websocket)}", + "group": "external", + "position": "after" + }, + { + "pattern": "app/**", + "group": "parent", + "position": "before" + } + ], + "alphabetize": { + "order": "asc", + "caseInsensitive": true + }, + "pathGroupsExcludedImportTypes": ["type"] + } + ] }, "overrides": [ { diff --git a/android/app/build.gradle b/android/app/build.gradle index b780ccdd93..f425e0240b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -224,6 +224,7 @@ configurations.all { dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' //noinspection GradleDynamicVersio implementation "com.facebook.react:react-native:+" // From node_modules diff --git a/android/app/src/main/java/com/mattermost/helpers/CustomPushNotificationHelper.java b/android/app/src/main/java/com/mattermost/helpers/CustomPushNotificationHelper.java index 3aa2b92ed5..7e4d45e74c 100644 --- a/android/app/src/main/java/com/mattermost/helpers/CustomPushNotificationHelper.java +++ b/android/app/src/main/java/com/mattermost/helpers/CustomPushNotificationHelper.java @@ -89,10 +89,6 @@ public class CustomPushNotificationHelper { } } -// if (serverUrl == null) { - message = "Unknown Server\n" + message; -// } - messagingStyle.addMessage(message, timestamp, sender.build()); } } diff --git a/android/app/src/main/java/com/mattermost/helpers/DatabaseHelper.java b/android/app/src/main/java/com/mattermost/helpers/DatabaseHelper.java deleted file mode 100644 index 6ce141a601..0000000000 --- a/android/app/src/main/java/com/mattermost/helpers/DatabaseHelper.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.mattermost.helpers; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; - -import com.nozbe.watermelondb.Database; - -public class DatabaseHelper { - private static final String DEFAULT_DATABASE_NAME = "app.db"; - private static Database defaultDatabase; - - private static void setDefaultDatabase(Context context) { - String databaseName = Uri.fromFile(context.getFilesDir()).toString() + "/" + DEFAULT_DATABASE_NAME; - defaultDatabase = new Database(databaseName, context); - } - - public static String getOnlyServerUrl(Context context) { - if (defaultDatabase == null) { - setDefaultDatabase(context); - } - - String emptyArray[] = {}; - String query = "SELECT url FROM Servers"; - Cursor cursor = defaultDatabase.rawQuery(query, emptyArray); - - if (cursor.getCount() == 1) { - cursor.moveToFirst(); - return cursor.getString(0); - } - - return null; - } -} diff --git a/android/app/src/main/java/com/mattermost/helpers/DatabaseHelper.kt b/android/app/src/main/java/com/mattermost/helpers/DatabaseHelper.kt new file mode 100644 index 0000000000..7d5564edac --- /dev/null +++ b/android/app/src/main/java/com/mattermost/helpers/DatabaseHelper.kt @@ -0,0 +1,525 @@ +package com.mattermost.helpers + +import android.content.Context +import android.net.Uri +import android.text.TextUtils +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.NoSuchKeyException +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.nozbe.watermelondb.Database +import com.nozbe.watermelondb.mapCursor +import org.json.JSONArray +import org.json.JSONObject +import java.lang.Exception +import java.util.* + +class DatabaseHelper { + var defaultDatabase: Database? = null + private set + + val onlyServerUrl: String? + get() { + val query = "SELECT url FROM Servers WHERE last_active_at != 0" + val cursor = defaultDatabase!!.rawQuery(query) + if (cursor.count == 1) { + cursor.moveToFirst() + val url = cursor.getString(0) + cursor.close() + return url + } + return null + } + + fun init(context: Context) { + if (defaultDatabase == null) { + setDefaultDatabase(context) + } + } + + fun find(db: Database, tableName: String, id: String?): ReadableMap? { + val args: Array = arrayOf(id) + try { + db.rawQuery("select * from $tableName where id == ? limit 1", args).use { cursor -> + if (cursor.count <= 0) { + return null + } + val resultMap = Arguments.createMap() + cursor.moveToFirst() + resultMap.mapCursor(cursor) + return resultMap + } + } catch (e: Exception) { + return null + } + } + + fun getDatabaseForServer(context: Context?, serverUrl: String): Database? { + val args: Array = arrayOf(serverUrl) + val query = "SELECT db_path FROM Servers WHERE url=?" + val cursor = defaultDatabase!!.rawQuery(query, args) + if (cursor.count == 1) { + cursor.moveToFirst() + val databasePath = cursor.getString(0) + cursor.close() + return Database(databasePath, context!!) + } + return null + } + + fun queryIds(db: Database, tableName: String, ids: Array): List { + val list: MutableList = ArrayList() + val args = TextUtils.join(",", Arrays.stream(ids).map { value: String? -> "?" }.toArray()) + try { + db.rawQuery("select distinct id from $tableName where id IN ($args)", ids as Array).use { cursor -> + if (cursor.count > 0) { + while (cursor.moveToNext()) { + list.add(cursor.getString(cursor.getColumnIndex("id"))) + } + } + } + } catch (e: Exception) { + e.printStackTrace() + } + return list + } + + fun queryByColumn(db: Database, tableName: String, columnName: String, values: Array): List { + val list: MutableList = ArrayList() + val args = TextUtils.join(",", Arrays.stream(values).map { value: Any? -> "?" }.toArray()) + try { + db.rawQuery("select distinct $columnName from $tableName where $columnName IN ($args)", values).use { cursor -> + if (cursor.count > 0) { + while (cursor.moveToNext()) { + list.add(cursor.getString(cursor.getColumnIndex(columnName))) + } + } + } + } catch (e: Exception) { + e.printStackTrace() + } + return list + } + + fun queryCurrentUserId(db: Database): String? { + val result = find(db, "System", "currentUserId")!! + return result.getString("value") + } + + fun queryPostSinceForChannel(db: Database?, channelId: String): Double? { + if (db != null) { + val postsInChannelQuery = "SELECT earliest, latest FROM PostsInChannel WHERE channel_id=? ORDER BY latest DESC LIMIT 1" + val cursor1 = db.rawQuery(postsInChannelQuery, arrayOf(channelId)) + if (cursor1.count == 1) { + cursor1.moveToFirst() + val earliest = cursor1.getDouble(0) + val latest = cursor1.getDouble(1) + cursor1.close() + val postQuery = "SELECT create_at FROM POST WHERE channel_id= ? AND delete_at=0 AND create_at BETWEEN ? AND ? ORDER BY create_at DESC" + val cursor2 = db.rawQuery(postQuery, arrayOf(channelId, earliest, latest)) + if (cursor2.count >= 60) { + cursor2.moveToFirst() + val createAt = cursor2.getDouble(0) + cursor2.close() + return createAt + } + } + } + return null + } + + fun handlePosts(db: Database, postsData: ReadableMap?, channelId: String) { + // Posts, PostInChannel, PostInThread, Reactions, Files, CustomEmojis, Users + if (postsData != null) { + val ordered = postsData.getArray("order")?.toArrayList() + val posts = ReadableMapUtils.toJSONObject(postsData.getMap("posts")).toMap() + val previousPostId = postsData.getString("prev_post_id") + val postsInThread = hashMapOf>() + var earliest = 0.0 + var latest = 0.0 + + if (ordered != null && posts.isNotEmpty()) { + val firstId = ordered.first() + val lastId = ordered.last() + var prevPostId = "" + + val sortedPosts = posts.toList().sortedBy { (_, value) -> + ((value as Map<*, *>).get("create_at") as Double) + } + + sortedPosts.forEachIndexed { index, it -> + val key = it.first + if (it.second != null) { + val post = (it.second as MutableMap) + + if (index == 0) { + post.putIfAbsent("prev_post_id", previousPostId) + } else if (!prevPostId.isNullOrEmpty()) { + post.putIfAbsent("prev_post_id", prevPostId) + } + + if (lastId == key) { + earliest = post.get("create_at") as Double + } else if (firstId == key) { + latest = post.get("create_at") as Double + } + + val jsonPost = JSONObject(post) + val rootId = post.get("root_id") as? String + + if (!rootId.isNullOrEmpty()) { + var thread = postsInThread.get(rootId)?.toMutableList() + if (thread == null) { + thread = mutableListOf() + } + + thread.add(jsonPost) + postsInThread.put(rootId, thread.toList()) + } + + if (find(db, "Post", key) == null) { + insertPost(db, jsonPost) + } else { + updatePost(db, jsonPost) + } + + if (ordered.contains(key)) { + prevPostId = key + } + } + } + } + + handlePostsInChannel(db, channelId, earliest, latest) + handlePostsInThread(db, postsInThread) + } + } + + fun handleUsers(db: Database, users: ReadableArray) { + for (i in 0 until users.size()) { + val user = users.getMap(i) + val roles = user.getString("roles") ?: "" + val isBot = try { + user.getBoolean("is_bot") + } catch (e: NoSuchKeyException) { + false + } + + + db.execute( + "insert into User (id, auth_service, update_at, delete_at, email, first_name, is_bot, is_guest, " + + "last_name, last_picture_update, locale, nickname, position, roles, status, username, notify_props, " + + "props, timezone, _status) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'created')", + arrayOf( + user.getString("id"), + user.getString("auth_service"), + user.getDouble("update_at"), + user.getDouble("delete_at"), + user.getString("email"), + user.getString("first_name"), + isBot, + roles.contains("system_guest"), + user.getString("last_name"), + user.getDouble("last_picture_update"), + user.getString("locale"), + user.getString("nickname"), + user.getString("position"), + roles, + "", + user.getString("username"), + "{}", + ReadableMapUtils.toJSONObject(user.getMap("props") ?: Arguments.createMap()).toString(), + ReadableMapUtils.toJSONObject(user.getMap("timezone") ?: Arguments.createMap()).toString(), + ) + ) + } + } + + private fun setDefaultDatabase(context: Context) { + val databaseName = "app.db" + val databasePath = Uri.fromFile(context.filesDir).toString() + "/" + databaseName + defaultDatabase = Database(databasePath, context) + } + + private fun insertPost(db: Database, post: JSONObject) { + var metadata: JSONObject? = null + var reactions: JSONArray? = null + var customEmojis: JSONArray? = null + var files: JSONArray? = null + + try { + metadata = post.getJSONObject("metadata") + reactions = metadata.remove("reactions") as JSONArray? + customEmojis = metadata.remove("emojis") as JSONArray? + files = metadata.remove("files") as JSONArray? + } catch (e: Exception) { + // no metadata found + metadata = JSONObject() + } + + db.execute( + "insert into Post " + + "(id, channel_id, create_at, delete_at, update_at, edit_at, is_pinned, message, metadata, original_id, pending_post_id, " + + "previous_post_id, root_id, type, user_id, props, _status)" + + " values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'created')", + arrayOf( + post.getString("id"), + post.getString("channel_id"), + post.getDouble("create_at"), + post.getDouble("delete_at"), + post.getDouble("update_at"), + post.getDouble("edit_at"), + post.getBoolean("is_pinned"), + post.getString("message"), + metadata.toString(), + post.getString("original_id"), + post.getString("pending_post_id"), + post.getString("prev_post_id"), + post.getString("root_id"), + post.getString("type"), + post.getString("user_id"), + post.getJSONObject("props").toString() + ) + ) + + if (reactions != null && reactions.length() > 0) { + insertReactions(db, reactions) + } + + if (customEmojis != null && customEmojis.length() > 0) { + insertCustomEmojis(db, customEmojis) + } + + if (files != null && files.length() > 0) { + insertFiles(db, files) + } + } + + private fun updatePost(db: Database, post: JSONObject) { + var metadata: JSONObject? = null + var reactions: JSONArray? = null + var customEmojis: JSONArray? = null + + try { + metadata = post.getJSONObject("metadata") + reactions = metadata.remove("reactions") as JSONArray? + customEmojis = metadata.remove("emojis") as JSONArray? + metadata.remove("files") + } catch (e: Exception) { + // no metadata found + metadata = JSONObject() + } + + db.execute( + "update Post SET channel_id = ?, create_at = ?, delete_at = ?, update_at =?, edit_at =?, " + + "is_pinned = ?, message = ?, metadata = ?, original_id = ?, pending_post_id = ?, previous_post_id = ?, " + + "root_id = ?, type = ?, user_id = ?, props = ?, _status = 'updated' " + + "where id = ?", + arrayOf( + post.getString("channel_id"), + post.getDouble("create_at"), + post.getDouble("delete_at"), + post.getDouble("update_at"), + post.getDouble("edit_at"), + post.getBoolean("is_pinned"), + post.getString("message"), + metadata.toString(), + post.getString("original_id"), + post.getString("pending_post_id"), + post.getString("prev_post_id"), + post.getString("root_id"), + post.getString("type"), + post.getString("user_id"), + post.getJSONObject("props").toString(), + post.getString("id"), + ) + ) + + if (reactions != null && reactions.length() > 0) { + db.execute("delete from Reaction where post_id = ?", arrayOf(post.getString("id"))) + insertReactions(db, reactions) + } + + if (customEmojis != null && customEmojis.length() > 0) { + insertCustomEmojis(db, customEmojis) + } + } + + private fun insertCustomEmojis(db: Database, customEmojis: JSONArray) { + for (i in 0 until customEmojis.length()) { + val emoji = customEmojis.getJSONObject(i) + if(find(db, "CustomEmoji", emoji.getString("id")) == null) { + db.execute( + "insert into CustomEmoji (id, name, _status) values (?, ?, 'created')", + arrayOf( + emoji.getString("id"), + emoji.getString("name"), + ) + ) + } + } + } + + private fun insertFiles(db: Database, files: JSONArray) { + for (i in 0 until files.length()) { + val file = files.getJSONObject(i) + db.execute( + "insert into File (id, extension, height, image_thumbnail, local_path, mime_type, name, post_id, size, width, _status) " + + "values (?, ?, ?, ?, '', ?, ?, ?, ?, ?, 'created')", + arrayOf( + file.getString("id"), + file.getString("extension"), + file.getInt("height"), + file.getString("mini_preview"), + file.getString("mime_type"), + file.getString("name"), + file.getString("post_id"), + file.getDouble("size"), + file.getInt("width") + ) + ) + } + } + + private fun insertReactions(db: Database, reactions: JSONArray) { + for (i in 0 until reactions.length()) { + val reaction = reactions.getJSONObject(i) + val id = RandomId.generate() + db.execute( + "insert into Reaction (id, create_at, emoji_name, post_id, user_id, _status) " + + "values (?, ?, ?, ?, ?, 'created')", + arrayOf( + id, + reaction.getDouble("create_at"), + reaction.getString("emoji_name"), + reaction.getString("post_id"), + reaction.getString("user_id") + ) + ) + } + } + + private fun handlePostsInChannel(db: Database, channelId: String, earliest: Double, latest: Double) { + db.rawQuery("select id, channel_id, earliest, latest from PostsInChannel where channel_id = ?", arrayOf(channelId)).use { cursor -> + if (cursor.count == 0) { + // create new post in channel + insertPostInChannel(db, channelId, earliest, latest) + return + } + + val resultArray = Arguments.createArray() + while (cursor.moveToNext()) { + val cursorMap = Arguments.createMap() + cursorMap.mapCursor(cursor) + resultArray.pushMap(cursorMap) + } + + val chunk = findPostInChannel(resultArray, earliest, latest) + if (chunk != null) { + db.execute( + "update PostsInChannel set earliest = ?, latest = ?, _status = 'updated' where id = ?", + arrayOf( + minOf(earliest, chunk.getDouble("earliest")), + maxOf(latest, chunk.getDouble("latest")), + chunk.getString("id") + ) + ) + return + } + + val newChunk = insertPostInChannel(db, channelId, earliest, latest) + mergePostsInChannel(db, resultArray, newChunk) + } + } + + private fun findPostInChannel(chunks: ReadableArray, earliest: Double, latest: Double): ReadableMap? { + for (i in 0 until chunks.size()) { + val chunk = chunks.getMap(i) + if (earliest >= chunk.getDouble("earliest") || latest <= chunk.getDouble("latest")) { + return chunk; + } + } + + return null; + } + + private fun insertPostInChannel(db: Database, channelId: String, earliest: Double, latest: Double): ReadableMap { + val id = RandomId.generate() + db.execute("insert into PostsInChannel (id, channel_id, earliest, latest, _status) values (?, ?, ?, ?, 'created')", + arrayOf(id, channelId, earliest, latest)) + + val map = Arguments.createMap() + map.putString("id", id) + map.putString("channel_id", channelId) + map.putDouble("earliest", earliest) + map.putDouble("latest", latest) + return map + } + + private fun mergePostsInChannel(db: Database, existingChunks: ReadableArray, newChunk: ReadableMap) { + for (i in 0 until existingChunks.size()) { + val chunk = existingChunks.getMap(i) + if (newChunk.getDouble("earliest") <= chunk.getDouble("earliest") && + newChunk.getDouble("latest") >= chunk.getDouble("latest")) { + db.execute("delete from PostsInChannel where id = ?", arrayOf(chunk.getString("id"))) + break + } + } + } + + private fun handlePostsInThread(db: Database, postsInThread: Map>) { + postsInThread.forEach { (key, list) -> + val sorted = list.sortedBy { it.getDouble("create_at") } + val earliest = sorted.first().getDouble("create_at") + val latest = sorted.last().getDouble("create_at") + db.rawQuery("select * from PostsInThread where root_id = ? order by latest desc", arrayOf(key)).use { cursor -> + if (cursor.count > 0) { + cursor.moveToFirst() + val cursorMap = Arguments.createMap() + cursorMap.mapCursor(cursor) + db.execute( + "update PostsInThread set earliest = ?, latest = ?, _status = 'updated' where id = ?", + arrayOf( + minOf(earliest, cursorMap.getDouble("earliest")), + maxOf(latest, cursorMap.getDouble("latest")), + key + ) + ) + return + } + + val id = RandomId.generate() + db.execute( + "insert into PostsInThread (id, root_id, earliest, latest, _status) " + + "values (?, ?, ?, ?, 'created')", + arrayOf(id, key, earliest, latest) + ) + } + } + } + + private fun JSONObject.toMap(): Map = keys().asSequence().associateWith { + when (val value = this[it]) + { + is JSONArray -> + { + val map = (0 until value.length()).associate { Pair(it.toString(), value[it]) } + JSONObject(map).toMap().values.toList() + } + is JSONObject -> value.toMap() + JSONObject.NULL -> null + else -> value + } + } + + companion object { + var instance: DatabaseHelper? = null + get() { + if (field == null) { + field = DatabaseHelper() + } + return field + } + private set + } +} diff --git a/android/app/src/main/java/com/mattermost/helpers/Network.java b/android/app/src/main/java/com/mattermost/helpers/Network.java new file mode 100644 index 0000000000..930a41cf77 --- /dev/null +++ b/android/app/src/main/java/com/mattermost/helpers/Network.java @@ -0,0 +1,67 @@ +package com.mattermost.helpers; + +import android.content.Context; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.ReadableMap; + +import com.mattermost.networkclient.APIClientModule; +import com.mattermost.networkclient.enums.RetryTypes; + +import okhttp3.HttpUrl; + + +public class Network { + private static APIClientModule clientModule; + private static final WritableMap clientOptions = Arguments.createMap(); + private static final Promise emptyPromise = new ResolvePromise(); + + public static void init(Context context) { + final ReactApplicationContext reactContext = new ReactApplicationContext(context); + clientModule = new APIClientModule(reactContext); + createClientOptions(); + } + + public static void get(String baseUrl, String endpoint, ReadableMap options, Promise promise) { + createClientIfNeeded(baseUrl); + clientModule.get(baseUrl, endpoint, options, promise); + } + + public static void post(String baseUrl, String endpoint, ReadableMap options, Promise promise) { + createClientIfNeeded(baseUrl); + clientModule.post(baseUrl, endpoint, options, promise); + } + + private static void createClientOptions() { + WritableMap headers = Arguments.createMap(); + headers.putString("X-Requested-With", "XMLHttpRequest"); + clientOptions.putMap("headers", headers); + + WritableMap retryPolicyConfiguration = Arguments.createMap(); + retryPolicyConfiguration.putString("type", RetryTypes.EXPONENTIAL_RETRY.getType()); + retryPolicyConfiguration.putDouble("retryLimit", 2); + retryPolicyConfiguration.putDouble("exponentialBackoffBase", 2); + retryPolicyConfiguration.putDouble("exponentialBackoffScale", 0.5); + clientOptions.putMap("retryPolicyConfiguration", retryPolicyConfiguration); + + WritableMap requestAdapterConfiguration = Arguments.createMap(); + requestAdapterConfiguration.putString("bearerAuthTokenResponseHeader", "token"); + clientOptions.putMap("requestAdapterConfiguration", requestAdapterConfiguration); + + WritableMap sessionConfiguration = Arguments.createMap(); + sessionConfiguration.putInt("httpMaximumConnectionsPerHost", 10); + sessionConfiguration.putDouble("timeoutIntervalForRequest", 30000); + sessionConfiguration.putDouble("timeoutIntervalForResource", 30000); + clientOptions.putMap("sessionConfiguration", sessionConfiguration); + } + + private static void createClientIfNeeded(String baseUrl) { + HttpUrl url = HttpUrl.parse(baseUrl); + if (url != null && !clientModule.hasClientFor(url)) { + clientModule.createClientFor(baseUrl, clientOptions, emptyPromise); + } + } +} diff --git a/android/app/src/main/java/com/mattermost/helpers/PushNotificationDataHelper.kt b/android/app/src/main/java/com/mattermost/helpers/PushNotificationDataHelper.kt new file mode 100644 index 0000000000..237a505252 --- /dev/null +++ b/android/app/src/main/java/com/mattermost/helpers/PushNotificationDataHelper.kt @@ -0,0 +1,199 @@ +package com.mattermost.helpers + +import android.content.Context +import android.os.Bundle +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.nozbe.watermelondb.Database +import java.io.IOException +import java.util.concurrent.Executors +import kotlin.coroutines.* +import kotlinx.coroutines.* + +class PushNotificationDataHelper(private val context: Context) { + private var scope = Executors.newSingleThreadExecutor() + fun fetchAndStoreDataForPushNotification(initialData: Bundle) { + scope.execute(Runnable { + runBlocking { + PushNotificationDataRunnable.start(context, initialData) + } + }) + } +} + +class PushNotificationDataRunnable { + companion object { + private val specialMentions = listOf("all", "here", "channel") + @Synchronized + suspend fun start(context: Context, initialData: Bundle) { + try { + val serverUrl: String = initialData.getString("server_url") ?: return + val channelId = initialData.getString("channel_id") + val db = DatabaseHelper.instance!!.getDatabaseForServer(context, serverUrl) + + if (db != null) { + var postData: ReadableMap? + var posts: ReadableMap? = null + var userIdsToLoad: ReadableArray? = null + var usernamesToLoad: ReadableArray? = null + + coroutineScope { + if (channelId != null) { + postData = fetchPosts(db, serverUrl, channelId) + posts = postData?.getMap("posts") + userIdsToLoad = postData?.getArray("userIdsToLoad") + usernamesToLoad = postData?.getArray("usernamesToLoad") + + if (userIdsToLoad != null && userIdsToLoad!!.size() > 0) { + val users = fetchUsersById(serverUrl, userIdsToLoad!!) + userIdsToLoad = users?.getArray("data") + } + + if (usernamesToLoad != null && usernamesToLoad!!.size() > 0) { + val users = fetchUsersByUsernames(serverUrl, usernamesToLoad!!) + usernamesToLoad = users?.getArray("data") + } + } + } + + db.transaction { + if (posts != null && channelId != null) { + DatabaseHelper.instance!!.handlePosts(db, posts!!.getMap("data"), channelId) + } + + if (userIdsToLoad != null && userIdsToLoad!!.size() > 0) { + DatabaseHelper.instance!!.handleUsers(db, userIdsToLoad!!) + } + + if (usernamesToLoad != null && usernamesToLoad!!.size() > 0) { + DatabaseHelper.instance!!.handleUsers(db, usernamesToLoad!!) + } + } + + db.close() + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private suspend fun fetchPosts(db: Database, serverUrl: String, channelId: String): ReadableMap? { + val regex = Regex("""\B@(([a-z0-9-._]*[a-z0-9_])[.-]*)""", setOf(RegexOption.IGNORE_CASE)) + val since = DatabaseHelper.instance!!.queryPostSinceForChannel(db, channelId) + val currentUserId = DatabaseHelper.instance!!.queryCurrentUserId(db)?.removeSurrounding("\"") + val currentUser = DatabaseHelper.instance!!.find(db, "User", currentUserId) + val currentUsername = currentUser?.getString("username") + val queryParams = if (since == null) "?page=0&per_page=60" else "?since=${since.toLong()}" + val endpoint = "/api/v4/channels/$channelId/posts$queryParams" + val postsResponse = fetch(serverUrl, endpoint) + val results = Arguments.createMap() + + if (postsResponse != null) { + val data = ReadableMapUtils.toMap(postsResponse) + results.putMap("posts", postsResponse) + val postsData = data.get("data") as? Map<*, *> + if (postsData != null) { + val postsMap = postsData.get("posts") + if (postsMap != null) { + val posts = ReadableMapUtils.toWritableMap(postsMap as? Map) + val iterator = posts.keySetIterator() + val userIds = mutableListOf() + val usernames = mutableListOf() + while(iterator.hasNextKey()) { + val key = iterator.nextKey() + val post = posts.getMap(key) + val userId = post?.getString("user_id") + if (userId != null && userId != currentUserId && !userIds.contains(userId)) { + userIds.add(userId) + } + val message = post?.getString("message") + if (message != null) { + val matchResults = regex.findAll(message) + matchResults.iterator().forEach { + val username = it.value.removePrefix("@") + if (!usernames.contains(username) && currentUsername != username && !specialMentions.contains(username)) { + usernames.add(username) + } + } + } + } + + val existingUserIds = DatabaseHelper.instance!!.queryIds(db, "User", userIds.toTypedArray()) + val existingUsernames = DatabaseHelper.instance!!.queryByColumn(db, "User", "username", usernames.toTypedArray()) + userIds.removeAll { it in existingUserIds } + usernames.removeAll { it in existingUsernames } + + if (userIds.size > 0) { + results.putArray("userIdsToLoad", ReadableArrayUtils.toWritableArray(userIds.toTypedArray())) + } + + if (usernames.size > 0) { + results.putArray("usernamesToLoad", ReadableArrayUtils.toWritableArray(usernames.toTypedArray())) + } + } + } + } + + + return results + } + + private suspend fun fetchUsersById(serverUrl: String, userIds: ReadableArray): ReadableMap? { + val endpoint = "api/v4/users/ids" + val options = Arguments.createMap() + options.putArray("body", ReadableArrayUtils.toWritableArray(ReadableArrayUtils.toArray(userIds))) + return fetchWithPost(serverUrl, endpoint, options); + } + + private suspend fun fetchUsersByUsernames(serverUrl: String, usernames: ReadableArray): ReadableMap? { + val endpoint = "api/v4/users/usernames" + val options = Arguments.createMap() + options.putArray("body", ReadableArrayUtils.toWritableArray(ReadableArrayUtils.toArray(usernames))) + return fetchWithPost(serverUrl, endpoint, options); + } + + private suspend fun fetch(serverUrl: String, endpoint: String): ReadableMap? { + return suspendCoroutine { cont -> + Network.get(serverUrl, endpoint, null, object : ResolvePromise() { + override fun resolve(value: Any?) { + val response = value as ReadableMap? + if (response != null && !response.getBoolean("ok")) { + val error = response.getMap("data") + cont.resumeWith(Result.failure((IOException("Unexpected code ${error?.getInt("status_code")} ${error?.getString("message")}")))) + } else { + cont.resumeWith(Result.success(response)) + } + } + + override fun reject(code: String, message: String) { + cont.resumeWith(Result.failure(IOException("Unexpected code $code $message"))) + } + + override fun reject(reason: Throwable?) { + cont.resumeWith(Result.failure(IOException("Unexpected code $reason"))) + } + }) + } + } + + private suspend fun fetchWithPost(serverUrl: String, endpoint: String, options: ReadableMap?) : ReadableMap? { + return suspendCoroutine { cont -> + Network.post(serverUrl, endpoint, options, object : ResolvePromise() { + override fun resolve(value: Any?) { + val response = value as ReadableMap? + cont.resumeWith(Result.success(response)) + } + + override fun reject(code: String, message: String) { + cont.resumeWith(Result.failure(IOException("Unexpected code $code $message"))) + } + + override fun reject(reason: Throwable?) { + cont.resumeWith(Result.failure(IOException("Unexpected code $reason"))) + } + }) + } + } + } +} diff --git a/android/app/src/main/java/com/mattermost/helpers/RandomId.kt b/android/app/src/main/java/com/mattermost/helpers/RandomId.kt new file mode 100644 index 0000000000..bebe1f4950 --- /dev/null +++ b/android/app/src/main/java/com/mattermost/helpers/RandomId.kt @@ -0,0 +1,22 @@ +package com.mattermost.helpers + +import kotlin.math.floor + +class RandomId { + companion object { + private const val alphabet = "0123456789abcdefghijklmnopqrstuvwxyz" + private const val alphabetLenght = alphabet.length + private const val idLenght = 16 + + fun generate(): String { + var id = "" + for (i in 1.rangeTo((idLenght / 2))) { + val random = floor(Math.random() * alphabetLenght * alphabetLenght) + id += alphabet[floor(random / alphabetLenght).toInt()] + id += alphabet[(random % alphabetLenght).toInt()] + } + + return id + } + } +} diff --git a/android/app/src/main/java/com/mattermost/helpers/ReadableArrayUtils.java b/android/app/src/main/java/com/mattermost/helpers/ReadableArrayUtils.java new file mode 100644 index 0000000000..eb2e473c8a --- /dev/null +++ b/android/app/src/main/java/com/mattermost/helpers/ReadableArrayUtils.java @@ -0,0 +1,125 @@ +package com.mattermost.helpers; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableType; +import com.facebook.react.bridge.WritableArray; + +import java.util.Map; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONException; + +public class ReadableArrayUtils { + public static JSONArray toJSONArray(ReadableArray readableArray) throws JSONException { + JSONArray jsonArray = new JSONArray(); + + for (int i = 0; i < readableArray.size(); i++) { + ReadableType type = readableArray.getType(i); + + switch (type) { + case Null: + jsonArray.put(i, null); + break; + case Boolean: + jsonArray.put(i, readableArray.getBoolean(i)); + break; + case Number: + jsonArray.put(i, readableArray.getDouble(i)); + break; + case String: + jsonArray.put(i, readableArray.getString(i)); + break; + case Map: + jsonArray.put(i, ReadableMapUtils.toJSONObject(readableArray.getMap(i))); + break; + case Array: + jsonArray.put(i, ReadableArrayUtils.toJSONArray(readableArray.getArray(i))); + break; + } + } + + return jsonArray; + } + + public static Object[] toArray(JSONArray jsonArray) throws JSONException { + Object[] array = new Object[jsonArray.length()]; + + for (int i = 0; i < jsonArray.length(); i++) { + Object value = jsonArray.get(i); + + if (value instanceof JSONObject) { + value = ReadableMapUtils.toMap((JSONObject) value); + } + if (value instanceof JSONArray) { + value = ReadableArrayUtils.toArray((JSONArray) value); + } + + array[i] = value; + } + + return array; + } + + public static Object[] toArray(ReadableArray readableArray) { + Object[] array = new Object[readableArray.size()]; + + for (int i = 0; i < readableArray.size(); i++) { + ReadableType type = readableArray.getType(i); + + switch (type) { + case Null: + array[i] = null; + break; + case Boolean: + array[i] = readableArray.getBoolean(i); + break; + case Number: + array[i] = readableArray.getDouble(i); + break; + case String: + array[i] = readableArray.getString(i); + break; + case Map: + array[i] = ReadableMapUtils.toMap(readableArray.getMap(i)); + break; + case Array: + array[i] = ReadableArrayUtils.toArray(readableArray.getArray(i)); + break; + } + } + + return array; + } + + public static WritableArray toWritableArray(Object[] array) { + WritableArray writableArray = Arguments.createArray(); + + for (Object value : array) { + if (value == null) { + writableArray.pushNull(); + } + if (value instanceof Boolean) { + writableArray.pushBoolean((Boolean) value); + } + if (value instanceof Double) { + writableArray.pushDouble((Double) value); + } + if (value instanceof Integer) { + writableArray.pushInt((Integer) value); + } + if (value instanceof String) { + writableArray.pushString((String) value); + } + if (value instanceof Map) { + writableArray.pushMap(ReadableMapUtils.toWritableMap((Map) value)); + } + if (value.getClass().isArray()) { + writableArray.pushArray(ReadableArrayUtils.toWritableArray((Object[]) value)); + } + } + + return writableArray; + } +} diff --git a/android/app/src/main/java/com/mattermost/helpers/ReadableMapUtils.java b/android/app/src/main/java/com/mattermost/helpers/ReadableMapUtils.java new file mode 100644 index 0000000000..4a25b5012e --- /dev/null +++ b/android/app/src/main/java/com/mattermost/helpers/ReadableMapUtils.java @@ -0,0 +1,135 @@ +package com.mattermost.helpers; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.ReadableMapKeySetIterator; +import com.facebook.react.bridge.ReadableType; +import com.facebook.react.bridge.WritableMap; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class ReadableMapUtils { + public static JSONObject toJSONObject(ReadableMap readableMap) throws JSONException { + JSONObject jsonObject = new JSONObject(); + + ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); + + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + ReadableType type = readableMap.getType(key); + + switch (type) { + case Null: + jsonObject.put(key, null); + break; + case Boolean: + jsonObject.put(key, readableMap.getBoolean(key)); + break; + case Number: + jsonObject.put(key, readableMap.getDouble(key)); + break; + case String: + jsonObject.put(key, readableMap.getString(key)); + break; + case Map: + jsonObject.put(key, ReadableMapUtils.toJSONObject(readableMap.getMap(key))); + break; + case Array: + jsonObject.put(key, ReadableArrayUtils.toJSONArray(readableMap.getArray(key))); + break; + } + } + + return jsonObject; + } + + public static Map toMap(JSONObject jsonObject) throws JSONException { + Map map = new HashMap<>(); + Iterator iterator = jsonObject.keys(); + + while (iterator.hasNext()) { + String key = iterator.next(); + Object value = jsonObject.get(key); + + if (value instanceof JSONObject) { + value = ReadableMapUtils.toMap((JSONObject) value); + } + if (value instanceof JSONArray) { + value = ReadableArrayUtils.toArray((JSONArray) value); + } + + map.put(key, value); + } + + return map; + } + + public static Map toMap(ReadableMap readableMap) { + Map map = new HashMap<>(); + ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); + + while (iterator.hasNextKey()) { + String key = iterator.nextKey(); + ReadableType type = readableMap.getType(key); + + switch (type) { + case Null: + map.put(key, null); + break; + case Boolean: + map.put(key, readableMap.getBoolean(key)); + break; + case Number: + map.put(key, readableMap.getDouble(key)); + break; + case String: + map.put(key, readableMap.getString(key)); + break; + case Map: + map.put(key, ReadableMapUtils.toMap(readableMap.getMap(key))); + break; + case Array: + map.put(key, ReadableArrayUtils.toArray(readableMap.getArray(key))); + break; + } + } + + return map; + } + + public static WritableMap toWritableMap(Map map) { + WritableMap writableMap = Arguments.createMap(); + Iterator iterator = map.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry pair = (Map.Entry)iterator.next(); + Object value = pair.getValue(); + + if (value == null) { + writableMap.putNull((String) pair.getKey()); + } else if (value instanceof Boolean) { + writableMap.putBoolean((String) pair.getKey(), (Boolean) value); + } else if (value instanceof Double) { + writableMap.putDouble((String) pair.getKey(), (Double) value); + } else if (value instanceof Integer) { + writableMap.putInt((String) pair.getKey(), (Integer) value); + } else if (value instanceof String) { + writableMap.putString((String) pair.getKey(), (String) value); + } else if (value instanceof Map) { + writableMap.putMap((String) pair.getKey(), ReadableMapUtils.toWritableMap((Map) value)); + } else if (value.getClass() != null && value.getClass().isArray()) { + writableMap.putArray((String) pair.getKey(), ReadableArrayUtils.toWritableArray((Object[]) value)); + } + + iterator.remove(); + } + + return writableMap; + } +} diff --git a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java index f226ec4905..536de78f3a 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java @@ -21,12 +21,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import com.mattermost.helpers.CustomPushNotificationHelper; import com.mattermost.helpers.DatabaseHelper; +import com.mattermost.helpers.Network; +import com.mattermost.helpers.PushNotificationDataHelper; import com.mattermost.helpers.ResolvePromise; -import com.wix.reactnativenotifications.core.NotificationIntentAdapter; -import com.wix.reactnativenotifications.core.ProxyService; import com.wix.reactnativenotifications.core.notification.PushNotification; import com.wix.reactnativenotifications.core.AppLaunchHelper; import com.wix.reactnativenotifications.core.AppLifecycleFacade; @@ -43,12 +44,16 @@ public class CustomPushNotification extends PushNotification { private static final String PUSH_TYPE_CLEAR = "clear"; private static final String PUSH_TYPE_SESSION = "session"; private static final String NOTIFICATIONS_IN_CHANNEL = "notificationsInChannel"; + private final PushNotificationDataHelper dataHelper; public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) { super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper); CustomPushNotificationHelper.createNotificationChannels(context); + dataHelper = new PushNotificationDataHelper(context); try { + Objects.requireNonNull(DatabaseHelper.Companion.getInstance()).init(context); + Network.init(context); PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); String version = String.valueOf(pInfo.versionCode); String storedVersion = null; @@ -151,7 +156,9 @@ public class CustomPushNotification extends PushNotification { public void resolve(@Nullable Object value) { if (isIdLoaded) { Bundle response = (Bundle) value; - addServerUrlToBundle(response); + if (value != null) { + addServerUrlToBundle(response); + } } } @@ -169,10 +176,14 @@ public class CustomPushNotification extends PushNotification { if (!mAppLifecycleFacade.isAppVisible()) { if (type.equals(PUSH_TYPE_MESSAGE)) { if (channelId != null) { + if (serverUrl != null) { + dataHelper.fetchAndStoreDataForPushNotification(mNotificationProps.asBundle()); + } + Map> notificationsInChannel = loadNotificationsMap(mContext); List list = notificationsInChannel.get(channelId); if (list == null) { - list = Collections.synchronizedList(new ArrayList(0)); + list = Collections.synchronizedList(new ArrayList<>(0)); } list.add(0, notificationId); @@ -259,7 +270,7 @@ public class CustomPushNotification extends PushNotification { private String addServerUrlToBundle(Bundle bundle) { String serverUrl = bundle.getString("server_url"); if (serverUrl == null) { - serverUrl = DatabaseHelper.getOnlyServerUrl(mContext); + serverUrl = Objects.requireNonNull(DatabaseHelper.Companion.getInstance()).getOnlyServerUrl(); bundle.putString("server_url", serverUrl); mNotificationProps = createProps(bundle); } @@ -269,13 +280,13 @@ public class CustomPushNotification extends PushNotification { private static void saveNotificationsMap(Context context, Map> inputMap) { SharedPreferences pSharedPref = context.getSharedPreferences(PUSH_NOTIFICATIONS, Context.MODE_PRIVATE); - if (pSharedPref != null && context != null) { + if (pSharedPref != null) { JSONObject json = new JSONObject(inputMap); String jsonString = json.toString(); SharedPreferences.Editor editor = pSharedPref.edit(); - editor.remove(NOTIFICATIONS_IN_CHANNEL).commit(); + editor.remove(NOTIFICATIONS_IN_CHANNEL).apply(); editor.putString(NOTIFICATIONS_IN_CHANNEL, jsonString); - editor.commit(); + editor.apply(); } } diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java index 127e03ee4a..e6dfc819b1 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java @@ -126,8 +126,10 @@ public class MainApplication extends NavigationApplication implements INotificat super.onCreate(); instance = this; + Context context = getApplicationContext(); + // Delete any previous temp files created by the app - File tempFolder = new File(getApplicationContext().getCacheDir(), RealPathUtil.CACHE_DIR_NAME); + File tempFolder = new File(context.getCacheDir(), RealPathUtil.CACHE_DIR_NAME); RealPathUtil.deleteTempFiles(tempFolder); Log.i("ReactNative", "Cleaning temp cache " + tempFolder.getAbsolutePath()); diff --git a/android/build.gradle b/android/build.gradle index 1cfccc6532..862cc615a0 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,8 +8,8 @@ buildscript { targetSdkVersion = 29 ndkVersion = "20.1.5948944" supportLibVersion = "28.0.0" - kotlinVersion = "1.4.30" - kotlin_version = "1.4.30" + kotlinVersion = "1.5.30" + kotlin_version = "1.5.30" firebaseVersion = "21.0.0" RNNKotlinVersion = kotlinVersion } diff --git a/app/actions/local/channel.ts b/app/actions/local/channel.ts index 39b47ec0b2..0b19be40a2 100644 --- a/app/actions/local/channel.ts +++ b/app/actions/local/channel.ts @@ -11,16 +11,15 @@ import {General} from '@constants'; import DatabaseManager from '@database/manager'; import {privateChannelJoinPrompt} from '@helpers/api/channel'; import {prepareMyChannelsForTeam, queryMyChannel} from '@queries/servers/channel'; -import {addChannelToTeamHistory, prepareMyTeams, queryMyTeamById, queryTeamById, queryTeamByName} from '@queries/servers/team'; import {queryCommonSystemValues, setCurrentChannelId, setCurrentTeamAndChannelId} from '@queries/servers/system'; +import {addChannelToTeamHistory, prepareMyTeams, queryMyTeamById, queryTeamById, queryTeamByName} from '@queries/servers/team'; import {PERMALINK_GENERIC_TEAM_NAME_REDIRECT} from '@utils/url'; -import type {IntlShape} from 'react-intl'; - import type ChannelModel from '@typings/database/models/servers/channel'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; import type MyTeamModel from '@typings/database/models/servers/my_team'; import type TeamModel from '@typings/database/models/servers/team'; +import type {IntlShape} from 'react-intl'; export const switchToChannel = async (serverUrl: string, channelId: string) => { const database = DatabaseManager.serverDatabases[serverUrl]?.database; diff --git a/app/actions/local/permalink.ts b/app/actions/local/permalink.ts index e475a0a9b0..8a6dbacb45 100644 --- a/app/actions/local/permalink.ts +++ b/app/actions/local/permalink.ts @@ -3,8 +3,6 @@ import {Keyboard} from 'react-native'; -import type {IntlShape} from 'react-intl'; - import {fetchMyChannelsForTeam} from '@actions/remote/channel'; import DatabaseManager from '@database/manager'; import {queryCommonSystemValues} from '@queries/servers/system'; @@ -15,6 +13,7 @@ import {changeOpacity} from '@utils/theme'; import {PERMALINK_GENERIC_TEAM_NAME_REDIRECT} from '@utils/url'; import type TeamModel from '@typings/database/models/servers/team'; +import type {IntlShape} from 'react-intl'; let showingPermalink = false; diff --git a/app/actions/local/post.ts b/app/actions/local/post.ts index 4620c51112..177698f091 100644 --- a/app/actions/local/post.ts +++ b/app/actions/local/post.ts @@ -8,8 +8,8 @@ import {queryPostById} from '@queries/servers/post'; import {queryCurrentUserId} from '@queries/servers/system'; import {generateId} from '@utils/general'; -import type UserModel from '@typings/database/models/servers/user'; import type PostModel from '@typings/database/models/servers/post'; +import type UserModel from '@typings/database/models/servers/user'; export const sendAddToChannelEphemeralPost = async (serverUrl: string, user: UserModel, addedUsernames: string[], messages: string[], channeId: string, postRootId = '') => { const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; diff --git a/app/actions/local/push_notification.ts b/app/actions/local/push_notification.ts index 8808dddf9c..3b2a3840e0 100644 --- a/app/actions/local/push_notification.ts +++ b/app/actions/local/push_notification.ts @@ -2,12 +2,12 @@ // See LICENSE.txt for license information. import moment from 'moment-timezone'; +import {createIntl} from 'react-intl'; import {getSessions} from '@actions/remote/session'; import {DEFAULT_LOCALE, getTranslations} from '@i18n'; import PushNotifications from '@init/push_notifications'; import {sortByNewest} from '@utils/general'; -import {createIntl} from 'react-intl'; export const scheduleExpiredNotification = async (serverUrl: string, config: Partial, userId: string, locale = DEFAULT_LOCALE) => { if (config.ExtendSessionLengthWithActivity === 'true') { diff --git a/app/actions/local/timezone.ts b/app/actions/local/timezone.ts index 955048a08f..2574a0871a 100644 --- a/app/actions/local/timezone.ts +++ b/app/actions/local/timezone.ts @@ -3,9 +3,9 @@ import {getTimeZone} from 'react-native-localize'; +import {updateMe} from '@actions/remote/user'; import DatabaseManager from '@database/manager'; import {queryUserById} from '@queries/servers/user'; -import {updateMe} from '@actions/remote/user'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/actions/remote/channel.ts b/app/actions/remote/channel.ts index 7a64e8e47c..367256ad8f 100644 --- a/app/actions/remote/channel.ts +++ b/app/actions/remote/channel.ts @@ -11,9 +11,8 @@ import {fetchRolesIfNeeded} from './role'; import {forceLogoutIfNecessary} from './session'; import {fetchProfilesPerChannels, fetchUsersByIds} from './user'; -import type {Model} from '@nozbe/watermelondb'; - import type {Client} from '@client/rest'; +import type {Model} from '@nozbe/watermelondb'; export type MyChannelsRequest = { channels?: Channel[]; diff --git a/app/actions/remote/general.ts b/app/actions/remote/general.ts index 374d720430..dd25cfdd9a 100644 --- a/app/actions/remote/general.ts +++ b/app/actions/remote/general.ts @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import type {ClientResponse} from '@mattermost/react-native-network-client'; - import {SYSTEM_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; import NetworkManager from '@init/network_manager'; @@ -11,6 +9,7 @@ import {queryExpandedLinks} from '@queries/servers/system'; import {forceLogoutIfNecessary} from './session'; import type {Client} from '@client/rest'; +import type {ClientResponse} from '@mattermost/react-native-network-client'; export const doPing = async (serverUrl: string) => { const client = await NetworkManager.createClient(serverUrl); diff --git a/app/actions/remote/reactions.ts b/app/actions/remote/reactions.ts index 4e4f382dc8..fce12e393e 100644 --- a/app/actions/remote/reactions.ts +++ b/app/actions/remote/reactions.ts @@ -1,5 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. + import {Q} from '@nozbe/watermelondb'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; diff --git a/app/actions/remote/session.ts b/app/actions/remote/session.ts index efc8965246..c1253d5633 100644 --- a/app/actions/remote/session.ts +++ b/app/actions/remote/session.ts @@ -11,12 +11,12 @@ import {queryDeviceToken} from '@queries/app/global'; import {queryCurrentUserId, queryCommonSystemValues} from '@queries/servers/system'; import {getCSRFFromCookie} from '@utils/security'; -import type {LoginArgs} from '@typings/database/database'; - -import {logError} from './error'; import {loginEntry} from './entry'; +import {logError} from './error'; import {fetchDataRetentionPolicy} from './systems'; +import type {LoginArgs} from '@typings/database/database'; + const HTTP_UNAUTHORIZED = 401; export const completeLogin = async (serverUrl: string, user: UserProfile) => { diff --git a/app/actions/remote/team.ts b/app/actions/remote/team.ts index f98c5695dc..2bb8aef17a 100644 --- a/app/actions/remote/team.ts +++ b/app/actions/remote/team.ts @@ -12,8 +12,9 @@ import {fetchMyChannelsForTeam} from './channel'; import {fetchPostsForUnreadChannels} from './post'; import {fetchRolesIfNeeded} from './role'; import {forceLogoutIfNecessary} from './session'; -import TeamModel from '@typings/database/models/servers/team'; -import TeamMembershipModel from '@typings/database/models/servers/team_membership'; + +import type TeamModel from '@typings/database/models/servers/team'; +import type TeamMembershipModel from '@typings/database/models/servers/team_membership'; export type MyTeamsRequest = { teams?: Team[]; diff --git a/app/actions/remote/user.ts b/app/actions/remote/user.ts index 4ecc45a39c..297d551ebc 100644 --- a/app/actions/remote/user.ts +++ b/app/actions/remote/user.ts @@ -2,22 +2,23 @@ // See LICENSE.txt for license information. import {Q} from '@nozbe/watermelondb'; + import {fetchRolesIfNeeded} from '@actions/remote/role'; import {Database, General} from '@constants'; import DatabaseManager from '@database/manager'; import {debounce} from '@helpers/api/general'; import analytics from '@init/analytics'; import NetworkManager from '@init/network_manager'; -import {prepareUsers, queryCurrentUser, queryUsersById, queryUsersByUsername} from '@queries/servers/user'; import {queryCurrentUserId} from '@queries/servers/system'; +import {prepareUsers, queryCurrentUser, queryUsersById, queryUsersByUsername} from '@queries/servers/user'; + +import {forceLogoutIfNecessary} from './session'; import type {Client} from '@client/rest'; import type {LoadMeArgs} from '@typings/database/database'; import type RoleModel from '@typings/database/models/servers/role'; import type UserModel from '@typings/database/models/servers/user'; -import {forceLogoutIfNecessary} from './session'; - export type ProfilesPerChannelRequest = { data?: ProfilesInChannelRequest[]; error?: never; diff --git a/app/client/rest/base.ts b/app/client/rest/base.ts index f98ed9bd5e..30b480c8ce 100644 --- a/app/client/rest/base.ts +++ b/app/client/rest/base.ts @@ -8,6 +8,9 @@ import {t} from '@i18n'; import {Analytics, create} from '@init/analytics'; import {setServerCredentials} from '@init/credentials'; +import * as ClientConstants from './constants'; +import ClientError from './error'; + import type { APIClientInterface, ClientHeaders, @@ -15,9 +18,6 @@ import type { RequestOptions, } from '@mattermost/react-native-network-client'; -import * as ClientConstants from './constants'; -import ClientError from './error'; - export default class ClientBase { analytics: Analytics|undefined; apiClient: APIClientInterface; diff --git a/app/client/rest/index.test.js b/app/client/rest/index.test.js index 8079576647..b7def04ffa 100644 --- a/app/client/rest/index.test.js +++ b/app/client/rest/index.test.js @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import assert from 'assert'; + import nock from 'nock'; import {HEADER_X_VERSION_ID} from '@client/rest/constants'; diff --git a/app/client/rest/index.ts b/app/client/rest/index.ts index 9107cb1d38..52444f3c6a 100644 --- a/app/client/rest/index.ts +++ b/app/client/rest/index.ts @@ -3,10 +3,10 @@ import mix from '@utils/mix'; -import {DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID} from './constants'; import ClientApps, {ClientAppsMix} from './apps'; import ClientBase from './base'; import ClientChannels, {ClientChannelsMix} from './channels'; +import {DEFAULT_LIMIT_AFTER, DEFAULT_LIMIT_BEFORE, HEADER_X_VERSION_ID} from './constants'; import ClientEmojis, {ClientEmojisMix} from './emojis'; import ClientFiles, {ClientFilesMix} from './files'; import ClientGeneral, {ClientGeneralMix} from './general'; diff --git a/app/components/app_version/index.tsx b/app/components/app_version/index.tsx index 21b29e595c..d2e96cebe2 100644 --- a/app/components/app_version/index.tsx +++ b/app/components/app_version/index.tsx @@ -5,8 +5,8 @@ import React from 'react'; import {StyleSheet, TextStyle, View} from 'react-native'; import DeviceInfo from 'react-native-device-info'; -import {t} from '@i18n'; import FormattedText from '@components/formatted_text'; +import {t} from '@i18n'; const style = StyleSheet.create({ info: { diff --git a/app/components/custom_status/custom_status_emoji.test.tsx b/app/components/custom_status/custom_status_emoji.test.tsx index ce65dd0ce5..1b76eee9ec 100644 --- a/app/components/custom_status/custom_status_emoji.test.tsx +++ b/app/components/custom_status/custom_status_emoji.test.tsx @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import Database from '@nozbe/watermelondb/Database'; import React from 'react'; import CustomStatusEmoji from '@components/custom_status/custom_status_emoji'; import {renderWithEverything} from '@test/intl-test-helper'; import TestHelper from '@test/test_helper'; -import Database from '@nozbe/watermelondb/Database'; describe('components/custom_status/custom_status_emoji', () => { let database: Database | undefined; diff --git a/app/components/custom_status/custom_status_text.test.tsx b/app/components/custom_status/custom_status_text.test.tsx index 720050c927..ea9072c434 100644 --- a/app/components/custom_status/custom_status_text.test.tsx +++ b/app/components/custom_status/custom_status_text.test.tsx @@ -1,5 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. + import React from 'react'; import CustomStatusText from '@components/custom_status/custom_status_text'; diff --git a/app/components/emoji/index.tsx b/app/components/emoji/index.tsx index 874a6e2303..2937703ad3 100644 --- a/app/components/emoji/index.tsx +++ b/app/components/emoji/index.tsx @@ -23,8 +23,8 @@ import NetworkManager from '@init/network_manager'; import {EmojiIndicesByAlias, Emojis} from '@utils/emoji'; import type {WithDatabaseArgs} from '@typings/database/database'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; import type SystemModel from '@typings/database/models/servers/system'; -import CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; const assetImages = new Map([['mattermost.png', require('@assets/images/emojis/mattermost.png')]]); diff --git a/app/components/error_text/error_text.test.tsx b/app/components/error_text/error_text.test.tsx index 7f5a4f9c93..9cdcf6e281 100644 --- a/app/components/error_text/error_text.test.tsx +++ b/app/components/error_text/error_text.test.tsx @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; import {render} from '@testing-library/react-native'; +import React from 'react'; import {Preferences} from '@constants'; diff --git a/app/components/formatted_markdown_text/index.tsx b/app/components/formatted_markdown_text/index.tsx index 75e89387f7..dbd9575bc7 100644 --- a/app/components/formatted_markdown_text/index.tsx +++ b/app/components/formatted_markdown_text/index.tsx @@ -11,7 +11,7 @@ import AtMention from '@components/markdown/at_mention'; import MarkdownLink from '@components/markdown/markdown_link'; import {useTheme} from '@context/theme'; import {getMarkdownTextStyles} from '@utils/markdown'; -import {concatStyles, changeOpacity, makeStyleSheetFromTheme} from '@app/utils/theme'; +import {concatStyles, changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import type {PrimitiveType} from 'intl-messageformat'; diff --git a/app/components/formatted_text/index.tsx b/app/components/formatted_text/index.tsx index a9ac28907a..d87ce89874 100644 --- a/app/components/formatted_text/index.tsx +++ b/app/components/formatted_text/index.tsx @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import {createElement, isValidElement} from 'react'; -import {StyleProp, Text, TextProps, TextStyle, ViewStyle} from 'react-native'; import {useIntl} from 'react-intl'; +import {StyleProp, Text, TextProps, TextStyle, ViewStyle} from 'react-native'; type FormattedTextProps = TextProps & { id: string; diff --git a/app/components/markdown/at_mention/index.tsx b/app/components/markdown/at_mention/index.tsx index e61ca8682a..4e80412360 100644 --- a/app/components/markdown/at_mention/index.tsx +++ b/app/components/markdown/at_mention/index.tsx @@ -11,13 +11,13 @@ import {useIntl} from 'react-intl'; import {DeviceEventEmitter, GestureResponderEvent, StyleProp, StyleSheet, Text, TextStyle, View} from 'react-native'; import {of as of$} from 'rxjs'; +import CompassIcon from '@components/compass_icon'; import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item'; -import {useTheme} from '@context/theme'; import {Navigation, Preferences} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; +import {useTheme} from '@context/theme'; import UserModel from '@database/models/server/user'; import {getTeammateNameDisplaySetting} from '@helpers/api/preference'; -import CompassIcon from '@components/compass_icon'; import {showModal, showModalOverCurrentContext} from '@screens/navigation'; import {displayUsername, getUserMentionKeys, getUsersByUsername} from '@utils/user'; diff --git a/app/components/markdown/index.tsx b/app/components/markdown/index.tsx index 5a956d6e9a..cfa3706062 100644 --- a/app/components/markdown/index.tsx +++ b/app/components/markdown/index.tsx @@ -21,9 +21,9 @@ import MarkdownLink from './markdown_link'; import MarkdownList from './markdown_list'; import MarkdownListItem from './markdown_list_item'; import MarkdownTable from './markdown_table'; +import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell'; import MarkdownTableImage from './markdown_table_image'; import MarkdownTableRow, {MarkdownTableRowProps} from './markdown_table_row'; -import MarkdownTableCell, {MarkdownTableCellProps} from './markdown_table_cell'; import {addListItemIndices, combineTextNodes, highlightMentions, pullOutImages} from './transform'; import type {MarkdownBlockStyles, MarkdownTextStyles, UserMentionKey} from '@typings/global/markdown'; diff --git a/app/components/markdown/markdown_block_quote/index.tsx b/app/components/markdown/markdown_block_quote/index.tsx index 88141bbe8f..2305896353 100644 --- a/app/components/markdown/markdown_block_quote/index.tsx +++ b/app/components/markdown/markdown_block_quote/index.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React, {ReactNode} from 'react'; - import {StyleSheet, TextStyle, View, ViewStyle} from 'react-native'; import CompassIcon from '@components/compass_icon'; diff --git a/app/components/markdown/markdown_code_block/index.tsx b/app/components/markdown/markdown_code_block/index.tsx index f8154caca9..780ab2b8f1 100644 --- a/app/components/markdown/markdown_code_block/index.tsx +++ b/app/components/markdown/markdown_code_block/index.tsx @@ -8,10 +8,10 @@ import {useIntl} from 'react-intl'; import {DeviceEventEmitter, Keyboard, StyleSheet, Text, TextStyle, View} from 'react-native'; import FormattedText from '@components/formatted_text'; -import {useTheme} from '@context/theme'; import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item'; import TouchableWithFeedback from '@components/touchable_with_feedback'; import {Navigation} from '@constants'; +import {useTheme} from '@context/theme'; import {goToScreen, showModalOverCurrentContext} from '@screens/navigation'; import {getDisplayNameForLanguage} from '@utils/markdown'; import {preventDoubleTap} from '@utils/tap'; diff --git a/app/components/markdown/markdown_link/index.tsx b/app/components/markdown/markdown_link/index.tsx index 79842ca33f..14494739ef 100644 --- a/app/components/markdown/markdown_link/index.tsx +++ b/app/components/markdown/markdown_link/index.tsx @@ -2,9 +2,9 @@ // See LICENSE.txt for license information. import {useManagedConfig} from '@mattermost/react-native-emm'; -import Clipboard from '@react-native-community/clipboard'; import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; +import Clipboard from '@react-native-community/clipboard'; import React, {Children, ReactElement, useCallback} from 'react'; import {useIntl} from 'react-intl'; import {Alert, DeviceEventEmitter, StyleSheet, Text, View} from 'react-native'; @@ -20,8 +20,8 @@ import DeepLinkTypes from '@constants/deep_linking'; import {useServerUrl} from '@context/server_url'; import {dismissAllModals, popToRoot, showModalOverCurrentContext} from '@screens/navigation'; import {errorBadChannel} from '@utils/draft'; -import {matchDeepLink, normalizeProtocol, tryOpenURL} from '@utils/url'; import {preventDoubleTap} from '@utils/tap'; +import {matchDeepLink, normalizeProtocol, tryOpenURL} from '@utils/url'; import type {WithDatabaseArgs} from '@typings/database/database'; import type SystemModel from '@typings/database/models/servers/system'; diff --git a/app/components/markdown/markdown_table_image/index.tsx b/app/components/markdown/markdown_table_image/index.tsx index f90ddd453b..eed6602f79 100644 --- a/app/components/markdown/markdown_table_image/index.tsx +++ b/app/components/markdown/markdown_table_image/index.tsx @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {useServerUrl} from '@context/server_url'; -import {generateId} from '@utils/general'; import React, {memo, useCallback, useRef, useState} from 'react'; import {StyleSheet, View} from 'react-native'; import parseUrl from 'url-parse'; @@ -10,7 +8,9 @@ import parseUrl from 'url-parse'; import CompassIcon from '@components/compass_icon'; import ProgressiveImage from '@components/progressive_image'; import TouchableWithFeedback from '@components/touchable_with_feedback'; +import {useServerUrl} from '@context/server_url'; import {openGallerWithMockFile} from '@utils/gallery'; +import {generateId} from '@utils/general'; import {calculateDimensions, isGifTooLarge} from '@utils/images'; type MarkdownTableImageProps = { diff --git a/app/components/post_list/combined_user_activity/combined_user_activity.tsx b/app/components/post_list/combined_user_activity/combined_user_activity.tsx index 8b548750f6..2a4c8bb493 100644 --- a/app/components/post_list/combined_user_activity/combined_user_activity.tsx +++ b/app/components/post_list/combined_user_activity/combined_user_activity.tsx @@ -7,8 +7,8 @@ import {Keyboard, StyleProp, View, ViewStyle} from 'react-native'; import {fetchMissingProfilesByIds, fetchMissingProfilesByUsernames} from '@actions/remote/user'; import Markdown from '@components/markdown'; -import SystemAvatar from '@app/components/system_avatar'; -import SystemHeader from '@app/components/system_header'; +import SystemAvatar from '@components/system_avatar'; +import SystemHeader from '@components/system_header'; import TouchableWithFeedback from '@components/touchable_with_feedback'; import {Post as PostConstants} from '@constants'; import {useServerUrl} from '@context/server_url'; diff --git a/app/components/post_list/index.tsx b/app/components/post_list/index.tsx index 62d692b030..5bae3aecf4 100644 --- a/app/components/post_list/index.tsx +++ b/app/components/post_list/index.tsx @@ -9,10 +9,10 @@ import {DeviceEventEmitter, FlatList, Platform, RefreshControl, StyleSheet, View import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; -import Post from '@components/post_list/post'; -import CombinedUserActivity from '@app/components/post_list/combined_user_activity'; +import CombinedUserActivity from '@components/post_list/combined_user_activity'; import DateSeparator from '@components/post_list/date_separator'; import NewMessagesLine from '@components/post_list/new_message_line'; +import Post from '@components/post_list/post'; import {Preferences} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import {useTheme} from '@context/theme'; @@ -26,7 +26,7 @@ import type PostModel from '@typings/database/models/servers/post'; import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; import type PreferenceModel from '@typings/database/models/servers/preference'; import type SystemModel from '@typings/database/models/servers/system'; -import UserModel from '@typings/database/models/servers/user'; +import type UserModel from '@typings/database/models/servers/user'; type RefreshProps = { children: ReactElement; diff --git a/app/components/post_list/post/avatar/index.tsx b/app/components/post_list/post/avatar/index.tsx index 2fdb4f03d5..c8cbbbc754 100644 --- a/app/components/post_list/post/avatar/index.tsx +++ b/app/components/post_list/post/avatar/index.tsx @@ -11,8 +11,8 @@ import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; import CompassIcon from '@components/compass_icon'; -import SystemAvatar from '@components/system_avatar'; import ProfilePicture from '@components/profile_picture'; +import SystemAvatar from '@components/system_avatar'; import TouchableWithFeedback from '@components/touchable_with_feedback'; import {View as ViewConstant} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; @@ -22,13 +22,12 @@ import NetworkManager from '@init/network_manager'; import {showModal} from '@screens/navigation'; import {preventDoubleTap} from '@utils/tap'; -import type {ImageSource} from 'react-native-vector-icons/Icon'; - import type {Client} from '@client/rest'; import type {WithDatabaseArgs} from '@typings/database/database'; import type PostModel from '@typings/database/models/servers/post'; -import type UserModel from '@typings/database/models/servers/user'; import type SystemModel from '@typings/database/models/servers/system'; +import type UserModel from '@typings/database/models/servers/user'; +import type {ImageSource} from 'react-native-vector-icons/Icon'; type AvatarProps = { author: UserModel; diff --git a/app/components/post_list/post/body/add_members/index.tsx b/app/components/post_list/post/body/add_members/index.tsx index 4658bce877..a80b7ceae6 100644 --- a/app/components/post_list/post/body/add_members/index.tsx +++ b/app/components/post_list/post/body/add_members/index.tsx @@ -11,8 +11,8 @@ import {switchMap} from 'rxjs/operators'; import {removePost, sendAddToChannelEphemeralPost} from '@actions/local/post'; import {addMembersToChannel} from '@actions/remote/channel'; -import AtMention from '@components/markdown/at_mention'; import FormattedText from '@components/formatted_text'; +import AtMention from '@components/markdown/at_mention'; import {General} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import {useServerUrl} from '@context/server_url'; @@ -23,8 +23,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import type {WithDatabaseArgs} from '@typings/database/database'; import type ChannelModel from '@typings/database/models/servers/channel'; import type PostModel from '@typings/database/models/servers/post'; +import type SystemModel from '@typings/database/models/servers/system'; import type UserModel from '@typings/database/models/servers/user'; -import SystemModel from '@typings/database/models/servers/system'; type AddMembersProps = { channelType: string | null; diff --git a/app/components/post_list/post/body/content/embedded_bindings/embed_text.tsx b/app/components/post_list/post/body/content/embedded_bindings/embed_text.tsx index 030be658dc..fbcff5de1b 100644 --- a/app/components/post_list/post/body/content/embedded_bindings/embed_text.tsx +++ b/app/components/post_list/post/body/content/embedded_bindings/embed_text.tsx @@ -6,7 +6,7 @@ import {LayoutChangeEvent, useWindowDimensions, ScrollView, View} from 'react-na import Animated from 'react-native-reanimated'; import Markdown from '@components/markdown'; -import ShowMoreButton from '@app/components/post_list/post/body/message/show_more_button'; +import ShowMoreButton from '@components/post_list/post/body/message/show_more_button'; import {useShowMoreAnimatedStyle} from '@hooks/show_more'; import {getMarkdownBlockStyles, getMarkdownTextStyles} from '@utils/markdown'; import {makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/components/post_list/post/body/content/image_preview/index.tsx b/app/components/post_list/post/body/content/image_preview/index.tsx index 7f65309ec2..7a6e7a717d 100644 --- a/app/components/post_list/post/body/content/image_preview/index.tsx +++ b/app/components/post_list/post/body/content/image_preview/index.tsx @@ -10,16 +10,16 @@ import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; import {getRedirectLocation} from '@actions/remote/general'; -import FileIcon from '@app/components/post_list/post/body/files/file_icon'; +import FileIcon from '@components/post_list/post/body/files/file_icon'; import ProgressiveImage from '@components/progressive_image'; import TouchableWithFeedback from '@components/touchable_with_feedback'; import {Device} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import {useServerUrl} from '@context/server_url'; -import useDidUpdate from '@hooks/did_update'; import {useSplitView} from '@hooks/device'; -import {generateId} from '@utils/general'; +import useDidUpdate from '@hooks/did_update'; import {openGallerWithMockFile} from '@utils/gallery'; +import {generateId} from '@utils/general'; import {calculateDimensions, getViewPortWidth, isGifTooLarge} from '@utils/images'; import {changeOpacity} from '@utils/theme'; import {isImageLink, isValidUrl} from '@utils/url'; diff --git a/app/components/post_list/post/body/content/message_attachments/action_menu/index.tsx b/app/components/post_list/post/body/content/message_attachments/action_menu/index.tsx index 13c7e88169..14077b3378 100644 --- a/app/components/post_list/post/body/content/message_attachments/action_menu/index.tsx +++ b/app/components/post_list/post/body/content/message_attachments/action_menu/index.tsx @@ -4,9 +4,8 @@ import React, {useCallback, useState} from 'react'; import {selectAttachmentMenuAction} from '@actions/local/post'; -import {useServerUrl} from '@context/server_url'; - import AutocompleteSelector from '@components/autocomplete_selector'; +import {useServerUrl} from '@context/server_url'; type Props = { dataSource?: string; diff --git a/app/components/post_list/post/body/content/message_attachments/attachment_image/index.tsx b/app/components/post_list/post/body/content/message_attachments/attachment_image/index.tsx index 896d22f847..34571369d5 100644 --- a/app/components/post_list/post/body/content/message_attachments/attachment_image/index.tsx +++ b/app/components/post_list/post/body/content/message_attachments/attachment_image/index.tsx @@ -4,13 +4,13 @@ import React, {useCallback, useRef, useState} from 'react'; import {View} from 'react-native'; -import FileIcon from '@app/components/post_list/post/body/files/file_icon'; +import FileIcon from '@components/post_list/post/body/files/file_icon'; import ProgressiveImage from '@components/progressive_image'; import TouchableWithFeedback from '@components/touchable_with_feedback'; import {Device} from '@constants'; import {useSplitView} from '@hooks/device'; -import {generateId} from '@utils/general'; import {openGallerWithMockFile} from '@utils/gallery'; +import {generateId} from '@utils/general'; import {isGifTooLarge, calculateDimensions, getViewPortWidth} from '@utils/images'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {isValidUrl} from '@utils/url'; diff --git a/app/components/post_list/post/body/content/message_attachments/attachment_text.tsx b/app/components/post_list/post/body/content/message_attachments/attachment_text.tsx index c734bfa20e..4ce3b0e7f3 100644 --- a/app/components/post_list/post/body/content/message_attachments/attachment_text.tsx +++ b/app/components/post_list/post/body/content/message_attachments/attachment_text.tsx @@ -6,7 +6,7 @@ import {LayoutChangeEvent, useWindowDimensions, ScrollView, StyleProp, StyleShee import Animated from 'react-native-reanimated'; import Markdown from '@components/markdown'; -import ShowMoreButton from '@app/components/post_list/post/body/message/show_more_button'; +import ShowMoreButton from '@components/post_list/post/body/message/show_more_button'; import {useShowMoreAnimatedStyle} from '@hooks/show_more'; import type {MarkdownBlockStyles, MarkdownTextStyles} from '@typings/global/markdown'; diff --git a/app/components/post_list/post/body/files/image_file.tsx b/app/components/post_list/post/body/files/image_file.tsx index 27868b3a06..2e05d4c019 100644 --- a/app/components/post_list/post/body/files/image_file.tsx +++ b/app/components/post_list/post/body/files/image_file.tsx @@ -12,9 +12,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import FileIcon from './file_icon'; -import type {ResizeMode} from 'react-native-fast-image'; - import type {Client} from '@client/rest'; +import type {ResizeMode} from 'react-native-fast-image'; type ImageFileProps = { backgroundColor?: string; diff --git a/app/components/post_list/post/body/index.tsx b/app/components/post_list/post/body/index.tsx index 138f058bbd..4450eea83b 100644 --- a/app/components/post_list/post/body/index.tsx +++ b/app/components/post_list/post/body/index.tsx @@ -17,8 +17,8 @@ import Files from './files'; import Message from './message'; import Reactions from './reactions'; +import type FileModel from '@typings/database/models/servers/file'; import type PostModel from '@typings/database/models/servers/post'; -import FileModel from '@typings/database/models/servers/file'; type BodyProps = { appsEnabled: boolean; diff --git a/app/components/post_list/post/body/message/message.tsx b/app/components/post_list/post/body/message/message.tsx index d22ea84517..d5f0086619 100644 --- a/app/components/post_list/post/body/message/message.tsx +++ b/app/components/post_list/post/body/message/message.tsx @@ -8,15 +8,14 @@ import Animated from 'react-native-reanimated'; import Markdown from '@components/markdown'; import {SEARCH} from '@constants/screens'; import {useShowMoreAnimatedStyle} from '@hooks/show_more'; -import {getMentionKeysForPost} from '@utils/post'; import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown'; - +import {getMentionKeysForPost} from '@utils/post'; import {makeStyleSheetFromTheme} from '@utils/theme'; import ShowMoreButton from './show_more_button'; -import type PostModel from '@typings/database/models/servers/post'; import type GroupModel from '@typings/database/models/servers/group'; +import type PostModel from '@typings/database/models/servers/post'; import type UserModel from '@typings/database/models/servers/user'; type MessageProps = { diff --git a/app/components/post_list/post/body/reactions/index.ts b/app/components/post_list/post/body/reactions/index.ts index 40fe353091..0afdd87a7a 100644 --- a/app/components/post_list/post/body/reactions/index.ts +++ b/app/components/post_list/post/body/reactions/index.ts @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import withObservables from '@nozbe/with-observables'; import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; +import withObservables from '@nozbe/with-observables'; import {from as from$, of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; diff --git a/app/components/post_list/post/header/header.tsx b/app/components/post_list/post/header/header.tsx index daac0f25de..de57551dad 100644 --- a/app/components/post_list/post/header/header.tsx +++ b/app/components/post_list/post/header/header.tsx @@ -9,8 +9,8 @@ import FormattedTime from '@components/formatted_time'; import {CHANNEL, THREAD} from '@constants/screens'; import {useTheme} from '@context/theme'; import {postUserDisplayName} from '@utils/post'; -import {displayUsername, getUserCustomStatus, getUserTimezone, isCustomStatusExpired} from '@utils/user'; import {makeStyleSheetFromTheme} from '@utils/theme'; +import {displayUsername, getUserCustomStatus, getUserTimezone, isCustomStatusExpired} from '@utils/user'; import HeaderCommentedOn from './commented_on'; import HeaderDisplayName from './display_name'; diff --git a/app/components/post_list/post/header/index.ts b/app/components/post_list/post/header/index.ts index 84f564c7fd..14787776b5 100644 --- a/app/components/post_list/post/header/index.ts +++ b/app/components/post_list/post/header/index.ts @@ -16,8 +16,8 @@ import Header from './header'; import type {WithDatabaseArgs} from '@typings/database/database'; import type PostModel from '@typings/database/models/servers/post'; -import type SystemModel from '@typings/database/models/servers/system'; import type PreferenceModel from '@typings/database/models/servers/preference'; +import type SystemModel from '@typings/database/models/servers/system'; type HeaderInputProps = { config: ClientConfig; diff --git a/app/components/post_list/post/index.ts b/app/components/post_list/post/index.ts index 76a5ec95e9..9cff702dc4 100644 --- a/app/components/post_list/post/index.ts +++ b/app/components/post_list/post/index.ts @@ -17,12 +17,12 @@ import {canManageChannelMembers, hasPermissionForPost} from '@utils/role'; import Post from './post'; import type {WithDatabaseArgs} from '@typings/database/database'; -import type PreferenceModel from '@typings/database/models/servers/preference'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; import type PostModel from '@typings/database/models/servers/post'; +import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread'; +import type PreferenceModel from '@typings/database/models/servers/preference'; import type SystemModel from '@typings/database/models/servers/system'; import type UserModel from '@typings/database/models/servers/user'; -import PostsInThreadModel from '@typings/database/models/servers/posts_in_thread'; -import CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; const {SERVER: {CUSTOM_EMOJI, POST, PREFERENCE, SYSTEM, USER}} = MM_TABLES; diff --git a/app/components/post_list/post/post.tsx b/app/components/post_list/post/post.tsx index 0c2c2d7001..8ac4d703e2 100644 --- a/app/components/post_list/post/post.tsx +++ b/app/components/post_list/post/post.tsx @@ -7,12 +7,12 @@ import {DeviceEventEmitter, Keyboard, StyleProp, View, ViewStyle} from 'react-na import {showPermalink} from '@actions/local/permalink'; import {removePost} from '@actions/local/post'; -import SystemAvatar from '@app/components/system_avatar'; -import SystemHeader from '@app/components/system_header'; +import SystemAvatar from '@components/system_avatar'; +import SystemHeader from '@components/system_header'; import TouchableWithFeedback from '@components/touchable_with_feedback'; import * as Screens from '@constants/screens'; -import {useTheme} from '@context/theme'; import {useServerUrl} from '@context/server_url'; +import {useTheme} from '@context/theme'; import {showModalOverCurrentContext} from '@screens/navigation'; import {fromAutoResponder, isFromWebhook, isPostPendingOrFailed, isSystemMessage} from '@utils/post'; import {preventDoubleTap} from '@utils/tap'; @@ -24,9 +24,9 @@ import Header from './header'; import PreHeader from './pre_header'; import SystemMessage from './system_message'; +import type FileModel from '@typings/database/models/servers/file'; import type PostModel from '@typings/database/models/servers/post'; import type UserModel from '@typings/database/models/servers/user'; -import FileModel from '@typings/database/models/servers/file'; type PostProps = { appsEnabled: boolean; diff --git a/app/components/post_list/post/system_message/index.tsx b/app/components/post_list/post/system_message/index.tsx index db0bda8d84..293f7f0423 100644 --- a/app/components/post_list/post/system_message/index.tsx +++ b/app/components/post_list/post/system_message/index.tsx @@ -3,10 +3,10 @@ import withObservables from '@nozbe/with-observables'; -import type PostModel from '@typings/database/models/servers/post'; - import SystemMessage from './system_message'; +import type PostModel from '@typings/database/models/servers/post'; + const withPost = withObservables(['post'], ({post}: {post: PostModel}) => ({ author: post.author.observe(), })); diff --git a/app/components/post_list/post/system_message/system_message.tsx b/app/components/post_list/post/system_message/system_message.tsx index b78bfe780c..5f5320644a 100644 --- a/app/components/post_list/post/system_message/system_message.tsx +++ b/app/components/post_list/post/system_message/system_message.tsx @@ -12,10 +12,9 @@ import {t} from '@i18n'; import {getMarkdownTextStyles} from '@utils/markdown'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import type {PrimitiveType} from 'intl-messageformat'; - import type PostModel from '@typings/database/models/servers/post'; import type UserModel from '@typings/database/models/servers/user'; +import type {PrimitiveType} from 'intl-messageformat'; type SystemMessageProps = { author?: UserModel; diff --git a/app/components/server_version/index.tsx b/app/components/server_version/index.tsx index 724c0e9c31..3fa19080fa 100644 --- a/app/components/server_version/index.tsx +++ b/app/components/server_version/index.tsx @@ -9,7 +9,7 @@ import {useIntl} from 'react-intl'; import {View} from '@constants'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import {isMinimumServerVersion} from '@utils/helpers'; -import {unsupportedServer} from '@app/utils/supported_server'; +import {unsupportedServer} from '@utils/supported_server'; import {isSystemAdmin} from '@utils/user'; import type {WithDatabaseArgs} from '@typings/database/database'; diff --git a/app/components/system_header/index.tsx b/app/components/system_header/index.tsx index 1367ac08f4..28e294cf31 100644 --- a/app/components/system_header/index.tsx +++ b/app/components/system_header/index.tsx @@ -17,10 +17,9 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; import {getUserTimezone} from '@utils/user'; import type {WithDatabaseArgs} from '@typings/database/database'; - +import type PreferenceModel from '@typings/database/models/servers/preference'; import type SystemModel from '@typings/database/models/servers/system'; import type UserModel from '@typings/database/models/servers/user'; -import type PreferenceModel from '@typings/database/models/servers/preference'; type withUserInputProps = { config: SystemModel; diff --git a/app/components/user_status/index.tsx b/app/components/user_status/index.tsx index c2ae63c7b6..60a55a1a1a 100644 --- a/app/components/user_status/index.tsx +++ b/app/components/user_status/index.tsx @@ -4,8 +4,8 @@ import React from 'react'; import CompassIcon from '@components/compass_icon'; -import {useTheme} from '@context/theme'; import {General} from '@constants'; +import {useTheme} from '@context/theme'; import {changeOpacity} from '@utils/theme'; type UserStatusProps = { diff --git a/app/constants/device.ts b/app/constants/device.ts index 6dd4bfadfe..d325a94a89 100644 --- a/app/constants/device.ts +++ b/app/constants/device.ts @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import {Platform} from 'react-native'; -import {FileSystem} from 'react-native-unimodules'; import DeviceInfo from 'react-native-device-info'; +import {FileSystem} from 'react-native-unimodules'; import keyMirror from '@utils/key_mirror'; diff --git a/app/constants/index.ts b/app/constants/index.ts index dddb889df0..8ba4d7b948 100644 --- a/app/constants/index.ts +++ b/app/constants/index.ts @@ -15,8 +15,8 @@ import Network from './network'; import Permissions from './permissions'; import Post from './post'; import Preferences from './preferences'; -import SSO, {REDIRECT_URL_SCHEME, REDIRECT_URL_SCHEME_DEV} from './sso'; import Screens from './screens'; +import SSO, {REDIRECT_URL_SCHEME, REDIRECT_URL_SCHEME_DEV} from './sso'; import View, {Upgrade} from './view'; import WebsocketEvents from './websocket'; diff --git a/app/context/theme/index.tsx b/app/context/theme/index.tsx index 39c6d277f6..b9c8d08793 100644 --- a/app/context/theme/index.tsx +++ b/app/context/theme/index.tsx @@ -11,8 +11,8 @@ import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import EphemeralStore from '@store/ephemeral_store'; import {setNavigationStackStyles} from '@utils/theme'; -import type Database from '@nozbe/watermelondb/Database'; import type {PreferenceModel, SystemModel} from '@database/models/server'; +import type Database from '@nozbe/watermelondb/Database'; type Props = { currentTeamId: SystemModel[]; diff --git a/app/database/manager/__mocks__/index.ts b/app/database/manager/__mocks__/index.ts index fd0d36f332..4c15ed8e6d 100644 --- a/app/database/manager/__mocks__/index.ts +++ b/app/database/manager/__mocks__/index.ts @@ -3,33 +3,31 @@ import {Database, Q} from '@nozbe/watermelondb'; import LokiJSAdapter from '@nozbe/watermelondb/adapters/lokijs'; - import logger from '@nozbe/watermelondb/utils/common/logger'; import {DeviceEventEmitter, Platform} from 'react-native'; import {FileSystem} from 'react-native-unimodules'; import urlParse from 'url-parse'; import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database'; -import AppDataOperator from '@database/operator/app_data_operator'; -import AppDatabaseMigrations from '@app/database/migration/app'; -import {InfoModel, GlobalModel, ServersModel} from '@database/models/app'; -import {schema as appSchema} from '@app/database/schema/app'; +import AppDatabaseMigrations from '@database/migration/app'; import ServerDatabaseMigrations from '@database/migration/server'; +import {InfoModel, GlobalModel, ServersModel} from '@database/models/app'; import {ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel, GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, TermsOfServiceModel, UserModel, } from '@database/models/server'; +import AppDataOperator from '@database/operator/app_data_operator'; +import ServerDataOperator from '@database/operator/server_data_operator'; +import {schema as appSchema} from '@database/schema/app'; import {serverSchema} from '@database/schema/server'; import {queryActiveServer, queryServer} from '@queries/app/servers'; +import {DatabaseType} from '@typings/database/enums'; import {deleteIOSDatabase} from '@utils/mattermost_managed'; import {hashCode} from '@utils/security'; import type {AppDatabase, CreateServerDatabaseArgs, Models, RegisterServerDatabaseArgs, ServerDatabase, ServerDatabases} from '@typings/database/database'; -import {DatabaseType} from '@typings/database/enums'; - -import ServerDataOperator from '../../operator/server_data_operator'; const {SERVERS} = MM_TABLES.APP; const APP_DATABASE = 'app'; diff --git a/app/database/manager/index.ts b/app/database/manager/index.ts index b5a24cc8fe..bfa346f00a 100644 --- a/app/database/manager/index.ts +++ b/app/database/manager/index.ts @@ -10,26 +10,25 @@ import {FileSystem} from 'react-native-unimodules'; import urlParse from 'url-parse'; import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database'; -import AppDataOperator from '@database/operator/app_data_operator'; import AppDatabaseMigrations from '@database/migration/app'; -import {InfoModel, GlobalModel, ServersModel} from '@database/models/app'; -import {schema as appSchema} from '@database/schema/app'; import ServerDatabaseMigrations from '@database/migration/server'; +import {InfoModel, GlobalModel, ServersModel} from '@database/models/app'; import {ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel, GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, TermsOfServiceModel, UserModel, } from '@database/models/server'; +import AppDataOperator from '@database/operator/app_data_operator'; +import ServerDataOperator from '@database/operator/server_data_operator'; +import {schema as appSchema} from '@database/schema/app'; import {serverSchema} from '@database/schema/server'; import {queryActiveServer, queryServer} from '@queries/app/servers'; +import {DatabaseType} from '@typings/database/enums'; import {deleteIOSDatabase, getIOSAppGroupDetails} from '@utils/mattermost_managed'; import {hashCode} from '@utils/security'; import type {AppDatabase, CreateServerDatabaseArgs, RegisterServerDatabaseArgs, Models, ServerDatabase, ServerDatabases} from '@typings/database/database'; -import {DatabaseType} from '@typings/database/enums'; - -import ServerDataOperator from '../operator/server_data_operator'; const {SERVERS} = MM_TABLES.APP; const APP_DATABASE = 'app'; diff --git a/app/database/manager/test_manual.ts b/app/database/manager/test_manual.ts index 410aafdbfe..838d4b8c15 100644 --- a/app/database/manager/test_manual.ts +++ b/app/database/manager/test_manual.ts @@ -5,11 +5,11 @@ import {Q} from '@nozbe/watermelondb'; import {Platform} from 'react-native'; import {MM_TABLES} from '@constants/database'; +import {DatabaseType} from '@typings/database/enums'; import {getIOSAppGroupDetails} from '@utils/mattermost_managed'; import DatabaseManager from './index'; -import {DatabaseType} from '@typings/database/enums'; import type ServersModel from '@typings/database/models/app/servers'; export default async () => { diff --git a/app/database/models/server/draft.ts b/app/database/models/server/draft.ts index 8a9e1fa5e7..04bc5d867f 100644 --- a/app/database/models/server/draft.ts +++ b/app/database/models/server/draft.ts @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Model, {Associations} from '@nozbe/watermelondb/Model'; import {field, json} from '@nozbe/watermelondb/decorators'; +import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; diff --git a/app/database/models/server/file.ts b/app/database/models/server/file.ts index 0120754a20..34127c79d4 100644 --- a/app/database/models/server/file.ts +++ b/app/database/models/server/file.ts @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import {Relation} from '@nozbe/watermelondb'; -import Model, {Associations} from '@nozbe/watermelondb/Model'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; +import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; diff --git a/app/database/models/server/group.ts b/app/database/models/server/group.ts index dd51e70796..1e32f1f390 100644 --- a/app/database/models/server/group.ts +++ b/app/database/models/server/group.ts @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Model, {Associations} from '@nozbe/watermelondb/Model'; import {children, field} from '@nozbe/watermelondb/decorators'; +import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; diff --git a/app/database/models/server/groups_channel.ts b/app/database/models/server/groups_channel.ts index e297256495..dbed805d22 100644 --- a/app/database/models/server/groups_channel.ts +++ b/app/database/models/server/groups_channel.ts @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import {Relation} from '@nozbe/watermelondb'; -import Model, {Associations} from '@nozbe/watermelondb/Model'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; +import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; diff --git a/app/database/operator/app_data_operator/comparator/index.ts b/app/database/operator/app_data_operator/comparator/index.ts index 35aaf60421..686d470b4b 100644 --- a/app/database/operator/app_data_operator/comparator/index.ts +++ b/app/database/operator/app_data_operator/comparator/index.ts @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import type InfoModel from '@typings/database/models/app/info'; import type GlobalModel from '@typings/database/models/app/global'; +import type InfoModel from '@typings/database/models/app/info'; export const isRecordInfoEqualToRaw = (record: InfoModel, raw: AppInfo) => { return (raw.build_number === record.buildNumber && raw.version_number === record.versionNumber); diff --git a/app/database/operator/app_data_operator/transformers/index.ts b/app/database/operator/app_data_operator/transformers/index.ts index 3e86234960..3073a575a7 100644 --- a/app/database/operator/app_data_operator/transformers/index.ts +++ b/app/database/operator/app_data_operator/transformers/index.ts @@ -3,13 +3,12 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers'; +import {OperationType} from '@typings/database/enums'; import type {Model} from '@nozbe/watermelondb'; - -import type InfoModel from '@typings/database/models/app/info'; import type {TransformerArgs} from '@typings/database/database'; -import {OperationType} from '@typings/database/enums'; import type GlobalModel from '@typings/database/models/app/global'; +import type InfoModel from '@typings/database/models/app/info'; const {INFO, GLOBAL} = MM_TABLES.APP; diff --git a/app/database/operator/base_data_operator/index.ts b/app/database/operator/base_data_operator/index.ts index 1ccde4ab23..1b35f3ae5d 100644 --- a/app/database/operator/base_data_operator/index.ts +++ b/app/database/operator/base_data_operator/index.ts @@ -9,10 +9,10 @@ import { getValidRecordsForUpdate, retrieveRecords, } from '@database/operator/utils/general'; +import {OperationType} from '@typings/database/enums'; import type {WriterInterface} from '@nozbe/watermelondb/Database'; import type Model from '@nozbe/watermelondb/Model'; - import type { HandleRecordsArgs, OperationArgs, @@ -20,7 +20,6 @@ import type { ProcessRecordsArgs, RecordPair, } from '@typings/database/database'; -import {OperationType} from '@typings/database/enums'; export interface BaseDataOperatorType { database: Database; diff --git a/app/database/operator/server_data_operator/handlers/channel.ts b/app/database/operator/server_data_operator/handlers/channel.ts index 4d2a1347f1..6a561eca80 100644 --- a/app/database/operator/server_data_operator/handlers/channel.ts +++ b/app/database/operator/server_data_operator/handlers/channel.ts @@ -17,9 +17,9 @@ import { } from '@database/operator/server_data_operator/transformers/channel'; import {getUniqueRawsBy} from '@database/operator/utils/general'; +import type {HandleChannelArgs, HandleChannelInfoArgs, HandleMyChannelArgs, HandleMyChannelSettingsArgs} from '@typings/database/database'; import type ChannelModel from '@typings/database/models/servers/channel'; import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; -import type {HandleChannelArgs, HandleChannelInfoArgs, HandleMyChannelArgs, HandleMyChannelSettingsArgs} from '@typings/database/database'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; diff --git a/app/database/operator/server_data_operator/handlers/index.test.ts b/app/database/operator/server_data_operator/handlers/index.test.ts index 99356fea6c..2ac3493002 100644 --- a/app/database/operator/server_data_operator/handlers/index.test.ts +++ b/app/database/operator/server_data_operator/handlers/index.test.ts @@ -16,9 +16,8 @@ import { transformTermsOfServiceRecord, } from '@database/operator/server_data_operator/transformers/general'; -import type {Model} from '@nozbe/watermelondb'; - import type ServerDataOperator from '..'; +import type {Model} from '@nozbe/watermelondb'; describe('*** DataOperator: Base Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/handlers/index.ts b/app/database/operator/server_data_operator/handlers/index.ts index 4401444209..1c3ab92958 100644 --- a/app/database/operator/server_data_operator/handlers/index.ts +++ b/app/database/operator/server_data_operator/handlers/index.ts @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import {MM_TABLES} from '@constants/database'; -import BaseDataOperator from '@database/operator/base_data_operator'; import DataOperatorException from '@database/exceptions/data_operator_exception'; +import BaseDataOperator from '@database/operator/base_data_operator'; import { isRecordCustomEmojiEqualToRaw, isRecordRoleEqualToRaw, @@ -19,10 +19,9 @@ import { import {getUniqueRawsBy} from '@database/operator/utils/general'; import type {Model} from '@nozbe/watermelondb'; - import type {HandleCustomEmojiArgs, HandleRoleArgs, HandleSystemArgs, HandleTOSArgs, OperationArgs} from '@typings/database/database'; -import type RoleModel from '@typings/database/models/servers/role'; import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; +import type RoleModel from '@typings/database/models/servers/role'; import type SystemModel from '@typings/database/models/servers/system'; import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service'; diff --git a/app/database/operator/server_data_operator/handlers/posts_in_channel.ts b/app/database/operator/server_data_operator/handlers/posts_in_channel.ts index d8e82352a2..82dee163cd 100644 --- a/app/database/operator/server_data_operator/handlers/posts_in_channel.ts +++ b/app/database/operator/server_data_operator/handlers/posts_in_channel.ts @@ -4,8 +4,8 @@ import {Q} from '@nozbe/watermelondb'; import {Database} from '@constants'; -import {transformPostsInChannelRecord} from '@database/operator/server_data_operator/transformers/post'; import {getPostListEdges} from '@database//operator/utils/post'; +import {transformPostsInChannelRecord} from '@database/operator/server_data_operator/transformers/post'; import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; diff --git a/app/database/operator/server_data_operator/handlers/posts_in_thread.ts b/app/database/operator/server_data_operator/handlers/posts_in_thread.ts index 56670952b6..4bf942b331 100644 --- a/app/database/operator/server_data_operator/handlers/posts_in_thread.ts +++ b/app/database/operator/server_data_operator/handlers/posts_in_thread.ts @@ -4,9 +4,9 @@ import {Q} from '@nozbe/watermelondb'; import {Database} from '@constants'; -import {getRawRecordPairs, getValidRecordsForUpdate} from '@database/operator/utils/general'; -import {transformPostInThreadRecord} from '@database/operator/server_data_operator/transformers/post'; import {getPostListEdges} from '@database//operator/utils/post'; +import {transformPostInThreadRecord} from '@database/operator/server_data_operator/transformers/post'; +import {getRawRecordPairs, getValidRecordsForUpdate} from '@database/operator/utils/general'; import type {RecordPair} from '@typings/database/database'; import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread'; diff --git a/app/database/operator/server_data_operator/handlers/user.ts b/app/database/operator/server_data_operator/handlers/user.ts index 589def61d5..58a4278ee4 100644 --- a/app/database/operator/server_data_operator/handlers/user.ts +++ b/app/database/operator/server_data_operator/handlers/user.ts @@ -17,14 +17,14 @@ import { import {getUniqueRawsBy} from '@database/operator/utils/general'; import {sanitizeReactions} from '@database/operator/utils/reaction'; -import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; -import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; import type { HandleChannelMembershipArgs, HandlePreferencesArgs, HandleReactionsArgs, HandleUsersArgs, } from '@typings/database/database'; +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; import type PreferenceModel from '@typings/database/models/servers/preference'; import type ReactionModel from '@typings/database/models/servers/reaction'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/database/operator/server_data_operator/transformers/channel.ts b/app/database/operator/server_data_operator/transformers/channel.ts index 458a2dbf26..8b059943bf 100644 --- a/app/database/operator/server_data_operator/transformers/channel.ts +++ b/app/database/operator/server_data_operator/transformers/channel.ts @@ -3,11 +3,11 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; +import {OperationType} from '@typings/database/enums'; +import type {TransformerArgs} from '@typings/database/database'; import type ChannelModel from '@typings/database/models/servers/channel'; import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; -import type {TransformerArgs} from '@typings/database/database'; -import {OperationType} from '@typings/database/enums'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; diff --git a/app/database/operator/server_data_operator/transformers/general.ts b/app/database/operator/server_data_operator/transformers/general.ts index 57ac030a94..3be08b8935 100644 --- a/app/database/operator/server_data_operator/transformers/general.ts +++ b/app/database/operator/server_data_operator/transformers/general.ts @@ -3,10 +3,10 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; - -import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; -import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; + +import type {TransformerArgs} from '@typings/database/database'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; import type RoleModel from '@typings/database/models/servers/role'; import type SystemModel from '@typings/database/models/servers/system'; import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service'; diff --git a/app/database/operator/server_data_operator/transformers/group.ts b/app/database/operator/server_data_operator/transformers/group.ts index 359f92287d..98b2790a6b 100644 --- a/app/database/operator/server_data_operator/transformers/group.ts +++ b/app/database/operator/server_data_operator/transformers/group.ts @@ -3,9 +3,9 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; +import {OperationType} from '@typings/database/enums'; import type {TransformerArgs} from '@typings/database/database'; -import {OperationType} from '@typings/database/enums'; import type GroupModel from '@typings/database/models/servers/group'; import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; import type GroupsChannelModel from '@typings/database/models/servers/groups_channel'; diff --git a/app/database/operator/server_data_operator/transformers/index.ts b/app/database/operator/server_data_operator/transformers/index.ts index ebb86780b2..e6468b0259 100644 --- a/app/database/operator/server_data_operator/transformers/index.ts +++ b/app/database/operator/server_data_operator/transformers/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import Model from '@nozbe/watermelondb/Model'; + import {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; diff --git a/app/database/operator/server_data_operator/transformers/post.ts b/app/database/operator/server_data_operator/transformers/post.ts index 809392f81d..605c6bfd72 100644 --- a/app/database/operator/server_data_operator/transformers/post.ts +++ b/app/database/operator/server_data_operator/transformers/post.ts @@ -3,10 +3,10 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; +import {OperationType} from '@typings/database/enums'; import type{TransformerArgs} from '@typings/database/database'; import type DraftModel from '@typings/database/models/servers/draft'; -import {OperationType} from '@typings/database/enums'; import type FileModel from '@typings/database/models/servers/file'; import type PostModel from '@typings/database/models/servers/post'; import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; diff --git a/app/database/operator/server_data_operator/transformers/team.ts b/app/database/operator/server_data_operator/transformers/team.ts index a01c3a0172..123a7f410d 100644 --- a/app/database/operator/server_data_operator/transformers/team.ts +++ b/app/database/operator/server_data_operator/transformers/team.ts @@ -2,10 +2,10 @@ // See LICENSE.txt for license information. import {MM_TABLES} from '@constants/database'; - import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; + +import type {TransformerArgs} from '@typings/database/database'; import type MyTeamModel from '@typings/database/models/servers/my_team'; import type SlashCommandModel from '@typings/database/models/servers/slash_command'; import type TeamModel from '@typings/database/models/servers/team'; diff --git a/app/database/operator/server_data_operator/transformers/user.test.ts b/app/database/operator/server_data_operator/transformers/user.test.ts index adc76e4de4..5a84553871 100644 --- a/app/database/operator/server_data_operator/transformers/user.test.ts +++ b/app/database/operator/server_data_operator/transformers/user.test.ts @@ -1,13 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. + import { transformChannelMembershipRecord, transformPreferenceRecord, transformReactionRecord, transformUserRecord, } from '@database/operator/server_data_operator/transformers/user'; - -// See LICENSE.txt for license information. import {createTestConnection} from '@database/operator/utils/create_test_connection'; import {OperationType} from '@typings/database/enums'; diff --git a/app/database/operator/server_data_operator/transformers/user.ts b/app/database/operator/server_data_operator/transformers/user.ts index 67def408c7..1905ea3f63 100644 --- a/app/database/operator/server_data_operator/transformers/user.ts +++ b/app/database/operator/server_data_operator/transformers/user.ts @@ -3,10 +3,10 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; - -import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; -import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; + +import type {TransformerArgs} from '@typings/database/database'; +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; import type PreferenceModel from '@typings/database/models/servers/preference'; import type ReactionModel from '@typings/database/models/servers/reaction'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/database/operator/utils/general.ts b/app/database/operator/utils/general.ts index 697d3f7c52..d4c7bf5eac 100644 --- a/app/database/operator/utils/general.ts +++ b/app/database/operator/utils/general.ts @@ -3,8 +3,8 @@ import {MM_TABLES} from '@constants/database'; -import type ChannelModel from '@typings/database/models/servers/channel'; import type {IdenticalRecordArgs, RangeOfValueArgs, RecordPair, RetrieveRecordsArgs} from '@typings/database/database'; +import type ChannelModel from '@typings/database/models/servers/channel'; import type PostModel from '@typings/database/models/servers/post'; import type SlashCommandModel from '@typings/database/models/servers/slash_command'; import type TeamModel from '@typings/database/models/servers/team'; diff --git a/app/database/operator/utils/test.ts b/app/database/operator/utils/test.ts index 7a7bc9a898..cfabade562 100644 --- a/app/database/operator/utils/test.ts +++ b/app/database/operator/utils/test.ts @@ -5,12 +5,11 @@ import DatabaseManager from '@database/manager'; import {createPostsChain, sanitizePosts} from '@database/operator/utils/post'; import {sanitizeReactions} from '@database/operator/utils/reaction'; -import type {WriterInterface} from '@nozbe/watermelondb/Database'; - -import type ReactionModel from '@typings/database/models/servers/reaction'; - import {mockedPosts, mockedReactions} from './mock'; +import type {WriterInterface} from '@nozbe/watermelondb/Database'; +import type ReactionModel from '@typings/database/models/servers/reaction'; + describe('DataOperator: Utils tests', () => { it('=> sanitizePosts: should filter between ordered and unordered posts', () => { const {postsOrdered, postsUnordered} = sanitizePosts({ diff --git a/app/database/schema/app/index.ts b/app/database/schema/app/index.ts index 96e2185480..8141bb5414 100644 --- a/app/database/schema/app/index.ts +++ b/app/database/schema/app/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {AppSchema, appSchema, tableSchema} from '@nozbe/watermelondb'; + import {MM_TABLES} from '@constants/database'; const {INFO, GLOBAL, SERVERS} = MM_TABLES.APP; diff --git a/app/helpers/database/groups.ts b/app/helpers/database/groups.ts index 23d61b9345..965f1b6754 100644 --- a/app/helpers/database/groups.ts +++ b/app/helpers/database/groups.ts @@ -5,9 +5,9 @@ import {MM_TABLES} from '@constants/database'; import type ChannelModel from '@typings/database/models/servers/channel'; import type GroupModel from '@typings/database/models/servers/group'; +import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; import type GroupsChannelModel from '@typings/database/models/servers/groups_channel'; import type GroupsTeamModel from '@typings/database/models/servers/groups_team'; -import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; import type PostModel from '@typings/database/models/servers/post'; import type TeamModel from '@typings/database/models/servers/team'; diff --git a/app/init/analytics.ts b/app/init/analytics.ts index 2289365989..24cb8641dd 100644 --- a/app/init/analytics.ts +++ b/app/init/analytics.ts @@ -1,8 +1,8 @@ // 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 DeviceInfo from 'react-native-device-info'; import LocalConfig from '@assets/config.json'; diff --git a/app/init/global_event_handler.ts b/app/init/global_event_handler.ts index 84234ecb15..508cd95980 100644 --- a/app/init/global_event_handler.ts +++ b/app/init/global_event_handler.ts @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Alert, DeviceEventEmitter, Linking, Platform} from 'react-native'; import CookieManager, {Cookie} from '@react-native-cookies/cookies'; +import {Alert, DeviceEventEmitter, Linking, Platform} from 'react-native'; import semver from 'semver'; import {fetchConfigAndLicense} from '@actions/remote/systems'; diff --git a/app/init/managed_app.ts b/app/init/managed_app.ts index 6c5bc8ba73..adcd2e5d05 100644 --- a/app/init/managed_app.ts +++ b/app/init/managed_app.ts @@ -2,8 +2,8 @@ // See LICENSE.txt for license information. import Emm, {ManagedConfig} from '@mattermost/react-native-emm'; -import {Alert, AlertButton, AppState, AppStateStatus, Platform} from 'react-native'; import JailMonkey from 'jail-monkey'; +import {Alert, AlertButton, AppState, AppStateStatus, Platform} from 'react-native'; import {DEFAULT_LOCALE, getTranslations, t} from '@i18n'; import {getIOSAppGroupDetails} from '@utils/mattermost_managed'; diff --git a/app/init/network_manager.ts b/app/init/network_manager.ts index 308e2aecb9..cbeb8de924 100644 --- a/app/init/network_manager.ts +++ b/app/init/network_manager.ts @@ -1,9 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {DeviceEventEmitter} from 'react-native'; -import DeviceInfo from 'react-native-device-info'; - import Emm from '@mattermost/react-native-emm'; import { APIClientErrorEvent, @@ -11,6 +8,8 @@ import { getOrCreateAPIClient, RetryTypes, } from '@mattermost/react-native-network-client'; +import {DeviceEventEmitter} from 'react-native'; +import DeviceInfo from 'react-native-device-info'; import LocalConfig from '@assets/config.json'; import {Client} from '@client/rest'; diff --git a/app/init/push_notifications.ts b/app/init/push_notifications.ts index fe14eede27..fb6977b210 100644 --- a/app/init/push_notifications.ts +++ b/app/init/push_notifications.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n'; import {AppState, DeviceEventEmitter, Platform} from 'react-native'; import DeviceInfo from 'react-native-device-info'; import { @@ -18,6 +17,7 @@ import { import {Device, General, Navigation} from '@constants'; import {GLOBAL_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; +import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n'; import {getLaunchPropsFromNotification, relaunchApp} from '@init/launch'; import NativeNotifications from '@notifications'; import {queryMentionCount} from '@queries/app/global'; diff --git a/app/queries/app/global.ts b/app/queries/app/global.ts index 6e0bcd3bd5..6efea1382e 100644 --- a/app/queries/app/global.ts +++ b/app/queries/app/global.ts @@ -1,9 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {GLOBAL_IDENTIFIERS, MM_TABLES} from '@constants/database'; import {Database} from '@nozbe/watermelondb'; +import {GLOBAL_IDENTIFIERS, MM_TABLES} from '@constants/database'; + import type Global from '@typings/database/models/app/global'; const {APP: {GLOBAL}} = MM_TABLES; diff --git a/app/queries/app/servers.ts b/app/queries/app/servers.ts index 7b5483c5f2..dfc864a504 100644 --- a/app/queries/app/servers.ts +++ b/app/queries/app/servers.ts @@ -1,9 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {MM_TABLES} from '@constants/database'; import {Database, Q} from '@nozbe/watermelondb'; +import {MM_TABLES} from '@constants/database'; + import type Servers from '@typings/database/models/app/servers'; const {APP: {SERVERS}} = MM_TABLES; diff --git a/app/queries/servers/team.ts b/app/queries/servers/team.ts index d40c1b3e0a..a35be7c18a 100644 --- a/app/queries/servers/team.ts +++ b/app/queries/servers/team.ts @@ -7,8 +7,8 @@ import {Database as DatabaseConstants} from '@constants'; import type ServerDataOperator from '@database/operator/server_data_operator'; import type MyTeamModel from '@typings/database/models/servers/my_team'; -import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history'; import type TeamModel from '@typings/database/models/servers/team'; +import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history'; const {MY_TEAM, TEAM, TEAM_CHANNEL_HISTORY} = DatabaseConstants.MM_TABLES.SERVER; diff --git a/app/screens/about/title.tsx b/app/screens/about/title.tsx index 1ca8798484..acb2860c8c 100644 --- a/app/screens/about/title.tsx +++ b/app/screens/about/title.tsx @@ -1,9 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import FormattedText from '@components/formatted_text'; import React from 'react'; +import FormattedText from '@components/formatted_text'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; import {makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/screens/channel/channel_nav_bar/channel_title/index.tsx b/app/screens/channel/channel_nav_bar/channel_title/index.tsx index 2fb659abba..d162950802 100644 --- a/app/screens/channel/channel_nav_bar/channel_title/index.tsx +++ b/app/screens/channel/channel_nav_bar/channel_title/index.tsx @@ -18,11 +18,11 @@ import ChannelDisplayName from './channel_display_name'; import ChannelGuestLabel from './channel_guest_label'; import type {WithDatabaseArgs} from '@typings/database/database'; -import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; import type ChannelModel from '@typings/database/models/servers/channel'; +import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; -import type UserModel from '@typings/database/models/servers/user'; import type SystemModel from '@typings/database/models/servers/system'; +import type UserModel from '@typings/database/models/servers/user'; type WithChannelArgs = WithDatabaseArgs & { currentUserId: SystemModel; diff --git a/app/screens/channel/channel_nav_bar/index.tsx b/app/screens/channel/channel_nav_bar/index.tsx index 0b5ee70fb2..5757c6c55b 100644 --- a/app/screens/channel/channel_nav_bar/index.tsx +++ b/app/screens/channel/channel_nav_bar/index.tsx @@ -7,9 +7,9 @@ import React from 'react'; import {DeviceEventEmitter, LayoutChangeEvent, Platform, useWindowDimensions, View} from 'react-native'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; -import {useTheme} from '@context/theme'; import {Device, View as ViewConstants} from '@constants'; import {MM_TABLES} from '@constants/database'; +import {useTheme} from '@context/theme'; import {useSplitView} from '@hooks/device'; import {makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/screens/channel/index.tsx b/app/screens/channel/index.tsx index 33af5de38e..e7b7491b83 100644 --- a/app/screens/channel/index.tsx +++ b/app/screens/channel/index.tsx @@ -3,7 +3,6 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; -import {goToScreen} from '@screens/navigation'; import React, {useMemo} from 'react'; import {useIntl} from 'react-intl'; import {Text, View} from 'react-native'; @@ -16,6 +15,7 @@ import StatusBar from '@components/status_bar'; import {Screens, Database} from '@constants'; import {useServerUrl} from '@context/server_url'; import {useTheme} from '@context/theme'; +import {goToScreen} from '@screens/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import ChannelNavBar from './channel_nav_bar'; diff --git a/app/screens/forgot_password/forgot_password.test.tsx b/app/screens/forgot_password/forgot_password.test.tsx index 98e49def6a..c1510c36ae 100644 --- a/app/screens/forgot_password/forgot_password.test.tsx +++ b/app/screens/forgot_password/forgot_password.test.tsx @@ -4,8 +4,8 @@ import {act, waitFor} from '@testing-library/react-native'; import React from 'react'; -import {Preferences} from '@constants'; import * as SessionAPICalls from '@actions/remote/session'; +import {Preferences} from '@constants'; import {renderWithIntl, fireEvent} from '@test/intl-test-helper'; import ForgotPassword from './index'; diff --git a/app/screens/forgot_password/index.tsx b/app/screens/forgot_password/index.tsx index aa15ee0fb4..498a7c30e4 100644 --- a/app/screens/forgot_password/index.tsx +++ b/app/screens/forgot_password/index.tsx @@ -7,9 +7,9 @@ import {Image, Text, TextInput, TouchableWithoutFeedback, View} from 'react-nati import Button from 'react-native-button'; import {SafeAreaView} from 'react-native-safe-area-context'; +import {sendPasswordResetEmail} from '@actions/remote/session'; import ErrorText from '@components/error_text'; import FormattedText from '@components/formatted_text'; -import {sendPasswordResetEmail} from '@actions/remote/session'; import {isEmail} from '@utils/helpers'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/screens/home/index.tsx b/app/screens/home/index.tsx index eef1860afb..5732582421 100644 --- a/app/screens/home/index.tsx +++ b/app/screens/home/index.tsx @@ -1,8 +1,8 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {NavigationContainer} from '@react-navigation/native'; import {createBottomTabNavigator, BottomTabBarProps} from '@react-navigation/bottom-tabs'; +import {NavigationContainer} from '@react-navigation/native'; import React from 'react'; import {Platform} from 'react-native'; import {enableScreens} from 'react-native-screens'; diff --git a/app/screens/home/tab_bar/account.tsx b/app/screens/home/tab_bar/account.tsx index 3971d7a873..befa7482c3 100644 --- a/app/screens/home/tab_bar/account.tsx +++ b/app/screens/home/tab_bar/account.tsx @@ -8,7 +8,7 @@ import {View} from 'react-native'; import {switchMap} from 'rxjs/operators'; import ProfilePicture from '@components/profile_picture'; -import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@app/constants/database'; +import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import {makeStyleSheetFromTheme} from '@utils/theme'; import type {WithDatabaseArgs} from '@typings/database/database'; diff --git a/app/screens/home/tab_bar/home.tsx b/app/screens/home/tab_bar/home.tsx index 7e3841f3ba..cc358d7ed7 100644 --- a/app/screens/home/tab_bar/home.tsx +++ b/app/screens/home/tab_bar/home.tsx @@ -5,16 +5,15 @@ import {Q} from '@nozbe/watermelondb'; import React, {useEffect, useState} from 'react'; import {Platform, View} from 'react-native'; -import {MM_TABLES} from '@constants/database'; import Badge from '@components/badge'; import CompassIcon from '@components/compass_icon'; +import {MM_TABLES} from '@constants/database'; import DatabaseManager from '@database/manager'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import type {Subscription} from 'rxjs'; - import type ServersModel from '@typings/database/models/app/servers'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; +import type {Subscription} from 'rxjs'; type Props = { isFocused: boolean; diff --git a/app/screens/home/tab_bar/index.tsx b/app/screens/home/tab_bar/index.tsx index d3c872e1e0..edb346a30d 100644 --- a/app/screens/home/tab_bar/index.tsx +++ b/app/screens/home/tab_bar/index.tsx @@ -3,8 +3,8 @@ import React, {useEffect, useState} from 'react'; import {DeviceEventEmitter, View, TouchableOpacity, useWindowDimensions} from 'react-native'; -import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated'; import {Shadow} from 'react-native-neomorph-shadows'; +import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/screens/index.tsx b/app/screens/index.tsx index cf9a3f9788..e1e94e26b8 100644 --- a/app/screens/index.tsx +++ b/app/screens/index.tsx @@ -5,13 +5,13 @@ import {withManagedConfig} from '@mattermost/react-native-emm'; import React from 'react'; import {IntlProvider} from 'react-intl'; import {Platform, StyleProp, ViewStyle} from 'react-native'; -import {Navigation, NavigationFunctionComponent} from 'react-native-navigation'; import {gestureHandlerRootHOC} from 'react-native-gesture-handler'; +import {Navigation, NavigationFunctionComponent} from 'react-native-navigation'; import {SafeAreaProvider} from 'react-native-safe-area-context'; import {Screens} from '@constants'; -import {DEFAULT_LOCALE, getTranslations} from '@i18n'; import {withServerDatabase} from '@database/components'; +import {DEFAULT_LOCALE, getTranslations} from '@i18n'; // TODO: Remove this and uncomment screens as they get added /* eslint-disable */ diff --git a/app/screens/login/index.tsx b/app/screens/login/index.tsx index a7c13ac1e2..234dd861dd 100644 --- a/app/screens/login/index.tsx +++ b/app/screens/login/index.tsx @@ -1,5 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {useManagedConfig} from '@mattermost/react-native-emm'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; import { @@ -21,11 +22,10 @@ import Button from 'react-native-button'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import {NavigationFunctionComponent} from 'react-native-navigation'; -import ErrorText from '@components/error_text'; -import {FORGOT_PASSWORD, MFA} from '@constants/screens'; -import FormattedText from '@components/formatted_text'; -import {useManagedConfig} from '@mattermost/react-native-emm'; import {login} from '@actions/remote/session'; +import ErrorText from '@components/error_text'; +import FormattedText from '@components/formatted_text'; +import {FORGOT_PASSWORD, MFA} from '@constants/screens'; import {t} from '@i18n'; import {goToScreen, resetToChannel} from '@screens/navigation'; import {preventDoubleTap} from '@utils/tap'; diff --git a/app/screens/login_options/index.tsx b/app/screens/login_options/index.tsx index c45755b0e3..a18d7e5a3d 100644 --- a/app/screens/login_options/index.tsx +++ b/app/screens/login_options/index.tsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {LOGIN, SSO} from '@constants/screens'; import React from 'react'; import {useIntl} from 'react-intl'; import {Image, ScrollView, StatusBar, Text} from 'react-native'; @@ -9,11 +8,10 @@ import {NavigationFunctionComponent} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; import FormattedText from '@components/formatted_text'; +import {LOGIN, SSO} from '@constants/screens'; import {goToScreen} from '@screens/navigation'; import {preventDoubleTap} from '@utils/tap'; -import {changeOpacity, makeStyleSheetFromTheme} from '@app/utils/theme'; - -import type {LaunchProps} from '@typings/launch'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import EmailOption from './email'; import GitLabOption from './gitlab'; @@ -23,6 +21,8 @@ import Office365Option from './office365'; import OpenIdOption from './open_id'; import SamlOption from './saml'; +import type {LaunchProps} from '@typings/launch'; + interface LoginOptionsProps extends LaunchProps { componentId: string; serverUrl: string; diff --git a/app/screens/mfa/index.tsx b/app/screens/mfa/index.tsx index 2ab213aa21..bf24c40281 100644 --- a/app/screens/mfa/index.tsx +++ b/app/screens/mfa/index.tsx @@ -16,9 +16,9 @@ import { import Button from 'react-native-button'; import {SafeAreaView} from 'react-native-safe-area-context'; +import {login} from '@actions/remote/session'; import ErrorText from '@components/error_text'; import FormattedText from '@components/formatted_text'; -import {login} from '@actions/remote/session'; import {t} from '@i18n'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; diff --git a/app/screens/mfa/mfa.test.tsx b/app/screens/mfa/mfa.test.tsx index 878d5e0dfb..8e1fa20d00 100644 --- a/app/screens/mfa/mfa.test.tsx +++ b/app/screens/mfa/mfa.test.tsx @@ -1,10 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {fireEvent, waitFor} from '@testing-library/react-native'; import React from 'react'; import {Preferences} from '@constants'; -import {fireEvent, waitFor} from '@testing-library/react-native'; import {renderWithIntl} from '@test/intl-test-helper'; import Mfa from './index'; diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index c8cf357ea1..1f09966f52 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -1,13 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import merge from 'deepmerge'; import {Appearance, DeviceEventEmitter, Keyboard, Platform} from 'react-native'; import {Navigation, Options, OptionsModalPresentationStyle} from 'react-native-navigation'; -import merge from 'deepmerge'; import {Device, Preferences, Screens} from '@constants'; import NavigationConstants from '@constants/navigation'; import EphemeralStore from '@store/ephemeral_store'; + import type {LaunchProps} from '@typings/launch'; Navigation.setDefaultOptions({ diff --git a/app/screens/server/index.tsx b/app/screens/server/index.tsx index e05df0ad0a..b5e4ea71da 100644 --- a/app/screens/server/index.tsx +++ b/app/screens/server/index.tsx @@ -22,13 +22,12 @@ import FormattedText from '@components/formatted_text'; import {Screens} from '@constants'; import NetworkManager from '@init/network_manager'; import {goToScreen} from '@screens/navigation'; +import {DeepLinkWithData, LaunchProps, LaunchType} from '@typings/launch'; import {isMinimumServerVersion} from '@utils/helpers'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {getServerUrlAfterRedirect, isValidUrl, sanitizeUrl} from '@utils/url'; -import {DeepLinkWithData, LaunchProps, LaunchType} from '@typings/launch'; - interface ServerProps extends LaunchProps { componentId: string; theme: Theme; diff --git a/app/screens/sso/index.tsx b/app/screens/sso/index.tsx index 201960a6cf..7b020c7290 100644 --- a/app/screens/sso/index.tsx +++ b/app/screens/sso/index.tsx @@ -4,16 +4,16 @@ import {useManagedConfig} from '@mattermost/react-native-emm'; import React, {useState} from 'react'; -import {SSO as SSOEnum} from '@constants'; import {ssoLogin} from '@actions/remote/session'; +import {SSO as SSOEnum} from '@constants'; import {resetToChannel} from '@screens/navigation'; import {isMinimumServerVersion} from '@utils/helpers'; -import type {LaunchProps} from '@typings/launch'; - import SSOWithRedirectURL from './sso_with_redirect_url'; import SSOWithWebView from './sso_with_webview'; +import type {LaunchProps} from '@typings/launch'; + interface SSOProps extends LaunchProps { config: Partial; license: Partial; diff --git a/app/screens/sso/sso_with_redirect_url.tsx b/app/screens/sso/sso_with_redirect_url.tsx index 8cc80d7155..980d750aff 100644 --- a/app/screens/sso/sso_with_redirect_url.tsx +++ b/app/screens/sso/sso_with_redirect_url.tsx @@ -10,7 +10,7 @@ import urlParse from 'url-parse'; import FormattedText from '@components/formatted_text'; import Loading from '@components/loading'; import {REDIRECT_URL_SCHEME, REDIRECT_URL_SCHEME_DEV} from '@constants'; -import NetworkManager from '@app/init/network_manager'; +import NetworkManager from '@init/network_manager'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {tryOpenURL} from '@utils/url'; diff --git a/app/utils/draft/index.ts b/app/utils/draft/index.ts index b08d4bbd24..8b3771a19d 100644 --- a/app/utils/draft/index.ts +++ b/app/utils/draft/index.ts @@ -4,10 +4,10 @@ import {MessageDescriptor} from '@formatjs/intl/src/types'; import {Alert, AlertButton} from 'react-native'; -import type {IntlShape} from 'react-intl'; - import {t} from '@i18n'; +import type {IntlShape} from 'react-intl'; + export function errorBadChannel(intl: IntlShape) { const message = { id: t('mobile.server_link.unreachable_channel.error'), diff --git a/app/utils/file/index.ts b/app/utils/file/index.ts index a4b9c6e41b..a1298733c1 100644 --- a/app/utils/file/index.ts +++ b/app/utils/file/index.ts @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import Model from '@nozbe/watermelondb/Model'; import mimeDB from 'mime-db'; import {Platform} from 'react-native'; import {FileSystem} from 'react-native-unimodules'; @@ -10,7 +11,6 @@ import {hashCode} from '@utils/security'; import {removeProtocol} from '@utils/url'; import type FileModel from '@typings/database/models/servers/file'; -import Model from '@nozbe/watermelondb/Model'; const EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/; const CONTENT_DISPOSITION_REGEXP = /inline;filename=".*\.([a-z]+)";/i; diff --git a/app/utils/markdown/index.ts b/app/utils/markdown/index.ts index 72fa13c6b2..56bc2813ca 100644 --- a/app/utils/markdown/index.ts +++ b/app/utils/markdown/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import {Platform, StyleSheet} from 'react-native'; + import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; export function getCodeFont() { diff --git a/app/utils/post/index.ts b/app/utils/post/index.ts index c073fcee49..2b023e5234 100644 --- a/app/utils/post/index.ts +++ b/app/utils/post/index.ts @@ -5,9 +5,9 @@ import {Post} from '@constants'; import {DEFAULT_LOCALE} from '@i18n'; import {displayUsername} from '@utils/user'; +import type GroupModel from '@typings/database/models/servers/group'; import type PostModel from '@typings/database/models/servers/post'; import type UserModel from '@typings/database/models/servers/user'; -import type GroupModel from '@typings/database/models/servers/group'; import type {UserMentionKey} from '@typings/global/markdown'; export function areConsecutivePosts(post: PostModel, previousPost: PostModel) { diff --git a/app/utils/sentry.ts b/app/utils/sentry.ts index 7961fb581d..83e416b7fb 100644 --- a/app/utils/sentry.ts +++ b/app/utils/sentry.ts @@ -1,10 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Platform} from 'react-native'; import {Breadcrumb, Severity} from '@sentry/types'; +import {Platform} from 'react-native'; import Config from '@assets/config.json'; + import {ClientError} from './client_error'; export const BREADCRUMB_UNCAUGHT_APP_ERROR = 'uncaught-app-error'; diff --git a/app/utils/url/index.ts b/app/utils/url/index.ts index 7c894c265c..93db88e345 100644 --- a/app/utils/url/index.ts +++ b/app/utils/url/index.ts @@ -1,11 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import GenericClient from '@mattermost/react-native-network-client'; import {Linking} from 'react-native'; import urlParse from 'url-parse'; -import GenericClient from '@mattermost/react-native-network-client'; - import {Files} from '@constants'; import {DeepLinkType, DeepLinkWithData} from '@typings/launch'; import {emptyFunction} from '@utils/general'; diff --git a/app/utils/url/test.ts b/app/utils/url/test.ts index c954a9fa2c..9efa367cbe 100644 --- a/app/utils/url/test.ts +++ b/app/utils/url/test.ts @@ -3,9 +3,8 @@ import {Linking} from 'react-native'; -import * as UrlUtils from '@utils/url'; - import {DeepLinkType} from '@typings/launch'; +import * as UrlUtils from '@utils/url'; /* eslint-disable max-nested-callbacks */ diff --git a/app/utils/user/index.ts b/app/utils/user/index.ts index 7064ca63c3..9f7aabde48 100644 --- a/app/utils/user/index.ts +++ b/app/utils/user/index.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import moment from 'moment-timezone'; + import {General, Preferences} from '@constants'; import {UserModel} from '@database/models/server'; import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n'; diff --git a/detox/e2e/path_builder.js b/detox/e2e/path_builder.js index 3e2050d7a5..36d829019c 100644 --- a/detox/e2e/path_builder.js +++ b/detox/e2e/path_builder.js @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. const path = require('path'); + const sanitizeFilename = require('sanitize-filename'); const SANITIZE_OPTIONS = {replacement: '_'}; diff --git a/detox/e2e/support/server_api/common.js b/detox/e2e/support/server_api/common.js index 5cfc0aa393..b9b5dbee9a 100644 --- a/detox/e2e/support/server_api/common.js +++ b/detox/e2e/support/server_api/common.js @@ -1,9 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import FormData from 'form-data'; import fs from 'fs'; +import FormData from 'form-data'; + import client from './client'; export const getResponseFromError = (err) => { diff --git a/detox/e2e/support/server_api/system.js b/detox/e2e/support/server_api/system.js index 8009b94b8c..6fb3712267 100644 --- a/detox/e2e/support/server_api/system.js +++ b/detox/e2e/support/server_api/system.js @@ -1,11 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import merge from 'deepmerge'; -import jestExpect from 'expect'; import path from 'path'; import testConfig from '@support/test_config'; +import merge from 'deepmerge'; +import jestExpect from 'expect'; import client from './client'; import {apiUploadFile, getResponseFromError} from './common'; diff --git a/index.ts b/index.ts index c591d0df88..9de4b84097 100644 --- a/index.ts +++ b/index.ts @@ -10,8 +10,8 @@ import DatabaseManager from './app/database/manager'; import {getAllServerCredentials} from './app/init/credentials'; import GlobalEventHandler from './app/init/global_event_handler'; import {initialLaunch} from './app/init/launch'; -import NetworkManager from './app/init/network_manager'; import ManagedApp from './app/init/managed_app'; +import NetworkManager from './app/init/network_manager'; import PushNotifications from './app/init/push_notifications'; import {registerScreens} from './app/screens'; import EphemeralStore from './app/store/ephemeral_store'; diff --git a/package-lock.json b/package-lock.json index 8384a3806a..c1e16bbd13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -127,6 +127,7 @@ "detox": "18.20.0", "eslint": "7.31.0", "eslint-plugin-header": "3.1.1", + "eslint-plugin-import": "2.23.4", "eslint-plugin-jest": "24.4.0", "eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#46ad99355644a719bf32082f472048f526605181", "eslint-plugin-react": "7.24.0", @@ -4858,7 +4859,7 @@ }, "node_modules/@mattermost/react-native-network-client": { "version": "0.1.0", - "resolved": "git+ssh://git@github.com/mattermost/react-native-network-client.git#52e2f9be66a5af660b7875bfbee6de859e339831", + "resolved": "git+ssh://git@github.com/mattermost/react-native-network-client.git#74cc214aea9e31878bc45f24c6bf31531a6e9b07", "license": "MIT", "dependencies": { "validator": "13.6.0", @@ -7541,6 +7542,12 @@ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "node_modules/@types/keyv": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.2.tgz", @@ -9014,6 +9021,23 @@ "node": ">=0.10.0" } }, + "node_modules/array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.flatmap": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", @@ -12627,6 +12651,117 @@ "eslint": ">=3.14.1" } }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", + "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-plugin-eslint-comments": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", @@ -12679,6 +12814,180 @@ "eslint": ">=7.7.0" } }, + "node_modules/eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/eslint-plugin-import/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-plugin-jest": { "version": "24.4.0", "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.4.0.tgz", @@ -21439,7 +21748,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -21454,7 +21762,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "peer": true, "engines": { "node": ">=4" } @@ -21463,7 +21770,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "peer": true, "engines": { "node": ">=4" } @@ -31074,6 +31380,39 @@ "node": ">=10" } }, + "node_modules/tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", @@ -36419,7 +36758,7 @@ "requires": {} }, "@mattermost/react-native-network-client": { - "version": "git+ssh://git@github.com/mattermost/react-native-network-client.git#52e2f9be66a5af660b7875bfbee6de859e339831", + "version": "git+ssh://git@github.com/mattermost/react-native-network-client.git#74cc214aea9e31878bc45f24c6bf31531a6e9b07", "from": "@mattermost/react-native-network-client@github:mattermost/react-native-network-client", "requires": { "validator": "13.6.0", @@ -38596,6 +38935,12 @@ "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/keyv": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.2.tgz", @@ -39821,6 +40166,17 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, "array.prototype.flatmap": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", @@ -42843,6 +43199,100 @@ "get-stdin": "^6.0.0" } }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz", + "integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + } + } + }, "eslint-plugin-eslint-comments": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", @@ -42877,6 +43327,143 @@ "dev": true, "requires": {} }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + } + } + }, "eslint-plugin-jest": { "version": "24.4.0", "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.4.0.tgz", @@ -49469,7 +50056,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "peer": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -49480,14 +50066,12 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "peer": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "peer": true + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" } } }, @@ -57246,6 +57830,35 @@ } } }, + "tsconfig-paths": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "tslib": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", diff --git a/package.json b/package.json index fe4bff0a0e..649df63b05 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,7 @@ "detox": "18.20.0", "eslint": "7.31.0", "eslint-plugin-header": "3.1.1", + "eslint-plugin-import": "2.23.4", "eslint-plugin-jest": "24.4.0", "eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#46ad99355644a719bf32082f472048f526605181", "eslint-plugin-react": "7.24.0", diff --git a/share_extension/index.tsx b/share_extension/index.tsx index fefa7425e3..47cd573f63 100644 --- a/share_extension/index.tsx +++ b/share_extension/index.tsx @@ -10,7 +10,6 @@ import { Text, StatusBar, } from 'react-native'; - import { Header, LearnMoreLinks, diff --git a/test/setup.ts b/test/setup.ts index 4f293217e7..c6e7f39340 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -3,9 +3,9 @@ /* eslint-disable react/no-multi-comp */ +import MockAsyncStorage from 'mock-async-storage'; import * as ReactNative from 'react-native'; -import MockAsyncStorage from 'mock-async-storage'; import 'react-native-gesture-handler/jestSetup'; require('react-native-reanimated/lib/reanimated2/jestUtils').setUpTests(); diff --git a/test/test_helper.js b/test/test_helper.js index 1a861cb6aa..fa83450822 100644 --- a/test/test_helper.js +++ b/test/test_helper.js @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. import assert from 'assert'; + import nock from 'nock'; import Config from '@assets/config.json'; diff --git a/types/database/database.d.ts b/types/database/database.d.ts index af97bf7828..2f51bb74df 100644 --- a/types/database/database.d.ts +++ b/types/database/database.d.ts @@ -8,14 +8,14 @@ import Model from '@nozbe/watermelondb/Model'; import {Clause} from '@nozbe/watermelondb/QueryDescription'; import {Class} from '@nozbe/watermelondb/utils/common'; +import {DatabaseType} from './enums'; + import type AppDataOperator from '@database/operator/app_data_operator'; -import type ServerDataOperator from '@app/database/operator/server_data_operator'; +import type ServerDataOperator from '@database/operator/server_data_operator'; import type {Config} from '@typings/database/models/servers/config'; import type {License} from '@typings/database/models/servers/license'; import type System from '@typings/database/models/servers/system'; -import {DatabaseType} from './enums'; - export type WithDatabaseArgs = { database: Database } export type CreateServerDatabaseConfig = { diff --git a/types/modules/react-native-slider.d.ts b/types/modules/react-native-slider.d.ts index 5c2d642836..4cd4306ec3 100644 --- a/types/modules/react-native-slider.d.ts +++ b/types/modules/react-native-slider.d.ts @@ -1,7 +1,6 @@ /* eslint-disable header/header */ declare module 'react-native-slider' { import {ComponentClass} from 'react'; - import { ImageSourcePropType, SpringAnimationConfig,