diff --git a/.gitignore b/.gitignore index a597d9eb59..2fa17c24c3 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,8 @@ local.properties *.iml *.hprof .cxx/ +*.keystore +!debug.keystore android/app/bin android/app/build android/build @@ -61,12 +63,6 @@ npm-debug.log yarn-error.log .yarninstall -# BUCK -buck-out/ -\.buckd/ -android/app/libs -*.keystore - # Vim [._]*.s[a-w][a-z] [._]s[a-w][a-z] @@ -114,3 +110,6 @@ launch.json # Notice.txt generation !build/notice-file + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 3065d8f3d1..275b5cc36d 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,4 +1,4 @@ -Submit feature requests to http://www.mattermost.org/feature-requests/. File non-security related bugs here in the following format: +Submit feature requests to https://portal.productboard.com/mattermost/33-what-matters-to-you. File non-security related bugs here in the following format: #### Summary Issue in one concise sentence. diff --git a/android/app/BUCK b/android/app/BUCK deleted file mode 100644 index 5aec4b5916..0000000000 --- a/android/app/BUCK +++ /dev/null @@ -1,65 +0,0 @@ -# To learn about Buck see [Docs](https://buckbuild.com/). -# To run your application with Buck: -# - install Buck -# - `npm start` - to start the packager -# - `cd android` -# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` -# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck -# - `buck install -r android/app` - compile, install and run application -# - -lib_deps = [] - -for jarfile in glob(['libs/*.jar']): - name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] - lib_deps.append(':' + name) - prebuilt_jar( - name = name, - binary_jar = jarfile, - ) - -for aarfile in glob(['libs/*.aar']): - name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] - lib_deps.append(':' + name) - android_prebuilt_aar( - name = name, - aar = aarfile, - ) - -android_library( - name = "all-libs", - exported_deps = lib_deps, -) - -android_library( - name = "app-code", - srcs = glob([ - "src/main/java/**/*.java", - ]), - deps = [ - ":all-libs", - ":build_config", - ":res", - ], -) - -android_build_config( - name = "build_config", - package = "com.mattermost.rnbeta", -) - -android_resource( - name = "res", - package = "com.mattermost.rnbeta", - res = "src/main/res", -) - -android_binary( - name = "app", - keystore = "//android/keystores:debug", - manifest = "src/main/AndroidManifest.xml", - package_type = "debug", - deps = [ - ":app-code", - ], -) diff --git a/android/app/build.gradle b/android/app/build.gradle index e58e62f6fb..b135678b06 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,88 +1,56 @@ apply plugin: "com.android.application" +apply plugin: "com.facebook.react" apply plugin: 'kotlin-android' import com.android.build.OutputFile -import org.apache.tools.ant.taskdefs.condition.Os + /** - * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets - * and bundleReleaseJsAndAssets). - * These basically call `react-native bundle` with the correct arguments during the Android build - * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the - * bundle directly from the development server. Below you can see all the possible configurations - * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "../../node_modules/react-native/react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation. If none specified and - * // "index.android.js" exists, it will be used. Otherwise "index.js" is - * // default. Can be overridden with ENTRY_FILE environment variable. - * entryFile: "index.android.js", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property can be in the following formats - * // 'bundleIn${productFlavor}${buildType}' - * // 'bundleIn${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // whether to disable dev mode in custom build variants (by default only disabled in release) - * // for example: to disable dev mode in the staging build type (if configured) - * devDisabledInStaging: true, - * // The configuration property can be in the following formats - * // 'devDisabledIn${productFlavor}${buildType}' - * // 'devDisabledIn${buildType}' - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"], - * - * // supply additional arguments to the packager - * extraPackagerArgs: [] - * ] + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. */ -project.ext.react = [ - entryFile: "index.ts", - bundleConfig: "metro.config.js", - bundleCommand: "bundle", - enableHermes: true, -] + react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + // codegenDir = file("../node_modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + entryFile = file("../../index.ts") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} -apply from: "../../node_modules/react-native/react.gradle" apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" if (System.getenv("SENTRY_ENABLED") == "true") { @@ -95,33 +63,35 @@ if (System.getenv("SENTRY_ENABLED") == "true") { } /** - * Set this to true to create two separate APKs instead of one: - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store */ def enableSeparateBuildPerCPUArchitecture = project.hasProperty('separateApk') ? project.property('separateApk').toBoolean() : false /** - * Run Proguard to shrink the Java bytecode in release builds. + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ def enableProguardInReleaseBuilds = false +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ def jscFlavor = 'org.webkit:android-jsc-intl:+' /** - * Whether to enable the Hermes VM. - * - * This should be set on project.ext.react and that value will be read here. If it is not set - * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode - * and the benefits of using Hermes will therefore be sharply reduced. - */ -def enableHermes = project.ext.react.get("enableHermes", false); - -/** - * Architectures to build native code for. + * Private function to get the list of Native Architectures you want to build. + * This reads the value from reactNativeArchitectures in your gradle.properties + * file and works together with the --active-arch-only flag of react-native run-android. */ def reactNativeArchitectures() { def value = project.getProperties().get("reactNativeArchitectures") @@ -131,84 +101,21 @@ def reactNativeArchitectures() { android { ndkVersion rootProject.ext.ndkVersion compileSdkVersion rootProject.ext.compileSdkVersion + namespace "com.mattermost.rnbeta" lintOptions { checkReleaseBuilds false abortOnError false } - packagingOptions { - pickFirst '**/libc++_shared.so' - } - defaultConfig { applicationId "com.mattermost.rnbeta" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 452 + versionCode 453 versionName "2.0.0" testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' - buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() - - if (isNewArchitectureEnabled()) { - // We configure the CMake build only if you decide to opt-in for the New Architecture. - externalNativeBuild { - cmake { - arguments "-DPROJECT_BUILD_DIR=$buildDir", - "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", - "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", - "-DNODE_MODULES_DIR=$rootDir/../node_modules", - "-DANDROID_STL=c++_shared" - } - } - if (!enableSeparateBuildPerCPUArchitecture) { - ndk { - abiFilters (*reactNativeArchitectures()) - } - } - } - } - - if (isNewArchitectureEnabled()) { - // We configure the NDK build only if you decide to opt-in for the New Architecture. - externalNativeBuild { - cmake { - path "$projectDir/src/main/jni/CMakeLists.txt" - } - } - def reactAndroidProjectDir = project(':ReactAndroid').projectDir - def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) { - dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck") - from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") - into("$buildDir/react-ndk/exported") - } - def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) { - dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck") - from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") - into("$buildDir/react-ndk/exported") - } - afterEvaluate { - // If you wish to add a custom TurboModule or component locally, - // you should uncomment this line. - // preBuild.dependsOn("generateCodegenArtifactsFromSchema") - preDebugBuild.dependsOn(packageReactNdkDebugLibs) - preReleaseBuild.dependsOn(packageReactNdkReleaseLibs) - - // Due to a bug inside AGP, we have to explicitly set a dependency - // between configureCMakeDebug* tasks and the preBuild tasks. - // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732 - configureCMakeDebugRelease.dependsOn(preReleaseBuild) - configureCMakeDebugDebug.dependsOn(preDebugBuild) - reactNativeArchitectures().each { architecture -> - tasks.findByName("configureCMakeDebugDebug[${architecture}]")?.configure { - dependsOn("preDebugBuild") - } - tasks.findByName("configureCMakeDebugRelease[${architecture}]")?.configure { - dependsOn("preReleaseBuild") - } - } - } } signingConfigs { @@ -281,70 +188,36 @@ repositories { } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") - //noinspection GradleDynamicVersio - implementation "com.facebook.react:react-native:+" // From node_modules + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' - - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" - - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { - exclude group:'com.facebook.fbjni' - } + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.facebook.flipper' - } - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { - exclude group:'com.facebook.flipper' + exclude group:'com.squareup.okhttp3', module:'okhttp' } - - if (enableHermes) { - //noinspection GradleDynamicVersion - implementation("com.facebook.react:hermes-engine:+") { // From node_modules - exclude group:'com.facebook.fbjni' - } + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") } else { implementation jscFlavor } + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - - implementation project(':reactnativenotifications') implementation "com.google.firebase:firebase-messaging:$firebaseVersion" - // For animated GIF support - implementation 'com.facebook.fresco:fresco:2.6.0' - implementation 'com.facebook.fresco:animated-gif:2.6.0' - // For WebP support, including animated WebP - implementation 'com.facebook.fresco:animated-webp:2.6.0' - implementation 'com.facebook.fresco:webpsupport:2.6.0' - androidTestImplementation('com.wix:detox:+') - + implementation project(':reactnativenotifications') implementation project(':watermelondb-jsi') } configurations.all { - if (isNewArchitectureEnabled()) { - // If new architecture is enabled, we let you build RN from source - // Otherwise we fallback to a prebuilt .aar bundled in the NPM package. - // This will be applied to all the imported transtitive dependency. - resolutionStrategy.dependencySubstitution { - substitute(module("com.facebook.react:react-native")) - .using(project(":ReactAndroid")) - .because("On New Architecture we're building React Native from source") - substitute(module("com.facebook.react:hermes-engine")) - .using(project(":ReactAndroid:hermes-engine")) - .because("On New Architecture we're building Hermes from source") - } - } resolutionStrategy { - force "com.facebook.soloader:soloader:0.10.1" eachDependency { DependencyResolveDetails details -> if (details.requested.name == 'play-services-base') { details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' @@ -359,13 +232,13 @@ configurations.all { details.useTarget group: details.requested.group, name: details.requested.name, version: '15.0.1' } if (details.requested.name == 'okhttp') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '4.9.2' + details.useTarget group: details.requested.group, name: details.requested.name, version: '4.10.0' } if (details.requested.name == 'okhttp-tls') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '4.9.2' + details.useTarget group: details.requested.group, name: details.requested.name, version: '4.10.0' } if (details.requested.name == 'okhttp-urlconnection') { - details.useTarget group: details.requested.group, name: details.requested.name, version: '4.9.2' + details.useTarget group: details.requested.group, name: details.requested.name, version: '4.10.0' } } } @@ -380,11 +253,3 @@ task copyDownloadableDepsToLibs(type: Copy) { apply plugin: 'com.google.gms.google-services' apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) - -def isNewArchitectureEnabled() { - // To opt-in for the New Architecture, you can either: - // - Set `newArchEnabled` to true inside the `gradle.properties` file - // - Invoke gradle with `-newArchEnabled=true` - // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` - return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" -} diff --git a/android/app/debug.keystore b/android/app/debug.keystore new file mode 100644 index 0000000000..364e105ed3 Binary files /dev/null and b/android/app/debug.keystore differ diff --git a/android/app/src/debug/java/com/rn/ReactNativeFlipper.java b/android/app/src/debug/java/com/mattermost/flipper/ReactNativeFlipper.java similarity index 93% rename from android/app/src/debug/java/com/rn/ReactNativeFlipper.java rename to android/app/src/debug/java/com/mattermost/flipper/ReactNativeFlipper.java index 1197406be4..bfffa468db 100644 --- a/android/app/src/debug/java/com/rn/ReactNativeFlipper.java +++ b/android/app/src/debug/java/com/mattermost/flipper/ReactNativeFlipper.java @@ -4,7 +4,7 @@ *

This source code is licensed under the MIT license found in the LICENSE file in the root * directory of this source tree. */ -package com.rn; +package com.mattermost.flipper; import android.content.Context; import com.facebook.flipper.android.AndroidFlipperClient; @@ -17,19 +17,22 @@ import com.facebook.flipper.plugins.inspector.DescriptorMapping; import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; -import com.facebook.flipper.plugins.react.ReactFlipperPlugin; import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; import com.facebook.react.ReactInstanceEventListener; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.ReactContext; import com.facebook.react.modules.network.NetworkingModule; import okhttp3.OkHttpClient; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the debug + * flavor of it. Here you can add your own plugins and customize the Flipper setup. + */ public class ReactNativeFlipper { public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { if (FlipperUtils.shouldEnableFlipper(context)) { final FlipperClient client = AndroidFlipperClient.getInstance(context); client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); - client.addPlugin(new ReactFlipperPlugin()); client.addPlugin(new DatabasesFlipperPlugin(context)); client.addPlugin(new SharedPreferencesFlipperPlugin(context)); client.addPlugin(CrashReporterPlugin.getInstance()); diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9fb7308cc5..1dd89c48e4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,10 +1,10 @@ - + + diff --git a/android/app/src/main/java/com/mattermost/newarchitecture/MainApplicationReactNativeHost.java b/android/app/src/main/java/com/mattermost/newarchitecture/MainApplicationReactNativeHost.java deleted file mode 100644 index 5a5d736bf9..0000000000 --- a/android/app/src/main/java/com/mattermost/newarchitecture/MainApplicationReactNativeHost.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.mattermost.newarchitecture; - -import android.app.Application; -import androidx.annotation.NonNull; -import com.facebook.react.PackageList; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.ReactPackageTurboModuleManagerDelegate; -import com.facebook.react.bridge.JSIModulePackage; -import com.facebook.react.bridge.JSIModuleProvider; -import com.facebook.react.bridge.JSIModuleSpec; -import com.facebook.react.bridge.JSIModuleType; -import com.facebook.react.bridge.JavaScriptContextHolder; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.UIManager; -import com.facebook.react.fabric.ComponentFactory; -import com.facebook.react.fabric.CoreComponentsRegistry; -import com.facebook.react.fabric.FabricJSIModuleProvider; -import com.facebook.react.fabric.ReactNativeConfig; -import com.facebook.react.uimanager.ViewManagerRegistry; -import com.mattermost.rnbeta.BuildConfig; -import com.mattermost.newarchitecture.components.MainComponentsRegistry; -import com.mattermost.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; -import java.util.ArrayList; -import java.util.List; - -/** - * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both - * TurboModule delegates and the Fabric Renderer. - * - *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the - * `newArchEnabled` property). Is ignored otherwise. - */ -public class MainApplicationReactNativeHost extends ReactNativeHost { - public MainApplicationReactNativeHost(Application application) { - super(application); - } - - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - List packages = new PackageList(this).getPackages(); - // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); - // TurboModules must also be loaded here providing a valid TurboReactPackage implementation: - // packages.add(new TurboReactPackage() { ... }); - // If you have custom Fabric Components, their ViewManagers should also be loaded here - // inside a ReactPackage. - return packages; - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - - @NonNull - @Override - protected ReactPackageTurboModuleManagerDelegate.Builder - getReactPackageTurboModuleManagerDelegateBuilder() { - // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary - // for the new architecture and to use TurboModules correctly. - return new MainApplicationTurboModuleManagerDelegate.Builder(); - } - - @Override - protected JSIModulePackage getJSIModulePackage() { - return new JSIModulePackage() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { - final List specs = new ArrayList<>(); - - // Here we provide a new JSIModuleSpec that will be responsible of providing the - // custom Fabric Components. - specs.add( - new JSIModuleSpec() { - @Override - public JSIModuleType getJSIModuleType() { - return JSIModuleType.UIManager; - } - - @Override - public JSIModuleProvider getJSIModuleProvider() { - final ComponentFactory componentFactory = new ComponentFactory(); - CoreComponentsRegistry.register(componentFactory); - - // Here we register a Components Registry. - // The one that is generated with the template contains no components - // and just provides you the one from React Native core. - MainComponentsRegistry.register(componentFactory); - - final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); - - ViewManagerRegistry viewManagerRegistry = - new ViewManagerRegistry( - reactInstanceManager.getOrCreateViewManagers(reactApplicationContext)); - - return new FabricJSIModuleProvider( - reactApplicationContext, - componentFactory, - ReactNativeConfig.DEFAULT_CONFIG, - viewManagerRegistry); - } - }); - return specs; - } - }; - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/newarchitecture/components/MainComponentsRegistry.java b/android/app/src/main/java/com/mattermost/newarchitecture/components/MainComponentsRegistry.java deleted file mode 100644 index 4168988bd2..0000000000 --- a/android/app/src/main/java/com/mattermost/newarchitecture/components/MainComponentsRegistry.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.mattermost.newarchitecture.components; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.fabric.ComponentFactory; -import com.facebook.soloader.SoLoader; - -/** - * Class responsible to load the custom Fabric Components. This class has native methods and needs a - * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ - * folder for you). - * - *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the - * `newArchEnabled` property). Is ignored otherwise. - */ -@DoNotStrip -public class MainComponentsRegistry { - static { - SoLoader.loadLibrary("fabricjni"); - } - - @DoNotStrip private final HybridData mHybridData; - - @DoNotStrip - private native HybridData initHybrid(ComponentFactory componentFactory); - - @DoNotStrip - private MainComponentsRegistry(ComponentFactory componentFactory) { - mHybridData = initHybrid(componentFactory); - } - - @DoNotStrip - public static MainComponentsRegistry register(ComponentFactory componentFactory) { - return new MainComponentsRegistry(componentFactory); - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java b/android/app/src/main/java/com/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java deleted file mode 100644 index a5e3176747..0000000000 --- a/android/app/src/main/java/com/mattermost/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.mattermost.newarchitecture.modules; - -import com.facebook.jni.HybridData; -import com.facebook.react.ReactPackage; -import com.facebook.react.ReactPackageTurboModuleManagerDelegate; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.soloader.SoLoader; -import java.util.List; - -/** - * Class responsible to load the TurboModules. This class has native methods and needs a - * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ - * folder for you). - * - *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the - * `newArchEnabled` property). Is ignored otherwise. - */ -public class MainApplicationTurboModuleManagerDelegate - extends ReactPackageTurboModuleManagerDelegate { - - private static volatile boolean sIsSoLibraryLoaded; - - protected MainApplicationTurboModuleManagerDelegate( - ReactApplicationContext reactApplicationContext, List packages) { - super(reactApplicationContext, packages); - } - - protected native HybridData initHybrid(); - - native boolean canCreateTurboModule(String moduleName); - - public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { - protected MainApplicationTurboModuleManagerDelegate build( - ReactApplicationContext context, List packages) { - return new MainApplicationTurboModuleManagerDelegate(context, packages); - } - } - - @Override - protected synchronized void maybeLoadOtherSoLibraries() { - if (!sIsSoLibraryLoaded) { - // If you change the name of your application .so file in the Android.mk file, - // make sure you update the name here as well. - SoLoader.loadLibrary("rndiffapp_appmodules"); - sIsSoLibraryLoaded = true; - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java b/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java index a8f89866f8..1a2772b09a 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java @@ -6,37 +6,36 @@ import androidx.annotation.Nullable; import android.view.KeyEvent; import android.content.res.Configuration; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.WritableMap; import com.facebook.react.ReactActivityDelegate; -import com.facebook.react.ReactRootView; import com.reactnativenavigation.NavigationActivity; import com.github.emilioicai.hwkeyboardevent.HWKeyboardEventModule; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactActivityDelegate; + public class MainActivity extends NavigationActivity { private boolean HWKeyboardConnected = false; - public static class MainActivityDelegate extends ReactActivityDelegate { - public MainActivityDelegate(NavigationActivity activity, String mainComponentName) { - super(activity, mainComponentName); - } + @Override + protected String getMainComponentName() { + return "Mattermost"; + } - @Override - protected ReactRootView createRootView() { - ReactRootView reactRootView = new ReactRootView(getContext()); - // If you opted-in for the New Architecture, we enable the Fabric Renderer. - reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); - return reactRootView; - } - - @Override - protected boolean isConcurrentRootEnabled() { - // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). - // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html - return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; - } + /** + * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link + * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. + */ + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new DefaultReactActivityDelegate( + this, + getMainComponentName(), + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled + // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). + DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled + ); } @Override 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 29d030d776..6892c087f6 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java @@ -1,7 +1,4 @@ package com.mattermost.rnbeta; - -import com.facebook.react.bridge.JSIModuleSpec; - import android.content.Context; import android.os.Bundle; import android.util.Log; @@ -23,11 +20,12 @@ import com.wix.reactnativenotifications.core.AppLifecycleFacade; import com.wix.reactnativenotifications.core.JsIOHelper; import com.facebook.react.PackageList; -import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactPackage; -import com.facebook.react.config.ReactFeatureFlags; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactNativeHost; import com.facebook.react.ReactNativeHost; import com.facebook.react.TurboReactPackage; +import com.facebook.react.bridge.JSIModuleSpec; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.JSIModulePackage; @@ -36,8 +34,8 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.modules.network.OkHttpClientProvider; import com.facebook.soloader.SoLoader; +import com.mattermost.flipper.ReactNativeFlipper; import com.mattermost.networkclient.RCTOkHttpClientFactory; -import com.mattermost.newarchitecture.MainApplicationReactNativeHost; import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage; public class MainApplication extends NavigationApplication implements INotificationsApplication { @@ -46,7 +44,7 @@ public class MainApplication extends NavigationApplication implements INotificat public Boolean sharedExtensionIsOpened = false; private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { + new DefaultReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; @@ -106,30 +104,26 @@ public class MainApplication extends NavigationApplication implements INotificat protected String getJSMainModuleName() { return "index"; } + + @Override + protected boolean isNewArchEnabled() { + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + @Override + protected Boolean isHermesEnabled() { + return BuildConfig.IS_HERMES_ENABLED; + } }; - - private final ReactNativeHost mNewArchitectureNativeHost = - new MainApplicationReactNativeHost(this); @Override public ReactNativeHost getReactNativeHost() { - if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { - return mNewArchitectureNativeHost; - } else { - return mReactNativeHost; - } + return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); instance = this; - - // If you opted-in for the New Architecture, we enable the TurboModule system - ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; - SoLoader.init(this, /* native exopackage */ false); - initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); - Context context = getApplicationContext(); // Delete any previous temp files created by the app @@ -141,6 +135,13 @@ public class MainApplication extends NavigationApplication implements INotificat // with a cookie jar defined in APIClientModule and an interceptor to intercept all // requests that originate from React Native's OKHttpClient OkHttpClientProvider.setOkHttpClientFactory(new RCTOkHttpClientFactory()); + + SoLoader.init(this, /* native exopackage */ false); + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + DefaultNewArchitectureEntryPoint.load(); + } + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } @Override @@ -153,26 +154,4 @@ public class MainApplication extends NavigationApplication implements INotificat new JsIOHelper() ); } - - /** - * Loads Flipper in React Native templates. Call this in the onCreate method with something like - * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); - */ - private static void initializeFlipper( - Context context, ReactInstanceManager reactInstanceManager) { - if (BuildConfig.DEBUG) { - try { - /* - We use reflection here to pick up the class that initializes Flipper, - since Flipper library is not available in release mode - */ - Class aClass = Class.forName("com.rn.ReactNativeFlipper"); - aClass - .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) - .invoke(null, context, reactInstanceManager); - } catch (Exception e) { - e.printStackTrace(); - } - } - } } diff --git a/android/app/src/main/java/com/mattermost/share/ShareUtils.java b/android/app/src/main/java/com/mattermost/share/ShareUtils.java index b8ca97e7ba..143326edf2 100644 --- a/android/app/src/main/java/com/mattermost/share/ShareUtils.java +++ b/android/app/src/main/java/com/mattermost/share/ShareUtils.java @@ -90,22 +90,26 @@ public class ShareUtils { } private static Bitmap getBitmapAtTime(Context context, String filePath, int time) { - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - if (URLUtil.isFileUrl(filePath)) { - String decodedPath; - try { - decodedPath = URLDecoder.decode(filePath, "UTF-8"); - } catch (UnsupportedEncodingException e) { - decodedPath = filePath; + try { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + if (URLUtil.isFileUrl(filePath)) { + String decodedPath; + try { + decodedPath = URLDecoder.decode(filePath, "UTF-8"); + } catch (UnsupportedEncodingException e) { + decodedPath = filePath; + } + + retriever.setDataSource(decodedPath.replace("file://", "")); + } else if (filePath.contains("content://")) { + retriever.setDataSource(context, Uri.parse(filePath)); } - retriever.setDataSource(decodedPath.replace("file://", "")); - } else if (filePath.contains("content://")) { - retriever.setDataSource(context, Uri.parse(filePath)); + Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); + retriever.release(); + return image; + } catch (Exception e) { + throw new IllegalStateException("File doesn't exist or not supported"); } - - Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); - retriever.release(); - return image; } } diff --git a/android/app/src/main/jni/CMakeLists.txt b/android/app/src/main/jni/CMakeLists.txt deleted file mode 100644 index 6e63f482b8..0000000000 --- a/android/app/src/main/jni/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.13) - -# Define the library name here. -project(rndiffapp_appmodules) - -# This file includes all the necessary to let you build your application with the New Architecture. -include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) diff --git a/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/android/app/src/main/jni/MainApplicationModuleProvider.cpp deleted file mode 100644 index d34a1e4989..0000000000 --- a/android/app/src/main/jni/MainApplicationModuleProvider.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "MainApplicationModuleProvider.h" - -#include -#include - -namespace facebook { -namespace react { - -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms) { - // Here you can provide your own module provider for TurboModules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a library called `samplelibrary`: - // - // auto module = samplelibrary_ModuleProvider(moduleName, params); - // if (module != nullptr) { - // return module; - // } - // return rncore_ModuleProvider(moduleName, params); - - // Module providers autolinked by RN CLI - auto rncli_module = rncli_ModuleProvider(moduleName, params); - if (rncli_module != nullptr) { - return rncli_module; - } - - return rncore_ModuleProvider(moduleName, params); -} - -} // namespace react -} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainApplicationModuleProvider.h b/android/app/src/main/jni/MainApplicationModuleProvider.h deleted file mode 100644 index 48f1d107a1..0000000000 --- a/android/app/src/main/jni/MainApplicationModuleProvider.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace facebook { -namespace react { - -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms); - -} // namespace react -} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp deleted file mode 100644 index 5fd688c509..0000000000 --- a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "MainApplicationTurboModuleManagerDelegate.h" -#include "MainApplicationModuleProvider.h" - -namespace facebook { -namespace react { - -jni::local_ref -MainApplicationTurboModuleManagerDelegate::initHybrid( - jni::alias_ref) { - return makeCxxInstance(); -} - -void MainApplicationTurboModuleManagerDelegate::registerNatives() { - registerHybrid({ - makeNativeMethod( - "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), - makeNativeMethod( - "canCreateTurboModule", - MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), - }); -} - -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) { - // Not implemented yet: provide pure-C++ NativeModules here. - return nullptr; -} - -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) { - return MainApplicationModuleProvider(name, params); -} - -bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( - const std::string &name) { - return getTurboModule(name, nullptr) != nullptr || - getTurboModule(name, {.moduleName = name}) != nullptr; -} - -} // namespace react -} // namespace facebook diff --git a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h deleted file mode 100644 index 58ced33388..0000000000 --- a/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -#include -#include - -namespace facebook { -namespace react { - -class MainApplicationTurboModuleManagerDelegate - : public jni::HybridClass< - MainApplicationTurboModuleManagerDelegate, - TurboModuleManagerDelegate> { - public: - // Adapt it to the package you used for your Java class. - static constexpr auto kJavaDescriptor = - "Lcom/rndiffapp/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; - - static jni::local_ref initHybrid(jni::alias_ref); - - static void registerNatives(); - - std::shared_ptr getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) override; - std::shared_ptr getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) override; - - /** - * Test-only method. Allows user to verify whether a TurboModule can be - * created by instances of this class. - */ - bool canCreateTurboModule(const std::string &name); -}; - -} // namespace react -} // namespace facebook diff --git a/android/app/src/main/jni/MainComponentsRegistry.cpp b/android/app/src/main/jni/MainComponentsRegistry.cpp deleted file mode 100644 index 54f598a486..0000000000 --- a/android/app/src/main/jni/MainComponentsRegistry.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "MainComponentsRegistry.h" - -#include -#include -#include -#include -#include - -namespace facebook { -namespace react { - -MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} - -std::shared_ptr -MainComponentsRegistry::sharedProviderRegistry() { - auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); - - // Autolinked providers registered by RN CLI - rncli_registerProviders(providerRegistry); - - // Custom Fabric Components go here. You can register custom - // components coming from your App or from 3rd party libraries here. - // - // providerRegistry->add(concreteComponentDescriptorProvider< - // AocViewerComponentDescriptor>()); - return providerRegistry; -} - -jni::local_ref -MainComponentsRegistry::initHybrid( - jni::alias_ref, - ComponentFactory *delegate) { - auto instance = makeCxxInstance(delegate); - - auto buildRegistryFunction = - [](EventDispatcher::Weak const &eventDispatcher, - ContextContainer::Shared const &contextContainer) - -> ComponentDescriptorRegistry::Shared { - auto registry = MainComponentsRegistry::sharedProviderRegistry() - ->createComponentDescriptorRegistry( - {eventDispatcher, contextContainer}); - - auto mutableRegistry = - std::const_pointer_cast(registry); - - mutableRegistry->setFallbackComponentDescriptor( - std::make_shared( - ComponentDescriptorParameters{ - eventDispatcher, contextContainer, nullptr})); - - return registry; - }; - - delegate->buildRegistryFunction = buildRegistryFunction; - return instance; -} - -void MainComponentsRegistry::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), - }); -} - -} // namespace react -} // namespace facebook diff --git a/android/app/src/main/jni/MainComponentsRegistry.h b/android/app/src/main/jni/MainComponentsRegistry.h deleted file mode 100644 index 07af8980b3..0000000000 --- a/android/app/src/main/jni/MainComponentsRegistry.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace facebook { -namespace react { - -class MainComponentsRegistry - : public facebook::jni::HybridClass { - public: - // Adapt it to the package you used for your Java class. - constexpr static auto kJavaDescriptor = - "Lcom/mattermost/newarchitecture/components/MainComponentsRegistry;"; - - static void registerNatives(); - - MainComponentsRegistry(ComponentFactory *delegate); - - private: - static std::shared_ptr - sharedProviderRegistry(); - - static jni::local_ref initHybrid( - jni::alias_ref, - ComponentFactory *delegate); -}; - -} // namespace react -} // namespace facebook \ No newline at end of file diff --git a/android/app/src/main/jni/OnLoad.cpp b/android/app/src/main/jni/OnLoad.cpp deleted file mode 100644 index ae1ef007d1..0000000000 --- a/android/app/src/main/jni/OnLoad.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "MainApplicationTurboModuleManagerDelegate.h" -#include "MainComponentsRegistry.h" - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { - return facebook::jni::initialize(vm, [] { - facebook::react::MainApplicationTurboModuleManagerDelegate:: - registerNatives(); - facebook::react::MainComponentsRegistry::registerNatives(); - }); -} \ No newline at end of file diff --git a/android/app/src/release/java/com/mattermost/flipper/ReactNativeFlipper.java b/android/app/src/release/java/com/mattermost/flipper/ReactNativeFlipper.java new file mode 100644 index 0000000000..ae3179b7cf --- /dev/null +++ b/android/app/src/release/java/com/mattermost/flipper/ReactNativeFlipper.java @@ -0,0 +1,19 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.mattermost.flipper; + +import android.content.Context; +import com.facebook.react.ReactInstanceManager; +/** + * Class responsible of loading Flipper inside your React Native application. This is the release + * flavor of it so it's empty as we don't want to load Flipper. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + // Do nothing as we don't want to initialize Flipper on Release. + } +} diff --git a/android/build.gradle b/android/build.gradle index 7672f725f8..11859e8dd4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,22 +2,18 @@ buildscript { ext { - buildToolsVersion = "31.0.0" + buildToolsVersion = "33.0.0" minSdkVersion = 24 - compileSdkVersion = 31 - targetSdkVersion = 31 - supportLibVersion = "31.0.0" + compileSdkVersion = 33 + targetSdkVersion = 33 + supportLibVersion = "33.0.0" kotlinVersion = "1.5.30" kotlin_version = "1.5.30" firebaseVersion = "21.0.0" RNNKotlinVersion = kotlinVersion - if (System.properties['os.arch'] == "aarch64") { - // For M1 Users we need to use the NDK 24 which added support for aarch64 - ndkVersion = "24.0.8215888" - } else { - // Otherwise we default to the side-by-side NDK version from AGP. - ndkVersion = "21.4.7075529" - } + + // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. + ndkVersion = "23.1.7779620" } repositories { mavenCentral() @@ -25,9 +21,8 @@ buildscript { google() } dependencies { - classpath("com.android.tools.build:gradle:7.2.1") + classpath("com.android.tools.build:gradle:7.3.1") classpath("com.facebook.react:react-native-gradle-plugin") - classpath("de.undercouch:gradle-download-task:5.0.1") classpath('com.google.gms:google-services:4.3.14') classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") @@ -38,50 +33,9 @@ buildscript { allprojects { repositories { - exclusiveContent { - // We get React Native's Android binaries exclusively through npm, - // from a local Maven repo inside node_modules/react-native/. - // (The use of exclusiveContent prevents looking elsewhere like Maven Central - // and potentially getting a wrong version.) - filter { - includeGroup "com.facebook.react" - } - forRepository { - maven { - url "$rootDir/../node_modules/react-native/android" - } - } - } - google() - mavenCentral() - mavenLocal() - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url("$rootDir/../node_modules/react-native/android") - - // Replace AAR from original RN with AAR from react-native-v8 - // url("$rootDir/../node_modules/react-native-v8/dist") - } - maven { - // Local Maven repo containing AARs with JSC library built for Android - url("$rootDir/../node_modules/jsc-android/dist") - - // prebuilt libv8android.so - // url("$rootDir/../node_modules/v8-android/dist") - } - maven { - url "https://www.jitpack.io" - } maven { url "$rootDir/../node_modules/detox/Detox-android" } - mavenCentral { - // We don't want to fetch react-native from Maven Central as there are - // older versions over there. - content { - excludeGroup "com.facebook.react" - } - } } } diff --git a/android/gradle.properties b/android/gradle.properties index 7b404d8c1e..7b2301ced7 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -40,4 +40,8 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false \ No newline at end of file +newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true diff --git a/android/settings.gradle b/android/settings.gradle index 25584d1873..95c1009da4 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,13 +1,5 @@ rootProject.name = 'Mattermost' include ':app' -includeBuild('../node_modules/react-native-gradle-plugin') -if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { - include(":ReactAndroid") - project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') - include(":ReactAndroid:hermes-engine") - project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') -} - include ':reactnativenotifications' project(':reactnativenotifications').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-notifications/lib/android/app') apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) @@ -15,3 +7,4 @@ include ':react-native-video' project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') include ':watermelondb-jsi' project(':watermelondb-jsi').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android-jsi') +includeBuild('../node_modules/react-native-gradle-plugin') diff --git a/app/actions/local/category.ts b/app/actions/local/category.ts index 26e8abb057..f3956dc9c0 100644 --- a/app/actions/local/category.ts +++ b/app/actions/local/category.ts @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; - import {CHANNELS_CATEGORY, DMS_CATEGORY} from '@constants/categories'; import DatabaseManager from '@database/manager'; import {prepareCategoryChannels, queryCategoriesByTeamIds, getCategoryById, prepareCategoriesAndCategoriesChannels} from '@queries/servers/categories'; @@ -11,6 +9,7 @@ import {queryMyTeams} from '@queries/servers/team'; import {isDMorGM} from '@utils/channel'; import {logError} from '@utils/log'; +import type {Model} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; export const deleteCategory = async (serverUrl: string, categoryId: string) => { diff --git a/app/actions/local/channel.test.ts b/app/actions/local/channel.test.ts index f739337790..5fbbae508b 100644 --- a/app/actions/local/channel.test.ts +++ b/app/actions/local/channel.test.ts @@ -1,13 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database} from '@nozbe/watermelondb'; import {DeviceEventEmitter} from 'react-native'; import {Navigation} from '@constants'; import {SYSTEM_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; -import ServerDataOperator from '@database/operator/server_data_operator'; import {getMyChannel} from '@queries/servers/channel'; import {getCommonSystemValues, getTeamHistory} from '@queries/servers/system'; import {getTeamChannelHistory} from '@queries/servers/team'; @@ -15,6 +13,9 @@ import {dismissAllModalsAndPopToRoot, dismissAllModalsAndPopToScreen} from '@scr import {switchToChannel} from './channel'; +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type {Database} from '@nozbe/watermelondb'; + let mockIsTablet: jest.Mock; const now = new Date('2020-01-01').getTime(); diff --git a/app/actions/local/channel.ts b/app/actions/local/channel.ts index be4c2e2194..f31cac9aa1 100644 --- a/app/actions/local/channel.ts +++ b/app/actions/local/channel.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; import {DeviceEventEmitter} from 'react-native'; import {General, Navigation as NavigationConstants, Preferences, Screens} from '@constants'; @@ -24,6 +23,7 @@ import {isTablet} from '@utils/helpers'; import {logError, logInfo} from '@utils/log'; import {displayGroupMessageName, displayUsername, getUserIdFromChannelName} from '@utils/user'; +import type {Model} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/actions/local/post.ts b/app/actions/local/post.ts index 98fe62ad51..5f8b99fdc1 100644 --- a/app/actions/local/post.ts +++ b/app/actions/local/post.ts @@ -3,6 +3,7 @@ import {fetchPostAuthors} from '@actions/remote/post'; import {ActionType, Post} from '@constants'; +import {MM_TABLES} from '@constants/database'; import DatabaseManager from '@database/manager'; import {getPostById, prepareDeletePost, queryPostsById} from '@queries/servers/post'; import {getCurrentUserId} from '@queries/servers/system'; @@ -18,6 +19,8 @@ import type MyChannelModel from '@typings/database/models/servers/my_channel'; import type PostModel from '@typings/database/models/servers/post'; import type UserModel from '@typings/database/models/servers/user'; +const {SERVER: {DRAFT, FILE, POST, POSTS_IN_THREAD, REACTION, THREAD, THREAD_PARTICIPANT, THREADS_IN_TEAM}} = MM_TABLES; + export const sendAddToChannelEphemeralPost = async (serverUrl: string, user: UserModel, addedUsernames: string[], messages: string[], channeId: string, postRootId = '') => { try { const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); @@ -244,3 +247,31 @@ export async function getPosts(serverUrl: string, ids: string[]) { return []; } } + +export async function deletePosts(serverUrl: string, postIds: string[]) { + try { + const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + + const postsFormatted = `'${postIds.join("','")}'`; + + await database.write(() => { + return database.adapter.unsafeExecute({ + sqls: [ + [`DELETE FROM ${POST} where id IN (${postsFormatted})`, []], + [`DELETE FROM ${REACTION} where post_id IN (${postsFormatted})`, []], + [`DELETE FROM ${FILE} where post_id IN (${postsFormatted})`, []], + [`DELETE FROM ${DRAFT} where root_id IN (${postsFormatted})`, []], + + [`DELETE FROM ${POSTS_IN_THREAD} where root_id IN (${postsFormatted})`, []], + + [`DELETE FROM ${THREAD} where id IN (${postsFormatted})`, []], + [`DELETE FROM ${THREAD_PARTICIPANT} where thread_id IN (${postsFormatted})`, []], + [`DELETE FROM ${THREADS_IN_TEAM} where thread_id IN (${postsFormatted})`, []], + ], + }); + }); + return {error: false}; + } catch (error) { + return {error}; + } +} diff --git a/app/actions/local/systems.ts b/app/actions/local/systems.ts index 070e4c8076..a64a7f3a30 100644 --- a/app/actions/local/systems.ts +++ b/app/actions/local/systems.ts @@ -1,14 +1,23 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {Q} from '@nozbe/watermelondb'; import deepEqual from 'deep-equal'; -import {SYSTEM_IDENTIFIERS} from '@constants/database'; +import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; import {getServerCredentials} from '@init/credentials'; -import {getConfig, getLicense} from '@queries/servers/system'; +import {queryAllChannelsForTeam} from '@queries/servers/channel'; +import {getConfig, getLicense, getGlobalDataRetentionPolicy, getGranularDataRetentionPolicies, getLastGlobalDataRetentionRun, getIsDataRetentionEnabled} from '@queries/servers/system'; import {logError} from '@utils/log'; +import {deletePosts} from './post'; + +import type {DataRetentionPoliciesRequest} from '@actions/remote/systems'; +import type PostModel from '@typings/database/models/servers/post'; + +const {SERVER: {POST}} = MM_TABLES; + export async function storeConfigAndLicense(serverUrl: string, config: ClientConfig, license: ClientLicense) { try { // If we have credentials for this server then update the values in the database @@ -74,6 +83,155 @@ export async function storeConfig(serverUrl: string, config: ClientConfig | unde return []; } +export async function storeDataRetentionPolicies(serverUrl: string, data: DataRetentionPoliciesRequest, prepareRecordsOnly = false) { + try { + const {globalPolicy, teamPolicies, channelPolicies} = data; + const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + const systems: IdValue[] = [{ + id: SYSTEM_IDENTIFIERS.DATA_RETENTION_POLICIES, + value: globalPolicy || {}, + }, { + id: SYSTEM_IDENTIFIERS.GRANULAR_DATA_RETENTION_POLICIES, + value: { + team: teamPolicies || [], + channel: channelPolicies || [], + }, + }]; + + return operator.handleSystem({ + systems, + prepareRecordsOnly, + }); + } catch { + return []; + } +} + +export async function updateLastDataRetentionRun(serverUrl: string, value?: number, prepareRecordsOnly = false) { + try { + const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + + const systems: IdValue[] = [{ + id: SYSTEM_IDENTIFIERS.LAST_DATA_RETENTION_RUN, + value: value || Date.now(), + }]; + + return operator.handleSystem({systems, prepareRecordsOnly}); + } catch (error) { + logError('Failed updateLastDataRetentionRun', error); + return {error}; + } +} + +export async function dataRetentionCleanup(serverUrl: string) { + try { + const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + + const isDataRetentionEnabled = await getIsDataRetentionEnabled(database); + if (!isDataRetentionEnabled) { + return {error: undefined}; + } + + const lastRunAt = await getLastGlobalDataRetentionRun(database); + const lastCleanedToday = new Date(lastRunAt).toDateString() === new Date().toDateString(); + + // Do not run if clean up is already done today + if (lastRunAt && lastCleanedToday) { + return {error: undefined}; + } + + const globalPolicy = await getGlobalDataRetentionPolicy(database); + const granularPoliciesData = await getGranularDataRetentionPolicies(database); + + // Get global data retention cutoff + let globalRetentionCutoff = 0; + if (globalPolicy?.message_deletion_enabled) { + globalRetentionCutoff = globalPolicy.message_retention_cutoff; + } + + // Get Granular data retention policies + let teamPolicies: TeamDataRetentionPolicy[] = []; + let channelPolicies: ChannelDataRetentionPolicy[] = []; + if (granularPoliciesData) { + teamPolicies = granularPoliciesData.team; + channelPolicies = granularPoliciesData.channel; + } + + const channelsCutoffs: {[key: string]: number} = {}; + + // Get channel level cutoff from team policies + for await (const teamPolicy of teamPolicies) { + const {team_id, post_duration} = teamPolicy; + const channelIds = await queryAllChannelsForTeam(database, team_id).fetchIds(); + if (channelIds.length) { + const cutoff = getDataRetentionPolicyCutoff(post_duration); + channelIds.forEach((channelId) => { + channelsCutoffs[channelId] = cutoff; + }); + } + } + + // Get channel level cutoff from channel policies + channelPolicies.forEach(({channel_id, post_duration}) => { + channelsCutoffs[channel_id] = getDataRetentionPolicyCutoff(post_duration); + }); + + const conditions = []; + + const channelIds = Object.keys(channelsCutoffs); + if (channelIds.length) { + // Fetch posts by channel level cutoff + for (const channelId of channelIds) { + const cutoff = channelsCutoffs[channelId]; + conditions.push(`(channel_id='${channelId}' AND create_at < ${cutoff})`); + } + + // Fetch posts by global cutoff which are not already fetched by channel level cutoff + conditions.push(`(channel_id NOT IN ('${channelIds.join("','")}') AND create_at < ${globalRetentionCutoff})`); + } else { + conditions.push(`create_at < ${globalRetentionCutoff}`); + } + + const postIds = await database.get(POST).query( + Q.unsafeSqlQuery(`SELECT * FROM ${POST} where ${conditions.join(' OR ')}`), + ).fetchIds(); + + if (postIds.length) { + const batchSize = 1000; + const deletePromises = []; + for (let i = 0; i < postIds.length; i += batchSize) { + const batch = postIds.slice(i, batchSize); + deletePromises.push( + deletePosts(serverUrl, batch), + ); + } + const deleteResult = await Promise.all(deletePromises); + for (const {error} of deleteResult) { + if (error) { + return {error}; + } + } + } + + await updateLastDataRetentionRun(serverUrl); + + return {error: undefined}; + } catch (error) { + logError('An error occurred while performing data retention cleanup', error); + return {error}; + } +} + +// Returns cutoff time based on the policy's post_duration +function getDataRetentionPolicyCutoff(postDuration: number) { + const periodDate = new Date(); + periodDate.setDate(periodDate.getDate() - postDuration); + periodDate.setHours(0); + periodDate.setMinutes(0); + periodDate.setSeconds(0); + return periodDate.getTime(); +} + export async function setLastServerVersionCheck(serverUrl: string, reset = false) { try { const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); diff --git a/app/actions/remote/apps.ts b/app/actions/remote/apps.ts index 8333d77fea..725112e142 100644 --- a/app/actions/remote/apps.ts +++ b/app/actions/remote/apps.ts @@ -1,16 +1,15 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; - import {sendEphemeralPost} from '@actions/local/post'; -import ClientError from '@client/rest/error'; import {AppCallResponseTypes} from '@constants/apps'; import NetworkManager from '@managers/network_manager'; import {cleanForm, createCallRequest, makeCallErrorResponse} from '@utils/apps'; import type {Client} from '@client/rest'; +import type ClientError from '@client/rest/error'; import type PostModel from '@typings/database/models/servers/post'; +import type {IntlShape} from 'react-intl'; export async function handleBindingClick(serverUrl: string, binding: AppBinding, context: AppContext, intl: IntlShape): Promise<{data?: AppCallResponse; error?: AppCallResponse}> { // Fetch form diff --git a/app/actions/remote/channel.ts b/app/actions/remote/channel.ts index 893b33e6e5..af1fb841d7 100644 --- a/app/actions/remote/channel.ts +++ b/app/actions/remote/channel.ts @@ -2,8 +2,6 @@ // See LICENSE.txt for license information. /* eslint-disable max-lines */ -import {Model} from '@nozbe/watermelondb'; -import {IntlShape} from 'react-intl'; import {DeviceEventEmitter} from 'react-native'; import {addChannelToDefaultCategory, storeCategories} from '@actions/local/category'; @@ -40,7 +38,9 @@ import {addCurrentUserToTeam, fetchTeamByName, removeCurrentUserFromTeam} from ' import {fetchProfilesInGroupChannels, fetchProfilesPerChannels, fetchUsersByIds, updateUsersNoLongerVisible} from './user'; import type {Client} from '@client/rest'; +import type {Model} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; +import type {IntlShape} from 'react-intl'; export type MyChannelsRequest = { categories?: CategoryWithChannels[]; diff --git a/app/actions/remote/command.ts b/app/actions/remote/command.ts index bcc7c25c19..e95576f697 100644 --- a/app/actions/remote/command.ts +++ b/app/actions/remote/command.ts @@ -1,11 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Alert} from 'react-native'; import {doAppSubmit, postEphemeralCallResponseForCommandArgs} from '@actions/remote/apps'; -import {Client} from '@client/rest'; import {AppCommandParser} from '@components/autocomplete/slash_suggestion/app_command_parser/app_command_parser'; import {AppCallResponseTypes} from '@constants/apps'; import DatabaseManager from '@database/manager'; @@ -18,6 +16,9 @@ import {showAppForm} from '@screens/navigation'; import {handleDeepLink, matchDeepLink} from '@utils/deep_link'; import {tryOpenURL} from '@utils/url'; +import type {Client} from '@client/rest'; +import type {IntlShape} from 'react-intl'; + export const executeCommand = async (serverUrl: string, intl: IntlShape, message: string, channelId: string, rootId?: string): Promise<{data?: CommandResponse; error?: string | {message: string}}> => { const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; if (!operator) { diff --git a/app/actions/remote/custom_emoji.ts b/app/actions/remote/custom_emoji.ts index cd034828b8..a2bec37a69 100644 --- a/app/actions/remote/custom_emoji.ts +++ b/app/actions/remote/custom_emoji.ts @@ -2,13 +2,14 @@ // See LICENSE.txt for license information. import {forceLogoutIfNecessary} from '@actions/remote/session'; -import {Client} from '@client/rest'; import {Emoji, General} from '@constants'; import DatabaseManager from '@database/manager'; import {debounce} from '@helpers/api/general'; import NetworkManager from '@managers/network_manager'; import {queryCustomEmojisByName} from '@queries/servers/custom_emoji'; +import type {Client} from '@client/rest'; + export const fetchCustomEmojis = async (serverUrl: string, page = 0, perPage = General.PAGE_SIZE_DEFAULT, sort = Emoji.SORT_BY_NAME) => { let client: Client; try { diff --git a/app/actions/remote/entry/app.ts b/app/actions/remote/entry/app.ts index 58d0210091..d825ea2e71 100644 --- a/app/actions/remote/entry/app.ts +++ b/app/actions/remote/entry/app.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {setLastServerVersionCheck} from '@actions/local/systems'; +import {dataRetentionCleanup, setLastServerVersionCheck} from '@actions/local/systems'; import {fetchConfigAndLicense} from '@actions/remote/systems'; import DatabaseManager from '@database/manager'; import {prepareCommonSystemValues, getCurrentTeamId, getWebSocketLastDisconnected, getCurrentChannelId, getConfig, getLicense} from '@queries/servers/system'; @@ -27,6 +27,9 @@ export async function appEntry(serverUrl: string, since = 0, isUpgrade = false) } } + // Run data retention cleanup + await dataRetentionCleanup(serverUrl); + // clear lastUnreadChannelId const removeLastUnreadChannelId = await prepareCommonSystemValues(operator, {lastUnreadChannelId: ''}); if (removeLastUnreadChannelId) { diff --git a/app/actions/remote/entry/common.ts b/app/actions/remote/entry/common.ts index 35ea06cd2f..beda43898e 100644 --- a/app/actions/remote/entry/common.ts +++ b/app/actions/remote/entry/common.ts @@ -1,8 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database, Model} from '@nozbe/watermelondb'; - +import {dataRetentionCleanup} from '@actions/local/systems'; import {fetchMissingDirectChannelsInfo, fetchMyChannelsForTeam, handleKickFromChannel, MyChannelsRequest} from '@actions/remote/channel'; import {fetchGroupsForMember} from '@actions/remote/groups'; import {fetchPostsForUnreadChannels} from '@actions/remote/post'; @@ -37,6 +36,7 @@ import {logDebug} from '@utils/log'; import {processIsCRTEnabled} from '@utils/thread'; import type ClientError from '@client/rest/error'; +import type {Database, Model} from '@nozbe/watermelondb'; export type AppEntryData = { initialTeamId: string; @@ -378,7 +378,9 @@ export const syncOtherServers = async (serverUrl: string) => { for (const server of servers) { if (server.url !== serverUrl && server.lastActiveAt > 0) { registerDeviceToken(server.url); - syncAllChannelMembersAndThreads(server.url); + syncAllChannelMembersAndThreads(server.url).then(() => { + dataRetentionCleanup(server.url); + }); autoUpdateTimezone(server.url); } } diff --git a/app/actions/remote/entry/gql_common.ts b/app/actions/remote/entry/gql_common.ts index 3006f2816c..32dae476f4 100644 --- a/app/actions/remote/entry/gql_common.ts +++ b/app/actions/remote/entry/gql_common.ts @@ -1,12 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database} from '@nozbe/watermelondb'; - import {storeConfigAndLicense} from '@actions/local/systems'; -import {MyChannelsRequest} from '@actions/remote/channel'; import {fetchGroupsForMember} from '@actions/remote/groups'; import {fetchPostsForUnreadChannels} from '@actions/remote/post'; +import {fetchDataRetentionPolicy} from '@actions/remote/systems'; import {MyTeamsRequest, updateCanJoinTeams} from '@actions/remote/team'; import {syncTeamThreads} from '@actions/remote/thread'; import {autoUpdateTimezone, updateAllUsersSince} from '@actions/remote/user'; @@ -18,14 +16,16 @@ import {selectDefaultTeam} from '@helpers/api/team'; import {queryAllChannels, queryAllChannelsForTeam} from '@queries/servers/channel'; import {prepareModels, truncateCrtRelatedTables} from '@queries/servers/entry'; import {getHasCRTChanged} from '@queries/servers/preference'; -import {getConfig} from '@queries/servers/system'; +import {getConfig, getIsDataRetentionEnabled} from '@queries/servers/system'; import {filterAndTransformRoles, getMemberChannelsFromGQLQuery, getMemberTeamsFromGQLQuery, gqlToClientChannelMembership, gqlToClientPreference, gqlToClientSidebarCategory, gqlToClientTeamMembership, gqlToClientUser} from '@utils/graphql'; import {logDebug} from '@utils/log'; import {processIsCRTEnabled} from '@utils/thread'; import {teamsToRemove, FETCH_UNREADS_TIMEOUT, entryRest, EntryResponse, entryInitialChannelId, restDeferredAppEntryActions, getRemoveTeamIds} from './common'; +import type {MyChannelsRequest} from '@actions/remote/channel'; import type ClientError from '@client/rest/error'; +import type {Database} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; export async function deferredAppEntryGraphQLActions( @@ -265,6 +265,12 @@ export const entry = async (serverUrl: string, teamId?: string, channelId?: stri result = entryRest(serverUrl, teamId, channelId, since); } + // Fetch data retention policies + const isDataRetentionEnabled = await getIsDataRetentionEnabled(database); + if (isDataRetentionEnabled) { + fetchDataRetentionPolicy(serverUrl); + } + return result; }; diff --git a/app/actions/remote/file.ts b/app/actions/remote/file.ts index feae6f6691..60fe5dd13a 100644 --- a/app/actions/remote/file.ts +++ b/app/actions/remote/file.ts @@ -1,20 +1,25 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ClientResponse, ClientResponseError} from '@mattermost/react-native-network-client'; - -import {Client} from '@client/rest'; -import ClientError from '@client/rest/error'; import {DOWNLOAD_TIMEOUT} from '@constants/network'; import NetworkManager from '@managers/network_manager'; import {forceLogoutIfNecessary} from './session'; +import type {Client} from '@client/rest'; +import type ClientError from '@client/rest/error'; +import type {ClientResponse, ClientResponseError} from '@mattermost/react-native-network-client'; + export const downloadFile = (serverUrl: string, fileId: string, desitnation: string) => { // Let it throw and handle it accordingly const client = NetworkManager.getClient(serverUrl); return client.apiClient.download(client.getFileRoute(fileId), desitnation.replace('file://', ''), {timeoutInterval: DOWNLOAD_TIMEOUT}); }; +export const downloadProfileImage = (serverUrl: string, userId: string, lastPictureUpdate: number, destination: string) => { // Let it throw and handle it accordingly + const client = NetworkManager.getClient(serverUrl); + return client.apiClient.download(client.getProfilePictureUrl(userId, lastPictureUpdate), destination.replace('file://', ''), {timeoutInterval: DOWNLOAD_TIMEOUT}); +}; + export const uploadFile = ( serverUrl: string, file: FileInfo, diff --git a/app/actions/remote/groups.ts b/app/actions/remote/groups.ts index 0ea353c85b..cd6997d21e 100644 --- a/app/actions/remote/groups.ts +++ b/app/actions/remote/groups.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client} from '@client/rest'; import DatabaseManager from '@database/manager'; import NetworkManager from '@managers/network_manager'; import {getChannelById} from '@queries/servers/channel'; @@ -9,6 +8,8 @@ import {getTeamById} from '@queries/servers/team'; import {forceLogoutIfNecessary} from './session'; +import type {Client} from '@client/rest'; + export const fetchGroup = async (serverUrl: string, id: string, fetchOnly = false) => { try { const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); diff --git a/app/actions/remote/post.ts b/app/actions/remote/post.ts index ba85a9240b..be2641b922 100644 --- a/app/actions/remote/post.ts +++ b/app/actions/remote/post.ts @@ -444,7 +444,7 @@ export async function fetchPostsBefore(serverUrl: string, channelId: string, pos } catch (error) { forceLogoutIfNecessary(serverUrl, error as ClientErrorProps); if (activeServerUrl === serverUrl) { - DeviceEventEmitter.emit(Events.LOADING_CHANNEL_POSTS, true); + DeviceEventEmitter.emit(Events.LOADING_CHANNEL_POSTS, false); } return {error}; } diff --git a/app/actions/remote/reactions.ts b/app/actions/remote/reactions.ts index 0684b7de51..5537acbf23 100644 --- a/app/actions/remote/reactions.ts +++ b/app/actions/remote/reactions.ts @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; - import {addRecentReaction} from '@actions/local/reactions'; import DatabaseManager from '@database/manager'; import NetworkManager from '@managers/network_manager'; @@ -14,6 +12,7 @@ import {getEmojiFirstAlias} from '@utils/emoji/helpers'; import {forceLogoutIfNecessary} from './session'; import type {Client} from '@client/rest'; +import type {Model} from '@nozbe/watermelondb'; import type PostModel from '@typings/database/models/servers/post'; export async function addReaction(serverUrl: string, postId: string, emojiName: string) { diff --git a/app/actions/remote/session.ts b/app/actions/remote/session.ts index df3460b914..68108e03b0 100644 --- a/app/actions/remote/session.ts +++ b/app/actions/remote/session.ts @@ -21,7 +21,6 @@ import {scheduleExpiredNotification} from '@utils/notification'; import {getCSRFFromCookie} from '@utils/security'; import {loginEntry} from './entry'; -import {fetchDataRetentionPolicy} from './systems'; import type ClientError from '@client/rest/error'; import type {LoginArgs} from '@typings/database/database'; @@ -42,11 +41,6 @@ export const completeLogin = async (serverUrl: string) => { return null; } - // Data retention - if (config?.DataRetentionEnableMessageDeletion === 'true' && license?.IsLicensed === 'true' && license?.DataRetention === 'true') { - fetchDataRetentionPolicy(serverUrl); - } - await DatabaseManager.setActiveServerDatabase(serverUrl); const systems: IdValue[] = []; diff --git a/app/actions/remote/systems.ts b/app/actions/remote/systems.ts index fbfbf1b52e..d8280b194b 100644 --- a/app/actions/remote/systems.ts +++ b/app/actions/remote/systems.ts @@ -1,12 +1,11 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {storeConfigAndLicense} from '@actions/local/systems'; +import {storeConfigAndLicense, storeDataRetentionPolicies} from '@actions/local/systems'; import {forceLogoutIfNecessary} from '@actions/remote/session'; -import {SYSTEM_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; import NetworkManager from '@managers/network_manager'; -import {logError} from '@utils/log'; +import {getCurrentUserId} from '@queries/servers/system'; import type ClientError from '@client/rest/error'; @@ -16,7 +15,47 @@ export type ConfigAndLicenseRequest = { error?: unknown; } -export const fetchDataRetentionPolicy = async (serverUrl: string) => { +export type DataRetentionPoliciesRequest = { + globalPolicy?: GlobalDataRetentionPolicy; + teamPolicies?: TeamDataRetentionPolicy[]; + channelPolicies?: ChannelDataRetentionPolicy[]; + error?: unknown; +} + +export const fetchDataRetentionPolicy = async (serverUrl: string, fetchOnly = false): Promise => { + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (!operator) { + return {error: `${serverUrl} database not found`}; + } + + try { + const {data: globalPolicy, error: globalPolicyError} = await fetchGlobalDataRetentionPolicy(serverUrl); + const {data: teamPolicies, error: teamPoliciesError} = await fetchAllGranularDataRetentionPolicies(serverUrl); + const {data: channelPolicies, error: channelPoliciesError} = await fetchAllGranularDataRetentionPolicies(serverUrl, true); + + const hasError = globalPolicyError || teamPoliciesError || channelPoliciesError; + if (hasError) { + return hasError; + } + + const data = { + globalPolicy, + teamPolicies: teamPolicies as TeamDataRetentionPolicy[], + channelPolicies: channelPolicies as ChannelDataRetentionPolicy[], + }; + + if (!fetchOnly) { + await storeDataRetentionPolicies(serverUrl, data); + } + + return data; + } catch (error) { + forceLogoutIfNecessary(serverUrl, error as ClientError); + return {error}; + } +}; + +export const fetchGlobalDataRetentionPolicy = async (serverUrl: string): Promise<{data?: GlobalDataRetentionPolicy; error?: unknown}> => { let client; try { client = NetworkManager.getClient(serverUrl); @@ -24,28 +63,47 @@ export const fetchDataRetentionPolicy = async (serverUrl: string) => { return {error}; } - let data = {}; try { - data = await client.getDataRetentionPolicy(); + const data = await client.getGlobalDataRetentionPolicy(); + return {data}; } catch (error) { forceLogoutIfNecessary(serverUrl, error as ClientError); return {error}; } +}; - const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; - if (operator) { - const systems: IdValue[] = [{ - id: SYSTEM_IDENTIFIERS.DATA_RETENTION_POLICIES, - value: JSON.stringify(data), - }]; - - operator.handleSystem({systems, prepareRecordsOnly: false}). - catch((error) => { - logError('An error occurred while saving data retention policies', error); - }); +export const fetchAllGranularDataRetentionPolicies = async ( + serverUrl: string, + isChannel = false, + page = 0, + policies: Array = [], +): Promise<{data?: Array; error?: unknown}> => { + let client; + try { + client = NetworkManager.getClient(serverUrl); + } catch (error) { + return {error}; } - return data; + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (!operator) { + return {error: `${serverUrl} database not found`}; + } + + const {database} = operator; + + const currentUserId = await getCurrentUserId(database); + let data; + if (isChannel) { + data = await client.getChannelDataRetentionPolicies(currentUserId, page); + } else { + data = await client.getTeamDataRetentionPolicies(currentUserId, page); + } + policies.push(...data.policies); + if (policies.length < data.total_count) { + await fetchAllGranularDataRetentionPolicies(serverUrl, isChannel, page + 1, policies); + } + return {data: policies}; }; export const fetchConfigAndLicense = async (serverUrl: string, fetchOnly = false): Promise => { diff --git a/app/actions/remote/team.ts b/app/actions/remote/team.ts index 1199288a97..2508e91b47 100644 --- a/app/actions/remote/team.ts +++ b/app/actions/remote/team.ts @@ -1,11 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; import {DeviceEventEmitter} from 'react-native'; import {removeUserFromTeam as localRemoveUserFromTeam} from '@actions/local/team'; -import {Client} from '@client/rest'; import {PER_PAGE_DEFAULT} from '@client/rest/constants'; import {Events} from '@constants'; import DatabaseManager from '@database/manager'; @@ -27,7 +25,9 @@ import {fetchPostsForChannel, fetchPostsForUnreadChannels} from './post'; import {fetchRolesIfNeeded} from './role'; import {forceLogoutIfNecessary} from './session'; +import type {Client} from '@client/rest'; import type ClientError from '@client/rest/error'; +import type {Model} from '@nozbe/watermelondb'; export type MyTeamsRequest = { teams?: Team[]; @@ -114,6 +114,54 @@ export async function addUserToTeam(serverUrl: string, teamId: string, userId: s } } +export async function addUsersToTeam(serverUrl: string, teamId: string, userIds: string[], fetchOnly = false) { + try { + const client = NetworkManager.getClient(serverUrl); + const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + EphemeralStore.startAddingToTeam(teamId); + + const members = await client.addUsersToTeamGracefully(teamId, userIds); + + if (!fetchOnly) { + const teamMemberships: TeamMembership[] = []; + const roles = []; + + for (const {member} of members) { + teamMemberships.push(member); + roles.push(...member.roles.split(' ')); + } + + fetchRolesIfNeeded(serverUrl, Array.from(new Set(roles))); + + if (operator) { + await operator.handleTeamMemberships({teamMemberships, prepareRecordsOnly: true}); + } + } + + EphemeralStore.finishAddingToTeam(teamId); + return {members}; + } catch (error) { + if (EphemeralStore.isAddingToTeam(teamId)) { + EphemeralStore.finishAddingToTeam(teamId); + } + + forceLogoutIfNecessary(serverUrl, error as ClientError); + return {error}; + } +} + +export async function sendEmailInvitesToTeam(serverUrl: string, teamId: string, emails: string[]) { + try { + const client = NetworkManager.getClient(serverUrl); + const members = await client.sendEmailInvitesToTeamGracefully(teamId, emails); + + return {members}; + } catch (error) { + forceLogoutIfNecessary(serverUrl, error as ClientError); + return {error}; + } +} + export async function fetchMyTeams(serverUrl: string, fetchOnly = false): Promise { let client; try { @@ -428,3 +476,28 @@ export async function handleKickFromTeam(serverUrl: string, teamId: string) { logDebug('Failed to kick user from team', error); } } + +export async function getTeamMembersByIds(serverUrl: string, teamId: string, userIds: string[], fetchOnly?: boolean) { + try { + const client = NetworkManager.getClient(serverUrl); + const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); + const members = await client.getTeamMembersByIds(teamId, userIds); + + if (!fetchOnly) { + const roles = []; + + for (const {roles: memberRoles} of members) { + roles.push(...memberRoles.split(' ')); + } + + fetchRolesIfNeeded(serverUrl, Array.from(new Set(roles))); + + await operator.handleTeamMemberships({teamMemberships: members, prepareRecordsOnly: true}); + } + + return {members}; + } catch (error) { + forceLogoutIfNecessary(serverUrl, error as ClientError); + return {error}; + } +} diff --git a/app/actions/remote/thread.ts b/app/actions/remote/thread.ts index 25f38abf10..f4e91b0de4 100644 --- a/app/actions/remote/thread.ts +++ b/app/actions/remote/thread.ts @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Model from '@nozbe/watermelondb/Model'; - import {markTeamThreadsAsRead, markThreadAsViewed, processReceivedThreads, switchToThread, updateTeamThreadsSync, updateThread} from '@actions/local/thread'; import {fetchPostThread} from '@actions/remote/post'; import {General} from '@constants'; @@ -19,6 +17,7 @@ import {getThreadsListEdges} from '@utils/thread'; import {forceLogoutIfNecessary} from './session'; import type {Client} from '@client/rest'; +import type Model from '@nozbe/watermelondb/Model'; type FetchThreadsOptions = { before?: string; diff --git a/app/actions/remote/user.ts b/app/actions/remote/user.ts index 195f316a20..a1d6dc9c78 100644 --- a/app/actions/remote/user.ts +++ b/app/actions/remote/user.ts @@ -3,7 +3,6 @@ /* eslint-disable max-lines */ -import {Model} from '@nozbe/watermelondb'; import {chunk} from 'lodash'; import {updateChannelsDisplayName} from '@actions/local/channel'; @@ -26,6 +25,7 @@ import {forceLogoutIfNecessary} from './session'; import type {Client} from '@client/rest'; import type ClientError from '@client/rest/error'; +import type {Model} from '@nozbe/watermelondb'; import type UserModel from '@typings/database/models/servers/user'; export type MyUserRequest = { diff --git a/app/actions/websocket/channel.ts b/app/actions/websocket/channel.ts index 189c7f7d12..9d29e73469 100644 --- a/app/actions/websocket/channel.ts +++ b/app/actions/websocket/channel.ts @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; - import {addChannelToDefaultCategory} from '@actions/local/category'; import { markChannelAsViewed, removeCurrentUserFromChannel, setChannelDeleteAt, @@ -22,6 +20,8 @@ import {getCurrentUser, getTeammateNameDisplay, getUserById} from '@queries/serv import EphemeralStore from '@store/ephemeral_store'; import {logDebug} from '@utils/log'; +import type {Model} from '@nozbe/watermelondb'; + // Received when current user created a channel in a different client export async function handleChannelCreatedEvent(serverUrl: string, msg: any) { const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; diff --git a/app/actions/websocket/posts.ts b/app/actions/websocket/posts.ts index 1c5877e18a..ead0530a12 100644 --- a/app/actions/websocket/posts.ts +++ b/app/actions/websocket/posts.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; import {DeviceEventEmitter} from 'react-native'; import {storeMyChannelsForTeam, markChannelAsUnread, markChannelAsViewed, updateLastPostAt} from '@actions/local/channel'; @@ -20,12 +19,11 @@ import NavigationStore from '@store/navigation_store'; import {isTablet} from '@utils/helpers'; import {isFromWebhook, isSystemMessage, shouldIgnorePost} from '@utils/post'; +import type {Model} from '@nozbe/watermelondb'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; function preparedMyChannelHack(myChannel: MyChannelModel) { - // @ts-expect-error hack accessing _preparedState if (!myChannel._preparedState) { - // @ts-expect-error hack setting _preparedState myChannel._preparedState = null; } } diff --git a/app/actions/websocket/teams.ts b/app/actions/websocket/teams.ts index c59d62d385..afd4ba6dd6 100644 --- a/app/actions/websocket/teams.ts +++ b/app/actions/websocket/teams.ts @@ -1,15 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; - import {removeUserFromTeam} from '@actions/local/team'; import {fetchMyChannelsForTeam} from '@actions/remote/channel'; import {fetchRoles} from '@actions/remote/role'; import {fetchMyTeam, handleKickFromTeam, updateCanJoinTeams} from '@actions/remote/team'; import {updateUsersNoLongerVisible} from '@actions/remote/user'; import DatabaseManager from '@database/manager'; -import ServerDataOperator from '@database/operator/server_data_operator'; import NetworkManager from '@managers/network_manager'; import {prepareCategoriesAndCategoriesChannels} from '@queries/servers/categories'; import {prepareMyChannelsForTeam} from '@queries/servers/channel'; @@ -19,6 +16,9 @@ import EphemeralStore from '@store/ephemeral_store'; import {setTeamLoading} from '@store/team_load_store'; import {logDebug} from '@utils/log'; +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type {Model} from '@nozbe/watermelondb'; + export async function handleTeamArchived(serverUrl: string, msg: WebSocketMessage) { try { const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); diff --git a/app/actions/websocket/users.ts b/app/actions/websocket/users.ts index 1cf23d41e0..71ba361fcc 100644 --- a/app/actions/websocket/users.ts +++ b/app/actions/websocket/users.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Model} from '@nozbe/watermelondb'; import {DeviceEventEmitter} from 'react-native'; import {updateChannelsDisplayName} from '@actions/local/channel'; @@ -16,6 +15,8 @@ import {getConfig, getLicense} from '@queries/servers/system'; import {getCurrentUser} from '@queries/servers/user'; import {displayUsername} from '@utils/user'; +import type {Model} from '@nozbe/watermelondb'; + export async function handleUserUpdatedEvent(serverUrl: string, msg: WebSocketMessage) { const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; if (!operator) { diff --git a/app/client/graphQL/entry.ts b/app/client/graphQL/entry.ts index b83e08d84b..7e6fb90ec5 100644 --- a/app/client/graphQL/entry.ts +++ b/app/client/graphQL/entry.ts @@ -1,11 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Client} from '@client/rest'; import {MEMBERS_PER_PAGE} from '@constants/graphql'; import NetworkManager from '@managers/network_manager'; import QueryNames from './constants'; +import type {Client} from '@client/rest'; + const doGQLQuery = async (serverUrl: string, query: string, variables: {[name: string]: any}, operationName: string) => { let client: Client; try { diff --git a/app/client/rest/base.ts b/app/client/rest/base.ts index 573f09aa29..c2aa06885c 100644 --- a/app/client/rest/base.ts +++ b/app/client/rest/base.ts @@ -177,10 +177,14 @@ export default class ClientBase { return `${this.getEmojisRoute()}/${emojiId}`; } - getDataRetentionRoute() { + getGlobalDataRetentionRoute() { return `${this.urlVersion}/data_retention`; } + getGranularDataRetentionRoute(userId: string) { + return `${this.getUserRoute(userId)}/data_retention`; + } + getRolesRoute() { return `${this.urlVersion}/roles`; } diff --git a/app/client/rest/files.ts b/app/client/rest/files.ts index 0a1f8a3d6e..c4cd648361 100644 --- a/app/client/rest/files.ts +++ b/app/client/rest/files.ts @@ -1,10 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ClientResponse, ClientResponseError, ProgressPromise, UploadRequestOptions} from '@mattermost/react-native-network-client'; - import {toMilliseconds} from '@utils/datetime'; +import type {ClientResponse, ClientResponseError, ProgressPromise, UploadRequestOptions} from '@mattermost/react-native-network-client'; + export interface ClientFilesMix { getFileUrl: (fileId: string, timestamp: number) => string; getFileThumbnailUrl: (fileId: string, timestamp: number) => string; diff --git a/app/client/rest/general.ts b/app/client/rest/general.ts index c5486d34ff..b4093ca254 100644 --- a/app/client/rest/general.ts +++ b/app/client/rest/general.ts @@ -3,8 +3,14 @@ import {buildQueryString} from '@utils/helpers'; +import {PER_PAGE_DEFAULT} from './constants'; import ClientError from './error'; +type PoliciesResponse = { + policies: T[]; + total_count: number; +} + export interface ClientGeneralMix { getOpenGraphMetadata: (url: string) => Promise; ping: (deviceId?: string, timeoutInterval?: number) => Promise; @@ -12,7 +18,9 @@ export interface ClientGeneralMix { getClientConfigOld: () => Promise; getClientLicenseOld: () => Promise; getTimezones: () => Promise; - getDataRetentionPolicy: () => Promise; + getGlobalDataRetentionPolicy: () => Promise; + getTeamDataRetentionPolicies: (userId: string, page?: number, perPage?: number) => Promise>; + getChannelDataRetentionPolicies: (userId: string, page?: number, perPage?: number) => Promise>; getRolesByNames: (rolesNames: string[]) => Promise; getRedirectLocation: (urlParam: string) => Promise>; } @@ -74,9 +82,23 @@ const ClientGeneral = (superclass: any) => class extends superclass { ); }; - getDataRetentionPolicy = () => { + getGlobalDataRetentionPolicy = () => { return this.doFetch( - `${this.getDataRetentionRoute()}/policy`, + `${this.getGlobalDataRetentionRoute()}/policy`, + {method: 'get'}, + ); + }; + + getTeamDataRetentionPolicies = (userId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getGranularDataRetentionRoute(userId)}/team_policies${buildQueryString({page, per_page: perPage})}`, + {method: 'get'}, + ); + }; + + getChannelDataRetentionPolicies = (userId: string, page = 0, perPage = PER_PAGE_DEFAULT) => { + return this.doFetch( + `${this.getGranularDataRetentionRoute(userId)}/channel_policies${buildQueryString({page, per_page: perPage})}`, {method: 'get'}, ); }; diff --git a/app/client/rest/teams.ts b/app/client/rest/teams.ts index 9c53c0350b..1902565680 100644 --- a/app/client/rest/teams.ts +++ b/app/client/rest/teams.ts @@ -18,7 +18,10 @@ export interface ClientTeamsMix { getMyTeamMembers: () => Promise; getTeamMembers: (teamId: string, page?: number, perPage?: number) => Promise; getTeamMember: (teamId: string, userId: string) => Promise; + getTeamMembersByIds: (teamId: string, userIds: string[]) => Promise; addToTeam: (teamId: string, userId: string) => Promise; + addUsersToTeamGracefully: (teamId: string, userIds: string[]) => Promise; + sendEmailInvitesToTeamGracefully: (teamId: string, emails: string[]) => Promise; joinTeam: (inviteId: string) => Promise; removeFromTeam: (teamId: string, userId: string) => Promise; getTeamStats: (teamId: string) => Promise; @@ -120,6 +123,13 @@ const ClientTeams = (superclass: any) => class extends superclass { ); }; + getTeamMembersByIds = (teamId: string, userIds: string[]) => { + return this.doFetch( + `${this.getTeamMembersRoute(teamId)}/ids`, + {method: 'post', body: userIds}, + ); + }; + addToTeam = async (teamId: string, userId: string) => { this.analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); @@ -130,6 +140,27 @@ const ClientTeams = (superclass: any) => class extends superclass { ); }; + addUsersToTeamGracefully = (teamId: string, userIds: string[]) => { + this.analytics.trackAPI('api_teams_batch_add_members', {team_id: teamId, count: userIds.length}); + + const members: Array<{team_id: string; user_id: string}> = []; + userIds.forEach((id) => members.push({team_id: teamId, user_id: id})); + + return this.doFetch( + `${this.getTeamMembersRoute(teamId)}/batch?graceful=true`, + {method: 'post', body: members}, + ); + }; + + sendEmailInvitesToTeamGracefully = (teamId: string, emails: string[]) => { + this.analytics.trackAPI('api_teams_invite_members', {team_id: teamId}); + + return this.doFetch( + `${this.getTeamRoute(teamId)}/invite/email?graceful=true`, + {method: 'post', body: emails}, + ); + }; + joinTeam = async (inviteId: string) => { const query = buildQueryString({invite_id: inviteId}); return this.doFetch( diff --git a/app/components/autocomplete/autocomplete.tsx b/app/components/autocomplete/autocomplete.tsx index 640fd4f34c..2f7998d71e 100644 --- a/app/components/autocomplete/autocomplete.tsx +++ b/app/components/autocomplete/autocomplete.tsx @@ -31,8 +31,9 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { elevation: 3, }, shadow: { + backgroundColor: theme.centerChannelBg, shadowColor: '#000', - shadowOpacity: 0.12, + shadowOpacity: 1, shadowRadius: 6, shadowOffset: { width: 0, diff --git a/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts b/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts index 899d760946..5b8f1431ce 100644 --- a/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts +++ b/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts @@ -1,9 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database} from '@nozbe/watermelondb'; -import {IntlShape} from 'react-intl'; - import {doAppFetchForm, doAppLookup} from '@actions/remote/apps'; import {fetchChannelById, fetchChannelByName, searchChannels} from '@actions/remote/channel'; import {fetchUsersByIds, fetchUsersByUsernames, searchUsers} from '@actions/remote/user'; @@ -17,8 +14,10 @@ import {createCallRequest, filterEmptyOptions} from '@utils/apps'; import {getChannelSuggestions, getUserSuggestions, inTextMentionSuggestions} from './mentions'; +import type {Database} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type UserModel from '@typings/database/models/servers/user'; +import type {IntlShape} from 'react-intl'; /* eslint-disable max-lines */ diff --git a/app/components/block/index.tsx b/app/components/block/index.tsx index b016afece2..de8fb4ca24 100644 --- a/app/components/block/index.tsx +++ b/app/components/block/index.tsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {MessageDescriptor} from '@formatjs/intl/src/types'; import React from 'react'; import {StyleProp, TextStyle, View, ViewProps, ViewStyle} from 'react-native'; @@ -9,6 +8,8 @@ import FormattedText from '@components/formatted_text'; import {useTheme} from '@context/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import type {MessageDescriptor} from '@formatjs/intl/src/types'; + const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { container: { diff --git a/app/components/channel_actions/add_people_box/index.tsx b/app/components/channel_actions/add_people_box/index.tsx index d3b106be80..4ef09ef6b2 100644 --- a/app/components/channel_actions/add_people_box/index.tsx +++ b/app/components/channel_actions/add_people_box/index.tsx @@ -3,12 +3,13 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {StyleProp, ViewStyle} from 'react-native'; import OptionBox from '@components/option_box'; import {Screens} from '@constants'; import {dismissBottomSheet, goToScreen, showModal} from '@screens/navigation'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { channelId: string; containerStyle?: StyleProp; diff --git a/app/components/channel_actions/favorite_box/favorite_box.tsx b/app/components/channel_actions/favorite_box/favorite_box.tsx index 06950b36f0..ee60331a39 100644 --- a/app/components/channel_actions/favorite_box/favorite_box.tsx +++ b/app/components/channel_actions/favorite_box/favorite_box.tsx @@ -3,13 +3,14 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {StyleProp, ViewStyle} from 'react-native'; import {toggleFavoriteChannel} from '@actions/remote/category'; import OptionBox from '@components/option_box'; import {useServerUrl} from '@context/server'; import {dismissBottomSheet} from '@screens/navigation'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { channelId: string; containerStyle?: StyleProp; diff --git a/app/components/channel_actions/info_box/index.tsx b/app/components/channel_actions/info_box/index.tsx index 6d236197fb..036e4a2b66 100644 --- a/app/components/channel_actions/info_box/index.tsx +++ b/app/components/channel_actions/info_box/index.tsx @@ -3,7 +3,6 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {StyleProp, ViewStyle} from 'react-native'; import CompassIcon from '@components/compass_icon'; import OptionBox from '@components/option_box'; @@ -12,6 +11,8 @@ import {Screens} from '@constants'; import {useTheme} from '@context/theme'; import {dismissBottomSheet, showModal} from '@screens/navigation'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { channelId: string; containerStyle?: StyleProp; diff --git a/app/components/channel_actions/mute_box/mute_box.tsx b/app/components/channel_actions/mute_box/mute_box.tsx index 4d96c7d5d2..8a9b086383 100644 --- a/app/components/channel_actions/mute_box/mute_box.tsx +++ b/app/components/channel_actions/mute_box/mute_box.tsx @@ -3,13 +3,14 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {StyleProp, ViewStyle} from 'react-native'; import {toggleMuteChannel} from '@actions/remote/channel'; import OptionBox from '@components/option_box'; import {useServerUrl} from '@context/server'; import {dismissBottomSheet} from '@screens/navigation'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { channelId: string; containerStyle?: StyleProp; diff --git a/app/components/channel_actions/set_header_box/set_header.tsx b/app/components/channel_actions/set_header_box/set_header.tsx index e9d67cc169..54ad73f87f 100644 --- a/app/components/channel_actions/set_header_box/set_header.tsx +++ b/app/components/channel_actions/set_header_box/set_header.tsx @@ -3,12 +3,13 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {StyleProp, ViewStyle} from 'react-native'; import OptionBox from '@components/option_box'; import {Screens} from '@constants'; import {dismissBottomSheet, goToScreen, showModal} from '@screens/navigation'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { channelId: string; containerStyle?: StyleProp; diff --git a/app/components/channel_item/__snapshots__/channel_item.test.tsx.snap b/app/components/channel_item/__snapshots__/channel_item.test.tsx.snap index 24c2442e29..ea25aef92e 100644 --- a/app/components/channel_item/__snapshots__/channel_item.test.tsx.snap +++ b/app/components/channel_item/__snapshots__/channel_item.test.tsx.snap @@ -2,6 +2,23 @@ exports[`components/channel_list/categories/body/channel_item should match snapshot 1`] = ` { let database: Database; const channel: Channel = { diff --git a/app/components/common_post_options/copy_permalink_option/copy_permalink_option.tsx b/app/components/common_post_options/copy_permalink_option/copy_permalink_option.tsx index 8ba0ee61d0..07b9c6a864 100644 --- a/app/components/common_post_options/copy_permalink_option/copy_permalink_option.tsx +++ b/app/components/common_post_options/copy_permalink_option/copy_permalink_option.tsx @@ -5,7 +5,6 @@ import Clipboard from '@react-native-clipboard/clipboard'; import React, {useCallback} from 'react'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {SNACK_BAR_TYPE} from '@constants/snack_bar'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; @@ -13,10 +12,11 @@ import {dismissBottomSheet} from '@screens/navigation'; import {showSnackBar} from '@utils/snack_bar'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { - bottomSheetId: typeof Screens[keyof typeof Screens]; - sourceScreen: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; + sourceScreen: AvailableScreens; post: PostModel; teamName: string; } diff --git a/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx b/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx index 6791dafdd9..475e55ea99 100644 --- a/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx +++ b/app/components/common_post_options/follow_thread_option/follow_thread_option.tsx @@ -5,15 +5,15 @@ import React, {useCallback} from 'react'; import {updateThreadFollowing} from '@actions/remote/thread'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; import type ThreadModel from '@typings/database/models/servers/thread'; +import type {AvailableScreens} from '@typings/screens/navigation'; type FollowThreadOptionProps = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; thread: ThreadModel; teamId?: string; }; diff --git a/app/components/common_post_options/reply_option.tsx b/app/components/common_post_options/reply_option.tsx index 6afa518792..3741e358ba 100644 --- a/app/components/common_post_options/reply_option.tsx +++ b/app/components/common_post_options/reply_option.tsx @@ -5,16 +5,16 @@ import React, {useCallback} from 'react'; import {fetchAndSwitchToThread} from '@actions/remote/thread'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { post: PostModel; - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; } const ReplyOption = ({post, bottomSheetId}: Props) => { const serverUrl = useServerUrl(); diff --git a/app/components/common_post_options/save_option.tsx b/app/components/common_post_options/save_option.tsx index fcb0fd396a..1abe0a5436 100644 --- a/app/components/common_post_options/save_option.tsx +++ b/app/components/common_post_options/save_option.tsx @@ -5,13 +5,14 @@ import React, {useCallback} from 'react'; import {deleteSavedPost, savePostPreference} from '@actions/remote/preference'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type CopyTextProps = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; isSaved: boolean; postId: string; } diff --git a/app/components/custom_status/__snapshots__/clear_button.test.tsx.snap b/app/components/custom_status/__snapshots__/clear_button.test.tsx.snap index 5f33922500..43b6af9005 100644 --- a/app/components/custom_status/__snapshots__/clear_button.test.tsx.snap +++ b/app/components/custom_status/__snapshots__/clear_button.test.tsx.snap @@ -2,6 +2,23 @@ exports[`components/custom_status/clear_button should match snapshot 1`] = ` { let database: Database | undefined; beforeAll(async () => { diff --git a/app/components/emoji/index.tsx b/app/components/emoji/index.tsx index 918f4bd23a..5fbe48f274 100644 --- a/app/components/emoji/index.tsx +++ b/app/components/emoji/index.tsx @@ -3,7 +3,7 @@ import React, {useMemo} from 'react'; -import {EmojiComponent, EmojiProps} from '@typings/components/emoji'; +import type {EmojiComponent, EmojiProps} from '@typings/components/emoji'; let emojiComponent: EmojiComponent; diff --git a/app/components/files/document_file.tsx b/app/components/files/document_file.tsx index 7c2f74a7fb..9ff052dd88 100644 --- a/app/components/files/document_file.tsx +++ b/app/components/files/document_file.tsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client'; import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; import {Platform, StatusBar, StatusBarStyle, StyleSheet, TouchableOpacity, View} from 'react-native'; @@ -21,6 +20,7 @@ import {emptyFunction} from '@utils/general'; import FileIcon from './file_icon'; import type {Client} from '@client/rest'; +import type {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client'; export type DocumentFileRef = { handlePreviewPress: () => void; diff --git a/app/components/files/image_file.tsx b/app/components/files/image_file.tsx index 0610a479fb..9146d05104 100644 --- a/app/components/files/image_file.tsx +++ b/app/components/files/image_file.tsx @@ -104,7 +104,8 @@ const ImageFile = ({ const props: ProgressiveImageProps = {}; if (file.localPath) { - props.defaultSource = {uri: file.localPath}; + const prefix = file.localPath.startsWith('file://') ? '' : 'file://'; + props.defaultSource = {uri: prefix + file.localPath}; } else if (file.id) { if (file.mini_preview && file.mime_type) { props.thumbnailUri = `data:${file.mime_type};base64,${file.mini_preview}`; diff --git a/app/components/illustrations/alert.tsx b/app/components/illustrations/alert.tsx new file mode 100644 index 0000000000..44aaf0e6e5 --- /dev/null +++ b/app/components/illustrations/alert.tsx @@ -0,0 +1,30 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import * as React from 'react'; +import Svg, {Path} from 'react-native-svg'; + +function AlertSvgComponent() { + return ( + + + + + + ); +} + +export default AlertSvgComponent; diff --git a/app/components/illustrations/error.tsx b/app/components/illustrations/error.tsx new file mode 100644 index 0000000000..7dd1b636c7 --- /dev/null +++ b/app/components/illustrations/error.tsx @@ -0,0 +1,34 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import * as React from 'react'; +import Svg, {G, Path, Defs, ClipPath, Rect} from 'react-native-svg'; + +function ErrorSvgComponent() { + return ( + + + + + + + + + + + ); +} + +export default ErrorSvgComponent; diff --git a/app/components/illustrations/success.tsx b/app/components/illustrations/success.tsx new file mode 100644 index 0000000000..ac5b3e1b18 --- /dev/null +++ b/app/components/illustrations/success.tsx @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +import * as React from 'react'; +import Svg, {Path} from 'react-native-svg'; + +function SuccessSvgComponent() { + return ( + + + + ); +} + +export default SuccessSvgComponent; diff --git a/app/components/loading_error/__snapshots__/index.test.tsx.snap b/app/components/loading_error/__snapshots__/index.test.tsx.snap index 200e83f611..f03c8a4193 100644 --- a/app/components/loading_error/__snapshots__/index.test.tsx.snap +++ b/app/components/loading_error/__snapshots__/index.test.tsx.snap @@ -73,6 +73,23 @@ exports[`Loading Error should match snapshot 1`] = ` Error description ; mentionName: string; - mentionStyle: TextStyle; + mentionStyle: StyleProp; onPostPress?: (e: GestureResponderEvent) => void; teammateNameDisplay: string; textStyle?: StyleProp; @@ -203,7 +203,7 @@ const AtMention = ({ } }, [managedConfig, intl, theme, bottom]); - const mentionTextStyle = []; + const mentionTextStyle: StyleProp = []; let backgroundColor; let canPress = false; diff --git a/app/components/markdown/markdown.tsx b/app/components/markdown/markdown.tsx index 0437097154..b0182e885d 100644 --- a/app/components/markdown/markdown.tsx +++ b/app/components/markdown/markdown.tsx @@ -5,7 +5,7 @@ import {useManagedConfig} from '@mattermost/react-native-emm'; import {Parser, Node} from 'commonmark'; import Renderer from 'commonmark-react-renderer'; import React, {ReactElement, useMemo, useRef} from 'react'; -import {Dimensions, GestureResponderEvent, Platform, StyleProp, Text, TextStyle, View, ViewStyle} from 'react-native'; +import {Dimensions, GestureResponderEvent, Platform, StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle} from 'react-native'; import CompassIcon from '@components/compass_icon'; import Emoji from '@components/emoji'; @@ -143,13 +143,15 @@ const Markdown = ({ if (disableAtMentions) { return renderText({context, literal: `@${mentionName}`}); } + const computedStyles = StyleSheet.flatten(computeTextStyle(textStyles, baseTextStyle, context)); + const {fontFamily, fontSize, fontWeight} = computedStyles; return ( ('default'); const [longMessageAlertShown, setLongMessageAlertShown] = useState(false); const disableCopyAndPaste = managedConfig.copyAndPasteProtection === 'true'; @@ -180,11 +180,6 @@ export default function PostInput({ const handlePostDraftSelectionChanged = useCallback((event: NativeSyntheticEvent | null, fromHandleTextChange = false) => { const cp = fromHandleTextChange ? cursorPosition : event!.nativeEvent.selection.end; - if (Platform.OS === 'ios') { - const newKeyboardType = switchKeyboardForCodeBlocks(value, cp); - setKeyboardType(newKeyboardType); - } - updateCursorPosition(cp); }, [updateCursorPosition, cursorPosition]); @@ -194,11 +189,6 @@ export default function PostInput({ checkMessageLength(newValue); - // Workaround to avoid iOS emdash autocorrect in Code Blocks - if (Platform.OS === 'ios') { - handlePostDraftSelectionChanged(null, true); - } - if ( newValue && lastTypingEventSent.current + timeBetweenUserTypingUpdatesMilliseconds < Date.now() && @@ -211,7 +201,6 @@ export default function PostInput({ }, [ updateValue, checkMessageLength, - handlePostDraftSelectionChanged, timeBetweenUserTypingUpdatesMilliseconds, channelId, rootId, @@ -228,7 +217,7 @@ export default function PostInput({ const handleHardwareEnterPress = useCallback((keyEvent: {pressedKey: string}) => { const topScreen = NavigationStore.getVisibleScreen(); - let sourceScreen = Screens.CHANNEL; + let sourceScreen: AvailableScreens = Screens.CHANNEL; if (rootId) { sourceScreen = Screens.THREAD; } else if (isTablet) { @@ -307,24 +296,24 @@ export default function PostInput({ return ( ); } diff --git a/app/components/post_draft/quick_actions/camera_quick_action/camera_type.tsx b/app/components/post_draft/quick_actions/camera_quick_action/camera_type.tsx index c42eccb1d4..e681c7a566 100644 --- a/app/components/post_draft/quick_actions/camera_quick_action/camera_type.tsx +++ b/app/components/post_draft/quick_actions/camera_quick_action/camera_type.tsx @@ -4,7 +4,6 @@ import React from 'react'; import {useIntl} from 'react-intl'; import {View} from 'react-native'; -import {CameraOptions} from 'react-native-image-picker'; import FormattedText from '@components/formatted_text'; import SlideUpPanelItem from '@components/slide_up_panel_item'; @@ -14,6 +13,8 @@ import {dismissBottomSheet} from '@screens/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {CameraOptions} from 'react-native-image-picker'; + type Props = { onPress: (options: CameraOptions) => void; } diff --git a/app/components/post_draft/quick_actions/camera_quick_action/index.tsx b/app/components/post_draft/quick_actions/camera_quick_action/index.tsx index f13817be11..cfba22fdf1 100644 --- a/app/components/post_draft/quick_actions/camera_quick_action/index.tsx +++ b/app/components/post_draft/quick_actions/camera_quick_action/index.tsx @@ -4,7 +4,6 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; import {Alert, StyleSheet} from 'react-native'; -import {CameraOptions} from 'react-native-image-picker'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import CompassIcon from '@components/compass_icon'; @@ -22,6 +21,7 @@ import {changeOpacity} from '@utils/theme'; import CameraType from './camera_type'; import type {QuickActionAttachmentProps} from '@typings/components/post_draft_quick_action'; +import type {CameraOptions} from 'react-native-image-picker'; const style = StyleSheet.create({ icon: { diff --git a/app/components/post_draft/send_handler/send_handler.tsx b/app/components/post_draft/send_handler/send_handler.tsx index 97c7e7e696..7c8c4b4a81 100644 --- a/app/components/post_draft/send_handler/send_handler.tsx +++ b/app/components/post_draft/send_handler/send_handler.tsx @@ -3,15 +3,14 @@ import React, {useCallback, useEffect, useState} from 'react'; import {useIntl} from 'react-intl'; -import {Alert, DeviceEventEmitter} from 'react-native'; +import {DeviceEventEmitter} from 'react-native'; import {getChannelTimezones} from '@actions/remote/channel'; import {executeCommand, handleGotoLocation} from '@actions/remote/command'; import {createPost} from '@actions/remote/post'; import {handleReactionToLatestPost} from '@actions/remote/reactions'; import {setStatus} from '@actions/remote/user'; -import {canEndCall, endCall, getEndCallMessage} from '@calls/actions/calls'; -import ClientError from '@client/rest/error'; +import {handleCallsSlashCommand} from '@calls/actions/calls'; import {Events, Screens} from '@constants'; import {PostPriorityType} from '@constants/post'; import {NOTIFY_ALL_MEMBERS} from '@constants/post_draft'; @@ -147,54 +146,19 @@ export default function SendHandler({ DraftUtils.alertChannelWideMention(intl, notifyAllMessage, doSubmitMessage, cancel); }, [intl, isTimezoneEnabled, channelTimezoneCount, doSubmitMessage]); - const handleEndCall = useCallback(async () => { - const hasPermissions = await canEndCall(serverUrl, channelId); - - if (!hasPermissions) { - Alert.alert( - intl.formatMessage({ - id: 'mobile.calls_end_permission_title', - defaultMessage: 'Error', - }), - intl.formatMessage({ - id: 'mobile.calls_end_permission_msg', - defaultMessage: 'You don\'t have permission to end the call. Please ask the call owner to end the call.', - })); - return; - } - - const message = await getEndCallMessage(serverUrl, channelId, currentUserId, intl); - const title = intl.formatMessage({id: 'mobile.calls_end_call_title', defaultMessage: 'End call'}); - - Alert.alert( - title, - message, - [ - { - text: intl.formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}), - }, - { - text: title, - onPress: async () => { - try { - await endCall(serverUrl, channelId); - } catch (e) { - const err = (e as ClientError).message || 'unable to complete command, see server logs'; - Alert.alert('Error', `Error: ${err}`); - } - }, - style: 'cancel', - }, - ], - ); - }, [serverUrl, channelId, currentUserId, intl]); - const sendCommand = useCallback(async () => { - if (value.trim() === '/call end') { - await handleEndCall(); - setSendingMessage(false); - clearDraft(); - return; + if (value.trim().startsWith('/call')) { + const {handled, error} = await handleCallsSlashCommand(value.trim(), serverUrl, channelId, currentUserId, intl); + if (handled) { + setSendingMessage(false); + clearDraft(); + return; + } + if (error) { + setSendingMessage(false); + DraftUtils.alertSlashCommandFailed(intl, error); + return; + } } const status = DraftUtils.getStatusFromSlashCommand(value); @@ -226,7 +190,7 @@ export default function SendHandler({ if (data?.goto_location && !value.startsWith('/leave')) { handleGotoLocation(serverUrl, intl, data.goto_location); } - }, [userIsOutOfOffice, currentUserId, intl, value, serverUrl, channelId, rootId, handleEndCall]); + }, [userIsOutOfOffice, currentUserId, intl, value, serverUrl, channelId, rootId]); const sendMessage = useCallback(() => { const notificationsToChannel = enableConfirmNotificationsToChannel && useChannelMentions; diff --git a/app/components/post_list/more_messages/more_messages.tsx b/app/components/post_list/more_messages/more_messages.tsx index 835ce0c6be..e1d438c146 100644 --- a/app/components/post_list/more_messages/more_messages.tsx +++ b/app/components/post_list/more_messages/more_messages.tsx @@ -46,7 +46,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { animatedContainer: { position: 'absolute', margin: 8, - backgroundColor: theme.buttonBg, }, cancelContainer: { alignItems: 'center', @@ -55,6 +54,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { justifyContent: 'center', }, container: { + backgroundColor: theme.buttonBg, flexDirection: 'row', justifyContent: 'space-evenly', alignItems: 'center', diff --git a/app/components/post_list/post/body/content/embedded_bindings/button_binding/index.tsx b/app/components/post_list/post/body/content/embedded_bindings/button_binding/index.tsx index 117098c75e..68efc1418c 100644 --- a/app/components/post_list/post/body/content/embedded_bindings/button_binding/index.tsx +++ b/app/components/post_list/post/body/content/embedded_bindings/button_binding/index.tsx @@ -132,8 +132,6 @@ const ButtonBinding = ({currentTeamId, binding, post, teamID, theme}: Props) => /> ); - - return null; }; const withTeamId = withObservables(['post'], ({post, database}: {post: PostModel} & WithDatabaseArgs) => ({ diff --git a/app/components/post_list/post/body/content/image_preview/image_preview.tsx b/app/components/post_list/post/body/content/image_preview/image_preview.tsx index 8285e40e22..14b5042347 100644 --- a/app/components/post_list/post/body/content/image_preview/image_preview.tsx +++ b/app/components/post_list/post/body/content/image_preview/image_preview.tsx @@ -69,8 +69,9 @@ const ImagePreview = ({expandedLink, isReplyPost, layoutWidth, link, location, m width: imageProps.width, height: imageProps.height, name: extractFilenameFromUrl(imageUrl) || 'imagePreview.png', - mime_type: lookupMimeType(imageUrl) || 'images/png', + mime_type: lookupMimeType(imageUrl) || 'image/png', type: 'image', + lastPictureUpdate: 0, }; openGalleryAtIndex(galleryIdentifier, 0, [item]); }; 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 321c1af05f..2d7f5ef225 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 @@ -72,8 +72,9 @@ const AttachmentImage = ({imageUrl, imageMetadata, layoutWidth, location, postId width: imageMetadata.width, height: imageMetadata.height, name: extractFilenameFromUrl(imageUrl) || 'attachmentImage.png', - mime_type: lookupMimeType(imageUrl) || 'images/png', + mime_type: lookupMimeType(imageUrl) || 'image/png', type: 'image', + lastPictureUpdate: 0, }; openGalleryAtIndex(galleryIdentifier, 0, [item]); }; diff --git a/app/components/post_list/post/body/content/opengraph/opengraph_image/index.tsx b/app/components/post_list/post/body/content/opengraph/opengraph_image/index.tsx index be80402004..a895b665d3 100644 --- a/app/components/post_list/post/body/content/opengraph/opengraph_image/index.tsx +++ b/app/components/post_list/post/body/content/opengraph/opengraph_image/index.tsx @@ -98,8 +98,9 @@ const OpengraphImage = ({isReplyPost, layoutWidth, location, metadata, openGraph width: imageDimensions.width, height: imageDimensions.height, name: extractFilenameFromUrl(imageUrl) || 'openGraph.png', - mime_type: lookupMimeType(imageUrl) || 'images/png', + mime_type: lookupMimeType(imageUrl) || 'image/png', type: 'image', + lastPictureUpdate: 0, }; openGalleryAtIndex(galleryIdentifier, 0, [item]); }; diff --git a/app/components/profile_picture/image.tsx b/app/components/profile_picture/image.tsx index 229012db89..482812883a 100644 --- a/app/components/profile_picture/image.tsx +++ b/app/components/profile_picture/image.tsx @@ -43,6 +43,7 @@ const Image = ({author, forwardRef, iconSize, size, source, url}: Props) => { const style = getStyleSheet(theme); const fIStyle = useMemo(() => ({ borderRadius: size / 2, + backgroundColor: theme.centerChannelBg, height: size, width: size, }), [size]); diff --git a/app/components/progressive_image/thumbnail.tsx b/app/components/progressive_image/thumbnail.tsx index 6ace4800f1..620dc33491 100644 --- a/app/components/progressive_image/thumbnail.tsx +++ b/app/components/progressive_image/thumbnail.tsx @@ -2,10 +2,11 @@ // See LICENSE.txt for license information. import React from 'react'; -import {ColorValue, StyleProp} from 'react-native'; import FastImage, {ImageStyle, Source} from 'react-native-fast-image'; import Animated, {SharedValue} from 'react-native-reanimated'; +import type {ColorValue, StyleProp} from 'react-native'; + // @ts-expect-error FastImage does work with Animated.createAnimatedComponent const AnimatedFastImage = Animated.createAnimatedComponent(FastImage); diff --git a/app/components/selected_chip/index.tsx b/app/components/selected_chip/index.tsx new file mode 100644 index 0000000000..3ea8e221dd --- /dev/null +++ b/app/components/selected_chip/index.tsx @@ -0,0 +1,100 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback} from 'react'; +import {Text, TouchableOpacity, View} from 'react-native'; +import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'; + +import CompassIcon from '@components/compass_icon'; +import {useTheme} from '@context/theme'; +import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +type SelectedChipProps = { + id: string; + text: string; + extra?: React.ReactNode; + onRemove: (id: string) => void; + testID?: string; +} + +export const USER_CHIP_HEIGHT = 32; +export const USER_CHIP_BOTTOM_MARGIN = 8; +const FADE_DURATION = 100; + +const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { + return { + container: { + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'row', + borderRadius: 16, + height: USER_CHIP_HEIGHT, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.08), + marginBottom: USER_CHIP_BOTTOM_MARGIN, + marginRight: 8, + paddingHorizontal: 7, + }, + extraContent: { + flexDirection: 'row', + alignItems: 'center', + color: theme.centerChannelColor, + }, + text: { + marginLeft: 8, + color: theme.centerChannelColor, + ...typography('Body', 100, 'SemiBold'), + }, + remove: { + justifyContent: 'center', + marginLeft: 7, + }, + }; +}); + +export default function SelectedChip({ + id, + text, + extra, + onRemove, + testID, +}: SelectedChipProps) { + const theme = useTheme(); + const style = getStyleFromTheme(theme); + + const onPress = useCallback(() => { + onRemove(id); + }, [onRemove, id]); + + return ( + + {extra && ( + + {extra} + + )} + + {text} + + + + + + ); +} diff --git a/app/components/selected_users/index.tsx b/app/components/selected_users/index.tsx index e2ffad6f76..feac09143c 100644 --- a/app/components/selected_users/index.tsx +++ b/app/components/selected_users/index.tsx @@ -6,6 +6,7 @@ import {LayoutChangeEvent, Platform, ScrollView, useWindowDimensions, View} from import Animated, {useAnimatedStyle, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; +import {USER_CHIP_BOTTOM_MARGIN, USER_CHIP_HEIGHT} from '@components/selected_chip'; import Toast from '@components/toast'; import {General} from '@constants'; import {useTheme} from '@context/theme'; @@ -13,7 +14,7 @@ import {useIsTablet, useKeyboardHeightWithDuration} from '@hooks/device'; import Button from '@screens/bottom_sheet/button'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import SelectedUser, {USER_CHIP_BOTTOM_MARGIN, USER_CHIP_HEIGHT} from './selected_user'; +import SelectedUser from './selected_user'; type Props = { @@ -95,6 +96,7 @@ const TOAST_BOTTOM_MARGIN = 24; const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { return { container: { + backgroundColor: theme.centerChannelBg, borderBottomWidth: 0, borderColor: changeOpacity(theme.centerChannelColor, 0.16), borderTopLeftRadius: 12, @@ -231,10 +233,10 @@ export default function SelectedUsers({ }, [showToast, keyboard]); const animatedViewStyle = useAnimatedStyle(() => ({ - height: withTiming(totalPanelHeight.value, {duration: 250}), + height: withTiming(totalPanelHeight.value + insets.bottom, {duration: 250}), borderWidth: isVisible ? 1 : 0, - maxHeight: isVisible ? PANEL_MAX_HEIGHT + BUTTON_HEIGHT : 0, - }), [totalPanelHeight.value, isVisible]); + maxHeight: isVisible ? PANEL_MAX_HEIGHT + BUTTON_HEIGHT + insets.bottom : 0, + }), [isVisible, insets]); const animatedButtonStyle = useAnimatedStyle(() => ({ opacity: withTiming(isVisible ? 1 : 0, {duration: isVisible ? 500 : 100}), diff --git a/app/components/selected_users/selected_user.tsx b/app/components/selected_users/selected_user.tsx index 03ecd506c6..c5d7cebe20 100644 --- a/app/components/selected_users/selected_user.tsx +++ b/app/components/selected_users/selected_user.tsx @@ -3,18 +3,9 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import { - Text, - TouchableOpacity, - View, -} from 'react-native'; -import Animated, {FadeIn, FadeOut} from 'react-native-reanimated'; -import CompassIcon from '@components/compass_icon'; import ProfilePicture from '@components/profile_picture'; -import {useTheme} from '@context/theme'; -import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import {typography} from '@utils/typography'; +import SelectedChip from '@components/selected_chip'; import {displayUsername} from '@utils/user'; type Props = { @@ -40,87 +31,34 @@ type Props = { testID?: string; } -export const USER_CHIP_HEIGHT = 32; -export const USER_CHIP_BOTTOM_MARGIN = 8; -const FADE_DURATION = 100; - -const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { - return { - container: { - alignItems: 'center', - justifyContent: 'center', - flexDirection: 'row', - borderRadius: 16, - height: USER_CHIP_HEIGHT, - backgroundColor: changeOpacity(theme.centerChannelColor, 0.08), - marginBottom: USER_CHIP_BOTTOM_MARGIN, - marginRight: 8, - paddingHorizontal: 7, - }, - remove: { - justifyContent: 'center', - marginLeft: 7, - }, - profileContainer: { - flexDirection: 'row', - alignItems: 'center', - marginRight: 8, - color: theme.centerChannelColor, - }, - text: { - color: theme.centerChannelColor, - ...typography('Body', 100, 'SemiBold'), - }, - }; -}); - export default function SelectedUser({ teammateNameDisplay, user, onRemove, testID, }: Props) { - const theme = useTheme(); - const style = getStyleFromTheme(theme); const intl = useIntl(); - const onPress = useCallback(() => { - onRemove(user.id); - }, [onRemove, user.id]); + const onPress = useCallback((id: string) => { + onRemove(id); + }, [onRemove]); const userItemTestID = `${testID}.${user.id}`; + return ( - - + - - - {displayUsername(user, intl.locale, teammateNameDisplay)} - - - - - + )} + onRemove={onPress} + testID={userItemTestID} + /> ); } diff --git a/app/components/server_icon/__snapshots__/server_icon.test.tsx.snap b/app/components/server_icon/__snapshots__/server_icon.test.tsx.snap index f6c642aa86..55309659d9 100644 --- a/app/components/server_icon/__snapshots__/server_icon.test.tsx.snap +++ b/app/components/server_icon/__snapshots__/server_icon.test.tsx.snap @@ -5,7 +5,19 @@ exports[`Server Icon Server Icon Component should match snapshot 1`] = ` ; diff --git a/app/components/syntax_highlight/renderer.tsx b/app/components/syntax_highlight/renderer.tsx index 71c45d3109..055e7af2e0 100644 --- a/app/components/syntax_highlight/renderer.tsx +++ b/app/components/syntax_highlight/renderer.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback} from 'react'; +import React, {useCallback, useRef} from 'react'; import {FlatList, ListRenderItemInfo, ScrollView, StyleSheet, Text} from 'react-native'; import {createStyleObject} from 'react-syntax-highlighter/create-element'; @@ -115,6 +115,7 @@ function createNativeElement({node, stylesheet, key, defaultColor, fontFamily, f } const CodeHighlightRenderer = ({defaultColor, digits, fontFamily, fontSize, rows, selectable, stylesheet}: Props) => { + const listKey = useRef(generateId()).current; const renderItem = useCallback(({item, index}: ListRenderItemInfo) => { return createNativeElement({ node: item, @@ -137,7 +138,9 @@ const CodeHighlightRenderer = ({defaultColor, digits, fontFamily, fontSize, rows ); diff --git a/app/components/threads_button/__snapshots__/threads_button.test.tsx.snap b/app/components/threads_button/__snapshots__/threads_button.test.tsx.snap index c7b564c6f8..c07f7a3829 100644 --- a/app/components/threads_button/__snapshots__/threads_button.test.tsx.snap +++ b/app/components/threads_button/__snapshots__/threads_button.test.tsx.snap @@ -2,6 +2,23 @@ exports[`Thread item in the channel list Threads Component should match snapshot 1`] = ` { const currentTeamId = observeCurrentTeamId(database); diff --git a/app/components/touchable_with_feedback/touchable_with_feedback.android.tsx b/app/components/touchable_with_feedback/touchable_with_feedback.android.tsx index e815745386..36f166bccb 100644 --- a/app/components/touchable_with_feedback/touchable_with_feedback.android.tsx +++ b/app/components/touchable_with_feedback/touchable_with_feedback.android.tsx @@ -40,7 +40,7 @@ const TouchableWithFeedbackAndroid = ({borderlessRipple = false, children, rippl {children} ); - case 'none': + default: return ( ); } - - return null; }; export default memo(TouchableWithFeedbackAndroid); diff --git a/app/components/touchable_with_feedback/touchable_with_feedback.ios.tsx b/app/components/touchable_with_feedback/touchable_with_feedback.ios.tsx index 0199eafbf8..170cda20df 100644 --- a/app/components/touchable_with_feedback/touchable_with_feedback.ios.tsx +++ b/app/components/touchable_with_feedback/touchable_with_feedback.ios.tsx @@ -41,7 +41,7 @@ const TouchableWithFeedbackIOS = ({testID, children, type = 'native', cancelTouc {children} ); - case 'none': + default: return ( ); } - - return null; }; export default memo(TouchableWithFeedbackIOS); diff --git a/app/components/tutorial_highlight/index.tsx b/app/components/tutorial_highlight/index.tsx index e83fcfa84b..182ad6e6e6 100644 --- a/app/components/tutorial_highlight/index.tsx +++ b/app/components/tutorial_highlight/index.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useEffect, useState} from 'react'; +import React, {useCallback} from 'react'; import {Modal, StyleSheet, useWindowDimensions, View} from 'react-native'; import HighlightItem from './item'; @@ -11,45 +11,43 @@ type Props = { itemBounds: TutorialItemBounds; itemBorderRadius?: number; onDismiss: () => void; + onLayout: () => void; onShow?: () => void; } -const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, onShow}: Props) => { +const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, onLayout, onShow}: Props) => { const {width, height} = useWindowDimensions(); - const [visible, setIsVisible] = useState(false); - const isLandscape = width > height; - const supportedOrientations = isLandscape ? 'landscape' : 'portrait'; - useEffect(() => { - const t = setTimeout(() => { - setIsVisible(true); - }, 500); - - return () => clearTimeout(t); - }, []); + const handleShowTutorial = useCallback(() => { + if (onShow) { + setTimeout(onShow, 1000); + } + }, [itemBounds]); return ( + {itemBounds.endX > 0 && + } {children} ); diff --git a/app/components/tutorial_highlight/item.tsx b/app/components/tutorial_highlight/item.tsx index de98bb12ae..dc96f45f50 100644 --- a/app/components/tutorial_highlight/item.tsx +++ b/app/components/tutorial_highlight/item.tsx @@ -14,22 +14,24 @@ type Props = { height: number; itemBounds: TutorialItemBounds; onDismiss: () => void; + onLayout: () => void; width: number; } -const HighlightItem = ({height, itemBounds, onDismiss, borderRadius = 0, width}: Props) => { +const HighlightItem = ({height, itemBounds, onDismiss, onLayout, borderRadius = 0, width}: Props) => { const theme = useTheme(); const isDark = tinyColor(theme.centerChannelBg).isDark(); const pathD = useMemo(() => { const parent = {startX: 0, startY: 0, endX: width, endY: height}; return constructRectangularPathWithBorderRadius(parent, itemBounds, borderRadius); - }, [borderRadius, itemBounds, width]); + }, [borderRadius, itemBounds, width, height]); return ( diff --git a/app/components/user_avatars_stack/index.tsx b/app/components/user_avatars_stack/index.tsx index 1e084d8546..8ea5efeea2 100644 --- a/app/components/user_avatars_stack/index.tsx +++ b/app/components/user_avatars_stack/index.tsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {BottomSheetProps} from '@gorhom/bottom-sheet'; import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; import {StyleProp, Text, TouchableOpacity, View, ViewStyle} from 'react-native'; @@ -20,6 +19,7 @@ import {typography} from '@utils/typography'; import UserAvatar from './user_avatar'; import UsersList from './users_list'; +import type {BottomSheetProps} from '@gorhom/bottom-sheet'; import type UserModel from '@typings/database/models/servers/user'; const OVERFLOW_DISPLAY_LIMIT = 99; diff --git a/app/components/user_item/user_item.tsx b/app/components/user_item/user_item.tsx index a16e3a443b..24c0812d78 100644 --- a/app/components/user_item/user_item.tsx +++ b/app/components/user_item/user_item.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {useMemo} from 'react'; import {IntlShape, useIntl} from 'react-intl'; import {StyleProp, Text, View, ViewStyle} from 'react-native'; @@ -81,7 +81,6 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme: Theme) => { color: changeOpacity(theme.centerChannelColor, 0.64), fontSize: 15, fontFamily: 'OpenSans', - flexShrink: 5, }, icon: { marginLeft: 4, @@ -113,6 +112,19 @@ const UserItem = ({ const userItemTestId = `${testID}.${user?.id}`; + let rowUsernameFlexShrink = 1; + if (user) { + for (const rowInfoElem of [bot, guest, Boolean(name.length), isCurrentUser]) { + if (rowInfoElem) { + rowUsernameFlexShrink++; + } + } + } + + const usernameTextStyle = useMemo(() => { + return [style.rowUsername, {flexShrink: rowUsernameFlexShrink}]; + }, [user, rowUsernameFlexShrink]); + return ( {bot && } {guest && } @@ -148,15 +160,15 @@ const UserItem = ({ testID={`${userItemTestId}.current_user_indicator`} /> } - {Boolean(user) && - - {` @${user!.username}`} - - } + {Boolean(user) && ( + + {` @${user!.username}`} + + )} {Boolean(isCustomStatusEnabled && !bot && customStatus?.emoji && !customStatusExpired) && ( @@ -111,6 +112,7 @@ exports[`components/channel_list_row should show no results 1`] = ` @@ -129,6 +131,14 @@ exports[`components/channel_list_row should show no results 1`] = ` onStartShouldSetResponderCapture={[Function]} > @@ -346,6 +357,7 @@ exports[`components/channel_list_row should show results and tutorial 1`] = ` > @@ -383,6 +395,7 @@ exports[`components/channel_list_row should show results and tutorial 1`] = ` @@ -401,6 +414,14 @@ exports[`components/channel_list_row should show results and tutorial 1`] = ` onStartShouldSetResponderCapture={[Function]} > + + + + + + + Long-press on an item to view a user's profile + + + + @@ -618,6 +720,7 @@ exports[`components/channel_list_row should show results no tutorial 1`] = ` > @@ -655,6 +758,7 @@ exports[`components/channel_list_row should show results no tutorial 1`] = ` @@ -673,6 +777,14 @@ exports[`components/channel_list_row should show results no tutorial 1`] = ` onStartShouldSetResponderCapture={[Function]} > diff --git a/app/components/user_list/index.test.tsx b/app/components/user_list/index.test.tsx index 26560b5351..122c491fda 100644 --- a/app/components/user_list/index.test.tsx +++ b/app/components/user_list/index.test.tsx @@ -1,7 +1,6 @@ // 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 {renderWithEverything} from '@test/intl-test-helper'; @@ -9,6 +8,8 @@ import TestHelper from '@test/test_helper'; import UserList from '.'; +import type Database from '@nozbe/watermelondb/Database'; + describe('components/channel_list_row', () => { let database: Database; const user: UserProfile = { diff --git a/app/components/user_list_row/index.tsx b/app/components/user_list_row/index.tsx index 94c5c27777..b908e17a02 100644 --- a/app/components/user_list_row/index.tsx +++ b/app/components/user_list_row/index.tsx @@ -4,6 +4,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; import { + InteractionManager, Platform, Text, View, @@ -122,13 +123,12 @@ function UserListRow({ const startTutorial = () => { viewRef.current?.measureInWindow((x, y, w, h) => { const bounds: TutorialItemBounds = { - startX: x - 20, + startX: x, startY: y, endX: x + w, endY: y + h, }; if (viewRef.current) { - setShowTutorial(true); setItemBounds(bounds); } }); @@ -140,12 +140,16 @@ function UserListRow({ }, []); useEffect(() => { - let time: NodeJS.Timeout; if (highlight && !tutorialWatched) { - time = setTimeout(startTutorial, 650); + if (isTablet) { + setShowTutorial(true); + return; + } + InteractionManager.runAfterInteractions(() => { + setShowTutorial(true); + }); } - return () => clearTimeout(time); - }, [highlight, tutorialWatched]); + }, [highlight, tutorialWatched, isTablet]); const handlePress = useCallback(() => { onPress?.(user); @@ -155,6 +159,10 @@ function UserListRow({ onLongPress?.(user); }, [onLongPress, user]); + const onLayout = useCallback(() => { + startTutorial(); + }, []); + const icon = useMemo(() => { if (!selectable) { return null; @@ -256,6 +264,7 @@ function UserListRow({ = { SYSTEM_AUTO_RESPONDER: 'system_auto_responder', CUSTOM_CALLS: 'custom_calls', + CUSTOM_CALLS_RECORDING: 'custom_calls_recording', }; export const PostPriorityColors = { diff --git a/app/constants/screens.ts b/app/constants/screens.ts index f3a2d7b3da..244d7fbc63 100644 --- a/app/constants/screens.ts +++ b/app/constants/screens.ts @@ -29,6 +29,7 @@ export const GLOBAL_THREADS = 'GlobalThreads'; export const HOME = 'Home'; export const INTEGRATION_SELECTOR = 'IntegrationSelector'; export const INTERACTIVE_DIALOG = 'InteractiveDialog'; +export const INVITE = 'Invite'; export const IN_APP_NOTIFICATION = 'InAppNotification'; export const JOIN_TEAM = 'JoinTeam'; export const LATEX = 'Latex'; @@ -96,6 +97,7 @@ export default { HOME, INTEGRATION_SELECTOR, INTERACTIVE_DIALOG, + INVITE, IN_APP_NOTIFICATION, JOIN_TEAM, LATEX, @@ -133,7 +135,7 @@ export default { THREAD_FOLLOW_BUTTON, THREAD_OPTIONS, USER_PROFILE, -}; +} as const; export const MODAL_SCREENS_WITHOUT_BACK = new Set([ BROWSE_CHANNELS, @@ -146,6 +148,7 @@ export const MODAL_SCREENS_WITHOUT_BACK = new Set([ EDIT_SERVER, FIND_CHANNELS, GALLERY, + INVITE, PERMALINK, ]); diff --git a/app/constants/server_errors.ts b/app/constants/server_errors.ts index 9799970b70..39810710d1 100644 --- a/app/constants/server_errors.ts +++ b/app/constants/server_errors.ts @@ -5,5 +5,6 @@ export default { DELETED_ROOT_POST_ERROR: 'api.post.create_post.root_id.app_error', TOWN_SQUARE_READ_ONLY_ERROR: 'api.post.create_post.town_square_read_only', PLUGIN_DISMISSED_POST_ERROR: 'plugin.message_will_be_posted.dismiss_post', + SEND_EMAIL_WITH_DEFAULTS_ERROR: 'api.team.invite_members.unable_to_send_email_with_defaults.app_error', TEAM_MEMBERSHIP_DENIAL_ERROR_ID: 'api.team.add_members.user_denied', }; diff --git a/app/database/components/index.tsx b/app/database/components/index.tsx index 0f22a50106..103c905544 100644 --- a/app/database/components/index.tsx +++ b/app/database/components/index.tsx @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database} from '@nozbe/watermelondb'; import DatabaseProvider from '@nozbe/watermelondb/DatabaseProvider'; import React, {ComponentType, useEffect, useState} from 'react'; @@ -11,6 +10,7 @@ import UserLocaleProvider from '@context/user_locale'; import DatabaseManager from '@database/manager'; import {subscribeActiveServers} from '@database/subscription/servers'; +import type {Database} from '@nozbe/watermelondb'; import type ServersModel from '@typings/database/models/app/servers'; type State = { diff --git a/app/database/manager/__mocks__/index.ts b/app/database/manager/__mocks__/index.ts index 0d38775cc8..a234993d1b 100644 --- a/app/database/manager/__mocks__/index.ts +++ b/app/database/manager/__mocks__/index.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database, Q} from '@nozbe/watermelondb'; +import {Database, Model, 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'; @@ -45,14 +45,14 @@ class DatabaseManager { private readonly serverModels: Models; constructor() { - this.appModels = [InfoModel, GlobalModel, ServersModel]; + this.appModels = [InfoModel, GlobalModel, ServersModel] as unknown[] as Model[]; this.serverModels = [ CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel, GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, ThreadModel, ThreadParticipantModel, ThreadInTeamModel, TeamThreadsSyncModel, UserModel, - ]; + ] as unknown[] as Model[]; this.databaseDirectory = ''; } diff --git a/app/database/manager/index.ts b/app/database/manager/index.ts index 93eed0b393..a780522b7d 100644 --- a/app/database/manager/index.ts +++ b/app/database/manager/index.ts @@ -43,14 +43,14 @@ class DatabaseManager { private readonly serverModels: Models; constructor() { - this.appModels = [InfoModel, GlobalModel, ServersModel]; + this.appModels = [InfoModel, GlobalModel, ServersModel] as unknown[] as Models; this.serverModels = [ CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, ConfigModel, CustomEmojiModel, DraftModel, FileModel, GroupModel, GroupChannelModel, GroupTeamModel, GroupMembershipModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, ThreadModel, ThreadParticipantModel, ThreadInTeamModel, TeamThreadsSyncModel, UserModel, - ]; + ] as unknown[] as Models; this.databaseDirectory = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupDatabase : `${FileSystem.DocumentDirectoryPath}/databases/`; } diff --git a/app/database/models/server/category_channel.ts b/app/database/models/server/category_channel.ts index 0db4942f21..287e24735f 100644 --- a/app/database/models/server/category_channel.ts +++ b/app/database/models/server/category_channel.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation, relation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type CategoryModel from '@typings/database/models/servers/category'; import type CategoryChannelInterface from '@typings/database/models/servers/category_channel'; import type ChannelModel from '@typings/database/models/servers/channel'; diff --git a/app/database/models/server/channel.ts b/app/database/models/server/channel.ts index cdb3768edd..89d41978fa 100644 --- a/app/database/models/server/channel.ts +++ b/app/database/models/server/channel.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Query, Relation} from '@nozbe/watermelondb'; import {children, field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Query, Relation} from '@nozbe/watermelondb'; import type CategoryChannelModel from '@typings/database/models/servers/category_channel'; import type ChannelModelInterface from '@typings/database/models/servers/channel'; import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; diff --git a/app/database/models/server/channel_info.ts b/app/database/models/server/channel_info.ts index 8d5fdcdea1..f257268638 100644 --- a/app/database/models/server/channel_info.ts +++ b/app/database/models/server/channel_info.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type ChannelInfoInterface from '@typings/database/models/servers/channel_info'; diff --git a/app/database/models/server/file.ts b/app/database/models/server/file.ts index 2394dcf3b1..aa60518611 100644 --- a/app/database/models/server/file.ts +++ b/app/database/models/server/file.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type FileModelInterface from '@typings/database/models/servers/file'; import type PostModel from '@typings/database/models/servers/post'; diff --git a/app/database/models/server/group_channel.ts b/app/database/models/server/group_channel.ts index 8a5d7c4e2d..fa5717f949 100644 --- a/app/database/models/server/group_channel.ts +++ b/app/database/models/server/group_channel.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type GroupModel from '@typings/database/models/servers/group'; import type GroupChannelInterface from '@typings/database/models/servers/group_channel'; diff --git a/app/database/models/server/group_membership.ts b/app/database/models/server/group_membership.ts index 54d39e5479..f45c227702 100644 --- a/app/database/models/server/group_membership.ts +++ b/app/database/models/server/group_membership.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type GroupModel from '@typings/database/models/servers/group'; import type GroupMembershipInterface from '@typings/database/models/servers/group_membership'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/database/models/server/group_team.ts b/app/database/models/server/group_team.ts index c2be191992..e8e5e6ff3b 100644 --- a/app/database/models/server/group_team.ts +++ b/app/database/models/server/group_team.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type GroupModel from '@typings/database/models/servers/group'; import type GroupTeamInterface from '@typings/database/models/servers/group_team'; import type TeamModel from '@typings/database/models/servers/team'; diff --git a/app/database/models/server/my_channel.ts b/app/database/models/server/my_channel.ts index ea01dfa3c2..a7a45ca9dd 100644 --- a/app/database/models/server/my_channel.ts +++ b/app/database/models/server/my_channel.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type MyChannelModelInterface from '@typings/database/models/servers/my_channel'; import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; @@ -66,7 +66,6 @@ export default class MyChannelModel extends Model implements MyChannelModelInter } resetPreparedState() { - // @ts-expect-error hack setting _preparedState this._preparedState = null; } } diff --git a/app/database/models/server/my_channel_settings.ts b/app/database/models/server/my_channel_settings.ts index e96aafde86..59b82959b5 100644 --- a/app/database/models/server/my_channel_settings.ts +++ b/app/database/models/server/my_channel_settings.ts @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {immutableRelation, json} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; +import type {Relation} from '@nozbe/watermelondb'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; import type MyChannelSettingsModelInterface from '@typings/database/models/servers/my_channel_settings'; diff --git a/app/database/models/server/my_team.ts b/app/database/models/server/my_team.ts index cb606a453b..da1854b448 100644 --- a/app/database/models/server/my_team.ts +++ b/app/database/models/server/my_team.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, relation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type MyTeamModelInterface from '@typings/database/models/servers/my_team'; import type TeamModel from '@typings/database/models/servers/team'; diff --git a/app/database/models/server/posts_in_channel.ts b/app/database/models/server/posts_in_channel.ts index 8abda43f3a..aae9a54f3a 100644 --- a/app/database/models/server/posts_in_channel.ts +++ b/app/database/models/server/posts_in_channel.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type PostsInChannelModelInterface from '@typings/database/models/servers/posts_in_channel'; diff --git a/app/database/models/server/posts_in_thread.ts b/app/database/models/server/posts_in_thread.ts index 838122b085..8618a3aef6 100644 --- a/app/database/models/server/posts_in_thread.ts +++ b/app/database/models/server/posts_in_thread.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type PostModel from '@typings/database/models/servers/post'; import type PostsInThreadModelInterface from '@typings/database/models/servers/posts_in_thread'; diff --git a/app/database/models/server/preference.ts b/app/database/models/server/preference.ts index e04c990d04..a75b41a5ca 100644 --- a/app/database/models/server/preference.ts +++ b/app/database/models/server/preference.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type PreferenceModelInterface from '@typings/database/models/servers/preference'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/database/models/server/reaction.ts b/app/database/models/server/reaction.ts index bc2dc0576e..be2fa78e8a 100644 --- a/app/database/models/server/reaction.ts +++ b/app/database/models/server/reaction.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type PostModel from '@typings/database/models/servers/post'; import type ReactionModelInterface from '@typings/database/models/servers/reaction'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/database/models/server/team_channel_history.ts b/app/database/models/server/team_channel_history.ts index 547d8689b0..924f43b22f 100644 --- a/app/database/models/server/team_channel_history.ts +++ b/app/database/models/server/team_channel_history.ts @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {immutableRelation, json} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; +import type {Relation} from '@nozbe/watermelondb'; import type TeamModel from '@typings/database/models/servers/team'; import type TeamChannelHistoryModelInterface from '@typings/database/models/servers/team_channel_history'; diff --git a/app/database/models/server/team_search_history.ts b/app/database/models/server/team_search_history.ts index 1118cc7b25..41b88ec546 100644 --- a/app/database/models/server/team_search_history.ts +++ b/app/database/models/server/team_search_history.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation, text} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type TeamModel from '@typings/database/models/servers/team'; import type TeamSearchHistoryModelInterface from '@typings/database/models/servers/team_search_history'; diff --git a/app/database/models/server/team_threads_sync.ts b/app/database/models/server/team_threads_sync.ts index 9b5a8409f5..f999436622 100644 --- a/app/database/models/server/team_threads_sync.ts +++ b/app/database/models/server/team_threads_sync.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type TeamModel from '@typings/database/models/servers/team'; import type TeamThreadsSyncModelInterface from '@typings/database/models/servers/team_threads_sync'; diff --git a/app/database/models/server/thread.ts b/app/database/models/server/thread.ts index 0efdf678bd..2c7c50d24a 100644 --- a/app/database/models/server/thread.ts +++ b/app/database/models/server/thread.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Query, Relation} from '@nozbe/watermelondb'; import {children, field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Query, Relation} from '@nozbe/watermelondb'; import type PostModel from '@typings/database/models/servers/post'; import type ThreadModelInterface from '@typings/database/models/servers/thread'; import type ThreadInTeamModel from '@typings/database/models/servers/thread_in_team'; diff --git a/app/database/models/server/thread_in_team.ts b/app/database/models/server/thread_in_team.ts index 50373e0b15..8825d5979f 100644 --- a/app/database/models/server/thread_in_team.ts +++ b/app/database/models/server/thread_in_team.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type TeamModel from '@typings/database/models/servers/team'; import type ThreadModel from '@typings/database/models/servers/thread'; import type ThreadInTeamModelInterface from '@typings/database/models/servers/thread_in_team'; diff --git a/app/database/models/server/thread_participant.ts b/app/database/models/server/thread_participant.ts index a70f10bc83..07f3ad3cfc 100644 --- a/app/database/models/server/thread_participant.ts +++ b/app/database/models/server/thread_participant.ts @@ -1,12 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; +import type {Relation} from '@nozbe/watermelondb'; import type ThreadModel from '@typings/database/models/servers/thread'; import type ThreadParticipantModelInterface from '@typings/database/models/servers/thread_participant'; import type UserModel from '@typings/database/models/servers/user'; diff --git a/app/database/models/server/user.ts b/app/database/models/server/user.ts index 1dc48e0f2a..59d089e142 100644 --- a/app/database/models/server/user.ts +++ b/app/database/models/server/user.ts @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Query} from '@nozbe/watermelondb'; import {children, field, json} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; +import type {Query} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; import type PostModel from '@typings/database/models/servers/post'; diff --git a/app/database/operator/app_data_operator/transformers/test.ts b/app/database/operator/app_data_operator/transformers/test.ts index c86517e106..944d80adb5 100644 --- a/app/database/operator/app_data_operator/transformers/test.ts +++ b/app/database/operator/app_data_operator/transformers/test.ts @@ -33,7 +33,7 @@ describe('** APP DATA TRANSFORMER **', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('InfoModel'); + expect(preparedRecords!.collection.table).toBe('Info'); }); it('=> transformGlobalRecord: should return an array of type Global', async () => { @@ -52,6 +52,6 @@ describe('** APP DATA TRANSFORMER **', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('GlobalModel'); + expect(preparedRecords!.collection.table).toBe('Global'); }); }); diff --git a/app/database/operator/base_data_operator/index.ts b/app/database/operator/base_data_operator/index.ts index 430b9a2915..78bc9b7491 100644 --- a/app/database/operator/base_data_operator/index.ts +++ b/app/database/operator/base_data_operator/index.ts @@ -11,7 +11,6 @@ import { } from '@database/operator/utils/general'; import {logWarning} from '@utils/log'; -import type {WriterInterface} from '@nozbe/watermelondb/Database'; import type Model from '@nozbe/watermelondb/Model'; import type { HandleRecordsArgs, @@ -186,7 +185,7 @@ export default class BaseDataOperator { async batchRecords(models: Model[]): Promise { try { if (models.length > 0) { - await this.database.write(async (writer: WriterInterface) => { + await this.database.write(async (writer) => { await writer.batch(...models); }); } diff --git a/app/database/operator/server_data_operator/handlers/category.test.ts b/app/database/operator/server_data_operator/handlers/category.test.ts index c7773a6800..b2188aef33 100644 --- a/app/database/operator/server_data_operator/handlers/category.test.ts +++ b/app/database/operator/server_data_operator/handlers/category.test.ts @@ -8,7 +8,7 @@ import { transformCategoryChannelRecord, } from '@database/operator/server_data_operator/transformers/category'; -import ServerDataOperator from '..'; +import type ServerDataOperator from '..'; describe('*** Operator: Category Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/handlers/channel.test.ts b/app/database/operator/server_data_operator/handlers/channel.test.ts index 4799f73aff..d3fe042478 100644 --- a/app/database/operator/server_data_operator/handlers/channel.test.ts +++ b/app/database/operator/server_data_operator/handlers/channel.test.ts @@ -15,7 +15,7 @@ import { transformMyChannelSettingsRecord, } from '@database/operator/server_data_operator/transformers/channel'; -import ServerDataOperator from '..'; +import type ServerDataOperator from '..'; describe('*** Operator: Channel Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/handlers/group.test.ts b/app/database/operator/server_data_operator/handlers/group.test.ts index f967c0d887..30cf6c2034 100644 --- a/app/database/operator/server_data_operator/handlers/group.test.ts +++ b/app/database/operator/server_data_operator/handlers/group.test.ts @@ -8,7 +8,7 @@ import { transformGroupRecord, } from '@database/operator/server_data_operator/transformers/group'; -import ServerDataOperator from '..'; +import type ServerDataOperator from '..'; describe('*** Operator: Group Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/handlers/post.test.ts b/app/database/operator/server_data_operator/handlers/post.test.ts index 69abea6a45..2d08b3b18b 100644 --- a/app/database/operator/server_data_operator/handlers/post.test.ts +++ b/app/database/operator/server_data_operator/handlers/post.test.ts @@ -9,7 +9,7 @@ import {buildDraftKey} from '@database/operator/server_data_operator/comparators import {transformDraftRecord} from '@database/operator/server_data_operator/transformers/post'; import {createPostsChain} from '@database/operator/utils/post'; -import ServerDataOperator from '..'; +import type ServerDataOperator from '..'; Q.sortBy = jest.fn().mockImplementation((field) => { return Q.where(field, Q.gte(0)); 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 dc8d964f28..6bb8f80404 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 @@ -6,6 +6,7 @@ import {Q} from '@nozbe/watermelondb'; import {Database} from '@constants'; import {getPostListEdges} from '@database//operator/utils/post'; import {transformPostsInChannelRecord} from '@database/operator/server_data_operator/transformers/post'; +import {emptyFunction} from '@utils/general'; import {logWarning} from '@utils/log'; import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; @@ -42,7 +43,7 @@ const PostsInChannelHandler = (superclass: any) => class extends superclass { for (const chunk of existingChunks) { if (newChunk.earliest <= chunk.earliest && newChunk.latest >= chunk.latest) { if (!prepareRecordsOnly) { - newChunk.prepareUpdate(); + newChunk.prepareUpdate(emptyFunction); } result.push(newChunk); result.push(chunk.prepareDestroyPermanently()); diff --git a/app/database/operator/server_data_operator/handlers/reaction.test.ts b/app/database/operator/server_data_operator/handlers/reaction.test.ts index 9cda5389c4..021d403509 100644 --- a/app/database/operator/server_data_operator/handlers/reaction.test.ts +++ b/app/database/operator/server_data_operator/handlers/reaction.test.ts @@ -2,7 +2,8 @@ // See LICENSE.txt for license information. import DatabaseManager from '@database/manager'; -import ServerDataOperator from '@database/operator/server_data_operator'; + +import type ServerDataOperator from '@database/operator/server_data_operator'; describe('*** Operator: User Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/handlers/team.test.ts b/app/database/operator/server_data_operator/handlers/team.test.ts index 721414903f..ac01b78594 100644 --- a/app/database/operator/server_data_operator/handlers/team.test.ts +++ b/app/database/operator/server_data_operator/handlers/team.test.ts @@ -14,7 +14,7 @@ import { transformTeamSearchHistoryRecord, } from '@database/operator/server_data_operator/transformers/team'; -import ServerDataOperator from '..'; +import type ServerDataOperator from '..'; describe('*** Operator: Team Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/handlers/thread.test.ts b/app/database/operator/server_data_operator/handlers/thread.test.ts index cacdf28c15..b7a987fb33 100644 --- a/app/database/operator/server_data_operator/handlers/thread.test.ts +++ b/app/database/operator/server_data_operator/handlers/thread.test.ts @@ -4,7 +4,7 @@ import DatabaseManager from '@database/manager'; import {transformThreadRecord, transformThreadParticipantRecord, transformThreadInTeamRecord, transformTeamThreadsSyncRecord} from '@database/operator/server_data_operator/transformers/thread'; -import ServerDataOperator from '..'; +import type ServerDataOperator from '..'; jest.mock('@database/operator/utils/thread', () => { return { diff --git a/app/database/operator/server_data_operator/handlers/thread.ts b/app/database/operator/server_data_operator/handlers/thread.ts index 605e71827f..5cb71befe4 100644 --- a/app/database/operator/server_data_operator/handlers/thread.ts +++ b/app/database/operator/server_data_operator/handlers/thread.ts @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import {Q} from '@nozbe/watermelondb'; -import Model from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import { @@ -14,6 +13,7 @@ import {sanitizeThreadParticipants} from '@database/operator/utils/thread'; import {logWarning} from '@utils/log'; import type Database from '@nozbe/watermelondb/Database'; +import type Model from '@nozbe/watermelondb/Model'; import type {HandleThreadsArgs, HandleThreadParticipantsArgs} from '@typings/database/database'; import type ThreadModel from '@typings/database/models/servers/thread'; import type ThreadInTeamModel from '@typings/database/models/servers/thread_in_team'; diff --git a/app/database/operator/server_data_operator/handlers/user.test.ts b/app/database/operator/server_data_operator/handlers/user.test.ts index 238329f624..18e8ed73ec 100644 --- a/app/database/operator/server_data_operator/handlers/user.test.ts +++ b/app/database/operator/server_data_operator/handlers/user.test.ts @@ -2,13 +2,14 @@ // See LICENSE.txt for license information. import DatabaseManager from '@database/manager'; -import ServerDataOperator from '@database/operator/server_data_operator'; import {buildPreferenceKey} from '@database/operator/server_data_operator/comparators'; import { transformPreferenceRecord, transformUserRecord, } from '@database/operator/server_data_operator/transformers/user'; +import type ServerDataOperator from '@database/operator/server_data_operator'; + describe('*** Operator: User Handlers tests ***', () => { let operator: ServerDataOperator; diff --git a/app/database/operator/server_data_operator/transformers/category.test.ts b/app/database/operator/server_data_operator/transformers/category.test.ts index 58930cbe25..7be88d50b6 100644 --- a/app/database/operator/server_data_operator/transformers/category.test.ts +++ b/app/database/operator/server_data_operator/transformers/category.test.ts @@ -34,7 +34,7 @@ describe('*** CATEGORY Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords.collection.modelClass.name).toBe('CategoryModel'); + expect(preparedRecords.collection.table).toBe('Category'); }); it('=> transformCategoryChannelRecord: should return an array of type CategoryChannelModel', async () => { @@ -58,6 +58,6 @@ describe('*** CATEGORY Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords.collection.modelClass.name).toBe('CategoryChannelModel'); + expect(preparedRecords.collection.table).toBe('CategoryChannel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/channel.test.ts b/app/database/operator/server_data_operator/transformers/channel.test.ts index 73f514d267..571bec3dc3 100644 --- a/app/database/operator/server_data_operator/transformers/channel.test.ts +++ b/app/database/operator/server_data_operator/transformers/channel.test.ts @@ -46,7 +46,7 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords.collection.modelClass.name).toBe('ChannelModel'); + expect(preparedRecords.collection.table).toBe('Channel'); }); it('=> transformMyChannelSettingsRecord: should return an array of type MyChannelSettings', async () => { @@ -82,7 +82,7 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('MyChannelSettingsModel'); + expect(preparedRecords!.collection.table).toBe('MyChannelSettings'); }); it('=> transformChannelInfoRecord: should return an array of type ChannelInfo', async () => { @@ -109,7 +109,7 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('ChannelInfoModel'); + expect(preparedRecords!.collection.table).toBe('ChannelInfo'); }); it('=> transformMyChannelRecord: should return an array of type MyChannel', async () => { @@ -138,7 +138,7 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('MyChannelModel'); + expect(preparedRecords!.collection.table).toBe('MyChannel'); }); it('=> transformChannelMembershipRecord: should return an array of type ChannelMembership', async () => { @@ -174,6 +174,6 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('ChannelMembershipModel'); + expect(preparedRecords!.collection.table).toBe('ChannelMembership'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/general.test.ts b/app/database/operator/server_data_operator/transformers/general.test.ts index ddf9cc2f64..12e25c6e1c 100644 --- a/app/database/operator/server_data_operator/transformers/general.test.ts +++ b/app/database/operator/server_data_operator/transformers/general.test.ts @@ -30,7 +30,7 @@ describe('*** Role Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('RoleModel'); + expect(preparedRecords!.collection.table).toBe('Role'); }); }); @@ -51,7 +51,7 @@ describe('*** System Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('SystemModel'); + expect(preparedRecords!.collection.table).toBe('System'); }); }); @@ -79,7 +79,7 @@ describe('*** CustomEmoj Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('CustomEmojiModel'); + expect(preparedRecords!.collection.table).toBe('CustomEmoji'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/group.test.ts b/app/database/operator/server_data_operator/transformers/group.test.ts index 28a84f2695..8ec75765ad 100644 --- a/app/database/operator/server_data_operator/transformers/group.test.ts +++ b/app/database/operator/server_data_operator/transformers/group.test.ts @@ -29,6 +29,6 @@ describe('*** GROUP Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords.collection.modelClass.name).toBe('GroupModel'); + expect(preparedRecords.collection.table).toBe('Group'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/index.ts b/app/database/operator/server_data_operator/transformers/index.ts index 611bfab74d..7e6d963c2d 100644 --- a/app/database/operator/server_data_operator/transformers/index.ts +++ b/app/database/operator/server_data_operator/transformers/index.ts @@ -1,11 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Model from '@nozbe/watermelondb/Model'; - import {OperationType} from '@constants/database'; -import type {TransformerArgs} from '@typings/database/database'; +import type Model from '@nozbe/watermelondb/Model'; +import type {PrepareBaseRecordArgs} from '@typings/database/database'; /** * prepareBaseRecord: This is the last step for each operator and depending on the 'action', it will either prepare an @@ -15,7 +14,7 @@ import type {TransformerArgs} from '@typings/database/database'; * @param {Database} operatorBase.database * @param {string} operatorBase.tableName * @param {RecordPair} operatorBase.value - * @param {((TransformerArgs) => void)} operatorBase.generator + * @param {((PrepareBaseRecordArgs) => void)} operatorBase.generator * @returns {Promise} */ export const prepareBaseRecord = async ({ @@ -24,10 +23,10 @@ export const prepareBaseRecord = async ({ tableName, value, fieldsMapper, -}: TransformerArgs): Promise => { +}: PrepareBaseRecordArgs): Promise => { if (action === OperationType.UPDATE) { const record = value.record as Model; - return record.prepareUpdate(() => fieldsMapper!(record)); + return record.prepareUpdate(() => fieldsMapper(record)); } return database.collections.get(tableName!).prepareCreate(fieldsMapper); diff --git a/app/database/operator/server_data_operator/transformers/post.test.ts b/app/database/operator/server_data_operator/transformers/post.test.ts index 67eea50924..53bea8c62e 100644 --- a/app/database/operator/server_data_operator/transformers/post.test.ts +++ b/app/database/operator/server_data_operator/transformers/post.test.ts @@ -48,7 +48,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('PostModel'); + expect(preparedRecords!.collection.table).toBe('Post'); }); it('=> transformPostInThreadRecord: should return an array of type PostsInThread', async () => { @@ -72,9 +72,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe( - 'PostsInThreadModel', - ); + expect(preparedRecords!.collection.table).toBe('PostsInThread'); }); it('=> transformFileRecord: should return an array of type File', async () => { @@ -107,7 +105,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('FileModel'); + expect(preparedRecords!.collection.table).toBe('File'); }); it('=> transformDraftRecord: should return an array of type Draft', async () => { @@ -132,7 +130,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('DraftModel'); + expect(preparedRecords!.collection.table).toBe('Draft'); }); it('=> transformPostsInChannelRecord: should return an array of type PostsInChannel', async () => { @@ -156,8 +154,6 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe( - 'PostsInChannelModel', - ); + expect(preparedRecords!.collection.table).toBe('PostsInChannel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/reaction.test.ts b/app/database/operator/server_data_operator/transformers/reaction.test.ts index 1b8675d4e7..7105da1a9d 100644 --- a/app/database/operator/server_data_operator/transformers/reaction.test.ts +++ b/app/database/operator/server_data_operator/transformers/reaction.test.ts @@ -30,6 +30,6 @@ describe('*** REACTION Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('ReactionModel'); + expect(preparedRecords!.collection.table).toBe('Reaction'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/team.test.ts b/app/database/operator/server_data_operator/transformers/team.test.ts index 810546fde6..faf04037d0 100644 --- a/app/database/operator/server_data_operator/transformers/team.test.ts +++ b/app/database/operator/server_data_operator/transformers/team.test.ts @@ -31,7 +31,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('MyTeamModel'); + expect(preparedRecords!.collection.table).toBe('MyTeam'); }); it('=> transformTeamRecord: should return an array of type Team', async () => { @@ -67,7 +67,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamModel'); + expect(preparedRecords!.collection.table).toBe('Team'); }); it('=> transformTeamChannelHistoryRecord: should return an array of type Team', async () => { @@ -89,7 +89,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamChannelHistoryModel'); + expect(preparedRecords!.collection.table).toBe('TeamChannelHistory'); }); it('=> transformTeamSearchHistoryRecord: should return an array of type TeamSearchHistory', async () => { @@ -113,7 +113,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamSearchHistoryModel'); + expect(preparedRecords!.collection.table).toBe('TeamSearchHistory'); }); it('=> transformTeamMembershipRecord: should return an array of type TeamMembership', async () => { @@ -141,6 +141,6 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamMembershipModel'); + expect(preparedRecords!.collection.table).toBe('TeamMembership'); }); }); 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 bf4d487349..05d886995c 100644 --- a/app/database/operator/server_data_operator/transformers/user.test.ts +++ b/app/database/operator/server_data_operator/transformers/user.test.ts @@ -22,7 +22,7 @@ describe('*** USER Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('PreferenceModel'); + expect(preparedRecords!.collection.table).toBe('Preference'); }); it('=> transformUserRecord: should return an array of type User', async () => { @@ -78,6 +78,6 @@ describe('*** USER Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('UserModel'); + expect(preparedRecords!.collection.table).toBe('User'); }); }); diff --git a/app/database/operator/utils/test.ts b/app/database/operator/utils/test.ts index 5399e5a976..94b00eba6e 100644 --- a/app/database/operator/utils/test.ts +++ b/app/database/operator/utils/test.ts @@ -7,8 +7,6 @@ import {sanitizeReactions} from '@database/operator/utils/reaction'; import {mockedPosts, mockedReactions} from './mock'; -import type {WriterInterface} from '@nozbe/watermelondb/Database'; - describe('DataOperator: Utils tests', () => { it('=> sanitizePosts: should filter between ordered and unordered posts', () => { const {postsOrdered, postsUnordered} = sanitizePosts({ @@ -96,7 +94,7 @@ describe('DataOperator: Utils tests', () => { // Jest in not using the same database instance amongst the Singletons; hence, we are creating the reaction record here // eslint-disable-next-line max-nested-callbacks - await server.database.write(async (writer: WriterInterface) => { + await server.database.write(async (writer) => { await writer.batch(...prepareRecords); }); diff --git a/app/hooks/android_back_handler.ts b/app/hooks/android_back_handler.ts index d789cf5299..0bb2525c29 100644 --- a/app/hooks/android_back_handler.ts +++ b/app/hooks/android_back_handler.ts @@ -6,7 +6,9 @@ import {BackHandler} from 'react-native'; import NavigationStore from '@store/navigation_store'; -const useAndroidHardwareBackHandler = (componentId: string, callback: () => void) => { +import type {AvailableScreens} from '@typings/screens/navigation'; + +const useAndroidHardwareBackHandler = (componentId: AvailableScreens | undefined, callback: () => void) => { useEffect(() => { const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { if (NavigationStore.getVisibleScreen() === componentId) { diff --git a/app/hooks/device.ts b/app/hooks/device.ts index c29a91ec50..0c6b29da7d 100644 --- a/app/hooks/device.ts +++ b/app/hooks/device.ts @@ -3,11 +3,12 @@ import React, {RefObject, useEffect, useRef, useState} from 'react'; import {AppState, Keyboard, NativeModules, Platform, useWindowDimensions, View} from 'react-native'; -import {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import {Device} from '@constants'; +import type {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; + const {MattermostManaged} = NativeModules; const isRunningInSplitView = MattermostManaged.isRunningInSplitView; diff --git a/app/hooks/header.ts b/app/hooks/header.ts index 0411612a3c..cbfde03572 100644 --- a/app/hooks/header.ts +++ b/app/hooks/header.ts @@ -2,13 +2,14 @@ // See LICENSE.txt for license information. import React, {useCallback, useMemo} from 'react'; -import {NativeScrollEvent} from 'react-native'; import Animated, {runOnJS, scrollTo, useAnimatedRef, useAnimatedScrollHandler, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import ViewConstants from '@constants/view'; import {useIsTablet} from '@hooks/device'; +import type {NativeScrollEvent} from 'react-native'; + type HeaderScrollContext = { dragging?: boolean; momentum?: string; diff --git a/app/hooks/keyboard_tracking.ts b/app/hooks/keyboard_tracking.ts index 95da896846..2cc198a890 100644 --- a/app/hooks/keyboard_tracking.ts +++ b/app/hooks/keyboard_tracking.ts @@ -2,11 +2,12 @@ // See LICENSE.txt for license information. import {RefObject, useEffect, useRef} from 'react'; -import {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; import {Navigation} from 'react-native-navigation'; import NavigationStore from '@store/navigation_store'; +import type {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; + export const useKeyboardTrackingPaused = (keyboardTrackingRef: RefObject, trackerId: string, screens: string[]) => { const isPostDraftPaused = useRef(false); diff --git a/app/init/managed_app.ts b/app/init/managed_app.ts index 234a5f783d..912d45f11d 100644 --- a/app/init/managed_app.ts +++ b/app/init/managed_app.ts @@ -78,7 +78,7 @@ class ManagedApp { const jailbreakProtection = config!.jailbreakProtection === 'true'; if (jailbreakProtection && !this.isTrustedDevice()) { - this.alertDeviceIsUntrusted(); + this.alertDeviceIsNotTrusted(); return; } @@ -88,14 +88,17 @@ class ManagedApp { } }; - alertDeviceIsUntrusted = () => { + alertDeviceIsNotTrusted = () => { // We use the default device locale as this is an app wide setting // and does not require any server data const locale = DEFAULT_LOCALE; const translations = getTranslations(locale); Alert.alert( translations[t('mobile.managed.blocked_by')].replace('{vendor}', this.vendor), - translations[t('mobile.managed.jailbreak')].replace('{vendor}', this.vendor), + translations[t('mobile.managed.jailbreak')]. + replace('{vendor}', this.vendor). + replace('{reason}', JailMonkey.jailBrokenMessage() || translations[t('mobile.managed.jailbreak_no_reason')]). + replace('{debug}', JSON.stringify(JailMonkey.androidRootedDetectionMethods || translations[t('mobile.managed.jailbreak_no_debug_info')])), [{ text: translations[t('mobile.managed.exit')], style: 'destructive', @@ -139,7 +142,7 @@ class ManagedApp { }; isTrustedDevice = () => { - return __DEV__ || JailMonkey.trustFall(); + return __DEV__ || !JailMonkey.isJailBroken(); }; onAppStateChange = async (appState: AppStateStatus) => { diff --git a/app/managers/draft_upload_manager/index.test.ts b/app/managers/draft_upload_manager/index.test.ts index f13f2ae845..545dcf60be 100644 --- a/app/managers/draft_upload_manager/index.test.ts +++ b/app/managers/draft_upload_manager/index.test.ts @@ -1,18 +1,19 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client'; import {AppState, AppStateStatus} from 'react-native'; import {addFilesToDraft} from '@actions/local/draft'; import {PROGRESS_TIME_TO_STORE} from '@constants/files'; import DatabaseManager from '@database/manager'; -import ServerDataOperator from '@database/operator/server_data_operator'; import {getDraft} from '@queries/servers/drafts'; import TestHelper from '@test/test_helper'; import {exportedForTesting} from '.'; +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type {ClientResponse, ProgressPromise} from '@mattermost/react-native-network-client'; + const {DraftUploadManager} = exportedForTesting; const url = 'baseHandler.test.com'; diff --git a/app/managers/draft_upload_manager/index.ts b/app/managers/draft_upload_manager/index.ts index 76d11764a9..44a9d74bc7 100644 --- a/app/managers/draft_upload_manager/index.ts +++ b/app/managers/draft_upload_manager/index.ts @@ -1,13 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ClientResponse, ClientResponseError} from '@mattermost/react-native-network-client'; import {AppState, AppStateStatus} from 'react-native'; import {updateDraftFile} from '@actions/local/draft'; import {uploadFile} from '@actions/remote/file'; import {PROGRESS_TIME_TO_STORE} from '@constants/files'; +import type {ClientResponse, ClientResponseError} from '@mattermost/react-native-network-client'; + type FileHandler = { [clientId: string]: { cancel?: () => void; diff --git a/app/products/calls/actions/calls.test.ts b/app/products/calls/actions/calls.test.ts index 672787e820..bf9437d74e 100644 --- a/app/products/calls/actions/calls.test.ts +++ b/app/products/calls/actions/calls.test.ts @@ -100,6 +100,7 @@ const addFakeCall = (serverUrl: string, channelId: string) => { describe('Actions.Calls', () => { const {newConnection} = require('@calls/connection/connection'); InCallManager.setSpeakerphoneOn = jest.fn(); + InCallManager.setForceSpeakerphoneOn = jest.fn(); // eslint-disable-next-line // @ts-ignore NetworkManager.getClient = () => mockClient; diff --git a/app/products/calls/actions/calls.ts b/app/products/calls/actions/calls.ts index c363eabefb..f935ff42f5 100644 --- a/app/products/calls/actions/calls.ts +++ b/app/products/calls/actions/calls.ts @@ -1,11 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import {Alert} from 'react-native'; import InCallManager from 'react-native-incall-manager'; +import {Navigation} from 'react-native-navigation'; import {forceLogoutIfNecessary} from '@actions/remote/session'; import {fetchUsersByIds} from '@actions/remote/user'; -import {needsRecordingWillBePostedAlert} from '@calls/alerts'; +import {leaveAndJoinWithAlert, needsRecordingWillBePostedAlert} from '@calls/alerts'; import { getCallsConfig, getCallsState, @@ -18,8 +20,10 @@ import { setCallForChannel, newCurrentCall, myselfLeftCall, + getCurrentCall, + getChannelsWithCalls, } from '@calls/state'; -import {General, Preferences} from '@constants'; +import {General, Preferences, Screens} from '@constants'; import Calls from '@constants/calls'; import DatabaseManager from '@database/manager'; import {getTeammateNameDisplaySetting} from '@helpers/api/preference'; @@ -28,6 +32,8 @@ import {getChannelById} from '@queries/servers/channel'; import {queryPreferencesByCategoryAndName} from '@queries/servers/preference'; import {getConfig, getLicense} from '@queries/servers/system'; import {getCurrentUser, getUserById} from '@queries/servers/user'; +import {dismissAllModalsAndPopToScreen} from '@screens/navigation'; +import NavigationStore from '@store/navigation_store'; import {logWarning} from '@utils/log'; import {displayUsername, getUserIdFromChannelName, isSystemAdmin} from '@utils/user'; @@ -228,7 +234,13 @@ export const enableChannelCalls = async (serverUrl: string, channelId: string, e return {}; }; -export const joinCall = async (serverUrl: string, channelId: string, userId: string, hasMicPermission: boolean): Promise<{ error?: string | Error; data?: string }> => { +export const joinCall = async ( + serverUrl: string, + channelId: string, + userId: string, + hasMicPermission: boolean, + title?: string, +): Promise<{ error?: string | Error; data?: string }> => { // Edge case: calls was disabled when app loaded, and then enabled, but app hasn't // reconnected its websocket since then (i.e., hasn't called batchLoadCalls yet) const {data: enabled} = await checkIsCallsPluginEnabled(serverUrl); @@ -246,7 +258,7 @@ export const joinCall = async (serverUrl: string, channelId: string, userId: str try { connection = await newConnection(serverUrl, channelId, () => { myselfLeftCall(); - }, setScreenShareURL, hasMicPermission); + }, setScreenShareURL, hasMicPermission, title); } catch (error: unknown) { await forceLogoutIfNecessary(serverUrl, error as ClientError); return {error: error as Error}; @@ -270,6 +282,16 @@ export const leaveCall = () => { setSpeakerphoneOn(false); }; +export const leaveCallPopCallScreen = async () => { + leaveCall(); + + // Need to pop the call screen, if it's somewhere in the stack. + if (NavigationStore.getScreensInStack().includes(Screens.CALL)) { + await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call'); + Navigation.pop(Screens.CALL).catch(() => null); + } +}; + export const muteMyself = () => { if (connection) { connection.mute(); @@ -307,7 +329,7 @@ export const sendReaction = (emoji: CallReactionEmoji) => { }; export const setSpeakerphoneOn = (speakerphoneOn: boolean) => { - InCallManager.setSpeakerphoneOn(speakerphoneOn); + InCallManager.setForceSpeakerphoneOn(speakerphoneOn); setSpeakerPhone(speakerphoneOn); }; @@ -419,3 +441,89 @@ export const stopCallRecording = async (serverUrl: string, callId: string) => { return data; }; + +// handleCallsSlashCommand will return true if the slash command was handled +export const handleCallsSlashCommand = async (value: string, serverUrl: string, channelId: string, currentUserId: string, intl: IntlShape): + Promise<{ handled?: boolean; error?: string }> => { + const tokens = value.split(' '); + if (tokens.length < 2 || tokens[0] !== '/call') { + return {handled: false}; + } + + switch (tokens[1]) { + case 'end': + await handleEndCall(serverUrl, channelId, currentUserId, intl); + return {handled: true}; + case 'start': { + if (getChannelsWithCalls(serverUrl)[channelId]) { + return { + error: intl.formatMessage({ + id: 'mobile.calls_start_call_exists', + defaultMessage: 'A call is already ongoing in the channel.', + }), + }; + } + const title = tokens.length > 2 ? tokens.slice(2).join(' ') : undefined; + await leaveAndJoinWithAlert(intl, serverUrl, channelId, title); + return {handled: true}; + } + case 'join': + await leaveAndJoinWithAlert(intl, serverUrl, channelId); + return {handled: true}; + case 'leave': + if (getCurrentCall()?.channelId === channelId) { + await leaveCallPopCallScreen(); + return {handled: true}; + } + return { + error: intl.formatMessage({ + id: 'mobile.calls_not_connected', + defaultMessage: 'You\'re not connected to a call in the current channel.', + }), + }; + } + + return {handled: false}; +}; + +const handleEndCall = async (serverUrl: string, channelId: string, currentUserId: string, intl: IntlShape) => { + const hasPermissions = await canEndCall(serverUrl, channelId); + + if (!hasPermissions) { + Alert.alert( + intl.formatMessage({ + id: 'mobile.calls_end_permission_title', + defaultMessage: 'Error', + }), + intl.formatMessage({ + id: 'mobile.calls_end_permission_msg', + defaultMessage: 'You don\'t have permission to end the call. Please ask the call owner to end the call.', + })); + return; + } + + const message = await getEndCallMessage(serverUrl, channelId, currentUserId, intl); + const title = intl.formatMessage({id: 'mobile.calls_end_call_title', defaultMessage: 'End call'}); + + Alert.alert( + title, + message, + [ + { + text: intl.formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}), + }, + { + text: title, + onPress: async () => { + try { + await endCall(serverUrl, channelId); + } catch (e) { + const err = (e as ClientError).message || 'unable to complete command, see server logs'; + Alert.alert('Error', `Error: ${err}`); + } + }, + style: 'cancel', + }, + ], + ); +}; diff --git a/app/products/calls/actions/index.ts b/app/products/calls/actions/index.ts index e8f579c9f4..612d9bfa2a 100644 --- a/app/products/calls/actions/index.ts +++ b/app/products/calls/actions/index.ts @@ -12,6 +12,7 @@ export { raiseHand, unraiseHand, setSpeakerphoneOn, + handleCallsSlashCommand, } from './calls'; export {hasMicrophonePermission} from './permissions'; diff --git a/app/products/calls/alerts.ts b/app/products/calls/alerts.ts index fc954f101d..1ff6fafc8b 100644 --- a/app/products/calls/alerts.ts +++ b/app/products/calls/alerts.ts @@ -2,20 +2,25 @@ // See LICENSE.txt for license information. import {Alert} from 'react-native'; -import {Navigation} from 'react-native-navigation'; -import {hasMicrophonePermission, joinCall, leaveCall, unmuteMyself} from '@calls/actions'; -import {LimitRestrictedInfo} from '@calls/observers'; -import {getCallsConfig, getCallsState, setMicPermissionsGranted} from '@calls/state'; +import {hasMicrophonePermission, joinCall, unmuteMyself} from '@calls/actions'; +import {leaveCallPopCallScreen} from '@calls/actions/calls'; +import { + getCallsConfig, + getCallsState, + getChannelsWithCalls, + getCurrentCall, + setMicPermissionsGranted, +} from '@calls/state'; import {errorAlert} from '@calls/utils'; -import {Screens} from '@constants'; import DatabaseManager from '@database/manager'; +import {getChannelById} from '@queries/servers/channel'; import {getCurrentUser} from '@queries/servers/user'; -import {dismissAllModals, dismissAllModalsAndPopToScreen} from '@screens/navigation'; -import NavigationStore from '@store/navigation_store'; +import {isDMorGM} from '@utils/channel'; import {logError} from '@utils/log'; import {isSystemAdmin} from '@utils/user'; +import type {LimitRestrictedInfo} from '@calls/observers'; import type {IntlShape} from 'react-intl'; // Only allow one recording alert per call. @@ -56,17 +61,39 @@ export const showLimitRestrictedAlert = (info: LimitRestrictedInfo, intl: IntlSh ); }; -export const leaveAndJoinWithAlert = ( +export const leaveAndJoinWithAlert = async ( intl: IntlShape, - serverUrl: string, - channelId: string, - leaveChannelName: string, - joinChannelName: string, - confirmToJoin: boolean, - newCall: boolean, - isDMorGM: boolean, + joinServerUrl: string, + joinChannelId: string, + title?: string, ) => { - if (confirmToJoin) { + let leaveChannelName = ''; + let joinChannelName = ''; + let joinChannelIsDMorGM = false; + let leaveServerUrl = ''; + let leaveChannelId = ''; + const newCall = !getChannelsWithCalls(joinServerUrl)[joinChannelId]; + + try { + const {database: joinDatabase} = DatabaseManager.getServerDatabaseAndOperator(joinServerUrl); + const joinChannel = await getChannelById(joinDatabase, joinChannelId); + joinChannelName = joinChannel?.displayName || ''; + joinChannelIsDMorGM = joinChannel ? isDMorGM(joinChannel) : false; + + const currentCall = getCurrentCall(); + if (currentCall) { + const {database: leaveDatabase} = DatabaseManager.getServerDatabaseAndOperator(currentCall.serverUrl); + const leaveChannel = await getChannelById(leaveDatabase, currentCall.channelId); + leaveChannelName = leaveChannel?.displayName || ''; + leaveServerUrl = currentCall.serverUrl; + leaveChannelId = currentCall.channelId; + } + } catch (error) { + logError('failed to getServerDatabase in leaveAndJoinWithAlert', error); + return; + } + + if (leaveServerUrl && leaveChannelId) { const {formatMessage} = intl; let joinMessage = formatMessage({ @@ -99,17 +126,24 @@ export const leaveAndJoinWithAlert = ( id: 'mobile.leave_and_join_confirmation', defaultMessage: 'Leave & Join', }), - onPress: () => doJoinCall(serverUrl, channelId, isDMorGM, newCall, intl), + onPress: () => doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title), style: 'cancel', }, ], ); } else { - doJoinCall(serverUrl, channelId, isDMorGM, newCall, intl); + doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title); } }; -const doJoinCall = async (serverUrl: string, channelId: string, isDMorGM: boolean, newCall: boolean, intl: IntlShape) => { +const doJoinCall = async ( + serverUrl: string, + channelId: string, + joinChannelIsDMorGM: boolean, + newCall: boolean, + intl: IntlShape, + title?: string, +) => { const {formatMessage} = intl; let user; @@ -155,14 +189,14 @@ const doJoinCall = async (serverUrl: string, channelId: string, isDMorGM: boolea const hasPermission = await hasMicrophonePermission(); setMicPermissionsGranted(hasPermission); - const res = await joinCall(serverUrl, channelId, user.id, hasPermission); + const res = await joinCall(serverUrl, channelId, user.id, hasPermission, title); if (res.error) { const seeLogs = formatMessage({id: 'mobile.calls_see_logs', defaultMessage: 'See server logs'}); errorAlert(res.error?.toString() || seeLogs, intl); return; } - if (isDMorGM) { + if (joinChannelIsDMorGM) { // FIXME (MM-46048) - HACK // There's a race condition between unmuting and receiving existing tracks from other participants. // Fixing this properly requires extensive and potentially breaking changes. @@ -222,14 +256,7 @@ export const recordingAlert = (isHost: boolean, intl: IntlShape) => { defaultMessage: 'Leave', }), onPress: async () => { - leaveCall(); - - // Need to pop the call screen, if it's somewhere in the stack. - await dismissAllModals(); - if (NavigationStore.getScreensInStack().includes(Screens.CALL)) { - await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call'); - Navigation.pop(Screens.CALL).catch(() => null); - } + await leaveCallPopCallScreen(); }, style: 'destructive', }, diff --git a/app/products/calls/components/call_avatar.tsx b/app/products/calls/components/call_avatar.tsx index ee704d4224..fdd41b1339 100644 --- a/app/products/calls/components/call_avatar.tsx +++ b/app/products/calls/components/call_avatar.tsx @@ -4,11 +4,11 @@ import React, {useMemo} from 'react'; import {View, StyleSheet, Text, Platform} from 'react-native'; -import {CallReactionEmoji} from '@calls/types/calls'; import CompassIcon from '@components/compass_icon'; import Emoji from '@components/emoji'; import ProfilePicture from '@components/profile_picture'; +import type {CallReactionEmoji} from '@calls/types/calls'; import type UserModel from '@typings/database/models/servers/user'; type Props = { diff --git a/app/products/calls/components/calls_custom_message/calls_custom_message.tsx b/app/products/calls/components/calls_custom_message/calls_custom_message.tsx index 16640f43f0..e651dcff4a 100644 --- a/app/products/calls/components/calls_custom_message/calls_custom_message.tsx +++ b/app/products/calls/components/calls_custom_message/calls_custom_message.tsx @@ -14,6 +14,7 @@ import FormattedTime from '@components/formatted_time'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; import {displayUsername, getUserTimezone} from '@utils/user'; import type {LimitRestrictedInfo} from '@calls/observers'; @@ -26,15 +27,16 @@ type Props = { author?: UserModel; isMilitaryTime: boolean; teammateNameDisplay?: string; - currentCallChannelId?: string; - leaveChannelName?: string; - joinChannelName?: string; - joinChannelIsDMorGM?: boolean; limitRestrictedInfo?: LimitRestrictedInfo; + ccChannelId?: string; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { return { + title: { + ...typography('Heading', 500), + color: theme.centerChannelColor, + }, messageStyle: { flexDirection: 'row', color: changeOpacity(theme.centerChannelColor, 0.6), @@ -108,7 +110,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { export const CallsCustomMessage = ({ post, currentUser, author, isMilitaryTime, teammateNameDisplay, - currentCallChannelId, leaveChannelName, joinChannelName, joinChannelIsDMorGM, limitRestrictedInfo, + ccChannelId, limitRestrictedInfo, }: Props) => { const intl = useIntl(); const theme = useTheme(); @@ -116,8 +118,7 @@ export const CallsCustomMessage = ({ const serverUrl = useServerUrl(); const timezone = getUserTimezone(currentUser); - const confirmToJoin = Boolean(currentCallChannelId && currentCallChannelId !== post.channelId); - const alreadyInTheCall = Boolean(currentCallChannelId && currentCallChannelId === post.channelId); + const alreadyInTheCall = Boolean(ccChannelId && ccChannelId === post.channelId); const isLimitRestricted = Boolean(limitRestrictedInfo?.limitRestricted); const joinHandler = () => { @@ -130,100 +131,110 @@ export const CallsCustomMessage = ({ return; } - leaveAndJoinWithAlert(intl, serverUrl, post.channelId, leaveChannelName || '', joinChannelName || '', confirmToJoin, false, Boolean(joinChannelIsDMorGM)); + leaveAndJoinWithAlert(intl, serverUrl, post.channelId); }; + const title = post.props.title ? ( + + {post.props.title} + + ) : null; + if (post.props.end_at) { return ( - - - - + {title} + + - + - {' '} - { + + + {' '} - } - {'•'} - + {'•'} + + - + ); } const joinTextStyle = [style.joinCallButtonText, isLimitRestricted && style.joinCallButtonTextRestricted]; return ( - - - - - - - - + <> + {title} + - { - alreadyInTheCall && + - } - { - !alreadyInTheCall && - - } - - + + + + + { + alreadyInTheCall && + + } + { + !alreadyInTheCall && + + } + + + ); }; diff --git a/app/products/calls/components/calls_custom_message/index.ts b/app/products/calls/components/calls_custom_message/index.ts index e2fa8be68f..3f4234817c 100644 --- a/app/products/calls/components/calls_custom_message/index.ts +++ b/app/products/calls/components/calls_custom_message/index.ts @@ -3,19 +3,16 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; -import {combineLatest, of as of$} from 'rxjs'; +import {of as of$} from 'rxjs'; import {distinctUntilChanged, switchMap} from 'rxjs/operators'; import {CallsCustomMessage} from '@calls/components/calls_custom_message/calls_custom_message'; import {observeIsCallLimitRestricted} from '@calls/observers'; import {observeCurrentCall} from '@calls/state'; import {Preferences} from '@constants'; -import DatabaseManager from '@database/manager'; import {getPreferenceAsBool} from '@helpers/api/preference'; -import {observeChannel} from '@queries/servers/channel'; import {queryPreferencesByCategoryAndName} from '@queries/servers/preference'; import {observeCurrentUser, observeTeammateNameDisplay, observeUser} from '@queries/servers/user'; -import {isDMorGM} from '@utils/channel'; import type {WithDatabaseArgs} from '@typings/database/database'; import type PostModel from '@typings/database/models/servers/post'; @@ -43,27 +40,8 @@ const enhanced = withObservables(['post'], ({serverUrl, post, database}: OwnProp }; } - const ccDatabase = observeCurrentCall().pipe( - switchMap((call) => of$(call?.serverUrl || '')), - distinctUntilChanged(), - switchMap((url) => of$(DatabaseManager.serverDatabases[url]?.database)), - ); - const currentCallChannelId = observeCurrentCall().pipe( - switchMap((call) => of$(call?.channelId || '')), - distinctUntilChanged(), - ); - const leaveChannelName = combineLatest([ccDatabase, currentCallChannelId]).pipe( - switchMap(([db, id]) => (db && id ? observeChannel(db, id) : of$(undefined))), - switchMap((c) => of$(c ? c.displayName : '')), - distinctUntilChanged(), - ); - const joinChannel = observeChannel(database, post.channelId); - const joinChannelName = joinChannel.pipe( - switchMap((chan) => of$(chan?.displayName || '')), - distinctUntilChanged(), - ); - const joinChannelIsDMorGM = joinChannel.pipe( - switchMap((chan) => of$(chan ? isDMorGM(chan) : false)), + const ccChannelId = observeCurrentCall().pipe( + switchMap((call) => of$(call?.channelId)), distinctUntilChanged(), ); @@ -72,11 +50,8 @@ const enhanced = withObservables(['post'], ({serverUrl, post, database}: OwnProp author, isMilitaryTime, teammateNameDisplay: observeTeammateNameDisplay(database), - currentCallChannelId, - leaveChannelName, - joinChannelName, - joinChannelIsDMorGM, limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, post.channelId), + ccChannelId, }; }); diff --git a/app/products/calls/components/channel_info_start/channel_info_start_button.tsx b/app/products/calls/components/channel_info_start/channel_info_start_button.tsx index 6cdeb09c83..0b699eac14 100644 --- a/app/products/calls/components/channel_info_start/channel_info_start_button.tsx +++ b/app/products/calls/components/channel_info_start/channel_info_start_button.tsx @@ -14,26 +14,18 @@ import type {LimitRestrictedInfo} from '@calls/observers'; export interface Props { serverUrl: string; - displayName: string; channelId: string; - channelIsDMorGM: boolean; isACallInCurrentChannel: boolean; - confirmToJoin: boolean; alreadyInCall: boolean; - currentCallChannelName: string; dismissChannelInfo: () => void; limitRestrictedInfo: LimitRestrictedInfo; } const ChannelInfoStartButton = ({ serverUrl, - displayName, channelId, - channelIsDMorGM, isACallInCurrentChannel, - confirmToJoin, alreadyInCall, - currentCallChannelName, dismissChannelInfo, limitRestrictedInfo, }: Props) => { @@ -46,11 +38,11 @@ const ChannelInfoStartButton = ({ } else if (isLimitRestricted) { showLimitRestrictedAlert(limitRestrictedInfo, intl); } else { - leaveAndJoinWithAlert(intl, serverUrl, channelId, currentCallChannelName, displayName, confirmToJoin, !isACallInCurrentChannel, channelIsDMorGM); + leaveAndJoinWithAlert(intl, serverUrl, channelId); } dismissChannelInfo(); - }, [isLimitRestricted, alreadyInCall, dismissChannelInfo, intl, serverUrl, channelId, currentCallChannelName, displayName, confirmToJoin, isACallInCurrentChannel]); + }, [isLimitRestricted, alreadyInCall, dismissChannelInfo, intl, serverUrl, channelId, isACallInCurrentChannel]); const [tryJoin, msgPostfix] = useTryCallsFunction(toggleJoinLeave); diff --git a/app/products/calls/components/channel_info_start/index.ts b/app/products/calls/components/channel_info_start/index.ts index cef55b4874..06bf3b22ce 100644 --- a/app/products/calls/components/channel_info_start/index.ts +++ b/app/products/calls/components/channel_info_start/index.ts @@ -3,15 +3,12 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; -import {combineLatest, of as of$} from 'rxjs'; +import {of as of$} from 'rxjs'; import {distinctUntilChanged, switchMap} from 'rxjs/operators'; import ChannelInfoStartButton from '@calls/components/channel_info_start/channel_info_start_button'; import {observeIsCallLimitRestricted} from '@calls/observers'; import {observeChannelsWithCalls, observeCurrentCall} from '@calls/state'; -import DatabaseManager from '@database/manager'; -import {observeChannel} from '@queries/servers/channel'; -import {isDMorGM} from '@utils/channel'; import type {WithDatabaseArgs} from '@typings/database/database'; @@ -21,43 +18,21 @@ type EnhanceProps = WithDatabaseArgs & { } const enhanced = withObservables([], ({serverUrl, channelId, database}: EnhanceProps) => { - const channel = observeChannel(database, channelId); - const displayName = channel.pipe( - switchMap((c) => of$(c?.displayName || '')), - distinctUntilChanged(), - ); - const channelIsDMorGM = channel.pipe( - switchMap((chan) => of$(chan ? isDMorGM(chan) : false)), - distinctUntilChanged(), - ); const isACallInCurrentChannel = observeChannelsWithCalls(serverUrl).pipe( switchMap((calls) => of$(Boolean(calls[channelId]))), distinctUntilChanged(), ); - const ccDatabase = observeCurrentCall().pipe( - switchMap((call) => of$(call?.serverUrl || '')), - distinctUntilChanged(), - switchMap((url) => of$(DatabaseManager.serverDatabases[url]?.database)), - ); const ccChannelId = observeCurrentCall().pipe( switchMap((call) => of$(call?.channelId)), distinctUntilChanged(), ); const confirmToJoin = ccChannelId.pipe(switchMap((ccId) => of$(ccId && ccId !== channelId))); const alreadyInCall = ccChannelId.pipe(switchMap((ccId) => of$(ccId && ccId === channelId))); - const currentCallChannelName = combineLatest([ccDatabase, ccChannelId]).pipe( - switchMap(([db, id]) => (db && id ? observeChannel(db, id) : of$(undefined))), - switchMap((c) => of$(c?.displayName || '')), - distinctUntilChanged(), - ); return { - displayName, - channelIsDMorGM, isACallInCurrentChannel, confirmToJoin, alreadyInCall, - currentCallChannelName, limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, channelId), }; }); diff --git a/app/products/calls/components/current_call_bar/current_call_bar.tsx b/app/products/calls/components/current_call_bar/current_call_bar.tsx index 171468c1dd..1cc2096745 100644 --- a/app/products/calls/components/current_call_bar/current_call_bar.tsx +++ b/app/products/calls/components/current_call_bar/current_call_bar.tsx @@ -4,7 +4,6 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; import {View, Text, TouchableOpacity, Pressable, Platform} from 'react-native'; -import {Options} from 'react-native-navigation'; import {muteMyself, unmuteMyself} from '@calls/actions'; import {recordingAlert, recordingWillBePostedAlert} from '@calls/alerts'; @@ -12,7 +11,6 @@ import CallAvatar from '@calls/components/call_avatar'; import PermissionErrorBar from '@calls/components/permission_error_bar'; import UnavailableIconWrapper from '@calls/components/unavailable_icon_wrapper'; import {usePermissionsChecker} from '@calls/hooks'; -import {CurrentCall} from '@calls/types/calls'; import CompassIcon from '@components/compass_icon'; import {Screens} from '@constants'; import {CURRENT_CALL_BAR_HEIGHT} from '@constants/view'; @@ -21,7 +19,9 @@ import {dismissAllModalsAndPopToScreen} from '@screens/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {displayUsername} from '@utils/user'; +import type {CurrentCall} from '@calls/types/calls'; import type UserModel from '@typings/database/models/servers/user'; +import type {Options} from 'react-native-navigation'; type Props = { displayName: string; diff --git a/app/products/calls/components/emoji_list.tsx b/app/products/calls/components/emoji_list.tsx index 7934abdbba..48bcef6f7f 100644 --- a/app/products/calls/components/emoji_list.tsx +++ b/app/products/calls/components/emoji_list.tsx @@ -6,7 +6,8 @@ import {StyleSheet, View} from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; import EmojiPill from '@calls/components/emoji_pill'; -import {ReactionStreamEmoji} from '@calls/types/calls'; + +import type {ReactionStreamEmoji} from '@calls/types/calls'; const styles = StyleSheet.create({ container: { diff --git a/app/products/calls/components/join_call_banner/index.ts b/app/products/calls/components/join_call_banner/index.ts index efaa0c32fb..5e4a2ebc1d 100644 --- a/app/products/calls/components/join_call_banner/index.ts +++ b/app/products/calls/components/join_call_banner/index.ts @@ -8,11 +8,9 @@ import {distinctUntilChanged, switchMap} from 'rxjs/operators'; import JoinCallBanner from '@calls/components/join_call_banner/join_call_banner'; import {observeIsCallLimitRestricted} from '@calls/observers'; -import {observeCallsState, observeCurrentCall} from '@calls/state'; +import {observeCallsState} from '@calls/state'; import {idsAreEqual} from '@calls/utils'; -import {observeChannel} from '@queries/servers/channel'; import {queryUsersById} from '@queries/servers/user'; -import {isDMorGM} from '@utils/channel'; import type {WithDatabaseArgs} from '@typings/database/database'; @@ -26,15 +24,6 @@ const enhanced = withObservables(['serverUrl', 'channelId'], ({ channelId, database, }: OwnProps & WithDatabaseArgs) => { - const channel = observeChannel(database, channelId); - const displayName = channel.pipe( - switchMap((c) => of$(c?.displayName)), - distinctUntilChanged(), - ); - const channelIsDMorGM = channel.pipe( - switchMap((chan) => of$(chan ? isDMorGM(chan) : false)), - distinctUntilChanged(), - ); const callsState = observeCallsState(serverUrl); const participants = callsState.pipe( switchMap((state) => of$(state.calls[channelId])), @@ -43,30 +32,13 @@ const enhanced = withObservables(['serverUrl', 'channelId'], ({ distinctUntilChanged((prev, curr) => idsAreEqual(prev, curr)), // Continue only if we have a different set of participant ids switchMap((ids) => (ids.length > 0 ? queryUsersById(database, ids).observeWithColumns(['last_picture_update']) : of$([]))), ); - const currentCallChannelId = observeCurrentCall().pipe( - switchMap((call) => of$(call?.channelId || undefined)), - distinctUntilChanged(), - ); - const inACall = currentCallChannelId.pipe( - switchMap((id) => of$(Boolean(id))), - distinctUntilChanged(), - ); - const currentCallChannelName = currentCallChannelId.pipe( - switchMap((id) => observeChannel(database, id || '')), - switchMap((c) => of$(c ? c.displayName : '')), - distinctUntilChanged(), - ); const channelCallStartTime = callsState.pipe( switchMap((cs) => of$(cs.calls[channelId]?.startTime || 0)), distinctUntilChanged(), ); return { - displayName, - channelIsDMorGM, participants, - inACall, - currentCallChannelName, channelCallStartTime, limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, channelId), }; diff --git a/app/products/calls/components/join_call_banner/join_call_banner.tsx b/app/products/calls/components/join_call_banner/join_call_banner.tsx index 2f35fc5964..77928e3012 100644 --- a/app/products/calls/components/join_call_banner/join_call_banner.tsx +++ b/app/products/calls/components/join_call_banner/join_call_banner.tsx @@ -21,11 +21,7 @@ import type UserModel from '@typings/database/models/servers/user'; type Props = { channelId: string; serverUrl: string; - displayName: string; - channelIsDMorGM: boolean; - inACall: boolean; participants: UserModel[]; - currentCallChannelName: string; channelCallStartTime: number; limitRestrictedInfo: LimitRestrictedInfo; } @@ -86,11 +82,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ const JoinCallBanner = ({ channelId, serverUrl, - displayName, - channelIsDMorGM, participants, - inACall, - currentCallChannelName, channelCallStartTime, limitRestrictedInfo, }: Props) => { @@ -104,7 +96,7 @@ const JoinCallBanner = ({ showLimitRestrictedAlert(limitRestrictedInfo, intl); return; } - leaveAndJoinWithAlert(intl, serverUrl, channelId, currentCallChannelName, displayName, inACall, false, channelIsDMorGM); + leaveAndJoinWithAlert(intl, serverUrl, channelId); }; return ( diff --git a/app/products/calls/connection/connection.ts b/app/products/calls/connection/connection.ts index e6bb5de328..cb72effbfb 100644 --- a/app/products/calls/connection/connection.ts +++ b/app/products/calls/connection/connection.ts @@ -12,6 +12,7 @@ import { mediaDevices, } from 'react-native-webrtc'; +import {setSpeakerPhone} from '@calls/state'; import {getICEServersConfigs} from '@calls/utils'; import {WebsocketEvents} from '@constants'; import {getServerCredentials} from '@init/credentials'; @@ -31,6 +32,7 @@ export async function newConnection( closeCb: () => void, setScreenShareURL: (url: string) => void, hasMicPermission: boolean, + title?: string, ) { let peer: Peer | null = null; let stream: MediaStream; @@ -203,8 +205,8 @@ export async function newConnection( } } - InCallManager.start({media: 'audio'}); - InCallManager.stopProximitySensor(); + InCallManager.start({media: 'video'}); + setSpeakerPhone(true); peer = new Peer(null, iceConfigs); peer.on('signal', (data: any) => { @@ -249,6 +251,7 @@ export async function newConnection( } else { ws.send('join', { channelID, + title, }); } }); diff --git a/app/products/calls/hooks.ts b/app/products/calls/hooks.ts index cc2b88f7fe..eba430542c 100644 --- a/app/products/calls/hooks.ts +++ b/app/products/calls/hooks.ts @@ -11,12 +11,13 @@ import Permissions from 'react-native-permissions'; import {initializeVoiceTrack} from '@calls/actions/calls'; import {setMicPermissionsGranted} from '@calls/state'; import {errorAlert} from '@calls/utils'; -import {Client} from '@client/rest'; -import ClientError from '@client/rest/error'; import {useServerUrl} from '@context/server'; import {useAppState} from '@hooks/device'; import NetworkManager from '@managers/network_manager'; +import type {Client} from '@client/rest'; +import type ClientError from '@client/rest/error'; + export const useTryCallsFunction = (fn: () => void) => { const intl = useIntl(); const serverUrl = useServerUrl(); diff --git a/app/products/calls/screens/call_screen/call_screen.tsx b/app/products/calls/screens/call_screen/call_screen.tsx index 95b1dbeb44..b1d0d47d60 100644 --- a/app/products/calls/screens/call_screen/call_screen.tsx +++ b/app/products/calls/screens/call_screen/call_screen.tsx @@ -31,7 +31,6 @@ import ReactionBar from '@calls/components/reaction_bar'; import UnavailableIconWrapper from '@calls/components/unavailable_icon_wrapper'; import {usePermissionsChecker} from '@calls/hooks'; import {useCallsConfig} from '@calls/state'; -import {CallParticipant, CurrentCall} from '@calls/types/calls'; import {sortParticipants} from '@calls/utils'; import CompassIcon from '@components/compass_icon'; import FormattedText from '@components/formatted_text'; @@ -40,6 +39,7 @@ import {Preferences, Screens, WebsocketEvents} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import DatabaseManager from '@database/manager'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import { bottomSheet, dismissAllModalsAndPopToScreen, @@ -53,8 +53,11 @@ import {mergeNavigationOptions} from '@utils/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {displayUsername} from '@utils/user'; +import type {CallParticipant, CurrentCall} from '@calls/types/calls'; +import type {AvailableScreens} from '@typings/screens/navigation'; + export type Props = { - componentId: string; + componentId: AvailableScreens; currentCall: CurrentCall | null; participantsDict: Dictionary; micPermissionsGranted: boolean; @@ -415,6 +418,10 @@ const CallScreen = ({ recordOptionTitle, stopRecording, stopRecordingOptionTitle, style, switchToThread, callThreadOptionTitle, openChannelOptionTitle]); + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + useEffect(() => { const listener = DeviceEventEmitter.addListener(WebsocketEvents.CALLS_CALL_END, ({channelId}) => { if (channelId === currentCall?.channelId && NavigationStore.getVisibleScreen() === componentId) { diff --git a/app/products/calls/screens/call_screen/index.ts b/app/products/calls/screens/call_screen/index.ts index aa59e70a43..89fc899d42 100644 --- a/app/products/calls/screens/call_screen/index.ts +++ b/app/products/calls/screens/call_screen/index.ts @@ -7,10 +7,10 @@ import {distinctUntilChanged, switchMap} from 'rxjs/operators'; import CallScreen from '@calls/screens/call_screen/call_screen'; import {observeCurrentCall, observeGlobalCallsState} from '@calls/state'; -import {CallParticipant} from '@calls/types/calls'; import DatabaseManager from '@database/manager'; import {observeTeammateNameDisplay, queryUsersById} from '@queries/servers/user'; +import type {CallParticipant} from '@calls/types/calls'; import type UserModel from '@typings/database/models/servers/user'; const enhanced = withObservables([], () => { diff --git a/app/products/calls/state/channels_with_calls.ts b/app/products/calls/state/channels_with_calls.ts index 150b8a4124..f16a16dea8 100644 --- a/app/products/calls/state/channels_with_calls.ts +++ b/app/products/calls/state/channels_with_calls.ts @@ -4,7 +4,7 @@ import {useEffect, useState} from 'react'; import {BehaviorSubject} from 'rxjs'; -import {ChannelsWithCalls} from '@calls/types/calls'; +import type {ChannelsWithCalls} from '@calls/types/calls'; const channelsWithCallsSubject: Dictionary> = {}; diff --git a/app/products/calls/state/current_call.ts b/app/products/calls/state/current_call.ts index b394bfa44c..a3eec20159 100644 --- a/app/products/calls/state/current_call.ts +++ b/app/products/calls/state/current_call.ts @@ -4,7 +4,7 @@ import {useEffect, useState} from 'react'; import {BehaviorSubject} from 'rxjs'; -import {CurrentCall} from '@calls/types/calls'; +import type {CurrentCall} from '@calls/types/calls'; const currentCallSubject = new BehaviorSubject(null); diff --git a/app/products/calls/utils.test.ts b/app/products/calls/utils.test.ts index 69046c25e3..634137a619 100644 --- a/app/products/calls/utils.test.ts +++ b/app/products/calls/utils.test.ts @@ -3,11 +3,12 @@ import assert from 'assert'; -import {CallsConfig} from '@calls/types/calls'; import {License} from '@constants'; import {getICEServersConfigs} from './utils'; +import type {CallsConfig} from '@calls/types/calls'; + describe('getICEServersConfigs', () => { it('backwards compatible case, no ICEServersConfigs present', () => { const config: CallsConfig = { diff --git a/app/products/calls/utils.ts b/app/products/calls/utils.ts index 2f94eefd79..dbe808cc60 100644 --- a/app/products/calls/utils.ts +++ b/app/products/calls/utils.ts @@ -70,7 +70,7 @@ export function isSupportedServerCalls(serverVersion?: string) { } export function isCallsCustomMessage(post: PostModel | Post): boolean { - return Boolean(post.type && post.type?.startsWith(Post.POST_TYPES.CUSTOM_CALLS)); + return Boolean(post.type && post.type === Post.POST_TYPES.CUSTOM_CALLS); } export function idsAreEqual(a: string[], b: string[]) { diff --git a/app/queries/servers/channel.ts b/app/queries/servers/channel.ts index 12e332dc68..e27eaf98df 100644 --- a/app/queries/servers/channel.ts +++ b/app/queries/servers/channel.ts @@ -374,7 +374,7 @@ export const queryTeamDefaultChannel = (database: Database, teamId: string) => { }; export const queryMyChannelsByTeam = (database: Database, teamId: string, includeDeleted = false) => { - const conditions: Q.Condition[] = [Q.where('team_id', Q.eq(teamId))]; + const conditions: Q.Where[] = [Q.where('team_id', Q.eq(teamId))]; if (!includeDeleted) { conditions.push(Q.where('delete_at', Q.eq(0))); } @@ -453,7 +453,7 @@ export const queryEmptyDirectAndGroupChannels = (database: Database) => { }; export function observeMyChannelMentionCount(database: Database, teamId?: string, columns = ['mentions_count', 'is_unread']): Observable { - const conditions: Q.Condition[] = [ + const conditions: Q.Where[] = [ Q.where('delete_at', Q.eq(0)), ]; @@ -616,7 +616,7 @@ export const queryChannelsForAutocomplete = (database: Database, matchTerm: stri Q.experimentalNestedJoin(CHANNEL_MEMBERSHIP, USER), ); } - const orConditions: Q.Condition[] = [ + const orConditions: Q.Where[] = [ Q.where('display_name', Q.like(matchTerm)), Q.where('name', Q.like(likeTerm)), ]; @@ -644,7 +644,7 @@ export const queryChannelsForAutocomplete = (database: Database, matchTerm: stri teamsToSearch.push(''); } - const andConditions: Q.Condition[] = [ + const andConditions: Q.Where[] = [ Q.where('team_id', Q.oneOf(teamsToSearch)), ]; if (!isSearch) { diff --git a/app/queries/servers/entry.ts b/app/queries/servers/entry.ts index c2774517f3..bafed89422 100644 --- a/app/queries/servers/entry.ts +++ b/app/queries/servers/entry.ts @@ -3,7 +3,6 @@ import {MM_TABLES} from '@constants/database'; import DatabaseManager from '@database/manager'; -import ServerDataOperator from '@database/operator/server_data_operator'; import {prepareCategoriesAndCategoriesChannels} from './categories'; import {prepareDeleteChannel, prepareMyChannelsForTeam} from './channel'; @@ -16,6 +15,7 @@ import type {MyChannelsRequest} from '@actions/remote/channel'; import type {MyPreferencesRequest} from '@actions/remote/preference'; import type {MyTeamsRequest} from '@actions/remote/team'; import type {MyUserRequest} from '@actions/remote/user'; +import type ServerDataOperator from '@database/operator/server_data_operator'; import type {Model} from '@nozbe/watermelondb'; import type ChannelModel from '@typings/database/models/servers/channel'; import type TeamModel from '@typings/database/models/servers/team'; diff --git a/app/queries/servers/post.ts b/app/queries/servers/post.ts index 20732b44bc..8e04c6fec0 100644 --- a/app/queries/servers/post.ts +++ b/app/queries/servers/post.ts @@ -20,24 +20,17 @@ const {SERVER: {POST, POSTS_IN_CHANNEL, POSTS_IN_THREAD, PREFERENCE}} = MM_TABLE export const prepareDeletePost = async (post: PostModel): Promise => { const preparedModels: Model[] = [post.prepareDestroyPermanently()]; - const relations: Array> = [post.drafts, post.postsInThread]; - for await (const relation of relations) { + const relations: Array> = [post.drafts, post.postsInThread, post.files, post.reactions]; + for await (const models of relations) { try { - const model = await relation.fetch(); - if (model) { - model.forEach((m) => preparedModels.push(m.prepareDestroyPermanently())); - } + models.forEach((m) => { + preparedModels.push(m.prepareDestroyPermanently()); + }); } catch { // Record not found, do nothing } } - const associatedChildren: Array|undefined> = [post.files, post.reactions]; - await Promise.all(associatedChildren.map(async (children) => { - const models = await children?.fetch(); - models?.forEach((model) => preparedModels.push(model.prepareDestroyPermanently())); - })); - // If thread exists, delete thread, participants and threadsInTeam try { const thread = await post.thread.fetch(); @@ -141,7 +134,7 @@ export const getLastPostInThread = async (database: Database, rootId: string) => }; export const queryPostsChunk = (database: Database, id: string, earliest: number, latest: number, inThread = false, includeDeleted = false, limit = 0) => { - const conditions: Q.Condition[] = [Q.where('create_at', Q.between(earliest, latest))]; + const conditions: Q.Where[] = [Q.where('create_at', Q.between(earliest, latest))]; if (inThread) { conditions.push(Q.where('root_id', id)); } else { diff --git a/app/queries/servers/system.ts b/app/queries/servers/system.ts index 5306d7e1f2..194fe48b2e 100644 --- a/app/queries/servers/system.ts +++ b/app/queries/servers/system.ts @@ -158,6 +158,50 @@ export const getConfigValue = async (database: Database, key: keyof ClientConfig return list.length ? list[0].value : undefined; }; +export const getLastGlobalDataRetentionRun = async (database: Database) => { + try { + const data = await database.get(SYSTEM).find(SYSTEM_IDENTIFIERS.LAST_DATA_RETENTION_RUN); + return data?.value || 0; + } catch { + return undefined; + } +}; + +export const getGlobalDataRetentionPolicy = async (database: Database) => { + try { + const data = await database.get(SYSTEM).find(SYSTEM_IDENTIFIERS.DATA_RETENTION_POLICIES); + return (data?.value || {}) as GlobalDataRetentionPolicy; + } catch { + return undefined; + } +}; + +export const getGranularDataRetentionPolicies = async (database: Database) => { + try { + const data = await database.get(SYSTEM).find(SYSTEM_IDENTIFIERS.GRANULAR_DATA_RETENTION_POLICIES); + return (data?.value || { + team: [], + channel: [], + }) as { + team: TeamDataRetentionPolicy[]; + channel: ChannelDataRetentionPolicy[]; + }; + } catch { + return undefined; + } +}; + +export const getIsDataRetentionEnabled = async (database: Database) => { + const license = await getLicense(database); + if (!license || !Object.keys(license)?.length) { + return null; + } + + const dataRetentionEnableMessageDeletion = await getConfigValue(database, 'DataRetentionEnableMessageDeletion'); + + return dataRetentionEnableMessageDeletion === 'true' && license?.IsLicensed === 'true' && license?.DataRetention === 'true'; +}; + export const observeConfig = (database: Database): Observable => { return database.get(CONFIG).query().observeWithColumns(['value']).pipe( switchMap((result) => of$(fromModelToClientConfig(result))), diff --git a/app/queries/servers/terms_of_service.ts b/app/queries/servers/terms_of_service.ts index 820ad88a5e..3b0de3f199 100644 --- a/app/queries/servers/terms_of_service.ts +++ b/app/queries/servers/terms_of_service.ts @@ -1,13 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database} from '@nozbe/watermelondb'; import {of as of$, combineLatest} from 'rxjs'; import {switchMap, distinctUntilChanged} from 'rxjs/operators'; import {observeLicense, observeConfigBooleanValue, observeConfigValue, observeConfigIntValue} from './system'; import {observeCurrentUser} from './user'; +import type {Database} from '@nozbe/watermelondb'; + export const observeShowToS = (database: Database) => { const isLicensed = observeLicense(database).pipe( switchMap((lcs) => (lcs ? of$(lcs.IsLicensed === 'true') : of$(false))), diff --git a/app/queries/servers/thread.ts b/app/queries/servers/thread.ts index 4a200ad8ef..b449e544ff 100644 --- a/app/queries/servers/thread.ts +++ b/app/queries/servers/thread.ts @@ -193,7 +193,7 @@ export const queryThreads = (database: Database, teamId?: string, onlyUnreads = ]; // Only get threads from available channel - const channelCondition: Q.Condition[] = [ + const channelCondition: Q.Where[] = [ Q.where('delete_at', 0), ]; diff --git a/app/screens/apps_form/apps_form_component.tsx b/app/screens/apps_form/apps_form_component.tsx index 0ce62822fb..b94ddf8aff 100644 --- a/app/screens/apps_form/apps_form_component.tsx +++ b/app/screens/apps_form/apps_form_component.tsx @@ -5,7 +5,6 @@ import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} fr import {useIntl} from 'react-intl'; import {Keyboard, ScrollView, Text, View} from 'react-native'; import Button from 'react-native-button'; -import {ImageResource} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; import {handleGotoLocation} from '@actions/remote/command'; @@ -27,6 +26,9 @@ import {buildNavigationButton, dismissModal, setButtons} from '../navigation'; import AppsFormField from './apps_form_field'; +import type {AvailableScreens} from '@typings/screens/navigation'; +import type {ImageResource} from 'react-native-navigation'; + const getStyleFromTheme = makeStyleSheetFromTheme((theme: Theme) => { return { container: { @@ -76,7 +78,7 @@ const makeCloseButton = (icon: ImageResource) => { export type Props = { form: AppForm; - componentId: string; + componentId: AvailableScreens; refreshOnSelect: (field: AppField, values: AppFormValues, value: AppFormValue) => Promise>; submit: (values: AppFormValues) => Promise>; performLookupCall: (field: AppField, values: AppFormValues, value: AppFormValue) => Promise>; diff --git a/app/screens/apps_form/index.tsx b/app/screens/apps_form/index.tsx index e890f3ec22..e9fd225fde 100644 --- a/app/screens/apps_form/index.tsx +++ b/app/screens/apps_form/index.tsx @@ -3,19 +3,24 @@ import React, {useCallback, useState} from 'react'; import {useIntl} from 'react-intl'; +import {Keyboard} from 'react-native'; import {doAppFetchForm, doAppLookup, doAppSubmit, postEphemeralCallResponseForContext} from '@actions/remote/apps'; import {handleGotoLocation} from '@actions/remote/command'; import {AppCallResponseTypes} from '@constants/apps'; import {useServerUrl} from '@context/server'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import {dismissModal} from '@screens/navigation'; import {createCallRequest, makeCallErrorResponse} from '@utils/apps'; import AppsFormComponent from './apps_form_component'; +import type {AvailableScreens} from '@typings/screens/navigation'; + export type Props = { form?: AppForm; context?: AppContext; - componentId: string; + componentId: AvailableScreens; }; function AppsFormContainer({ @@ -189,6 +194,13 @@ function AppsFormContainer({ return doAppLookup(serverUrl, creq, intl); }, [context, serverUrl, intl]); + const close = useCallback(() => { + Keyboard.dismiss(); + dismissModal({componentId}); + }, [componentId]); + + useAndroidHardwareBackHandler(componentId, close); + if (!currentForm?.submit || !context) { return null; } diff --git a/app/screens/bottom_sheet/index.tsx b/app/screens/bottom_sheet/index.tsx index 1a64f68309..7a3a5772c8 100644 --- a/app/screens/bottom_sheet/index.tsx +++ b/app/screens/bottom_sheet/index.tsx @@ -16,6 +16,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import Indicator from './indicator'; +import type {AvailableScreens} from '@typings/screens/navigation'; import type {WithSpringConfig} from 'react-native-reanimated'; export {default as BottomSheetButton, BUTTON_HEIGHT} from './button'; @@ -23,7 +24,7 @@ export {default as BottomSheetContent, TITLE_HEIGHT} from './content'; type Props = { closeButtonId?: string; - componentId: string; + componentId: AvailableScreens; contentStyle?: StyleProp; initialSnapIndex?: number; footerComponent?: React.FC; @@ -38,6 +39,7 @@ const PADDING_TOP_TABLET = 8; export const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { return { bottomSheet: { + backgroundColor: theme.centerChannelBg, borderTopStartRadius: 24, borderTopEndRadius: 24, shadowOffset: { @@ -94,6 +96,10 @@ const BottomSheet = ({ const styles = getStyleSheet(theme); const interaction = useRef(); + useEffect(() => { + interaction.current = InteractionManager.createInteractionHandle(); + }, []); + const bottomSheetBackgroundStyle = useMemo(() => [ styles.bottomSheetBackground, {borderWidth: isTablet ? 0 : 1}, @@ -116,7 +122,9 @@ const BottomSheet = ({ }, [close]); const handleAnimationStart = useCallback(() => { - interaction.current = InteractionManager.createInteractionHandle(); + if (!interaction.current) { + interaction.current = InteractionManager.createInteractionHandle(); + } }, []); const handleClose = useCallback(() => { diff --git a/app/screens/browse_channels/browse_channels.tsx b/app/screens/browse_channels/browse_channels.tsx index f70e4a0072..0b3445cd08 100644 --- a/app/screens/browse_channels/browse_channels.tsx +++ b/app/screens/browse_channels/browse_channels.tsx @@ -4,7 +4,6 @@ import React, {useCallback, useEffect, useState} from 'react'; import {IntlShape, useIntl} from 'react-intl'; import {Keyboard, Platform, StyleSheet, View} from 'react-native'; -import {ImageResource, OptionsTopBarButton} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; import {joinChannel, switchToChannelById} from '@actions/remote/channel'; @@ -13,6 +12,7 @@ import Search from '@components/search'; import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal, goToScreen, setButtons} from '@screens/navigation'; import {alertErrorWithFallback} from '@utils/draft'; @@ -21,7 +21,8 @@ import {changeOpacity, getKeyboardAppearanceFromTheme} from '@utils/theme'; import ChannelDropdown from './channel_dropdown'; import ChannelList from './channel_list'; -import type {NavButtons} from '@typings/screens/navigation'; +import type {AvailableScreens, NavButtons} from '@typings/screens/navigation'; +import type {ImageResource, OptionsTopBarButton} from 'react-native-navigation'; const CLOSE_BUTTON_ID = 'close-browse-channels'; const CREATE_BUTTON_ID = 'create-pub-channel'; @@ -73,7 +74,7 @@ const style = StyleSheet.create({ type Props = { // Screen Props (do not change during the lifetime of the screen) - componentId: string; + componentId: AvailableScreens; closeButton: ImageResource; // Properties not changing during the lifetime of the screen) @@ -169,6 +170,7 @@ export default function BrowseChannels(props: Props) { useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, [close]); useNavButtonPressed(CREATE_BUTTON_ID, componentId, handleCreate, [handleCreate]); + useAndroidHardwareBackHandler(componentId, close); useEffect(() => { // Update header buttons in case anything related to the header changes diff --git a/app/screens/browse_channels/search_handler.tsx b/app/screens/browse_channels/search_handler.tsx index f50eb95fba..2e59bb66fd 100644 --- a/app/screens/browse_channels/search_handler.tsx +++ b/app/screens/browse_channels/search_handler.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React, {useCallback, useEffect, useReducer, useRef, useState} from 'react'; -import {ImageResource} from 'react-native-navigation'; import {fetchArchivedChannels, fetchChannels, fetchSharedChannels, searchChannels} from '@actions/remote/channel'; import {General} from '@constants'; @@ -12,11 +11,13 @@ import useDidUpdate from '@hooks/did_update'; import BrowseChannels, {ARCHIVED, PUBLIC, SHARED} from './browse_channels'; import type MyChannelModel from '@typings/database/models/servers/my_channel'; +import type {AvailableScreens} from '@typings/screens/navigation'; +import type {ImageResource} from 'react-native-navigation'; type Props = { // Screen Props (do not change during the lifetime of the screen) - componentId: string; + componentId: AvailableScreens; categoryId?: string; closeButton: ImageResource; diff --git a/app/screens/channel/channel.tsx b/app/screens/channel/channel.tsx index bb26e3181c..2a22fcf9f4 100644 --- a/app/screens/channel/channel.tsx +++ b/app/screens/channel/channel.tsx @@ -2,8 +2,7 @@ // See LICENSE.txt for license information. import React, {useCallback, useEffect, useRef, useState} from 'react'; -import {BackHandler, LayoutChangeEvent, NativeEventSubscription, StyleSheet, View} from 'react-native'; -import {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; +import {LayoutChangeEvent, StyleSheet, View} from 'react-native'; import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; import CurrentCallBar from '@calls/components/current_call_bar'; @@ -13,6 +12,7 @@ import FreezeScreen from '@components/freeze_screen'; import PostDraft from '@components/post_draft'; import {Screens} from '@constants'; import {ACCESSORIES_CONTAINER_NATIVE_ID} from '@constants/post_draft'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useChannelSwitch} from '@hooks/channel_switch'; import {useAppState, useIsTablet} from '@hooks/device'; import {useDefaultHeaderHeight} from '@hooks/header'; @@ -20,15 +20,17 @@ import {useKeyboardTrackingPaused} from '@hooks/keyboard_tracking'; import {useTeamSwitch} from '@hooks/team_switch'; import {popTopScreen} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; -import NavigationStore from '@store/navigation_store'; import ChannelPostList from './channel_post_list'; import ChannelHeader from './header'; +import type {AvailableScreens} from '@typings/screens/navigation'; +import type {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; + type ChannelProps = { serverUrl: string; channelId: string; - componentId?: string; + componentId?: AvailableScreens; isCallInCurrentChannel: boolean; isInACall: boolean; isInCurrentChannelCall: boolean; @@ -63,24 +65,12 @@ const Channel = ({ const postDraftRef = useRef(null); const [containerHeight, setContainerHeight] = useState(0); const shouldRender = !switchingTeam && !switchingChannels && shouldRenderPosts && Boolean(channelId); + const handleBack = () => { + popTopScreen(componentId); + }; useKeyboardTrackingPaused(postDraftRef, channelId, trackKeyboardForScreens); - - useEffect(() => { - let back: NativeEventSubscription|undefined; - if (!isTablet && componentId) { - back = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getVisibleScreen() === componentId) { - popTopScreen(componentId); - return true; - } - - return false; - }); - } - - return () => back?.remove(); - }, [componentId, isTablet]); + useAndroidHardwareBackHandler(componentId, handleBack); const marginTop = defaultHeight + (isTablet ? 0 : -insets.top); useEffect(() => { diff --git a/app/screens/channel/channel_post_list/index.ts b/app/screens/channel/channel_post_list/index.ts index c46ceb12e2..39e60924ca 100644 --- a/app/screens/channel/channel_post_list/index.ts +++ b/app/screens/channel/channel_post_list/index.ts @@ -5,7 +5,6 @@ import {Q} from '@nozbe/watermelondb'; import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; import React from 'react'; -import {AppStateStatus} from 'react-native'; import {combineLatest, of as of$} from 'rxjs'; import {switchMap, distinctUntilChanged} from 'rxjs/operators'; @@ -19,6 +18,7 @@ import {observeIsCRTEnabled} from '@queries/servers/thread'; import ChannelPostList from './channel_post_list'; import type {WithDatabaseArgs} from '@typings/database/database'; +import type {AppStateStatus} from 'react-native'; const enhanced = withObservables(['channelId', 'forceQueryAfterAppState'], ({database, channelId}: {channelId: string; forceQueryAfterAppState: AppStateStatus} & WithDatabaseArgs) => { const isCRTEnabledObserver = observeIsCRTEnabled(database); diff --git a/app/screens/channel/header/header.tsx b/app/screens/channel/header/header.tsx index d01e81232c..e98dc06e87 100644 --- a/app/screens/channel/header/header.tsx +++ b/app/screens/channel/header/header.tsx @@ -27,6 +27,7 @@ import OtherMentionsBadge from './other_mentions_badge'; import QuickActions, {MARGIN, SEPARATOR_HEIGHT} from './quick_actions'; import type {HeaderRightButton} from '@components/navigation_header/header'; +import type {AvailableScreens} from '@typings/screens/navigation'; type ChannelProps = { channelId: string; @@ -34,7 +35,7 @@ type ChannelProps = { customStatus?: UserCustomStatus; isCustomStatusEnabled: boolean; isCustomStatusExpired: boolean; - componentId?: string; + componentId?: AvailableScreens; displayName: string; isOwnDirectMessage: boolean; memberCount?: number; @@ -97,7 +98,7 @@ const ChannelHeader = ({ const onBackPress = useCallback(() => { Keyboard.dismiss(); popTopScreen(componentId); - }, []); + }, [componentId]); const onTitlePress = useCallback(preventDoubleTap(() => { let title; diff --git a/app/screens/channel_info/app_bindings/index.tsx b/app/screens/channel_info/app_bindings/index.tsx index e9dcffb976..b73e8e2465 100644 --- a/app/screens/channel_info/app_bindings/index.tsx +++ b/app/screens/channel_info/app_bindings/index.tsx @@ -11,9 +11,10 @@ import {AppBindingLocations} from '@constants/apps'; import {useAppBinding} from '@hooks/apps'; import AppsManager from '@managers/apps_manager'; import {observeCurrentTeamId} from '@queries/servers/system'; -import {WithDatabaseArgs} from '@typings/database/database'; import {preventDoubleTap} from '@utils/tap'; +import type {WithDatabaseArgs} from '@typings/database/database'; + type Props = { channelId: string; teamId: string; diff --git a/app/screens/channel_info/channel_info.tsx b/app/screens/channel_info/channel_info.tsx index cb9c660d6c..a18c536d64 100644 --- a/app/screens/channel_info/channel_info.tsx +++ b/app/screens/channel_info/channel_info.tsx @@ -9,6 +9,7 @@ import ChannelInfoEnableCalls from '@calls/components/channel_info_enable_calls' import ChannelActions from '@components/channel_actions'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -19,10 +20,12 @@ import Extra from './extra'; import Options from './options'; import Title from './title'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { channelId: string; closeButtonId: string; - componentId: string; + componentId: AvailableScreens; type?: ChannelType; canEnableDisableCalls: boolean; isCallsEnabledInChannel: boolean; @@ -66,6 +69,7 @@ const ChannelInfo = ({ }, [componentId]); useNavButtonPressed(closeButtonId, componentId, onPressed, []); + useAndroidHardwareBackHandler(componentId, onPressed); return ( { +const Code = ({code, componentId, language, textStyle}: Props) => { const managedConfig = useManagedConfig(); + useAndroidHardwareBackHandler(componentId, popTopScreen); return ( { mounted.current = true; diff --git a/app/screens/create_or_edit_channel/create_or_edit_channel.tsx b/app/screens/create_or_edit_channel/create_or_edit_channel.tsx index f3d7dd5aaa..bfc4657353 100644 --- a/app/screens/create_or_edit_channel/create_or_edit_channel.tsx +++ b/app/screens/create_or_edit_channel/create_or_edit_channel.tsx @@ -4,7 +4,6 @@ import React, {useCallback, useEffect, useMemo, useReducer, useState} from 'react'; import {useIntl} from 'react-intl'; import {Keyboard} from 'react-native'; -import {ImageResource} from 'react-native-navigation'; import {createChannel, patchChannel as handlePatchChannel, switchToChannelById} from '@actions/remote/channel'; import CompassIcon from '@components/compass_icon'; @@ -12,6 +11,7 @@ import {General} from '@constants'; import {MIN_CHANNEL_NAME_LENGTH} from '@constants/channel'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {buildNavigationButton, dismissModal, popTopScreen, setButtons} from '@screens/navigation'; import {validateDisplayName} from '@utils/channel'; @@ -20,9 +20,11 @@ import ChannelInfoForm from './channel_info_form'; import type ChannelModel from '@typings/database/models/servers/channel'; import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; +import type {AvailableScreens} from '@typings/screens/navigation'; +import type {ImageResource} from 'react-native-navigation'; type Props = { - componentId: string; + componentId: AvailableScreens; channel?: ChannelModel; channelInfo?: ChannelInfoModel; headerOnly?: boolean; @@ -49,7 +51,7 @@ interface RequestAction { error?: string; } -const close = (componentId: string, isModal: boolean): void => { +const close = (componentId: AvailableScreens, isModal: boolean): void => { Keyboard.dismiss(); if (isModal) { dismissModal({componentId}); @@ -228,6 +230,7 @@ const CreateOrEditChannel = ({ useNavButtonPressed(CLOSE_BUTTON_ID, componentId, handleClose, [handleClose]); useNavButtonPressed(CREATE_BUTTON_ID, componentId, onCreateChannel, [onCreateChannel]); useNavButtonPressed(EDIT_BUTTON_ID, componentId, onUpdateChannel, [onUpdateChannel]); + useAndroidHardwareBackHandler(componentId, handleClose); return ( void; diff --git a/app/screens/custom_status/custom_status.tsx b/app/screens/custom_status/custom_status.tsx index 367f587c2c..fc1d6d86cd 100644 --- a/app/screens/custom_status/custom_status.tsx +++ b/app/screens/custom_status/custom_status.tsx @@ -35,6 +35,7 @@ import CustomStatusSuggestions from './components/custom_status_suggestions'; import RecentCustomStatuses from './components/recent_custom_statuses'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; type NewStatusType = { emoji?: string; @@ -47,7 +48,7 @@ type Props = { customStatusExpirySupported: boolean; currentUser: UserModel; recentCustomStatuses: UserCustomStatus[]; - componentId: string; + componentId: AvailableScreens; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { diff --git a/app/screens/custom_status_clear_after/index.tsx b/app/screens/custom_status_clear_after/index.tsx index 76aaa8aab0..e82be68e75 100644 --- a/app/screens/custom_status_clear_after/index.tsx +++ b/app/screens/custom_status_clear_after/index.tsx @@ -11,7 +11,6 @@ import { Navigation, NavigationButtonPressedEvent, NavigationComponent, - NavigationComponentProps, Options, } from 'react-native-navigation'; @@ -26,8 +25,10 @@ import ClearAfterMenuItem from './components/clear_after_menu_item'; import type {WithDatabaseArgs} from '@typings/database/database'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; -interface Props extends NavigationComponentProps { +interface Props { + componentId: AvailableScreens; currentUser: UserModel; handleClearAfterClick: (duration: CustomStatusDuration, expiresAt: string) => void; initialDuration: CustomStatusDuration; diff --git a/app/screens/edit_post/edit_post.tsx b/app/screens/edit_post/edit_post.tsx index 9aa8abe602..a565be0851 100644 --- a/app/screens/edit_post/edit_post.tsx +++ b/app/screens/edit_post/edit_post.tsx @@ -3,7 +3,7 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {Alert, Keyboard, KeyboardType, LayoutChangeEvent, Platform, SafeAreaView, useWindowDimensions, View} from 'react-native'; +import {Alert, Keyboard, LayoutChangeEvent, Platform, SafeAreaView, useWindowDimensions, View} from 'react-native'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import {deletePost, editPost} from '@actions/remote/post'; @@ -11,18 +11,19 @@ import Autocomplete from '@components/autocomplete'; import Loading from '@components/loading'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useAutocompleteDefaultAnimatedValues} from '@hooks/autocomplete'; import {useIsTablet, useKeyboardHeight, useModalPosition} from '@hooks/device'; import useDidUpdate from '@hooks/did_update'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import PostError from '@screens/edit_post/post_error'; import {buildNavigationButton, dismissModal, setButtons} from '@screens/navigation'; -import {switchKeyboardForCodeBlocks} from '@utils/markdown'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import EditPostInput, {EditPostInputRef} from './edit_post_input'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; const AUTOCOMPLETE_SEPARATION = 8; @@ -46,7 +47,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { const RIGHT_BUTTON = buildNavigationButton('edit-post', 'edit_post.save.button'); type EditPostProps = { - componentId: string; + componentId: AvailableScreens; closeButtonId: string; post: PostModel; maxPostSize: number; @@ -54,7 +55,6 @@ type EditPostProps = { canDelete: boolean; } const EditPost = ({componentId, maxPostSize, post, closeButtonId, hasFilesAttached, canDelete}: EditPostProps) => { - const [keyboardType, setKeyboardType] = useState('default'); const [postMessage, setPostMessage] = useState(post.message); const [cursorPosition, setCursorPosition] = useState(post.message.length); const [errorLine, setErrorLine] = useState(); @@ -109,9 +109,6 @@ const EditPost = ({componentId, maxPostSize, post, closeButtonId, hasFilesAttach }, []); const onTextSelectionChange = useCallback((curPos: number = cursorPosition) => { - if (Platform.OS === 'ios') { - setKeyboardType(switchKeyboardForCodeBlocks(postMessage, curPos)); - } setCursorPosition(curPos); }, [cursorPosition, postMessage]); @@ -197,13 +194,13 @@ const EditPost = ({componentId, maxPostSize, post, closeButtonId, hasFilesAttach useNavButtonPressed(RIGHT_BUTTON.id, componentId, onSavePostMessage, [postMessage]); useNavButtonPressed(closeButtonId, componentId, onClose, []); + useAndroidHardwareBackHandler(componentId, onClose); const bottomSpace = (dimensions.height - containerHeight - modalPosition); const autocompletePosition = Platform.select({ - ios: isTablet ? - Math.max(0, keyboardHeight - bottomSpace) : - keyboardHeight || insets.bottom, - default: 0}) + AUTOCOMPLETE_SEPARATION; + ios: isTablet ? Math.max(0, keyboardHeight - bottomSpace) : keyboardHeight || insets.bottom, + default: 0, + }) + AUTOCOMPLETE_SEPARATION; const autocompleteAvailableSpace = containerHeight - autocompletePosition; const [animatedAutocompletePosition, animatedAutocompleteAvailableSpace] = useAutocompleteDefaultAnimatedValues(autocompletePosition, autocompleteAvailableSpace); @@ -235,7 +232,6 @@ const EditPost = ({componentId, maxPostSize, post, closeButtonId, hasFilesAttach } void; @@ -37,15 +39,17 @@ type PostInputProps = { } const EditPostInput = forwardRef(({ - keyboardType, message, onChangeText, onTextSelectionChange, hasError, + message, onChangeText, onTextSelectionChange, hasError, }: PostInputProps, ref) => { const intl = useIntl(); const theme = useTheme(); const styles = getStyleSheet(theme); const {height} = useWindowDimensions(); + const managedConfig = useManagedConfig(); const textInputHeight = (height / 2) - HEIGHT_DIFF; + const disableCopyAndPaste = managedConfig.copyAndPasteProtection === 'true'; - const inputRef = useRef(null); + const inputRef = useRef(); const inputStyle = useMemo(() => { return [styles.input, {height: textInputHeight}]; @@ -68,17 +72,20 @@ const EditPostInput = forwardRef(({ return ( - = { gitlab: 'GitLab', google: 'Google Apps', diff --git a/app/screens/edit_profile/components/form.tsx b/app/screens/edit_profile/components/form.tsx index 1a87accb3d..0dec755a31 100644 --- a/app/screens/edit_profile/components/form.tsx +++ b/app/screens/edit_profile/components/form.tsx @@ -5,7 +5,6 @@ import React, {useCallback, useMemo, useRef} from 'react'; import {MessageDescriptor, useIntl} from 'react-intl'; import {Keyboard, StyleSheet, View} from 'react-native'; -import {FloatingTextInputRef} from '@components/floating_text_input_label'; import {useTheme} from '@context/theme'; import {t} from '@i18n'; @@ -13,6 +12,7 @@ import DisabledFields from './disabled_fields'; import EmailField from './email_field'; import Field from './field'; +import type {FloatingTextInputRef} from '@components/floating_text_input_label'; import type UserModel from '@typings/database/models/servers/user'; import type {FieldConfig, FieldSequence, UserInfo} from '@typings/screens/edit_profile'; diff --git a/app/screens/edit_profile/components/profile_image_picker.tsx b/app/screens/edit_profile/components/profile_image_picker.tsx index 7aead7a2e7..815e116d4b 100644 --- a/app/screens/edit_profile/components/profile_image_picker.tsx +++ b/app/screens/edit_profile/components/profile_image_picker.tsx @@ -6,7 +6,6 @@ import {useIntl} from 'react-intl'; import {TouchableOpacity} from 'react-native'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; -import {Client} from '@client/rest'; import CompassIcon from '@components/compass_icon'; import FormattedText from '@components/formatted_text'; import {ITEM_HEIGHT} from '@components/slide_up_panel_item'; @@ -23,6 +22,7 @@ import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {Client} from '@client/rest'; import type UserModel from '@typings/database/models/servers/user'; const hitSlop = {top: 100, bottom: 20, right: 20, left: 100}; diff --git a/app/screens/edit_server/form.tsx b/app/screens/edit_server/form.tsx index 8c29b38cad..1bdc58e210 100644 --- a/app/screens/edit_server/form.tsx +++ b/app/screens/edit_server/form.tsx @@ -5,7 +5,6 @@ import React, {MutableRefObject, useCallback, useEffect, useRef} from 'react'; import {useIntl} from 'react-intl'; import {Keyboard, Platform, useWindowDimensions, View} from 'react-native'; import Button from 'react-native-button'; -import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import FloatingTextInput, {FloatingTextInputRef} from '@components/floating_text_input_label'; import FormattedText from '@components/formatted_text'; @@ -17,6 +16,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; import {removeProtocol, stripTrailingSlashes} from '@utils/url'; +import type {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; + type Props = { buttonDisabled: boolean; connecting: boolean; diff --git a/app/screens/edit_server/index.tsx b/app/screens/edit_server/index.tsx index aec4167a4f..7331823cf0 100644 --- a/app/screens/edit_server/index.tsx +++ b/app/screens/edit_server/index.tsx @@ -5,10 +5,11 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; import {Platform, View} from 'react-native'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; -import {Navigation} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; import DatabaseManager from '@database/manager'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {getServerByDisplayName} from '@queries/app/servers'; import Background from '@screens/background'; import {dismissModal} from '@screens/navigation'; @@ -18,10 +19,11 @@ import Form from './form'; import Header from './header'; import type ServersModel from '@typings/database/models/app/servers'; +import type {AvailableScreens} from '@typings/screens/navigation'; interface ServerProps { closeButtonId?: string; - componentId: string; + componentId: AvailableScreens; server: ServersModel; theme: Theme; } @@ -49,20 +51,14 @@ const EditServer = ({closeButtonId, componentId, server, theme}: ServerProps) => const [displayNameError, setDisplayNameError] = useState(); const styles = getStyleSheet(theme); + const close = () => { + dismissModal({componentId}); + }; + useEffect(() => { setButtonDisabled(Boolean(!displayName || displayName === server.displayName)); }, [displayName]); - useEffect(() => { - const navigationEvents = Navigation.events().registerNavigationButtonPressedListener(({buttonId}) => { - if (closeButtonId && buttonId === closeButtonId) { - dismissModal({componentId}); - } - }); - - return () => navigationEvents.remove(); - }, []); - const handleUpdate = useCallback(async () => { if (buttonDisabled) { return; @@ -93,6 +89,9 @@ const EditServer = ({closeButtonId, componentId, server, theme}: ServerProps) => setDisplayNameError(undefined); }, []); + useNavButtonPressed(closeButtonId || '', componentId, close, []); + useAndroidHardwareBackHandler(componentId, close); + return ( diff --git a/app/screens/emoji_picker/index.tsx b/app/screens/emoji_picker/index.tsx index 002c524ea6..d6423e4ca2 100644 --- a/app/screens/emoji_picker/index.tsx +++ b/app/screens/emoji_picker/index.tsx @@ -10,8 +10,10 @@ import BottomSheet from '@screens/bottom_sheet'; import Picker from './picker'; import PickerFooter from './picker/footer'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { - componentId: string; + componentId: AvailableScreens; onEmojiPress: (emoji: string) => void; closeButtonId: string; }; diff --git a/app/screens/emoji_picker/picker/header/bottom_sheet_search.tsx b/app/screens/emoji_picker/picker/header/bottom_sheet_search.tsx index 4710997052..4200010aac 100644 --- a/app/screens/emoji_picker/picker/header/bottom_sheet_search.tsx +++ b/app/screens/emoji_picker/picker/header/bottom_sheet_search.tsx @@ -3,10 +3,11 @@ import {useBottomSheet} from '@gorhom/bottom-sheet'; import React, {useCallback} from 'react'; -import {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native'; import SearchBar, {SearchProps} from '@components/search'; +import type {NativeSyntheticEvent, TextInputFocusEventData} from 'react-native'; + const BottomSheetSearch = ({onFocus, ...props}: SearchProps) => { const {expand} = useBottomSheet(); diff --git a/app/screens/emoji_picker/picker/header/skintone_selector/skintone_selector.tsx b/app/screens/emoji_picker/picker/header/skintone_selector/skintone_selector.tsx index 5f6ffdbe68..8e5e847972 100644 --- a/app/screens/emoji_picker/picker/header/skintone_selector/skintone_selector.tsx +++ b/app/screens/emoji_picker/picker/header/skintone_selector/skintone_selector.tsx @@ -114,6 +114,7 @@ const SkinToneSelector = ({skinTone = 'default', containerWidth, isSearching, tu return { width: withDelay(isSearching.value ? 0 : 700, withTiming(isSearching.value ? 0 : 32, {duration: isSearching.value ? 50 : 300})), marginLeft: Platform.OS === 'android' ? 10 : undefined, + height: 34, }; }, []); diff --git a/app/screens/find_channels/index.tsx b/app/screens/find_channels/index.tsx index 264e38c6d5..37e5176c24 100644 --- a/app/screens/find_channels/index.tsx +++ b/app/screens/find_channels/index.tsx @@ -1,13 +1,14 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {Keyboard, View} from 'react-native'; -import {Navigation} from 'react-native-navigation'; import SearchBar from '@components/search'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useKeyboardHeight} from '@hooks/device'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal} from '@screens/navigation'; import {changeOpacity, getKeyboardAppearanceFromTheme, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; @@ -16,9 +17,11 @@ import FilteredList from './filtered_list'; import QuickOptions from './quick_options'; import UnfilteredList from './unfiltered_list'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { closeButtonId: string; - componentId: string; + componentId: AvailableScreens; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -70,15 +73,8 @@ const FindChannels = ({closeButtonId, componentId}: Props) => { } }, []); - useEffect(() => { - const navigationEvents = Navigation.events().registerNavigationButtonPressedListener(({buttonId}) => { - if (closeButtonId && buttonId === closeButtonId) { - close(); - } - }); - - return () => navigationEvents.remove(); - }, []); + useNavButtonPressed(closeButtonId, componentId, close, []); + useAndroidHardwareBackHandler(componentId, close); return ( ({ }, })); -const ForgotPassword = ({serverUrl, theme}: Props) => { +const ForgotPassword = ({componentId, serverUrl, theme}: Props) => { const dimensions = useWindowDimensions(); const translateX = useSharedValue(dimensions.width); const isTablet = useIsTablet(); @@ -263,11 +267,17 @@ const ForgotPassword = ({serverUrl, theme}: Props) => { translateX.value = -dimensions.width; }, }; - const unsubscribe = Navigation.events().registerComponentListener(listener, Screens.FORGOT_PASSWORD); + const unsubscribe = Navigation.events().registerComponentListener(listener, componentId); return () => unsubscribe.remove(); }, [dimensions]); + useEffect(() => { + translateX.value = 0; + }, []); + + useAndroidHardwareBackHandler(componentId, onReturn); + return ( diff --git a/app/screens/gallery/footer/download_with_action/index.tsx b/app/screens/gallery/footer/download_with_action/index.tsx index ce8b4c5d00..ac804ca8f5 100644 --- a/app/screens/gallery/footer/download_with_action/index.tsx +++ b/app/screens/gallery/footer/download_with_action/index.tsx @@ -14,7 +14,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'; import Share from 'react-native-share'; import {updateLocalFilePath} from '@actions/local/file'; -import {downloadFile} from '@actions/remote/file'; +import {downloadFile, downloadProfileImage} from '@actions/remote/file'; import CompassIcon from '@components/compass_icon'; import ProgressBar from '@components/progress_bar'; import Toast from '@components/toast'; @@ -22,6 +22,7 @@ import {GALLERY_FOOTER_HEIGHT} from '@constants/gallery'; import {useServerUrl} from '@context/server'; import {alertFailedToOpenDocument} from '@utils/document'; import {fileExists, getLocalFilePathFromFile, hasWriteStoragePermission} from '@utils/file'; +import {pathWithPrefix} from '@utils/files'; import {galleryItemToFileInfo} from '@utils/gallery'; import {typography} from '@utils/typography'; @@ -105,6 +106,7 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction, gallery switch (item.type) { case 'image': + case 'avatar': message = intl.formatMessage({id: 'gallery.image_saved', defaultMessage: 'Image saved'}); break; case 'video': @@ -177,7 +179,7 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction, gallery updateLocalFilePath(serverUrl, item.id, path); Share.open({ - url: path, + url: pathWithPrefix('file://', path), saveToFiles: true, }).catch(() => { // do nothing @@ -191,12 +193,15 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction, gallery if (mounted.current) { try { const applicationName = DeviceInfo.getApplicationName(); + const cameraType = item.type === 'avatar' ? 'image' : item.type; await CameraRoll.save(path, { - type: item.type === 'image' ? 'photo' : 'video', + type: cameraType === 'image' ? 'photo' : 'video', album: applicationName, }); setSaved(true); - updateLocalFilePath(serverUrl, item.id, path); + if (item.type !== 'avatar') { + updateLocalFilePath(serverUrl, item.id, path); + } } catch { setError(intl.formatMessage({id: 'gallery.save_failed', defaultMessage: 'Unable to save the file'})); } @@ -231,7 +236,7 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction, gallery Share.open({ message: '', title: '', - url: path, + url: pathWithPrefix('file://', path), showAppsToView: true, }).catch(() => { // do nothing @@ -269,7 +274,11 @@ const DownloadWithAction = ({action, item, onDownloadSuccess, setAction, gallery data: {path}, }); } else { - downloadPromise.current = downloadFile(serverUrl, item.id!, path); + if (item.type === 'avatar') { + downloadPromise.current = downloadProfileImage(serverUrl, item.id!, item.lastPictureUpdate, path); + } else { + downloadPromise.current = downloadFile(serverUrl, item.id!, path); + } downloadPromise.current?.then(actionToExecute).catch(() => { setError(intl.formatMessage({id: 'download.error', defaultMessage: 'Unable to download the file. Try again later'})); }); diff --git a/app/screens/gallery/gallery.tsx b/app/screens/gallery/gallery.tsx index 3f294f44f9..49f6f5e1d9 100644 --- a/app/screens/gallery/gallery.tsx +++ b/app/screens/gallery/gallery.tsx @@ -10,12 +10,12 @@ import {useGallery} from '@context/gallery'; import {freezeOtherScreens, measureItem} from '@utils/gallery'; import DocumentRenderer from './document_renderer'; -import {ImageRendererProps} from './image_renderer'; import LightboxSwipeout, {LightboxSwipeoutRef, RenderItemInfo} from './lightbox_swipeout'; import Backdrop, {BackdropProps} from './lightbox_swipeout/backdrop'; import VideoRenderer from './video_renderer'; import GalleryViewer from './viewer'; +import type {ImageRendererProps} from './image_renderer'; import type {GalleryItemType} from '@typings/screens/gallery'; // @ts-expect-error FastImage does work with Animated.createAnimatedComponent diff --git a/app/screens/gallery/image_renderer/index.tsx b/app/screens/gallery/image_renderer/index.tsx index 56c50001cb..258a58dae9 100644 --- a/app/screens/gallery/image_renderer/index.tsx +++ b/app/screens/gallery/image_renderer/index.tsx @@ -3,11 +3,11 @@ import React, {useMemo} from 'react'; -import {PagerProps} from '../pager'; -import {RenderPageProps} from '../pager/page'; - import ImageTransformer, {ImageTransformerProps} from './transformer'; +import type {PagerProps} from '../pager'; +import type {RenderPageProps} from '../pager/page'; + export interface Handlers { onTap?: ImageTransformerProps['onTap']; onDoubleTap?: ImageTransformerProps['onDoubleTap']; diff --git a/app/screens/gallery/index.tsx b/app/screens/gallery/index.tsx index de8eb82fa9..6cc1ef0f0d 100644 --- a/app/screens/gallery/index.tsx +++ b/app/screens/gallery/index.tsx @@ -5,7 +5,7 @@ import React, {useCallback, useMemo, useRef, useState} from 'react'; import {NativeModules, useWindowDimensions, Platform} from 'react-native'; import {Navigation} from 'react-native-navigation'; -import {Screens} from '@constants'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useIsTablet} from '@hooks/device'; import {useGalleryControls} from '@hooks/gallery'; import {dismissOverlay} from '@screens/navigation'; @@ -16,15 +16,17 @@ import Gallery, {GalleryRef} from './gallery'; import Header from './header'; import type {GalleryItemType} from '@typings/screens/gallery'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { + componentId: AvailableScreens; galleryIdentifier: string; hideActions: boolean; initialIndex: number; items: GalleryItemType[]; } -const GalleryScreen = ({galleryIdentifier, hideActions, initialIndex, items}: Props) => { +const GalleryScreen = ({componentId, galleryIdentifier, hideActions, initialIndex, items}: Props) => { const dim = useWindowDimensions(); const isTablet = useIsTablet(); const [localIndex, setLocalIndex] = useState(initialIndex); @@ -55,7 +57,7 @@ const GalleryScreen = ({galleryIdentifier, hideActions, initialIndex, items}: Pr } freezeOtherScreens(false); requestAnimationFrame(async () => { - dismissOverlay(Screens.GALLERY); + dismissOverlay(componentId); }); }, [isTablet]); @@ -63,6 +65,8 @@ const GalleryScreen = ({galleryIdentifier, hideActions, initialIndex, items}: Pr setLocalIndex(index); }, []); + useAndroidHardwareBackHandler(componentId, close); + return ( <>

, diff --git a/app/screens/gallery/viewer/index.tsx b/app/screens/gallery/viewer/index.tsx index 08002bec67..a805e90dca 100644 --- a/app/screens/gallery/viewer/index.tsx +++ b/app/screens/gallery/viewer/index.tsx @@ -5,10 +5,10 @@ import React, {useCallback, useRef} from 'react'; import {runOnJS} from 'react-native-reanimated'; import ImageRenderer, {Handlers, ImageRendererProps} from '../image_renderer'; -import {InteractionType} from '../image_renderer/transformer'; import Pager from '../pager'; -import {RenderPageProps} from '../pager/page'; +import type {InteractionType} from '../image_renderer/transformer'; +import type {RenderPageProps} from '../pager/page'; import type {GalleryItemType} from '@typings/screens/gallery'; export interface GalleryViewerProps extends Handlers { diff --git a/app/screens/global_threads/global_threads.tsx b/app/screens/global_threads/global_threads.tsx index 695dc45ac8..a2cc13252c 100644 --- a/app/screens/global_threads/global_threads.tsx +++ b/app/screens/global_threads/global_threads.tsx @@ -10,6 +10,7 @@ import {setGlobalThreadsTab} from '@actions/local/systems'; import NavigationHeader from '@components/navigation_header'; import RoundedHeaderContext from '@components/rounded_header_context'; import {useServerUrl} from '@context/server'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useAppState, useIsTablet} from '@hooks/device'; import {useDefaultHeaderHeight} from '@hooks/header'; import {useTeamSwitch} from '@hooks/team_switch'; @@ -17,8 +18,10 @@ import {popTopScreen} from '@screens/navigation'; import ThreadsList from './threads_list'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { - componentId?: string; + componentId?: AvailableScreens; globalThreadsTab: GlobalThreadsTab; }; @@ -64,6 +67,8 @@ const GlobalThreads = ({componentId, globalThreadsTab}: Props) => { popTopScreen(componentId); }, [componentId]); + useAndroidHardwareBackHandler(componentId, onBackPress); + return ( - - Test Team! - + + + Test Team! + + + + + + - - - & { diff --git a/app/screens/home/channel_list/categories_list/categories/categories.test.tsx b/app/screens/home/channel_list/categories_list/categories/categories.test.tsx index 59b61b50e5..630c439b73 100644 --- a/app/screens/home/channel_list/categories_list/categories/categories.test.tsx +++ b/app/screens/home/channel_list/categories_list/categories/categories.test.tsx @@ -1,14 +1,16 @@ // 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 {act} from 'react-test-renderer'; import {renderWithEverything} from '@test/intl-test-helper'; import TestHelper from '@test/test_helper'; import Categories from '.'; +import type Database from '@nozbe/watermelondb/Database'; + describe('components/channel_list/categories', () => { let database: Database; beforeAll(async () => { @@ -17,11 +19,15 @@ describe('components/channel_list/categories', () => { }); it('render without error', () => { + jest.useFakeTimers(); const wrapper = renderWithEverything( , {database}, ); + act(() => jest.runAllTimers()); + expect(wrapper.toJSON()).toBeTruthy(); + jest.useRealTimers(); }); }); diff --git a/app/screens/home/channel_list/categories_list/categories/header/__snapshots__/header.test.tsx.snap b/app/screens/home/channel_list/categories_list/categories/header/__snapshots__/header.test.tsx.snap index 04486bdd36..95a4271e43 100644 --- a/app/screens/home/channel_list/categories_list/categories/header/__snapshots__/header.test.tsx.snap +++ b/app/screens/home/channel_list/categories_list/categories/header/__snapshots__/header.test.tsx.snap @@ -2,6 +2,23 @@ exports[`components/channel_list/categories/header should match snapshot 1`] = ` { let database: Database; diff --git a/app/screens/home/channel_list/categories_list/header/__snapshots__/header.test.tsx.snap b/app/screens/home/channel_list/categories_list/header/__snapshots__/header.test.tsx.snap index a016dddf93..b032311b6a 100644 --- a/app/screens/home/channel_list/categories_list/header/__snapshots__/header.test.tsx.snap +++ b/app/screens/home/channel_list/categories_list/header/__snapshots__/header.test.tsx.snap @@ -19,46 +19,115 @@ exports[`components/channel_list/header Channel List Header Component should mat - - Test! - + + + Test! + + + + + + - - - `; diff --git a/app/screens/home/channel_list/categories_list/header/header.tsx b/app/screens/home/channel_list/categories_list/header/header.tsx index ea94719e49..c776b97990 100644 --- a/app/screens/home/channel_list/categories_list/header/header.tsx +++ b/app/screens/home/channel_list/categories_list/header/header.tsx @@ -26,12 +26,13 @@ import LoadingUnreads from './loading_unreads'; import PlusMenu from './plus_menu'; import {SEPARATOR_HEIGHT} from './plus_menu/separator'; +const PLUS_BUTTON_SIZE = 28; + type Props = { canCreateChannels: boolean; canJoinChannels: boolean; canInvitePeople: boolean; displayName?: string; - inviteId?: string; iconPad?: boolean; onHeaderPress?: () => void; pushProxyStatus: string; @@ -60,9 +61,10 @@ const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({ }, plusButton: { backgroundColor: changeOpacity(theme.sidebarText, 0.08), - height: 28, - width: 28, - borderRadius: 14, + height: PLUS_BUTTON_SIZE, + width: PLUS_BUTTON_SIZE, + borderRadius: PLUS_BUTTON_SIZE / 2, + marginTop: PLUS_BUTTON_SIZE / 4, justifyContent: 'center', alignItems: 'center', }, @@ -88,6 +90,13 @@ const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({ justifyContent: 'space-between', height: 40, }, + outsideBox: { + flexDirection: 'row', + justifyContent: 'space-between', + }, + firstBox: { + width: '85%', // ratio derived from the design + }, })); const hitSlop: Insets = {top: 10, bottom: 30, left: 20, right: 20}; @@ -97,7 +106,6 @@ const ChannelListHeader = ({ canJoinChannels, canInvitePeople, displayName, - inviteId, iconPad, onHeaderPress, pushProxyStatus, @@ -124,8 +132,6 @@ const ChannelListHeader = ({ canCreateChannels={canCreateChannels} canJoinChannels={canJoinChannels} canInvitePeople={canInvitePeople} - displayName={displayName} - inviteId={inviteId} /> ); }; @@ -171,59 +177,63 @@ const ChannelListHeader = ({ let header; if (displayName) { header = ( - <> - - - - - {displayName} - - - - - - - - - - {serverDisplayName} - - {(pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED) && ( - + + + - - - )} - + + + {displayName} + + + + + + + {serverDisplayName} + + {(pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED) && ( + + + + )} + + - + + + + ); } else { header = ( diff --git a/app/screens/home/channel_list/categories_list/header/index.ts b/app/screens/home/channel_list/categories_list/header/index.ts index 4d638cf3dc..1aa6d23ebf 100644 --- a/app/screens/home/channel_list/categories_list/header/index.ts +++ b/app/screens/home/channel_list/categories_list/header/index.ts @@ -52,9 +52,6 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { displayName: team.pipe( switchMap((t) => of$(t?.displayName)), ), - inviteId: team.pipe( - switchMap((t) => of$(t?.inviteId)), - ), pushProxyStatus: observePushVerificationStatus(database), }; }); diff --git a/app/screens/home/channel_list/categories_list/header/plus_menu/index.tsx b/app/screens/home/channel_list/categories_list/header/plus_menu/index.tsx index 4fabba5a9d..61b8a78aab 100644 --- a/app/screens/home/channel_list/categories_list/header/plus_menu/index.tsx +++ b/app/screens/home/channel_list/categories_list/header/plus_menu/index.tsx @@ -3,13 +3,9 @@ import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; -import {Platform} from 'react-native'; -import Share from 'react-native-share'; -import {ShareOptions} from 'react-native-share/lib/typescript/types'; import CompassIcon from '@components/compass_icon'; import {Screens} from '@constants'; -import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {dismissBottomSheet, showModal} from '@screens/navigation'; @@ -20,20 +16,17 @@ type Props = { canCreateChannels: boolean; canJoinChannels: boolean; canInvitePeople: boolean; - displayName?: string; - inviteId?: string; } -const PlusMenuList = ({canCreateChannels, canJoinChannels, canInvitePeople, displayName, inviteId}: Props) => { +const PlusMenuList = ({canCreateChannels, canJoinChannels, canInvitePeople}: Props) => { const intl = useIntl(); const theme = useTheme(); - const serverUrl = useServerUrl(); const browseChannels = useCallback(async () => { await dismissBottomSheet(); const title = intl.formatMessage({id: 'browse_channels.title', defaultMessage: 'Browse channels'}); - const closeButton = await CompassIcon.getImageSource('close', 24, theme.sidebarHeaderTextColor); + const closeButton = CompassIcon.getImageSourceSync('close', 24, theme.sidebarHeaderTextColor); showModal(Screens.BROWSE_CHANNELS, title, { closeButton, @@ -51,64 +44,20 @@ const PlusMenuList = ({canCreateChannels, canJoinChannels, canInvitePeople, disp await dismissBottomSheet(); const title = intl.formatMessage({id: 'create_direct_message.title', defaultMessage: 'Create Direct Message'}); - const closeButton = await CompassIcon.getImageSource('close', 24, theme.sidebarHeaderTextColor); + const closeButton = CompassIcon.getImageSourceSync('close', 24, theme.sidebarHeaderTextColor); showModal(Screens.CREATE_DIRECT_MESSAGE, title, { closeButton, }); }, [intl, theme]); - const invitePeopleToTeam = async () => { + const invitePeopleToTeam = useCallback(async () => { await dismissBottomSheet(); - const url = `${serverUrl}/signup_user_complete/?id=${inviteId}`; - const title = intl.formatMessage({id: 'invite_people_to_team.title', defaultMessage: 'Join the {team} team'}, {team: displayName}); - const message = intl.formatMessage({id: 'invite_people_to_team.message', defaultMessage: 'Here’s a link to collaborate and communicate with us on Mattermost.'}); - const icon = 'data:/;base64,'; - - const options: ShareOptions = Platform.select({ - ios: { - activityItemSources: [ - { - placeholderItem: { - type: 'url', - content: url, - }, - item: { - default: { - type: 'text', - content: `${message} ${url}`, - }, - copyToPasteBoard: { - type: 'url', - content: url, - }, - }, - subject: { - default: title, - }, - linkMetadata: { - originalUrl: url, - url, - title, - icon, - }, - }, - ], - }, - default: { - title, - subject: title, - url, - showAppsToView: true, - }, - }); - - Share.open( - options, - ).catch(() => { - // do nothing - }); - }; + showModal( + Screens.INVITE, + intl.formatMessage({id: 'invite.title', defaultMessage: 'Invite'}), + ); + }, [intl, theme]); return ( <> diff --git a/app/screens/home/channel_list/categories_list/index.test.tsx b/app/screens/home/channel_list/categories_list/index.test.tsx index d941a826f3..e6d8f3586a 100644 --- a/app/screens/home/channel_list/categories_list/index.test.tsx +++ b/app/screens/home/channel_list/categories_list/index.test.tsx @@ -1,17 +1,19 @@ // 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 {act} from 'react-test-renderer'; import {SYSTEM_IDENTIFIERS} from '@constants/database'; -import ServerDataOperator from '@database/operator/server_data_operator'; import {getTeamById} from '@queries/servers/team'; import {renderWithEverything} from '@test/intl-test-helper'; import TestHelper from '@test/test_helper'; import CategoriesList from '.'; +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type Database from '@nozbe/watermelondb/Database'; + describe('components/categories_list', () => { let database: Database; let operator: ServerDataOperator; @@ -41,6 +43,7 @@ describe('components/categories_list', () => { }); it('should render channel list with thread menu', () => { + jest.useFakeTimers(); const wrapper = renderWithEverything( { />, {database}, ); + act(() => { + jest.runAllTimers(); + }); expect(wrapper.toJSON()).toBeTruthy(); + jest.useRealTimers(); }); it('should render team error', async () => { @@ -59,6 +66,7 @@ describe('components/categories_list', () => { prepareRecordsOnly: false, }); + jest.useFakeTimers(); const wrapper = renderWithEverything( { {database}, ); + act(() => { + jest.runAllTimers(); + }); expect(wrapper.toJSON()).toMatchSnapshot(); + jest.useRealTimers(); await operator.handleSystem({ systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID, value: TestHelper.basicTeam!.id}], @@ -77,6 +89,7 @@ describe('components/categories_list', () => { }); it('should render channels error', () => { + jest.useFakeTimers(); const wrapper = renderWithEverything( { />, {database}, ); + act(() => { + jest.runAllTimers(); + }); expect(wrapper.toJSON()).toMatchSnapshot(); }); }); diff --git a/app/screens/home/channel_list/categories_list/subheader/search_field/__snapshots__/index.test.tsx.snap b/app/screens/home/channel_list/categories_list/subheader/search_field/__snapshots__/index.test.tsx.snap index 37c9b7a893..dfc0b22461 100644 --- a/app/screens/home/channel_list/categories_list/subheader/search_field/__snapshots__/index.test.tsx.snap +++ b/app/screens/home/channel_list/categories_list/subheader/search_field/__snapshots__/index.test.tsx.snap @@ -2,6 +2,14 @@ exports[`Search Field should match snapshot 1`] = ` { viewRef.current?.measureInWindow((x, y, w, h) => { const bounds: TutorialItemBounds = { - startX: x - 20, + startX: x, startY: y, - endX: x + w + 20, + endX: x + w, endY: y + h, }; if (viewRef.current) { - setShowTutorial(true); setItemBounds(bounds); } }); }; + const onLayout = useCallback(() => { + swipeable.current?.close(); + startTutorial(); + }, []); + const containerStyle = useMemo(() => { const style: StyleProp = [styles.container]; if (isActive) { @@ -344,12 +348,16 @@ const ServerItem = ({ }, [server.lastActiveAt, isActive]); useEffect(() => { - let time: NodeJS.Timeout; if (highlight && !tutorialWatched) { - time = setTimeout(startTutorial, 650); + if (isTablet) { + setShowTutorial(true); + return; + } + InteractionManager.runAfterInteractions(() => { + setShowTutorial(true); + }); } - return () => clearTimeout(time); - }, [highlight, tutorialWatched]); + }, [highlight, tutorialWatched, isTablet]); const serverItem = `server_list.server_item.${server.displayName.replace(/ /g, '_').toLocaleLowerCase()}`; const serverItemTestId = isActive ? `${serverItem}.active` : `${serverItem}.inactive`; @@ -466,6 +474,8 @@ const ServerItem = ({ itemBounds={itemBounds} onDismiss={handleDismissTutorial} onShow={handleShowTutorial} + onLayout={onLayout} + itemBorderRadius={8} > preference.name); diff --git a/app/screens/home/search/initial/initial.tsx b/app/screens/home/search/initial/initial.tsx index 76b0a3611f..dc0c8dd4ec 100644 --- a/app/screens/home/search/initial/initial.tsx +++ b/app/screens/home/search/initial/initial.tsx @@ -2,15 +2,14 @@ // See LICENSE.txt for license information. import React, {Dispatch, RefObject, SetStateAction} from 'react'; -import Animated from 'react-native-reanimated'; - -import {SearchRef} from '@components/search'; -import {TeamModel} from '@database/models/server'; import Modifiers from './modifiers'; import RecentSearches from './recent_searches'; +import type {SearchRef} from '@components/search'; +import type TeamModel from '@typings/database/models/servers/team'; import type TeamSearchHistoryModel from '@typings/database/models/servers/team_search_history'; +import type Animated from 'react-native-reanimated'; type Props = { recentSearches: TeamSearchHistoryModel[]; diff --git a/app/screens/home/search/initial/modifiers/index.tsx b/app/screens/home/search/initial/modifiers/index.tsx index 11f73c3ef2..e1896c8100 100644 --- a/app/screens/home/search/initial/modifiers/index.tsx +++ b/app/screens/home/search/initial/modifiers/index.tsx @@ -7,9 +7,7 @@ import {View} from 'react-native'; import Animated, {useSharedValue, useAnimatedStyle, withTiming} from 'react-native-reanimated'; import FormattedText from '@components/formatted_text'; -import {SearchRef} from '@components/search'; import {useTheme} from '@context/theme'; -import {TeamModel} from '@database/models/server'; import TeamPickerIcon from '@screens/home/search/team_picker_icon'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; @@ -17,6 +15,9 @@ import {typography} from '@utils/typography'; import Modifier, {ModifierItem} from './modifier'; import ShowMoreButton from './show_more'; +import type {SearchRef} from '@components/search'; +import type TeamModel from '@typings/database/models/servers/team'; + const MODIFIER_LABEL_HEIGHT = 48; const TEAM_PICKER_ICON_SIZE = 32; const NUM_ITEMS_BEFORE_EXPAND = 4; diff --git a/app/screens/home/search/initial/modifiers/modifier.tsx b/app/screens/home/search/initial/modifiers/modifier.tsx index bb75cb3f90..de83ed113a 100644 --- a/app/screens/home/search/initial/modifiers/modifier.tsx +++ b/app/screens/home/search/initial/modifiers/modifier.tsx @@ -5,9 +5,10 @@ import React, {Dispatch, RefObject, SetStateAction, useCallback} from 'react'; import {Platform, StyleSheet} from 'react-native'; import OptionItem from '@components/option_item'; -import {SearchRef} from '@components/search'; import {preventDoubleTap} from '@utils/tap'; +import type {SearchRef} from '@components/search'; + const styles = StyleSheet.create({ container: { marginLeft: 20, diff --git a/app/screens/home/search/results/file_options/mobile_options.tsx b/app/screens/home/search/results/file_options/mobile_options.tsx index cb8d305ea1..cd8e784b13 100644 --- a/app/screens/home/search/results/file_options/mobile_options.tsx +++ b/app/screens/home/search/results/file_options/mobile_options.tsx @@ -1,16 +1,17 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React from 'react'; -import {EdgeInsets} from 'react-native-safe-area-context'; import {ITEM_HEIGHT} from '@components/slide_up_panel_item'; import {bottomSheet} from '@screens/navigation'; -import {GalleryAction} from '@typings/screens/gallery'; import {bottomSheetSnapPoint} from '@utils/helpers'; import Header, {HEADER_HEIGHT} from './header'; import OptionMenus from './option_menus'; +import type {GalleryAction} from '@typings/screens/gallery'; +import type {EdgeInsets} from 'react-native-safe-area-context'; + type Props = { fileInfo: FileInfo; insets: EdgeInsets; diff --git a/app/screens/home/search/results/file_options/option_menus/option_menus.tsx b/app/screens/home/search/results/file_options/option_menus/option_menus.tsx index ef1a552d46..ce0d2be8ad 100644 --- a/app/screens/home/search/results/file_options/option_menus/option_menus.tsx +++ b/app/screens/home/search/results/file_options/option_menus/option_menus.tsx @@ -8,7 +8,8 @@ import OptionItem from '@components/option_item'; import {useServerUrl} from '@context/server'; import {useIsTablet} from '@hooks/device'; import {dismissBottomSheet} from '@screens/navigation'; -import {GalleryAction} from '@typings/screens/gallery'; + +import type {GalleryAction} from '@typings/screens/gallery'; type Props = { canDownloadFiles?: boolean; diff --git a/app/screens/home/search/results/file_options/tablet_options.tsx b/app/screens/home/search/results/file_options/tablet_options.tsx index 9dc4641c76..d21d7bf20b 100644 --- a/app/screens/home/search/results/file_options/tablet_options.tsx +++ b/app/screens/home/search/results/file_options/tablet_options.tsx @@ -5,13 +5,13 @@ import {Overlay} from 'react-native-elements'; import {ITEM_HEIGHT} from '@components/option_item'; import {useTheme} from '@context/theme'; -import {GalleryAction} from '@typings/screens/gallery'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; -import {XyOffset} from '../file_result'; - import OptionMenus from './option_menus'; +import type {XyOffset} from '../file_result'; +import type {GalleryAction} from '@typings/screens/gallery'; + const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ tablet: { backgroundColor: theme.centerChannelBg, diff --git a/app/screens/home/search/results/file_result.tsx b/app/screens/home/search/results/file_result.tsx index 119612f8c7..9a536e71b0 100644 --- a/app/screens/home/search/results/file_result.tsx +++ b/app/screens/home/search/results/file_result.tsx @@ -6,11 +6,12 @@ import {Dimensions, StyleSheet, View} from 'react-native'; import File from '@components/files/file'; import {useIsTablet} from '@hooks/device'; -import {GalleryAction} from '@typings/screens/gallery'; import {getViewPortWidth} from '@utils/images'; import TabletOptions from './file_options/tablet_options'; +import type {GalleryAction} from '@typings/screens/gallery'; + export type XyOffset = {x: number; y: number} | undefined; const styles = StyleSheet.create({ diff --git a/app/screens/home/search/results/file_results.tsx b/app/screens/home/search/results/file_results.tsx index d1e2aa08c6..7912cac365 100644 --- a/app/screens/home/search/results/file_results.tsx +++ b/app/screens/home/search/results/file_results.tsx @@ -9,7 +9,6 @@ import NoResultsWithTerm from '@components/no_results_with_term'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device'; import {useImageAttachments} from '@hooks/files'; -import {GalleryAction} from '@typings/screens/gallery'; import { getChannelNamesWithID, getFileInfosIndexes, @@ -26,6 +25,7 @@ import Toasts from './file_options/toasts'; import FileResult from './file_result'; import type ChannelModel from '@typings/database/models/servers/channel'; +import type {GalleryAction} from '@typings/screens/gallery'; type Props = { canDownloadFiles: boolean; @@ -128,6 +128,8 @@ const FileResults = ({ data={orderedFileInfos} indicatorStyle='black' initialNumToRender={10} + + //@ts-expect-error key not defined in types listKey={'files'} maxToRenderPerBatch={5} nestedScrollEnabled={true} diff --git a/app/screens/home/search/results/header.tsx b/app/screens/home/search/results/header.tsx index 0ba4fd47fb..17abcdfdb5 100644 --- a/app/screens/home/search/results/header.tsx +++ b/app/screens/home/search/results/header.tsx @@ -8,7 +8,6 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'; import Badge from '@components/badge'; import CompassIcon from '@components/compass_icon'; import {useTheme} from '@context/theme'; -import {TeamModel} from '@database/models/server'; import {useIsTablet} from '@hooks/device'; import {TITLE_SEPARATOR_MARGIN, TITLE_SEPARATOR_MARGIN_TABLET, TITLE_HEIGHT} from '@screens/bottom_sheet/content'; import TeamPickerIcon from '@screens/home/search/team_picker_icon'; @@ -21,6 +20,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import Filter, {DIVIDERS_HEIGHT, FILTER_ITEM_HEIGHT, NUMBER_FILTER_ITEMS} from './filter'; import SelectButton from './header_button'; +import type TeamModel from '@typings/database/models/servers/team'; + type Props = { onTabSelect: (tab: TabType) => void; onFilterChanged: (filter: FileFilter) => void; diff --git a/app/screens/home/search/results/post_results.tsx b/app/screens/home/search/results/post_results.tsx index 1d92d16ab9..92edfb4a9c 100644 --- a/app/screens/home/search/results/post_results.tsx +++ b/app/screens/home/search/results/post_results.tsx @@ -76,6 +76,8 @@ const PostResults = ({ data={orderedPosts} indicatorStyle='black' initialNumToRender={5} + + //@ts-expect-error key not defined in types listKey={'posts'} maxToRenderPerBatch={5} nestedScrollEnabled={true} diff --git a/app/screens/home/search/search.tsx b/app/screens/home/search/search.tsx index c9aadd2310..ebdaf21d46 100644 --- a/app/screens/home/search/search.tsx +++ b/app/screens/home/search/search.tsx @@ -4,7 +4,7 @@ import {useIsFocused, useNavigation} from '@react-navigation/native'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {FlatList, LayoutChangeEvent, Platform, StyleSheet, ViewProps} from 'react-native'; +import {FlatList, LayoutChangeEvent, Platform, StyleSheet, ViewStyle} from 'react-native'; import Animated, {useAnimatedStyle, useDerivedValue, withTiming} from 'react-native-reanimated'; import {Edge, SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; @@ -16,11 +16,9 @@ import FreezeScreen from '@components/freeze_screen'; import Loading from '@components/loading'; import NavigationHeader from '@components/navigation_header'; import RoundedHeaderContext from '@components/rounded_header_context'; -import {SearchRef} from '@components/search'; import {BOTTOM_TAB_HEIGHT} from '@constants/view'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; -import {TeamModel} from '@database/models/server'; import {useKeyboardHeight} from '@hooks/device'; import useDidUpdate from '@hooks/did_update'; import {useCollapsibleHeader} from '@hooks/header'; @@ -31,7 +29,9 @@ import Initial from './initial'; import Results from './results'; import Header from './results/header'; +import type {SearchRef} from '@components/search'; import type PostModel from '@typings/database/models/servers/post'; +import type TeamModel from '@typings/database/models/servers/team'; const EDGES: Edge[] = ['bottom', 'left', 'right']; const AnimatedFlatList = Animated.createAnimatedComponent(FlatList); @@ -227,12 +227,12 @@ const SearchScreen = ({teamId, teams}: Props) => { handleSearch(newTeamId, lastSearchedValue); }, [lastSearchedValue, handleSearch]); - const initialContainerStyle = useMemo(() => { + const initialContainerStyle: ViewStyle = useMemo(() => { return { paddingTop: scrollPaddingTop, flexGrow: 1, justifyContent: (resultsLoading || loading) ? 'center' : 'flex-start', - } as ViewProps; + }; }, [loading, resultsLoading, scrollPaddingTop]); const renderInitialOrLoadingItem = useCallback(() => { diff --git a/app/screens/in_app_notification/index.tsx b/app/screens/in_app_notification/index.tsx index 2e9f718d12..1e2c2e5c23 100644 --- a/app/screens/in_app_notification/index.tsx +++ b/app/screens/in_app_notification/index.tsx @@ -20,8 +20,10 @@ import Icon from './icon'; import Server from './server'; import Title from './title'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type InAppNotificationProps = { - componentId: string; + componentId: AvailableScreens; notification: NotificationWithData; serverName?: string; serverUrl: string; diff --git a/app/screens/index.tsx b/app/screens/index.tsx index b4249035e1..a95e48dbbe 100644 --- a/app/screens/index.tsx +++ b/app/screens/index.tsx @@ -133,6 +133,9 @@ Navigation.setLazyComponentRegistrator((screenName) => { case Screens.INTERACTIVE_DIALOG: screen = withServerDatabase(require('@screens/interactive_dialog').default); break; + case Screens.INVITE: + screen = withServerDatabase(require('@screens/invite').default); + break; case Screens.IN_APP_NOTIFICATION: { const notificationScreen = require('@screens/in_app_notification').default; Navigation.registerComponent(Screens.IN_APP_NOTIFICATION, () => diff --git a/app/screens/integration_selector/channel_list_row/__snapshots__/index.test.tsx.snap b/app/screens/integration_selector/channel_list_row/__snapshots__/index.test.tsx.snap index cda0c91b2c..f27cb3e51c 100644 --- a/app/screens/integration_selector/channel_list_row/__snapshots__/index.test.tsx.snap +++ b/app/screens/integration_selector/channel_list_row/__snapshots__/index.test.tsx.snap @@ -12,6 +12,23 @@ exports[`components/integration_selector/channel_list_row should match snapshot } > { let database: Database; const channel: Channel = { diff --git a/app/screens/integration_selector/custom_list/index.test.tsx b/app/screens/integration_selector/custom_list/index.test.tsx index 66cd540c09..a02dea405d 100644 --- a/app/screens/integration_selector/custom_list/index.test.tsx +++ b/app/screens/integration_selector/custom_list/index.test.tsx @@ -1,7 +1,6 @@ // 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 {Text} from 'react-native'; @@ -11,6 +10,8 @@ import TestHelper from '@test/test_helper'; import CustomList from '.'; +import type Database from '@nozbe/watermelondb/Database'; + describe('components/integration_selector/custom_list', () => { let database: Database; beforeAll(async () => { diff --git a/app/screens/integration_selector/custom_list_row/__snapshots__/index.test.tsx.snap b/app/screens/integration_selector/custom_list_row/__snapshots__/index.test.tsx.snap index 17dfeb003e..a3b3a1a3d4 100644 --- a/app/screens/integration_selector/custom_list_row/__snapshots__/index.test.tsx.snap +++ b/app/screens/integration_selector/custom_list_row/__snapshots__/index.test.tsx.snap @@ -2,6 +2,23 @@ exports[`components/integration_selector/custom_list_row should match snapshot 1`] = ` { let database: Database; beforeAll(async () => { diff --git a/app/screens/integration_selector/integration_selector.tsx b/app/screens/integration_selector/integration_selector.tsx index 06339c6ac9..2a29f6ab59 100644 --- a/app/screens/integration_selector/integration_selector.tsx +++ b/app/screens/integration_selector/integration_selector.tsx @@ -14,6 +14,7 @@ import {General, View as ViewConstants} from '@constants'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {debounce} from '@helpers/api/general'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {t} from '@i18n'; import { @@ -29,6 +30,8 @@ import CustomList from './custom_list'; import OptionListRow from './option_list_row'; import SelectedOptions from './selected_options'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type DataType = DialogOption | Channel | UserProfile; type DataTypeList = DialogOption[] | Channel[] | UserProfile[]; type Selection = DataType | DataTypeList; @@ -115,7 +118,7 @@ export type Props = { selected: SelectedDialogValue; theme: Theme; teammateNameDisplay: string; - componentId: string; + componentId: AvailableScreens; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { @@ -344,6 +347,7 @@ function IntegrationSelector( // Effects useNavButtonPressed(SUBMIT_BUTTON_ID, componentId, onHandleMultiselectSubmit, [onHandleMultiselectSubmit]); + useAndroidHardwareBackHandler(componentId, close); useEffect(() => { return () => { diff --git a/app/screens/integration_selector/option_list_row/__snapshots__/index.test.tsx.snap b/app/screens/integration_selector/option_list_row/__snapshots__/index.test.tsx.snap index ef481625d8..04e4e0e5a2 100644 --- a/app/screens/integration_selector/option_list_row/__snapshots__/index.test.tsx.snap +++ b/app/screens/integration_selector/option_list_row/__snapshots__/index.test.tsx.snap @@ -13,6 +13,23 @@ exports[`components/integration_selector/option_list_row should match snapshot f } > { let database: Database; beforeAll(async () => { diff --git a/app/screens/integration_selector/selected_option/__snapshots__/index.test.tsx.snap b/app/screens/integration_selector/selected_option/__snapshots__/index.test.tsx.snap index 86293ea8ba..32747e02c6 100644 --- a/app/screens/integration_selector/selected_option/__snapshots__/index.test.tsx.snap +++ b/app/screens/integration_selector/selected_option/__snapshots__/index.test.tsx.snap @@ -31,6 +31,23 @@ exports[`components/integration_selector/selected_option should match snapshot f channel { let database: Database; beforeAll(async () => { diff --git a/app/screens/integration_selector/selected_options/__snapshots__/index.test.tsx.snap b/app/screens/integration_selector/selected_options/__snapshots__/index.test.tsx.snap index 57e7383a07..c975db49aa 100644 --- a/app/screens/integration_selector/selected_options/__snapshots__/index.test.tsx.snap +++ b/app/screens/integration_selector/selected_options/__snapshots__/index.test.tsx.snap @@ -51,6 +51,23 @@ exports[`components/integration_selector/selected_options should match snapshot channel { let database: Database; beforeAll(async () => { diff --git a/app/screens/interactive_dialog/dialog_element.tsx b/app/screens/interactive_dialog/dialog_element.tsx index 1b29c664e4..573c80b825 100644 --- a/app/screens/interactive_dialog/dialog_element.tsx +++ b/app/screens/interactive_dialog/dialog_element.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React, {useCallback} from 'react'; -import {KeyboardTypeOptions} from 'react-native'; import AutocompleteSelector from '@components/autocomplete_selector'; import BoolSetting from '@components/settings/bool_setting'; @@ -10,6 +9,8 @@ import RadioSetting from '@components/settings/radio_setting'; import TextSetting from '@components/settings/text_setting'; import {selectKeyboardType as selectKB} from '@utils/integrations'; +import type {KeyboardTypeOptions} from 'react-native'; + const TEXT_DEFAULT_MAX_LENGTH = 150; const TEXTAREA_DEFAULT_MAX_LENGTH = 3000; diff --git a/app/screens/interactive_dialog/index.tsx b/app/screens/interactive_dialog/index.tsx index b89f2a646f..d8f56a3cc9 100644 --- a/app/screens/interactive_dialog/index.tsx +++ b/app/screens/interactive_dialog/index.tsx @@ -12,6 +12,7 @@ import CompassIcon from '@components/compass_icon'; import ErrorText from '@components/error_text'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {buildNavigationButton, dismissModal, setButtons} from '@screens/navigation'; import {checkDialogElementForError, checkIfErrorsMatchElements} from '@utils/integrations'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -19,6 +20,8 @@ import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import DialogElement from './dialog_element'; import DialogIntroductionText from './dialog_introduction_text'; +import type {AvailableScreens} from '@typings/screens/navigation'; + const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { return { container: { @@ -40,7 +43,7 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { type Props = { config: InteractiveDialogConfig; - componentId: string; + componentId: AvailableScreens; } const close = () => { @@ -217,6 +220,8 @@ function InteractiveDialog({ }; }, [serverUrl, url, callbackId, state, handleSubmit, submitting]); + useAndroidHardwareBackHandler(componentId, close); + return ( { + const team = observeCurrentTeam(database); + + return { + teamId: team.pipe( + switchMap((t) => of$(t?.id)), + ), + teamDisplayName: team.pipe( + switchMap((t) => of$(t?.displayName)), + ), + teamLastIconUpdate: team.pipe( + switchMap((t) => of$(t?.lastTeamIconUpdatedAt)), + ), + teamInviteId: team.pipe( + switchMap((t) => of$(t?.inviteId)), + ), + teammateNameDisplay: observeTeammateNameDisplay(database), + isAdmin: observeCurrentUser(database).pipe( + map((user) => isSystemAdmin(user?.roles || '')), + distinctUntilChanged(), + ), + }; +}); + +export default withDatabase(enhanced(Invite)); diff --git a/app/screens/invite/invite.tsx b/app/screens/invite/invite.tsx new file mode 100644 index 0000000000..8f8640fea1 --- /dev/null +++ b/app/screens/invite/invite.tsx @@ -0,0 +1,419 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback, useEffect, useState, useRef} from 'react'; +import {IntlShape, useIntl} from 'react-intl'; +import {Keyboard, View, LayoutChangeEvent} from 'react-native'; +import {SafeAreaView} from 'react-native-safe-area-context'; + +import {getTeamMembersByIds, addUsersToTeam, sendEmailInvitesToTeam} from '@actions/remote/team'; +import {searchProfiles} from '@actions/remote/user'; +import CompassIcon from '@components/compass_icon'; +import Loading from '@components/loading'; +import {ServerErrors} from '@constants'; +import {useServerUrl} from '@context/server'; +import {useTheme} from '@context/theme'; +import {useModalPosition} from '@hooks/device'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; +import {dismissModal, setButtons} from '@screens/navigation'; +import {isEmail} from '@utils/helpers'; +import {mergeNavigationOptions} from '@utils/navigation'; +import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; +import {isGuest} from '@utils/user'; + +import Selection from './selection'; +import Summary from './summary'; + +import type {AvailableScreens, NavButtons} from '@typings/screens/navigation'; +import type {OptionsTopBarButton} from 'react-native-navigation'; + +const CLOSE_BUTTON_ID = 'close-invite'; +const SEND_BUTTON_ID = 'send-invite'; +const TIMEOUT_MILLISECONDS = 200; +const DEFAULT_RESULT = {sent: [], notSent: []}; + +const makeLeftButton = (theme: Theme): OptionsTopBarButton => ({ + id: CLOSE_BUTTON_ID, + icon: CompassIcon.getImageSourceSync('close', 24, theme.sidebarHeaderTextColor), + testID: 'invite.close.button', +}); + +const makeRightButton = (theme: Theme, formatMessage: IntlShape['formatMessage'], enabled: boolean): OptionsTopBarButton => ({ + id: SEND_BUTTON_ID, + text: formatMessage({id: 'invite.send_invite', defaultMessage: 'Send'}), + showAsAction: 'always', + testID: 'invite.send.button', + color: theme.sidebarHeaderTextColor, + disabledColor: changeOpacity(theme.sidebarHeaderTextColor, 0.4), + enabled, +}); + +const closeModal = async () => { + Keyboard.dismiss(); + await dismissModal(); +}; + +const getStyleSheet = makeStyleSheetFromTheme(() => { + return { + container: { + flex: 1, + flexDirection: 'column', + }, + loadingContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + }; +}); + +export type EmailInvite = string; + +export type SearchResult = UserProfile|EmailInvite; + +export type InviteResult = { + userId: string; + reason: string; +}; + +export type Result = { + sent: InviteResult[]; + notSent: InviteResult[]; +} + +enum Stage { + SELECTION = 'selection', + RESULT = 'result', + LOADING = 'loading', +} + +type InviteProps = { + componentId: AvailableScreens; + teamId: string; + teamDisplayName: string; + teamLastIconUpdate: number; + teamInviteId: string; + teammateNameDisplay: string; + isAdmin: boolean; +} + +export default function Invite({ + componentId, + teamId, + teamDisplayName, + teamLastIconUpdate, + teamInviteId, + teammateNameDisplay, + isAdmin, +}: InviteProps) { + const intl = useIntl(); + const {formatMessage, locale} = intl; + const theme = useTheme(); + const styles = getStyleSheet(theme); + const serverUrl = useServerUrl(); + const mainView = useRef(null); + const modalPosition = useModalPosition(mainView); + + const searchTimeoutId = useRef(null); + const retryTimeoutId = useRef(null); + + const [term, setTerm] = useState(''); + const [searchResults, setSearchResults] = useState([]); + const [selectedIds, setSelectedIds] = useState<{[id: string]: SearchResult}>({}); + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(DEFAULT_RESULT); + const [wrapperHeight, setWrapperHeight] = useState(0); + const [stage, setStage] = useState(Stage.SELECTION); + const [sendError, setSendError] = useState(''); + + const selectedCount = Object.keys(selectedIds).length; + + const onLayoutWrapper = useCallback((e: LayoutChangeEvent) => { + setWrapperHeight(e.nativeEvent.layout.height); + }, []); + + const searchUsers = useCallback(async (searchTerm: string) => { + if (searchTerm === '') { + handleClearSearch(); + return; + } + + const {data} = await searchProfiles(serverUrl, searchTerm.toLowerCase()); + const results: SearchResult[] = data ?? []; + + if (!results.length && isEmail(searchTerm.trim())) { + results.push(searchTerm.trim() as EmailInvite); + } + + setSearchResults(results); + }, [serverUrl, teamId]); + + const handleReset = () => { + setStage(Stage.LOADING); + setSendError(''); + setTerm(''); + setSearchResults([]); + setResult(DEFAULT_RESULT); + setStage(Stage.SELECTION); + }; + + const handleClearSearch = useCallback(() => { + setTerm(''); + setSearchResults([]); + }, []); + + const handleSearchChange = useCallback((text: string) => { + setLoading(true); + setTerm(text); + + if (searchTimeoutId.current) { + clearTimeout(searchTimeoutId.current); + } + + searchTimeoutId.current = setTimeout(async () => { + await searchUsers(text); + setLoading(false); + }, TIMEOUT_MILLISECONDS); + }, [searchUsers]); + + const handleSelectItem = useCallback((item: SearchResult) => { + const email = typeof item === 'string'; + const id = email ? item : (item as UserProfile).id; + const newSelectedIds = Object.assign({}, selectedIds); + + if (!selectedIds[id]) { + newSelectedIds[id] = item; + } + + setSelectedIds(newSelectedIds); + + handleClearSearch(); + }, [selectedIds, handleClearSearch]); + + const handleRetry = () => { + setSendError(''); + setStage(Stage.LOADING); + + retryTimeoutId.current = setTimeout(() => { + handleSend(); + }, TIMEOUT_MILLISECONDS); + }; + + const handleSendError = () => { + setSendError(formatMessage({id: 'invite.send_error', defaultMessage: 'Something went wrong while trying to send invitations. Please check your network connection and try again.'})); + setResult(DEFAULT_RESULT); + setStage(Stage.RESULT); + }; + + const handleSend = async () => { + if (!selectedCount) { + return; + } + + setStage(Stage.LOADING); + + const userIds = []; + const emails = []; + + for (const [id, item] of Object.entries(selectedIds)) { + if (typeof item === 'string') { + emails.push(item); + } else { + userIds.push(id); + } + } + + const currentMemberIds = new Set(); + + if (userIds.length) { + const {members: currentTeamMembers = [], error: getTeamMembersByIdsError} = await getTeamMembersByIds(serverUrl, teamId, userIds); + + if (getTeamMembersByIdsError) { + handleSendError(); + return; + } + + for (const {user_id: currentMemberId} of currentTeamMembers) { + currentMemberIds.add(currentMemberId); + } + } + + const sent: InviteResult[] = []; + const notSent: InviteResult[] = []; + const usersToAdd = []; + + for (const userId of userIds) { + if (isGuest((selectedIds[userId] as UserProfile).roles)) { + notSent.push({userId, reason: formatMessage({id: 'invite.members.user_is_guest', defaultMessage: 'Contact your admin to make this guest a full member'})}); + } else if (currentMemberIds.has(userId)) { + notSent.push({userId, reason: formatMessage({id: 'invite.members.already_member', defaultMessage: 'This person is already a team member'})}); + } else { + usersToAdd.push(userId); + } + } + + if (usersToAdd.length) { + const {members, error: addUsersToTeamError} = await addUsersToTeam(serverUrl, teamId, usersToAdd); + + if (addUsersToTeamError) { + handleSendError(); + return; + } + + if (members) { + const membersWithError: Record = {}; + for (const {user_id, error} of members) { + if (error) { + membersWithError[user_id] = error.message; + } + } + + for (const userId of usersToAdd) { + if (membersWithError[userId]) { + notSent.push({userId, reason: membersWithError[userId]}); + } else { + sent.push({userId, reason: formatMessage({id: 'invite.summary.member_invite', defaultMessage: 'Invited as a member of {teamDisplayName}'}, {teamDisplayName})}); + } + } + } + } + + if (emails.length) { + const {members, error: sendEmailInvitesToTeamError} = await sendEmailInvitesToTeam(serverUrl, teamId, emails); + + if (sendEmailInvitesToTeamError) { + handleSendError(); + return; + } + + if (members) { + const membersWithError: Record = {}; + for (const {email, error} of members) { + if (error) { + membersWithError[email] = isAdmin && error.server_error_id === ServerErrors.SEND_EMAIL_WITH_DEFAULTS_ERROR ? ( + formatMessage({id: 'invite.summary.smtp_failure', defaultMessage: 'SMTP is not configured in System Console'}) + ) : ( + error.message + ); + } + } + + for (const email of emails) { + if (membersWithError[email]) { + notSent.push({userId: email, reason: membersWithError[email]}); + } else { + sent.push({userId: email, reason: formatMessage({id: 'invite.summary.email_invite', defaultMessage: 'An invitation email has been sent'})}); + } + } + } + } + + setResult({sent, notSent}); + setStage(Stage.RESULT); + }; + + useNavButtonPressed(CLOSE_BUTTON_ID, componentId, closeModal, [closeModal]); + useNavButtonPressed(SEND_BUTTON_ID, componentId, handleSend, [handleSend]); + + useEffect(() => { + const buttons: NavButtons = { + leftButtons: [makeLeftButton(theme)], + rightButtons: stage === Stage.SELECTION ? [makeRightButton(theme, formatMessage, selectedCount > 0)] : [], + }; + + setButtons(componentId, buttons); + }, [theme, locale, componentId, selectedCount > 0, stage === Stage.SELECTION, sendError]); + + useEffect(() => { + mergeNavigationOptions(componentId, { + topBar: { + title: { + color: theme.sidebarHeaderTextColor, + text: stage === Stage.RESULT ? ( + formatMessage({id: 'invite.title.summary', defaultMessage: 'Invite summary'}) + ) : ( + formatMessage({id: 'invite.title', defaultMessage: 'Invite'}) + ), + }, + }, + }); + }, [componentId, locale, theme, stage === Stage.RESULT]); + + useEffect(() => { + return () => { + if (searchTimeoutId.current) { + clearTimeout(searchTimeoutId.current); + } + + if (retryTimeoutId.current) { + clearTimeout(retryTimeoutId.current); + } + }; + }, []); + + const handleRemoveItem = useCallback((id: string) => { + const newSelectedIds = Object.assign({}, selectedIds); + + Reflect.deleteProperty(newSelectedIds, id); + + setSelectedIds(newSelectedIds); + }, [selectedIds]); + + const renderContent = () => { + switch (stage) { + case Stage.LOADING: + return ( + + ); + case Stage.RESULT: + return ( + + ); + default: + return ( + + ); + } + }; + + return ( + + {renderContent()} + + ); +} diff --git a/app/screens/invite/selection.tsx b/app/screens/invite/selection.tsx new file mode 100644 index 0000000000..b31bccbd67 --- /dev/null +++ b/app/screens/invite/selection.tsx @@ -0,0 +1,349 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback, useState, useMemo} from 'react'; +import { + Keyboard, + Platform, + View, + LayoutChangeEvent, + useWindowDimensions, + FlatList, + ListRenderItemInfo, + ScrollView, +} from 'react-native'; +import Animated, {useAnimatedStyle, useDerivedValue} from 'react-native-reanimated'; +import {useSafeAreaInsets} from 'react-native-safe-area-context'; + +import SelectedChip from '@components/selected_chip'; +import SelectedUser from '@components/selected_users/selected_user'; +import TouchableWithFeedback from '@components/touchable_with_feedback'; +import UserItem from '@components/user_item'; +import {MAX_LIST_HEIGHT, MAX_LIST_TABLET_DIFF} from '@constants/autocomplete'; +import {useTheme} from '@context/theme'; +import {useAutocompleteDefaultAnimatedValues} from '@hooks/autocomplete'; +import {useIsTablet, useKeyboardHeight} from '@hooks/device'; +import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; + +import SelectionSearchBar from './selection_search_bar'; +import SelectionTeamBar from './selection_team_bar'; +import TextItem, {TextItemType} from './text_item'; + +import type {SearchResult} from './invite'; + +const AUTOCOMPLETE_ADJUST = 5; +const KEYBOARD_HEIGHT_ADJUST = 3; + +const INITIAL_BATCH_TO_RENDER = 15; +const SCROLL_EVENT_THROTTLE = 60; + +const keyboardDismissProp = Platform.select({ + android: { + onScrollBeginDrag: Keyboard.dismiss, + }, + ios: { + keyboardDismissMode: 'on-drag' as const, + }, +}); + +const keyExtractor = (item: SearchResult) => ( + typeof item === 'string' ? item : (item as UserProfile).id +); + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + container: { + display: 'flex', + flex: 1, + }, + searchList: { + left: 20, + right: 20, + position: 'absolute', + bottom: Platform.select({ios: 'auto', default: undefined}), + }, + searchListBorder: { + borderWidth: 1, + borderColor: changeOpacity(theme.centerChannelColor, 0.2), + borderRadius: 4, + elevation: 3, + }, + searchListPadding: { + paddingVertical: 8, + }, + searchListShadow: { + shadowColor: '#000', + shadowOpacity: 0.12, + shadowRadius: 6, + shadowOffset: { + width: 0, + height: 6, + }, + borderRadius: 4, + backgroundColor: theme.centerChannelBg, + }, + searchListFlatList: { + backgroundColor: theme.centerChannelBg, + borderRadius: 4, + }, + selectedItems: { + display: 'flex', + flexGrowth: 1, + }, + selectedItemsContainer: { + alignItems: 'flex-start', + flexDirection: 'row', + flexWrap: 'wrap', + marginHorizontal: 20, + marginVertical: 16, + }, + }; +}); + +type SelectionProps = { + teamId: string; + teamDisplayName: string; + teamLastIconUpdate: number; + teamInviteId: string; + teammateNameDisplay: string; + serverUrl: string; + term: string; + searchResults: SearchResult[]; + selectedIds: {[id: string]: SearchResult}; + modalPosition: number; + wrapperHeight: number; + loading: boolean; + testID: string; + onSearchChange: (text: string) => void; + onSelectItem: (item: SearchResult) => void; + onRemoveItem: (id: string) => void; + onClose: () => Promise; +} + +export default function Selection({ + teamId, + teamDisplayName, + teamLastIconUpdate, + teamInviteId, + teammateNameDisplay, + serverUrl, + term, + searchResults, + selectedIds, + modalPosition, + wrapperHeight, + loading, + testID, + onSearchChange, + onSelectItem, + onRemoveItem, + onClose, +}: SelectionProps) { + const theme = useTheme(); + const styles = getStyleSheet(theme); + const dimensions = useWindowDimensions(); + const insets = useSafeAreaInsets(); + const isTablet = useIsTablet(); + const keyboardHeight = useKeyboardHeight(); + + const [teamBarHeight, setTeamBarHeight] = useState(0); + const [searchBarHeight, setSearchBarHeight] = useState(0); + + const onLayoutSelectionTeamBar = useCallback((e: LayoutChangeEvent) => { + setTeamBarHeight(e.nativeEvent.layout.height); + }, []); + + const onLayoutSearchBar = useCallback((e: LayoutChangeEvent) => { + setSearchBarHeight(e.nativeEvent.layout.height); + }, []); + + const handleOnRemoveItem = (id: string) => { + onRemoveItem(id); + }; + + const bottomSpace = dimensions.height - wrapperHeight - modalPosition; + const otherElementsSize = teamBarHeight + searchBarHeight; + const insetsAdjust = (keyboardHeight + KEYBOARD_HEIGHT_ADJUST) || insets.bottom; + + const keyboardOverlap = Platform.select({ + ios: isTablet ? ( + Math.max(0, keyboardHeight - bottomSpace) + ) : ( + insetsAdjust + ), + default: 0, + }); + const keyboardAdjust = Platform.select({ + ios: isTablet ? keyboardOverlap : insetsAdjust, + default: 0, + }); + + const workingSpace = wrapperHeight - keyboardOverlap; + const spaceOnTop = otherElementsSize - AUTOCOMPLETE_ADJUST; + const spaceOnBottom = workingSpace - (otherElementsSize + keyboardAdjust); + const autocompletePosition = spaceOnBottom > spaceOnTop ? ( + otherElementsSize + ) : ( + workingSpace - otherElementsSize + ); + const autocompleteAvailableSpace = spaceOnBottom > spaceOnTop ? spaceOnBottom : spaceOnTop; + const isLandscape = dimensions.width > dimensions.height; + const maxHeightAdjust = (isTablet && isLandscape) ? MAX_LIST_TABLET_DIFF : 0; + const defaultMaxHeight = MAX_LIST_HEIGHT - maxHeightAdjust; + + const [animatedAutocompletePosition, animatedAutocompleteAvailableSpace] = useAutocompleteDefaultAnimatedValues(autocompletePosition, autocompleteAvailableSpace); + + const maxHeight = useDerivedValue(() => { + return Math.min(animatedAutocompleteAvailableSpace.value, defaultMaxHeight); + }, [animatedAutocompleteAvailableSpace, defaultMaxHeight]); + + const searchListContainerAnimatedStyle = useAnimatedStyle(() => ({ + top: animatedAutocompletePosition.value, + maxHeight: maxHeight.value, + }), [animatedAutocompletePosition, maxHeight]); + + const searchListContainerStyle = useMemo(() => { + const style = []; + + style.push( + styles.searchList, + searchListContainerAnimatedStyle, + ); + + if (Platform.OS === 'ios') { + style.push(styles.searchListShadow); + } + + return style; + }, [searchResults, styles, searchListContainerAnimatedStyle]); + + const searchListFlatListStyle = useMemo(() => { + const style = []; + + style.push(styles.searchListFlatList); + + if (searchResults.length) { + style.push(styles.searchListBorder, styles.searchListPadding); + } + + return style; + }, [searchResults, styles]); + + const renderNoResults = useCallback(() => { + if (!term || loading) { + return null; + } + + return ( + + + + ); + }, [term, loading]); + + const renderItem = useCallback(({item}: ListRenderItemInfo) => { + const key = keyExtractor(item); + + return ( + onSelectItem(item)} + underlayColor={changeOpacity(theme.buttonBg, 0.08)} + type='native' + testID={`invite.search_list_item.${key}`} + > + {typeof item === 'string' ? ( + + ) : ( + + )} + + ); + }, [searchResults, onSelectItem]); + + const renderSelectedItems = useMemo(() => { + const selectedItems = []; + + for (const id of Object.keys(selectedIds)) { + const selectedItem = selectedIds[id]; + + selectedItems.push(typeof selectedItem === 'string' ? ( + + ) : ( + + )); + } + + return selectedItems; + }, [selectedIds]); + + return ( + + + + {Object.keys(selectedIds).length > 0 && ( + + {renderSelectedItems} + + )} + + + + + ); +} diff --git a/app/screens/invite/selection_search_bar.tsx b/app/screens/invite/selection_search_bar.tsx new file mode 100644 index 0000000000..ad5f9b5e68 --- /dev/null +++ b/app/screens/invite/selection_search_bar.tsx @@ -0,0 +1,131 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback, useState, useMemo} from 'react'; +import {useIntl} from 'react-intl'; +import {View, TextInput, LayoutChangeEvent} from 'react-native'; + +import FormattedText from '@components/formatted_text'; +import {useTheme} from '@context/theme'; +import {makeStyleSheetFromTheme, changeOpacity, getKeyboardAppearanceFromTheme} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const SEARCH_BAR_TITLE_MARGIN_TOP = 24; +const SEARCH_BAR_MARGIN_TOP = 16; + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + container: { + display: 'flex', + }, + searchBarTitleText: { + marginHorizontal: 20, + marginTop: SEARCH_BAR_TITLE_MARGIN_TOP, + color: theme.centerChannelColor, + ...typography('Heading', 700, 'SemiBold'), + }, + searchBar: { + marginHorizontal: 20, + marginTop: SEARCH_BAR_MARGIN_TOP, + }, + searchInput: { + height: 48, + backgroundColor: 'transparent', + ...typography('Body', 200, 'Regular'), + lineHeight: 20, + color: theme.centerChannelColor, + borderWidth: 1, + borderColor: changeOpacity(theme.centerChannelColor, 0.16), + borderRadius: 4, + paddingHorizontal: 16, + }, + searchInputPlaceholder: { + color: changeOpacity(theme.centerChannelColor, 0.64), + }, + }; +}); + +type SelectionSearchBarProps = { + term: string; + onSearchChange: (text: string) => void; + onLayoutContainer: (e: LayoutChangeEvent) => void; +} + +export default function SelectionSearchBar({ + term, + onSearchChange, + onLayoutContainer, +}: SelectionSearchBarProps) { + const {formatMessage} = useIntl(); + const theme = useTheme(); + const styles = getStyleSheet(theme); + const [isFocused, setIsFocused] = useState(false); + + const onLayoutSearchBar = useCallback((e: LayoutChangeEvent) => { + onLayoutContainer(e); + }, [onLayoutContainer]); + + const onTextInputFocus = () => { + setIsFocused(true); + }; + + const onTextInputBlur = () => { + setIsFocused(false); + }; + + const handleSearchChange = (text: string) => { + onSearchChange(text); + }; + + const searchInputStyle = useMemo(() => { + const style = []; + + style.push(styles.searchInput); + + if (isFocused) { + style.push({ + borderWidth: 2, + borderColor: theme.buttonBg, + }); + } + + return style; + }, [isFocused, styles]); + + return ( + + + + + + + ); +} diff --git a/app/screens/invite/selection_team_bar.tsx b/app/screens/invite/selection_team_bar.tsx new file mode 100644 index 0000000000..0a1dd3f0b7 --- /dev/null +++ b/app/screens/invite/selection_team_bar.tsx @@ -0,0 +1,216 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback} from 'react'; +import {useIntl} from 'react-intl'; +import { + Platform, + View, + Text, + TouchableOpacity, + LayoutChangeEvent, +} from 'react-native'; +import Share from 'react-native-share'; + +import CompassIcon from '@components/compass_icon'; +import FormattedText from '@components/formatted_text'; +import TeamIcon from '@components/team_sidebar/team_list/team_item/team_icon'; +import {useServerDisplayName} from '@context/server'; +import {useTheme} from '@context/theme'; +import {preventDoubleTap} from '@utils/tap'; +import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; +import {typography} from '@utils/typography'; + +import type {ShareOptions} from 'react-native-share/lib/typescript/types'; + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + container: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + width: '100%', + paddingVertical: 16, + paddingHorizontal: 20, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.04), + }, + iconContainer: { + width: 40, + height: 40, + }, + textContainer: { + display: 'flex', + flexDirection: 'column', + }, + teamText: { + color: theme.centerChannelColor, + marginLeft: 12, + ...typography('Body', 200, 'SemiBold'), + }, + serverText: { + color: changeOpacity(theme.centerChannelColor, 0.72), + marginLeft: 12, + ...typography('Body', 75, 'Regular'), + }, + shareLink: { + display: 'flex', + marginLeft: 'auto', + }, + shareLinkButton: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + height: 40, + paddingHorizontal: 20, + backgroundColor: changeOpacity(theme.buttonBg, 0.08), + borderRadius: 4, + }, + shareLinkText: { + color: theme.buttonBg, + ...typography('Body', 100, 'SemiBold'), + paddingLeft: 7, + }, + shareLinkIcon: { + color: theme.buttonBg, + }, + }; +}); + +type SelectionTeamBarProps = { + teamId: string; + teamDisplayName: string; + teamLastIconUpdate: number; + teamInviteId: string; + serverUrl: string; + onLayoutContainer: (e: LayoutChangeEvent) => void; + onClose: () => Promise; +} + +export default function SelectionTeamBar({ + teamId, + teamDisplayName, + teamLastIconUpdate, + teamInviteId, + serverUrl, + onLayoutContainer, + onClose, +}: SelectionTeamBarProps) { + const {formatMessage} = useIntl(); + const theme = useTheme(); + const styles = getStyleSheet(theme); + const serverDisplayName = useServerDisplayName(); + + const handleOnLayoutContainer = useCallback((e: LayoutChangeEvent) => { + onLayoutContainer(e); + }, [onLayoutContainer]); + + const handleOnShareLink = async () => { + const url = `${serverUrl}/signup_user_complete/?id=${teamInviteId}`; + const title = formatMessage({id: 'invite_people_to_team.title', defaultMessage: 'Join the {team} team'}, {team: teamDisplayName}); + const message = formatMessage({id: 'invite_people_to_team.message', defaultMessage: 'Here’s a link to collaborate and communicate with us on Mattermost.'}); + const icon = 'data:/;base64,'; + + const options: ShareOptions = Platform.select({ + ios: { + activityItemSources: [ + { + placeholderItem: { + type: 'url', + content: url, + }, + item: { + default: { + type: 'text', + content: `${message} ${url}`, + }, + copyToPasteBoard: { + type: 'url', + content: url, + }, + }, + subject: { + default: title, + }, + linkMetadata: { + originalUrl: url, + url, + title, + icon, + }, + }, + ], + }, + default: { + title, + subject: title, + url, + showAppsToView: true, + }, + }); + + await onClose(); + + Share.open( + options, + ).catch(() => { + // do nothing + }); + }; + + const handleShareLink = useCallback(preventDoubleTap(() => handleOnShareLink()), []); + + return ( + + + + + + + {teamDisplayName} + + + {serverDisplayName} + + + + + + + + + + ); +} diff --git a/app/screens/invite/summary.tsx b/app/screens/invite/summary.tsx new file mode 100644 index 0000000000..d06c64ef59 --- /dev/null +++ b/app/screens/invite/summary.tsx @@ -0,0 +1,300 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React, {useCallback, useMemo} from 'react'; +import {useIntl} from 'react-intl'; +import {View, Text, ScrollView} from 'react-native'; +import Button from 'react-native-button'; + +import CompassIcon from '@components/compass_icon'; +import FormattedText from '@components/formatted_text'; +import AlertSvg from '@components/illustrations/alert'; +import ErrorSvg from '@components/illustrations/error'; +import SuccessSvg from '@components/illustrations/success'; +import {useTheme} from '@context/theme'; +import {t} from '@i18n'; +import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; +import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; +import {typography} from '@utils/typography'; + +import SummaryReport, {SummaryReportType} from './summary_report'; + +import type {SearchResult, Result} from './invite'; + +const MAX_WIDTH_CONTENT = 480; + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + container: { + display: 'flex', + flex: 1, + }, + summary: { + display: 'flex', + flex: 1, + }, + summaryContainer: { + display: 'flex', + flexGrow: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'stretch', + marginTop: 20, + marginHorizontal: 20, + paddingBottom: 20, + }, + summaryContent: { + flexGrow: 1, + flexDirection: 'column', + justifyContent: 'center', + maxWidth: MAX_WIDTH_CONTENT, + }, + summarySvg: { + marginBottom: 20, + alignSelf: 'center', + }, + summaryMessageText: { + color: theme.centerChannelColor, + ...typography('Heading', 700, 'SemiBold'), + textAlign: 'center', + marginHorizontal: 32, + marginBottom: 24, + }, + summaryErrorText: { + color: changeOpacity(theme.centerChannelColor, 0.72), + ...typography('Body', 200, 'Regular'), + textAlign: 'center', + }, + footer: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + borderTopWidth: 1, + borderTopColor: changeOpacity(theme.centerChannelColor, 0.16), + padding: 20, + }, + summaryButtonContainer: { + flexGrow: 1, + flexDirection: 'row', + justifyContent: 'center', + }, + summaryButtonTextContainer: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + height: 24, + }, + summaryButtonIcon: { + marginRight: 7, + color: theme.buttonColor, + + }, + }; +}); + +enum SummaryButtonType { + DONE = 'done', + RETRY = 'retry', + BACK = 'back', +} + +type SummaryProps = { + result: Result; + selectedIds: {[id: string]: SearchResult}; + error?: string; + testID: string; + onClose: () => void; + onRetry: () => void; + onBack: () => void; +} + +export default function Summary({ + result, + selectedIds, + error, + testID, + onClose, + onRetry, + onBack, +}: SummaryProps) { + const {formatMessage, locale} = useIntl(); + const theme = useTheme(); + const styles = getStyleSheet(theme); + + const {sent, notSent} = result; + const sentCount = sent.length; + const notSentCount = notSent.length; + + const styleSummaryMessageText = useMemo(() => { + const style = []; + + style.push(styles.summaryMessageText); + + if (error) { + style.push({marginBottom: 8}); + } + + return style; + }, [error, styles]); + + let svg = <>; + let message = ''; + + if (error) { + svg = ; + message = formatMessage( + { + id: 'invite.summary.error', + defaultMessage: '{invitationsCount, plural, one {Invitation} other {Invitations}} could not be sent successfully', + }, + {invitationsCount: sentCount + notSentCount}, + ); + } else if (!sentCount && notSentCount) { + svg = ; + message = formatMessage( + { + id: 'invite.summary.not_sent', + defaultMessage: '{notSentCount, plural, one {Invitation wasn’t} other {Invitations weren’t}} sent', + }, + {notSentCount}, + ); + } else if (sentCount && !notSentCount) { + svg = ; + message = formatMessage( + { + id: 'invite.summary.sent', + defaultMessage: 'Your {sentCount, plural, one {invitation has} other {invitations have}} been sent', + }, + {sentCount}, + ); + } else if (sentCount && notSentCount) { + svg = ; + message = formatMessage( + { + id: 'invite.summary.some_not_sent', + defaultMessage: '{notSentCount, plural, one {An invitation was} other {Some invitations were}} not sent', + }, + {notSentCount}, + ); + } + + const renderButton = useCallback((type: SummaryButtonType) => { + let onPress; + let iconName = ''; + let text; + let styleButtonText = buttonTextStyle(theme, 'lg', 'primary'); + let styleButtonBackground = buttonBackgroundStyle(theme, 'lg', 'primary'); + const styleButtonIcon = []; + styleButtonIcon.push(styles.summaryButtonIcon); + + switch (type) { + case SummaryButtonType.BACK: + onPress = onBack; + iconName = 'chevron-left'; + text = { + id: t('invite.summary.back'), + defaultMessage: 'Go back', + }; + styleButtonText = buttonTextStyle(theme, 'lg', 'tertiary'); + styleButtonBackground = [buttonBackgroundStyle(theme, 'lg', 'tertiary'), {marginRight: 8}]; + styleButtonIcon.push({color: theme.buttonBg}); + break; + case SummaryButtonType.RETRY: + onPress = onRetry; + iconName = 'refresh'; + text = { + id: t('invite.summary.try_again'), + defaultMessage: 'Try again', + }; + break; + case SummaryButtonType.DONE: + default: + onPress = onClose; + text = { + id: t('invite.summary.done'), + defaultMessage: 'Done', + }; + break; + } + + return ( + + ); + }, [theme, locale, onClose, onRetry, onBack]); + + return ( + + + + + {svg} + + + {message} + + {error ? ( + + {error} + + ) : ( + <> + {notSent.length > 0 && ( + + )} + {sent.length > 0 && ( + + )} + + )} + + + + + {error ? ( + <> + {renderButton(SummaryButtonType.BACK)} + {renderButton(SummaryButtonType.RETRY)} + + ) : ( + renderButton(SummaryButtonType.DONE) + )} + + + + ); +} diff --git a/app/screens/invite/summary_report.tsx b/app/screens/invite/summary_report.tsx new file mode 100644 index 0000000000..874e002678 --- /dev/null +++ b/app/screens/invite/summary_report.tsx @@ -0,0 +1,150 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {useIntl} from 'react-intl'; +import {View, Text} from 'react-native'; + +import CompassIcon from '@components/compass_icon'; +import UserItem from '@components/user_item'; +import {useTheme} from '@context/theme'; +import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; +import {typography} from '@utils/typography'; + +import TextItem, {TextItemType} from './text_item'; + +import type {SearchResult, InviteResult} from './invite'; + +const COLOR_SUCCESS = '#3db887'; +const COLOR_ERROR = '#d24b4e'; + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + container: { + display: 'flex', + flexDirection: 'column', + borderWidth: 1, + borderColor: changeOpacity(theme.centerChannelColor, 0.16), + borderRadius: 4, + marginBottom: 16, + paddingVertical: 8, + }, + title: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: 20, + paddingVertical: 12, + }, + titleText: { + marginLeft: 12, + ...typography('Heading', 300, 'SemiBold'), + color: theme.centerChannelColor, + }, + item: { + display: 'flex', + flexDirection: 'column', + paddingVertical: 12, + }, + user: { + paddingTop: 0, + paddingBottom: 0, + height: 'auto', + }, + reason: { + paddingLeft: 56, + paddingRight: 20, + ...typography('Body', 75, 'Regular'), + color: changeOpacity(theme.centerChannelColor, 0.64), + }, + }; +}); + +export enum SummaryReportType { + SENT = 'sent', + NOT_SENT = 'not_sent', +} + +type SummaryReportProps = { + type: SummaryReportType; + invites: InviteResult[]; + selectedIds: {[id: string]: SearchResult}; + testID: string; +} + +export default function SummaryReport({ + type, + invites, + selectedIds, + testID, +}: SummaryReportProps) { + const {formatMessage} = useIntl(); + const theme = useTheme(); + const styles = getStyleSheet(theme); + + const count = invites.length; + + const sent = type === SummaryReportType.SENT; + const message = sent ? ( + formatMessage( + { + id: 'invite.summary.report.sent', + defaultMessage: '{count} successful {count, plural, one {invitation} other {invitations}}', + }, + {count}, + ) + ) : ( + formatMessage( + { + id: 'invite.summary.report.notSent', + defaultMessage: '{count} {count, plural, one {invitation} other {invitations}} not sent', + }, + {count}, + ) + ); + + return ( + + + + + {message} + + + {invites.map(({userId, reason}) => { + const item = selectedIds[userId]; + + return ( + + {typeof item === 'string' ? ( + + ) : ( + + )} + + {reason} + + + ); + })} + + ); +} diff --git a/app/screens/invite/text_item.tsx b/app/screens/invite/text_item.tsx new file mode 100644 index 0000000000..9a14e3ae1c --- /dev/null +++ b/app/screens/invite/text_item.tsx @@ -0,0 +1,111 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {useIntl} from 'react-intl'; +import {View, Text} from 'react-native'; + +import CompassIcon from '@components/compass_icon'; +import {useTheme} from '@context/theme'; +import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme'; +import {typography} from '@utils/typography'; + +const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { + return { + item: { + paddingHorizontal: 20, + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }, + search: { + height: 40, + paddingVertical: 8, + paddingHorizontal: 16, + }, + itemText: { + display: 'flex', + ...typography('Body', 200, 'Regular'), + color: theme.centerChannelColor, + }, + itemTerm: { + display: 'flex', + ...typography('Body', 200, 'SemiBold'), + color: theme.centerChannelColor, + marginLeft: 4, + }, + itemImage: { + alignItems: 'center', + justifyContent: 'center', + height: 24, + width: 24, + borderRadius: 12, + backgroundColor: changeOpacity(theme.centerChannelColor, 0.08), + marginRight: 12, + }, + itemIcon: { + color: changeOpacity(theme.centerChannelColor, 0.56), + }, + }; +}); + +export enum TextItemType { + SEARCH_INVITE = 'search_invite', + SEARCH_NO_RESULTS = 'search_no_results', + SUMMARY = 'summary', +} + +type TextItemProps = { + text?: string; + type: TextItemType; + testID: string; +} + +export default function TextItem({ + text = '', + type, + testID, +}: TextItemProps) { + const {formatMessage} = useIntl(); + const theme = useTheme(); + const styles = getStyleSheet(theme); + + const search = type === TextItemType.SEARCH_INVITE || type === TextItemType.SEARCH_NO_RESULTS; + const email = type === TextItemType.SEARCH_INVITE || type === TextItemType.SUMMARY; + + return ( + + {email && ( + + + ) + } + {search && ( + + {email ? ( + formatMessage({id: 'invite.search.email_invite', defaultMessage: 'invite'}) + ) : ( + formatMessage({id: 'invite.search.no_results', defaultMessage: 'No one found matching'}) + )} + + )} + + {text} + + + ); +} diff --git a/app/screens/join_team/index.ts b/app/screens/join_team/index.ts index 46b52cdea8..8303c5db6a 100644 --- a/app/screens/join_team/index.ts +++ b/app/screens/join_team/index.ts @@ -7,11 +7,11 @@ import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; import {queryMyTeams} from '@queries/servers/team'; -import MyTeamModel from '@typings/database/models/servers/my_team'; import JoinTeam from './join_team'; import type {WithDatabaseArgs} from '@typings/database/database'; +import type MyTeamModel from '@typings/database/models/servers/my_team'; const membershipsToIdSet = (mm: MyTeamModel[]) => { return new Set(mm.map((m) => m.id)); diff --git a/app/screens/join_team/join_team.tsx b/app/screens/join_team/join_team.tsx index 68e804957a..b2752b35d3 100644 --- a/app/screens/join_team/join_team.tsx +++ b/app/screens/join_team/join_team.tsx @@ -12,6 +12,7 @@ import Loading from '@components/loading'; import TeamList from '@components/team_list'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {dismissModal} from '@screens/navigation'; import {logDebug} from '@utils/log'; @@ -19,11 +20,14 @@ import {alertTeamAddError} from '@utils/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { joinedIds: Set; - componentId: string; + componentId: AvailableScreens; closeButtonId: string; } + const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ container: { paddingHorizontal: 10, @@ -111,6 +115,7 @@ export default function JoinTeam({ }, [componentId]); useNavButtonPressed(closeButtonId, componentId, onClosePressed, []); + useAndroidHardwareBackHandler(componentId, onClosePressed); const hasOtherTeams = Boolean(otherTeams.length); diff --git a/app/screens/latex/index.tsx b/app/screens/latex/index.tsx index 8205a59a5c..aeaa280020 100644 --- a/app/screens/latex/index.tsx +++ b/app/screens/latex/index.tsx @@ -7,11 +7,16 @@ import MathView from 'react-native-math-view'; import {SafeAreaView, Edge} from 'react-native-safe-area-context'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import {popTopScreen} from '@screens/navigation'; import {splitLatexCodeInLines} from '@utils/markdown/latex'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { + componentId: AvailableScreens; content: string; } @@ -53,7 +58,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }; }); -const Latex = ({content}: Props) => { +const Latex = ({componentId, content}: Props) => { const theme = useTheme(); const style = getStyleSheet(theme); const lines = splitLatexCodeInLines(content); @@ -66,6 +71,10 @@ const Latex = ({content}: Props) => { return {'Render error: ' + error.message}; }; + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + return ( ; diff --git a/app/screens/login/index.tsx b/app/screens/login/index.tsx index 2bfea2686d..c40c65af97 100644 --- a/app/screens/login/index.tsx +++ b/app/screens/login/index.tsx @@ -10,10 +10,12 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import FormattedText from '@components/formatted_text'; import {Screens} from '@constants'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useIsTablet} from '@hooks/device'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import NetworkManager from '@managers/network_manager'; import Background from '@screens/background'; -import {dismissModal, goToScreen, loginAnimationOptions} from '@screens/navigation'; +import {dismissModal, goToScreen, loginAnimationOptions, popTopScreen} from '@screens/navigation'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; @@ -23,10 +25,11 @@ import LoginOptionsSeparator from './login_options_separator'; import SsoOptions from './sso_options'; import type {LaunchProps} from '@typings/launch'; +import type {AvailableScreens} from '@typings/screens/navigation'; export interface LoginOptionsProps extends LaunchProps { closeButtonId?: string; - componentId: string; + componentId: AvailableScreens; config: ClientConfig; hasLoginForm: boolean; license: ClientLicense; @@ -132,6 +135,14 @@ const LoginOptions = ({ }; }, []); + const dismiss = () => { + dismissModal({componentId}); + }; + + const pop = () => { + popTopScreen(componentId); + }; + useEffect(() => { const navigationEvents = Navigation.events().registerNavigationButtonPressedListener(({buttonId}) => { if (closeButtonId && buttonId === closeButtonId) { @@ -161,6 +172,9 @@ const LoginOptions = ({ return () => unsubscribe.remove(); }, [dimensions]); + useNavButtonPressed(closeButtonId || '', componentId, dismiss, []); + useAndroidHardwareBackHandler(componentId, pop); + let additionalContainerStyle; if (numberSSOs < 3 || !hasLoginForm || (isTablet && dimensions.height > dimensions.width)) { additionalContainerStyle = styles.flex; diff --git a/app/screens/mfa/index.tsx b/app/screens/mfa/index.tsx index e612d73885..d2f8edefd9 100644 --- a/app/screens/mfa/index.tsx +++ b/app/screens/mfa/index.tsx @@ -15,11 +15,11 @@ import ClientError from '@client/rest/error'; import FloatingTextInput from '@components/floating_text_input_label'; import FormattedText from '@components/formatted_text'; import Loading from '@components/loading'; -import {Screens} from '@constants'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useIsTablet} from '@hooks/device'; import {t} from '@i18n'; import Background from '@screens/background'; -import {resetToTeams} from '@screens/navigation'; +import {popTopScreen, resetToTeams} from '@screens/navigation'; import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -27,7 +27,10 @@ import {typography} from '@utils/typography'; import Shield from './mfa.svg'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type MFAProps = { + componentId: AvailableScreens; config: Partial; goToHome: (time: number, error?: never) => void; license: Partial; @@ -93,7 +96,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ const AnimatedSafeArea = Animated.createAnimatedComponent(SafeAreaView); -const MFA = ({config, goToHome, license, loginId, password, serverDisplayName, serverUrl, theme}: MFAProps) => { +const MFA = ({componentId, config, goToHome, license, loginId, password, serverDisplayName, serverUrl, theme}: MFAProps) => { const dimensions = useWindowDimensions(); const translateX = useSharedValue(dimensions.width); const isTablet = useIsTablet(); @@ -176,11 +179,19 @@ const MFA = ({config, goToHome, license, loginId, password, serverDisplayName, s translateX.value = -dimensions.width; }, }; - const unsubscribe = Navigation.events().registerComponentListener(listener, Screens.MFA); + const unsubscribe = Navigation.events().registerComponentListener(listener, componentId); return () => unsubscribe.remove(); }, [dimensions]); + useEffect(() => { + translateX.value = 0; + }, []); + + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + return ( diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index e3698876dc..ed23cffa2d 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -19,7 +19,7 @@ import {changeOpacity, setNavigatorStyles} from '@utils/theme'; import type {BottomSheetFooterProps} from '@gorhom/bottom-sheet'; import type {LaunchProps} from '@typings/launch'; -import type {NavButtons} from '@typings/screens/navigation'; +import type {AvailableScreens, NavButtons} from '@typings/screens/navigation'; const {MattermostManaged} = NativeModules; const isRunningInSplitView = MattermostManaged.isRunningInSplitView; @@ -67,7 +67,7 @@ function onCommandListener(name: string, params: any) { function onPoppedListener({componentId}: ScreenPoppedEvent) { // screen pop does not trigger registerCommandListener, but does trigger screenPoppedListener - NavigationStore.removeScreenFromStack(componentId); + NavigationStore.removeScreenFromStack(componentId as AvailableScreens); } function onScreenWillAppear(event: ComponentWillAppearEvent) { @@ -225,7 +225,7 @@ export function getThemeFromState(): Theme { // This is a temporary helper function to avoid // crashes when trying to load a screen that does // NOT exists, this should be removed for GA -function isScreenRegistered(screen: string) { +function isScreenRegistered(screen: AvailableScreens) { const notImplemented = NOT_READY.includes(screen) || !Object.values(Screens).includes(screen); if (notImplemented) { Alert.alert( @@ -425,7 +425,7 @@ export function resetToTeams() { }); } -export function goToScreen(name: string, title: string, passProps = {}, options = {}) { +export function goToScreen(name: AvailableScreens, title: string, passProps = {}, options = {}) { if (!isScreenRegistered(name)) { return ''; } @@ -475,7 +475,7 @@ export function goToScreen(name: string, title: string, passProps = {}, options }); } -export async function popTopScreen(screenId?: string) { +export async function popTopScreen(screenId?: AvailableScreens) { try { if (screenId) { await Navigation.pop(screenId); @@ -513,7 +513,7 @@ export async function dismissAllModalsAndPopToRoot() { * @param passProps Props to pass to the screen * @param options Navigation options */ -export async function dismissAllModalsAndPopToScreen(screenId: string, title: string, passProps = {}, options = {}) { +export async function dismissAllModalsAndPopToScreen(screenId: AvailableScreens, title: string, passProps = {}, options = {}) { await dismissAllModals(); if (NavigationStore.getScreensInStack().includes(screenId)) { let mergeOptions = options; @@ -539,7 +539,7 @@ export async function dismissAllModalsAndPopToScreen(screenId: string, title: st } } -export function showModal(name: string, title: string, passProps = {}, options: Options = {}) { +export function showModal(name: AvailableScreens, title: string, passProps = {}, options: Options = {}) { if (!isScreenRegistered(name)) { return; } @@ -591,7 +591,7 @@ export function showModal(name: string, title: string, passProps = {}, options: }); } -export function showModalOverCurrentContext(name: string, passProps = {}, options: Options = {}) { +export function showModalOverCurrentContext(name: AvailableScreens, passProps = {}, options: Options = {}) { const title = ''; let animations; switch (Platform.OS) { @@ -650,7 +650,7 @@ export function showModalOverCurrentContext(name: string, passProps = {}, option showModal(name, title, passProps, mergeOptions); } -export async function dismissModal(options?: Options & { componentId: string}) { +export async function dismissModal(options?: Options & { componentId: AvailableScreens}) { if (!NavigationStore.hasModalsOpened()) { return; } @@ -693,7 +693,7 @@ export const buildNavigationButton = (id: string, testID: string, icon?: ImageRe text, }); -export function setButtons(componentId: string, buttons: NavButtons = {leftButtons: [], rightButtons: []}) { +export function setButtons(componentId: AvailableScreens, buttons: NavButtons = {leftButtons: [], rightButtons: []}) { const options = { topBar: { ...buttons, @@ -703,7 +703,7 @@ export function setButtons(componentId: string, buttons: NavButtons = {leftButto mergeNavigationOptions(componentId, options); } -export function showOverlay(name: string, passProps = {}, options: Options = {}) { +export function showOverlay(name: AvailableScreens, passProps = {}, options: Options = {}) { if (!isScreenRegistered(name)) { return; } @@ -728,7 +728,7 @@ export function showOverlay(name: string, passProps = {}, options: Options = {}) }); } -export async function dismissOverlay(componentId: string) { +export async function dismissOverlay(componentId: AvailableScreens) { try { await Navigation.dismissOverlay(componentId); } catch (error) { @@ -769,7 +769,7 @@ export async function bottomSheet({title, renderContent, footerComponent, snapPo } } -export async function dismissBottomSheet(alternativeScreen = Screens.BOTTOM_SHEET) { +export async function dismissBottomSheet(alternativeScreen: AvailableScreens = Screens.BOTTOM_SHEET) { DeviceEventEmitter.emit(Events.CLOSE_BOTTOM_SHEET); await NavigationStore.waitUntilScreensIsRemoved(alternativeScreen); } @@ -777,7 +777,7 @@ export async function dismissBottomSheet(alternativeScreen = Screens.BOTTOM_SHEE type AsBottomSheetArgs = { closeButtonId: string; props?: Record; - screen: typeof Screens[keyof typeof Screens]; + screen: AvailableScreens; theme: Theme; title: string; } diff --git a/app/screens/onboarding/illustrations/calls.tsx b/app/screens/onboarding/illustrations/calls.tsx index 183a9ffc7b..56c532f511 100644 --- a/app/screens/onboarding/illustrations/calls.tsx +++ b/app/screens/onboarding/illustrations/calls.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React from 'react'; -import {StyleProp, ViewStyle} from 'react-native'; import Svg, { Ellipse, Path, @@ -10,6 +9,8 @@ import Svg, { G, } from 'react-native-svg'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { theme: Theme; styles: StyleProp; diff --git a/app/screens/onboarding/illustrations/chat.tsx b/app/screens/onboarding/illustrations/chat.tsx index 4126a79ae1..91f8b65b5a 100644 --- a/app/screens/onboarding/illustrations/chat.tsx +++ b/app/screens/onboarding/illustrations/chat.tsx @@ -2,13 +2,14 @@ // See LICENSE.txt for license information. import * as React from 'react'; -import {StyleProp, ViewStyle} from 'react-native'; import Svg, { G, Path, Ellipse, } from 'react-native-svg'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { theme: Theme; styles: StyleProp; diff --git a/app/screens/onboarding/illustrations/integrations.tsx b/app/screens/onboarding/illustrations/integrations.tsx index 17fad9ac7b..56c9c584bf 100644 --- a/app/screens/onboarding/illustrations/integrations.tsx +++ b/app/screens/onboarding/illustrations/integrations.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React from 'react'; -import {StyleProp, ViewStyle} from 'react-native'; import Svg, { Rect, Path, @@ -15,6 +14,8 @@ import Svg, { Stop, } from 'react-native-svg'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { theme: Theme; styles: StyleProp; diff --git a/app/screens/onboarding/illustrations/team_communication.tsx b/app/screens/onboarding/illustrations/team_communication.tsx index d5ec426c79..95edb40149 100644 --- a/app/screens/onboarding/illustrations/team_communication.tsx +++ b/app/screens/onboarding/illustrations/team_communication.tsx @@ -2,7 +2,6 @@ // See LICENSE.txt for license information. import React from 'react'; -import {StyleProp, ViewStyle} from 'react-native'; import Svg, { Ellipse, Path, @@ -10,6 +9,8 @@ import Svg, { G, } from 'react-native-svg'; +import type {StyleProp, ViewStyle} from 'react-native'; + type Props = { theme: Theme; styles: StyleProp; diff --git a/app/screens/onboarding/index.tsx b/app/screens/onboarding/index.tsx index 4aea8fab10..3010b4a687 100644 --- a/app/screens/onboarding/index.tsx +++ b/app/screens/onboarding/index.tsx @@ -11,6 +11,7 @@ import { Platform, NativeSyntheticEvent, NativeScrollEvent, + BackHandler, } from 'react-native'; import {Navigation} from 'react-native-navigation'; import Animated, {useAnimatedStyle, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated'; @@ -111,6 +112,19 @@ const Onboarding = ({ }; }, []); + useEffect(() => { + const listener = BackHandler.addEventListener('hardwareBackPress', () => { + if (!currentIndex.value) { + return false; + } + + moveToSlide(currentIndex.value - 1); + return true; + }); + + return () => listener.remove(); + }, []); + return ( { diff --git a/app/screens/post_options/options/delete_post_option.tsx b/app/screens/post_options/options/delete_post_option.tsx index 6ef2e478db..08fc88fa8f 100644 --- a/app/screens/post_options/options/delete_post_option.tsx +++ b/app/screens/post_options/options/delete_post_option.tsx @@ -7,15 +7,15 @@ import {Alert} from 'react-native'; import {deletePost} from '@actions/remote/post'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; combinedPost?: Post | PostModel; post: PostModel; } diff --git a/app/screens/post_options/options/edit_option.tsx b/app/screens/post_options/options/edit_option.tsx index d444d10d94..d7ff22c1c2 100644 --- a/app/screens/post_options/options/edit_option.tsx +++ b/app/screens/post_options/options/edit_option.tsx @@ -12,9 +12,10 @@ import {t} from '@i18n'; import {dismissBottomSheet, showModal} from '@screens/navigation'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; post: PostModel; canDelete: boolean; } diff --git a/app/screens/post_options/options/mark_unread_option/mark_unread_option.tsx b/app/screens/post_options/options/mark_unread_option/mark_unread_option.tsx index 79b2573c96..caa0ac6cbd 100644 --- a/app/screens/post_options/options/mark_unread_option/mark_unread_option.tsx +++ b/app/screens/post_options/options/mark_unread_option/mark_unread_option.tsx @@ -12,11 +12,12 @@ import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; isCRTEnabled: boolean; - sourceScreen: typeof Screens[keyof typeof Screens]; + sourceScreen: AvailableScreens; post: PostModel; teamId: string; } diff --git a/app/screens/post_options/options/pin_channel_option.tsx b/app/screens/post_options/options/pin_channel_option.tsx index 1ffb873f9c..b62d495c16 100644 --- a/app/screens/post_options/options/pin_channel_option.tsx +++ b/app/screens/post_options/options/pin_channel_option.tsx @@ -5,13 +5,14 @@ import React, {useCallback} from 'react'; import {togglePinPost} from '@actions/remote/post'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type PinChannelProps = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; isPostPinned: boolean; postId: string; } diff --git a/app/screens/post_options/post_options.tsx b/app/screens/post_options/post_options.tsx index bc4572a1d9..e94c3315d3 100644 --- a/app/screens/post_options/post_options.tsx +++ b/app/screens/post_options/post_options.tsx @@ -28,6 +28,7 @@ import ReactionBar from './reaction_bar'; import type PostModel from '@typings/database/models/servers/post'; import type ThreadModel from '@typings/database/models/servers/thread'; +import type {AvailableScreens} from '@typings/screens/navigation'; const POST_OPTIONS_BUTTON = 'close-post-options'; @@ -40,10 +41,10 @@ type PostOptionsProps = { canReply: boolean; combinedPost?: Post | PostModel; isSaved: boolean; - sourceScreen: typeof Screens[keyof typeof Screens]; + sourceScreen: AvailableScreens; post: PostModel; thread?: ThreadModel; - componentId: string; + componentId: AvailableScreens; bindings: AppBinding[]; serverUrl: string; }; diff --git a/app/screens/post_options/reaction_bar/reaction_bar.tsx b/app/screens/post_options/reaction_bar/reaction_bar.tsx index 00663fea6f..93a25af9af 100644 --- a/app/screens/post_options/reaction_bar/reaction_bar.tsx +++ b/app/screens/post_options/reaction_bar/reaction_bar.tsx @@ -24,8 +24,10 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; import PickReaction from './pick_reaction'; import Reaction from './reaction'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type QuickReactionProps = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; recentEmojis: string[]; postId: string; }; diff --git a/app/screens/review_app/index.tsx b/app/screens/review_app/index.tsx index 9013cd8ed4..b8e5176674 100644 --- a/app/screens/review_app/index.tsx +++ b/app/screens/review_app/index.tsx @@ -13,14 +13,17 @@ import CompassIcon from '@components/compass_icon'; import ReviewAppIllustration from '@components/illustrations/review_app'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useBackNavigation from '@hooks/navigate_back'; import {dismissOverlay, showShareFeedbackOverlay} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { hasAskedBefore: boolean; - componentId: string; + componentId: AvailableScreens; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -151,6 +154,7 @@ const ReviewApp = ({ }, [close, componentId]); useBackNavigation(onPressClose); + useAndroidHardwareBackHandler(componentId, onPressClose); const doAfterAnimation = useCallback(() => { executeAfterDone.current(); diff --git a/app/screens/server/form.tsx b/app/screens/server/form.tsx index faed9cef4d..28b1865c61 100644 --- a/app/screens/server/form.tsx +++ b/app/screens/server/form.tsx @@ -5,7 +5,6 @@ import React, {MutableRefObject, useCallback, useEffect, useRef} from 'react'; import {useIntl} from 'react-intl'; import {Keyboard, Platform, useWindowDimensions, View} from 'react-native'; import Button from 'react-native-button'; -import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import FloatingTextInput, {FloatingTextInputRef} from '@components/floating_text_input_label'; import FormattedText from '@components/formatted_text'; @@ -16,6 +15,8 @@ import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; + type Props = { autoFocus?: boolean; buttonDisabled: boolean; diff --git a/app/screens/server/index.tsx b/app/screens/server/index.tsx index c45feab09c..9183aa6a17 100644 --- a/app/screens/server/index.tsx +++ b/app/screens/server/index.tsx @@ -4,7 +4,7 @@ import {useManagedConfig} from '@mattermost/react-native-emm'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {Alert, Platform, useWindowDimensions, View} from 'react-native'; +import {Alert, BackHandler, Platform, useWindowDimensions, View} from 'react-native'; import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import {Navigation} from 'react-native-navigation'; import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; @@ -13,15 +13,15 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import {doPing} from '@actions/remote/general'; import {fetchConfigAndLicense} from '@actions/remote/systems'; import LocalConfig from '@assets/config.json'; -import ClientError from '@client/rest/error'; import AppVersion from '@components/app_version'; import {Screens, Launch} from '@constants'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import {t} from '@i18n'; import PushNotifications from '@init/push_notifications'; import NetworkManager from '@managers/network_manager'; import {getServerByDisplayName, getServerByIdentifier} from '@queries/app/servers'; import Background from '@screens/background'; -import {dismissModal, goToScreen, loginAnimationOptions} from '@screens/navigation'; +import {dismissModal, goToScreen, loginAnimationOptions, popTopScreen} from '@screens/navigation'; import {getErrorMessage} from '@utils/client_error'; import {canReceiveNotifications} from '@utils/push_proxy'; import {loginOptions} from '@utils/server'; @@ -31,12 +31,14 @@ import {getServerUrlAfterRedirect, isValidUrl, sanitizeUrl} from '@utils/url'; import ServerForm from './form'; import ServerHeader from './header'; +import type ClientError from '@client/rest/error'; import type {DeepLinkWithData, LaunchProps} from '@typings/launch'; +import type {AvailableScreens} from '@typings/screens/navigation'; interface ServerProps extends LaunchProps { animated?: boolean; closeButtonId?: string; - componentId: string; + componentId: AvailableScreens; isModal?: boolean; theme: Theme; } @@ -92,6 +94,11 @@ const Server = ({ const disableServerUrl = Boolean(managedConfig?.allowOtherServers === 'false' && managedConfig?.serverUrl); const additionalServer = launchType === Launch.AddServerFromDeepLink || launchType === Launch.AddServer; + const dismiss = () => { + NetworkManager.invalidateClient(url); + dismissModal({componentId}); + }; + useEffect(() => { let serverName: string | undefined = defaultDisplayName || managedConfig?.serverName || LocalConfig.DefaultServerName; let serverUrl: string | undefined = defaultServerUrl || managedConfig?.serverUrl || LocalConfig.DefaultServerUrl; @@ -157,18 +164,26 @@ const Server = ({ }, [componentId, url, dimensions]); useEffect(() => { - const navigationEvents = Navigation.events().registerNavigationButtonPressedListener(({buttonId}) => { - if (closeButtonId && buttonId === closeButtonId) { - NetworkManager.invalidateClient(url); - dismissModal({componentId}); + const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { + if (LocalConfig.ShowOnboarding && animated) { + popTopScreen(Screens.SERVER); + return true; } + if (isModal) { + dismiss(); + return true; + } + + return false; }); PushNotifications.registerIfNeeded(); - return () => navigationEvents.remove(); + return () => backHandler.remove(); }, []); + useNavButtonPressed(closeButtonId || '', componentId, dismiss, []); + const displayLogin = (serverUrl: string, config: ClientConfig, license: ClientLicense) => { const {enabledSSOs, hasLoginForm, numberSSOs, ssoOptions} = loginOptions(config, license); const passProps = { diff --git a/app/screens/settings/about/about.tsx b/app/screens/settings/about/about.tsx index 4f46840b48..e9554a68fb 100644 --- a/app/screens/settings/about/about.tsx +++ b/app/screens/settings/about/about.tsx @@ -11,7 +11,9 @@ import CompassIcon from '@components/compass_icon'; import FormattedText from '@components/formatted_text'; import AboutLinks from '@constants/about_links'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {t} from '@i18n'; +import {popTopScreen} from '@screens/navigation'; import SettingContainer from '@screens/settings/setting_container'; import SettingSeparator from '@screens/settings/settings_separator'; import {preventDoubleTap} from '@utils/tap'; @@ -24,6 +26,8 @@ import Subtitle from './subtitle'; import Title from './title'; import TosPrivacyContainer from './tos_privacy'; +import type {AvailableScreens} from '@typings/screens/navigation'; + const MATTERMOST_BUNDLE_IDS = ['com.mattermost.rnbeta', 'com.mattermost.rn']; const getStyleSheet = makeStyleSheetFromTheme((theme) => { @@ -92,10 +96,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }); type AboutProps = { + componentId: AvailableScreens; config: ClientConfig; license: ClientLicense; } -const About = ({config, license}: AboutProps) => { +const About = ({componentId, config, license}: AboutProps) => { const intl = useIntl(); const theme = useTheme(); const styles = getStyleSheet(theme); @@ -162,6 +167,10 @@ const About = ({config, license}: AboutProps) => { }; }, [config]); + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + return ( diff --git a/app/screens/settings/advanced/index.tsx b/app/screens/settings/advanced/index.tsx index 8a9a1a0d99..af67f829e4 100644 --- a/app/screens/settings/advanced/index.tsx +++ b/app/screens/settings/advanced/index.tsx @@ -17,6 +17,7 @@ import {makeStyleSheetFromTheme} from '@utils/theme'; import SettingContainer from '../setting_container'; import SettingOption from '../setting_option'; +import type {AvailableScreens} from '@typings/screens/navigation'; import type {ReadDirItem} from 'react-native-fs'; const getStyleSheet = makeStyleSheetFromTheme((theme) => { @@ -31,7 +32,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { const EMPTY_FILES: ReadDirItem[] = []; type AdvancedSettingsProps = { - componentId: string; + componentId: AvailableScreens; }; const AdvancedSettings = ({componentId}: AdvancedSettingsProps) => { const theme = useTheme(); diff --git a/app/screens/settings/config.ts b/app/screens/settings/config.ts index 84d477468c..9e65b269c5 100644 --- a/app/screens/settings/config.ts +++ b/app/screens/settings/config.ts @@ -5,6 +5,7 @@ import {t} from '@i18n'; import {goToScreen} from '@screens/navigation'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; import type {IntlShape} from 'react-intl'; export const getSaveButton = (buttonId: string, intl: IntlShape, color: string) => ({ @@ -17,7 +18,7 @@ export const getSaveButton = (buttonId: string, intl: IntlShape, color: string) ...typography('Body', 100, 'SemiBold'), }); -export const gotoSettingsScreen = (screen: string, title: string) => { +export const gotoSettingsScreen = (screen: AvailableScreens, title: string) => { const passProps = {}; const options = { topBar: { diff --git a/app/screens/settings/display/display.tsx b/app/screens/settings/display/display.tsx index b6b5d9a45a..d957c521cc 100644 --- a/app/screens/settings/display/display.tsx +++ b/app/screens/settings/display/display.tsx @@ -6,8 +6,9 @@ import {useIntl} from 'react-intl'; import {Screens} from '@constants'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {t} from '@i18n'; -import {goToScreen} from '@screens/navigation'; +import {goToScreen, popTopScreen} from '@screens/navigation'; import {gotoSettingsScreen} from '@screens/settings/config'; import {preventDoubleTap} from '@utils/tap'; import {getUserTimezoneProps} from '@utils/user'; @@ -16,6 +17,7 @@ import SettingContainer from '../setting_container'; import SettingItem from '../setting_item'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; const TIME_FORMAT = [ { @@ -40,12 +42,13 @@ const TIMEZONE_FORMAT = [ ]; type DisplayProps = { + componentId: AvailableScreens; currentUser: UserModel; hasMilitaryTimeFormat: boolean; isThemeSwitchingEnabled: boolean; isTimezoneEnabled: boolean; } -const Display = ({currentUser, hasMilitaryTimeFormat, isThemeSwitchingEnabled, isTimezoneEnabled}: DisplayProps) => { +const Display = ({componentId, currentUser, hasMilitaryTimeFormat, isThemeSwitchingEnabled, isTimezoneEnabled}: DisplayProps) => { const intl = useIntl(); const theme = useTheme(); const timezone = useMemo(() => getUserTimezoneProps(currentUser), [currentUser.timezone]); @@ -68,6 +71,10 @@ const Display = ({currentUser, hasMilitaryTimeFormat, isThemeSwitchingEnabled, i gotoSettingsScreen(screen, title); }); + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + return ( {isThemeSwitchingEnabled && ( diff --git a/app/screens/settings/display_clock/display_clock.tsx b/app/screens/settings/display_clock/display_clock.tsx index 71b195e651..812510b07b 100644 --- a/app/screens/settings/display_clock/display_clock.tsx +++ b/app/screens/settings/display_clock/display_clock.tsx @@ -16,13 +16,15 @@ import SettingContainer from '../setting_container'; import SettingOption from '../setting_option'; import SettingSeparator from '../settings_separator'; +import type {AvailableScreens} from '@typings/screens/navigation'; + const CLOCK_TYPE = { NORMAL: 'NORMAL', MILITARY: 'MILITARY', } as const; type DisplayClockProps = { - componentId: string; + componentId: AvailableScreens; currentUserId: string; hasMilitaryTimeFormat: boolean; } diff --git a/app/screens/settings/display_theme/display_theme.tsx b/app/screens/settings/display_theme/display_theme.tsx index 7af4775e77..e5de3ec359 100644 --- a/app/screens/settings/display_theme/display_theme.tsx +++ b/app/screens/settings/display_theme/display_theme.tsx @@ -15,9 +15,11 @@ import SettingContainer from '../setting_container'; import CustomTheme from './custom_theme'; import {ThemeTiles} from './theme_tiles'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type DisplayThemeProps = { allowedThemeKeys: string[]; - componentId: string; + componentId: AvailableScreens; currentTeamId: string; currentUserId: string; } diff --git a/app/screens/settings/display_timezone/display_timezone.tsx b/app/screens/settings/display_timezone/display_timezone.tsx index bd45432655..9e8e0b4983 100644 --- a/app/screens/settings/display_timezone/display_timezone.tsx +++ b/app/screens/settings/display_timezone/display_timezone.tsx @@ -19,10 +19,11 @@ import SettingOption from '../setting_option'; import SettingSeparator from '../settings_separator'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; type DisplayTimezoneProps = { currentUser: UserModel; - componentId: string; + componentId: AvailableScreens; } const DisplayTimezone = ({currentUser, componentId}: DisplayTimezoneProps) => { const intl = useIntl(); diff --git a/app/screens/settings/display_timezone_select/index.tsx b/app/screens/settings/display_timezone_select/index.tsx index 10edbded25..967fb54b2a 100644 --- a/app/screens/settings/display_timezone_select/index.tsx +++ b/app/screens/settings/display_timezone_select/index.tsx @@ -18,6 +18,8 @@ import {getTimezoneRegion} from '@utils/user'; import TimezoneRow from './timezone_row'; +import type {AvailableScreens} from '@typings/screens/navigation'; + const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { flexGrow: { @@ -54,7 +56,7 @@ const getItemLayout = (_data: string[], index: number) => ({ }); type SelectTimezonesProps = { - componentId: string; + componentId: AvailableScreens; onBack: (tz: string) => void; currentTimezone: string; } diff --git a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx index aff5d93b80..157c58f045 100644 --- a/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx +++ b/app/screens/settings/notification_auto_responder/notification_auto_responder.tsx @@ -23,6 +23,7 @@ import SettingOption from '../setting_option'; import SettingSeparator from '../settings_separator'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; const label = { id: t('notification_settings.auto_responder.message'), @@ -57,7 +58,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }); type NotificationAutoResponderProps = { - componentId: string; + componentId: AvailableScreens; currentUser: UserModel; } const NotificationAutoResponder = ({currentUser, componentId}: NotificationAutoResponderProps) => { diff --git a/app/screens/settings/notification_email/notification_email.tsx b/app/screens/settings/notification_email/notification_email.tsx index a94de6655f..c88e12c118 100644 --- a/app/screens/settings/notification_email/notification_email.tsx +++ b/app/screens/settings/notification_email/notification_email.tsx @@ -24,6 +24,7 @@ import SettingOption from '../setting_option'; import SettingSeparator from '../settings_separator'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { @@ -54,7 +55,7 @@ const emailFooterCRTText = { }; type NotificationEmailProps = { - componentId: string; + componentId: AvailableScreens; currentUser: UserModel; emailInterval: string; enableEmailBatching: boolean; diff --git a/app/screens/settings/notification_mention/mention_settings.tsx b/app/screens/settings/notification_mention/mention_settings.tsx index 03b7316d20..90885d8bce 100644 --- a/app/screens/settings/notification_mention/mention_settings.tsx +++ b/app/screens/settings/notification_mention/mention_settings.tsx @@ -23,6 +23,7 @@ import SettingOption from '../setting_option'; import SettingSeparator from '../settings_separator'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; const mentionHeaderText = { id: t('notification_settings.mentions.keywords_mention'), @@ -72,7 +73,7 @@ const getMentionProps = (currentUser: UserModel) => { }; type MentionSectionProps = { - componentId: string; + componentId: AvailableScreens; currentUser: UserModel; isCRTEnabled: boolean; } diff --git a/app/screens/settings/notification_mention/notification_mention.tsx b/app/screens/settings/notification_mention/notification_mention.tsx index 2642522b93..45a362775a 100644 --- a/app/screens/settings/notification_mention/notification_mention.tsx +++ b/app/screens/settings/notification_mention/notification_mention.tsx @@ -8,9 +8,10 @@ import SettingContainer from '../setting_container'; import MentionSettings from './mention_settings'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; type NotificationMentionProps = { - componentId: string; + componentId: AvailableScreens; currentUser: UserModel; isCRTEnabled: boolean; } diff --git a/app/screens/settings/notification_push/notification_push.tsx b/app/screens/settings/notification_push/notification_push.tsx index 4075108b6a..02251b393a 100644 --- a/app/screens/settings/notification_push/notification_push.tsx +++ b/app/screens/settings/notification_push/notification_push.tsx @@ -19,9 +19,10 @@ import MobilePushStatus from './push_status'; import MobilePushThread from './push_thread'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; type NotificationMobileProps = { - componentId: string; + componentId: AvailableScreens; currentUser: UserModel; isCRTEnabled: boolean; sendPushNotifications: boolean; diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx index e7bbd92a4b..d687d9bd37 100644 --- a/app/screens/settings/notifications/notifications.tsx +++ b/app/screens/settings/notifications/notifications.tsx @@ -5,7 +5,9 @@ import React, {useCallback, useMemo} from 'react'; import {useIntl} from 'react-intl'; import {General, Screens} from '@constants'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {t} from '@i18n'; +import {popTopScreen} from '@screens/navigation'; import {gotoSettingsScreen} from '@screens/settings/config'; import {getEmailInterval, getEmailIntervalTexts, getNotificationProps} from '@utils/user'; @@ -13,6 +15,7 @@ import SettingContainer from '../setting_container'; import SettingItem from '../setting_item'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; const mentionTexts = { crtOn: { @@ -26,6 +29,7 @@ const mentionTexts = { }; type NotificationsProps = { + componentId: AvailableScreens; currentUser: UserModel; emailInterval: string; enableAutoResponder: boolean; @@ -34,6 +38,7 @@ type NotificationsProps = { sendEmailNotifications: boolean; } const Notifications = ({ + componentId, currentUser, emailInterval, enableAutoResponder, @@ -86,6 +91,10 @@ const Notifications = ({ gotoSettingsScreen(screen, title); }, []); + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + return ( { @@ -40,7 +42,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }); type SettingsProps = { - componentId: string; + componentId: AvailableScreens; helpLink: string; showHelp: boolean; siteName: string; @@ -75,7 +77,6 @@ const Settings = ({componentId, helpLink, showHelp, siteName}: SettingsProps) => }, []); useAndroidHardwareBackHandler(componentId, close); - useNavButtonPressed(CLOSE_BUTTON_ID, componentId, close, []); const goToNotifications = preventDoubleTap(() => { diff --git a/app/screens/share_feedback/index.tsx b/app/screens/share_feedback/index.tsx index 50269f4838..65a87f3e4c 100644 --- a/app/screens/share_feedback/index.tsx +++ b/app/screens/share_feedback/index.tsx @@ -12,13 +12,16 @@ import CompassIcon from '@components/compass_icon'; import ShareFeedbackIllustration from '@components/illustrations/share_feedback'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import useBackNavigation from '@hooks/navigate_back'; import {dismissOverlay} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { - componentId: string; + componentId: AvailableScreens; } const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -117,6 +120,7 @@ const ShareFeedback = ({ }, [close, componentId]); useBackNavigation(onPressNo); + useAndroidHardwareBackHandler(componentId, onPressNo); const doAfterAnimation = useCallback(() => { executeAfterDone.current(); diff --git a/app/screens/snack_bar/index.tsx b/app/screens/snack_bar/index.tsx index 9d28a2b6fa..ec218850b9 100644 --- a/app/screens/snack_bar/index.tsx +++ b/app/screens/snack_bar/index.tsx @@ -27,10 +27,21 @@ import {dismissOverlay} from '@screens/navigation'; import {makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; + +type SnackBarProps = { + componentId: AvailableScreens; + onAction?: () => void; + barType: keyof typeof SNACK_BAR_TYPE; + sourceScreen: AvailableScreens; +} + const SNACK_BAR_WIDTH = 96; const SNACK_BAR_HEIGHT = 56; const SNACK_BAR_BOTTOM_RATIO = 0.04; +const caseScreens: AvailableScreens[] = [Screens.PERMALINK, Screens.MENTIONS, Screens.SAVED_MESSAGES]; + const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { return { text: { @@ -70,13 +81,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => { }; }); -type SnackBarProps = { - componentId: string; - onAction?: () => void; - barType: keyof typeof SNACK_BAR_TYPE; - sourceScreen: typeof Screens[keyof typeof Screens]; -} - const SnackBar = ({barType, componentId, onAction, sourceScreen}: SnackBarProps) => { const [showSnackBar, setShowSnackBar] = useState(); const intl = useIntl(); @@ -115,7 +119,7 @@ const SnackBar = ({barType, componentId, onAction, sourceScreen}: SnackBarProps) width: (SNACK_BAR_WIDTH / 100) * diffWidth, }; break; - case [Screens.PERMALINK, Screens.MENTIONS, Screens.SAVED_MESSAGES].includes(sourceScreen): + case caseScreens.includes(sourceScreen): tabletStyle = { marginBottom: 0, marginLeft: 0, diff --git a/app/screens/sso/index.tsx b/app/screens/sso/index.tsx index 0718d53752..84e0338aeb 100644 --- a/app/screens/sso/index.tsx +++ b/app/screens/sso/index.tsx @@ -11,19 +11,22 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import {ssoLogin} from '@actions/remote/session'; import ClientError from '@client/rest/error'; import {Screens, Sso} from '@constants'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; import NetworkManager from '@managers/network_manager'; import Background from '@screens/background'; -import {dismissModal, resetToHome, resetToTeams} from '@screens/navigation'; +import {dismissModal, popTopScreen, resetToHome, resetToTeams} from '@screens/navigation'; import {logWarning} from '@utils/log'; import SSOWithRedirectURL from './sso_with_redirect_url'; import SSOWithWebView from './sso_with_webview'; import type {LaunchProps} from '@typings/launch'; +import type {AvailableScreens} from '@typings/screens/navigation'; interface SSOProps extends LaunchProps { closeButtonId?: string; - componentId: string; + componentId: AvailableScreens; config: Partial; license: Partial; ssoType: string; @@ -114,6 +117,13 @@ const SSO = ({ resetToHome({extra, launchError: hasError, launchType, serverUrl, time}); }; + const dismiss = () => { + if (serverUrl) { + NetworkManager.invalidateClient(serverUrl); + } + dismissModal({componentId}); + }; + const transform = useAnimatedStyle(() => { const duration = Platform.OS === 'android' ? 250 : 350; return { @@ -136,18 +146,19 @@ const SSO = ({ }, [dimensions]); useEffect(() => { - const navigationEvents = Navigation.events().registerNavigationButtonPressedListener(({buttonId}) => { - if (closeButtonId && buttonId === closeButtonId) { - if (serverUrl) { - NetworkManager.invalidateClient(serverUrl); - } - dismissModal({componentId}); - } - }); - - return () => navigationEvents.remove(); + translateX.value = 0; }, []); + useNavButtonPressed(closeButtonId || '', componentId, dismiss, []); + useAndroidHardwareBackHandler(componentId, () => { + if (closeButtonId) { + dismiss(); + return; + } + + popTopScreen(componentId); + }); + const props = { doSSOLogin, loginError, diff --git a/app/screens/sso/sso.test.tsx b/app/screens/sso/sso.test.tsx index 7fd6adaaaf..69ec1fd965 100644 --- a/app/screens/sso/sso.test.tsx +++ b/app/screens/sso/sso.test.tsx @@ -3,7 +3,7 @@ import React from 'react'; -import {Preferences} from '@constants'; +import {Preferences, Screens} from '@constants'; import LaunchType from '@constants/launch'; import {renderWithIntl} from '@test/intl-test-helper'; @@ -23,7 +23,7 @@ jest.mock('@utils/url', () => { describe('SSO', () => { const baseProps = { - componentId: 'SSO', + componentId: Screens.SSO, license: { IsLicensed: 'true', }, diff --git a/app/screens/sso/sso_with_webview.tsx b/app/screens/sso/sso_with_webview.tsx index 2f70cc7ab1..0a58643734 100644 --- a/app/screens/sso/sso_with_webview.tsx +++ b/app/screens/sso/sso_with_webview.tsx @@ -6,12 +6,6 @@ import React, {useEffect} from 'react'; import {useIntl} from 'react-intl'; import {Alert, Platform, Text, View} from 'react-native'; import {WebView} from 'react-native-webview'; -import { - WebViewErrorEvent, - WebViewMessageEvent, - WebViewNavigation, - WebViewNavigationEvent, -} from 'react-native-webview/lib/WebViewTypes'; import urlParse from 'url-parse'; import Loading from '@components/loading'; @@ -19,6 +13,13 @@ import {Sso} from '@constants'; import {popTopScreen} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import type { + WebViewErrorEvent, + WebViewMessageEvent, + WebViewNavigation, + WebViewNavigationEvent, +} from 'react-native-webview/lib/WebViewTypes'; + interface SSOWithWebViewProps { completeUrlPath: string; doSSOLogin: (bearerToken: string, csrfToken: string) => void; diff --git a/app/screens/table/index.tsx b/app/screens/table/index.tsx index 7b870a1058..5343d6d217 100644 --- a/app/screens/table/index.tsx +++ b/app/screens/table/index.tsx @@ -5,7 +5,13 @@ import React from 'react'; import {Platform, ScrollView, StyleSheet} from 'react-native'; import {SafeAreaView} from 'react-native-safe-area-context'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import {popTopScreen} from '@screens/navigation'; + +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { + componentId: AvailableScreens; renderAsFlex: boolean; renderRows: (isFullView: boolean) => JSX.Element|null; width: number; @@ -30,10 +36,14 @@ const styles = StyleSheet.create({ }, }); -const Table = ({renderAsFlex, renderRows, width}: Props) => { +const Table = ({componentId, renderAsFlex, renderRows, width}: Props) => { const content = renderRows(true); const viewStyle = renderAsFlex ? styles.displayFlex : {width}; + useAndroidHardwareBackHandler(componentId, () => { + popTopScreen(componentId); + }); + if (Platform.OS === 'android') { return ( diff --git a/app/screens/terms_of_service/terms_of_service.tsx b/app/screens/terms_of_service/terms_of_service.tsx index 09cfe737f2..be3360621a 100644 --- a/app/screens/terms_of_service/terms_of_service.tsx +++ b/app/screens/terms_of_service/terms_of_service.tsx @@ -26,10 +26,12 @@ import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import {typography} from '@utils/typography'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { siteName?: string; showToS: boolean; - componentId: string; + componentId: AvailableScreens; } const getStyleSheet = makeStyleSheetFromTheme((theme) => { diff --git a/app/screens/thread/thread.tsx b/app/screens/thread/thread.tsx index 148a9d05d2..4f91220736 100644 --- a/app/screens/thread/thread.tsx +++ b/app/screens/thread/thread.tsx @@ -3,7 +3,6 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {LayoutChangeEvent, StyleSheet, View} from 'react-native'; -import {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; import CurrentCallBar from '@calls/components/current_call_bar'; @@ -13,6 +12,7 @@ import PostDraft from '@components/post_draft'; import RoundedHeaderContext from '@components/rounded_header_context'; import {Screens} from '@constants'; import {THREAD_ACCESSORIES_CONTAINER_NATIVE_ID} from '@constants/post_draft'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; import {useAppState} from '@hooks/device'; import useDidUpdate from '@hooks/did_update'; import {useKeyboardTrackingPaused} from '@hooks/keyboard_tracking'; @@ -22,9 +22,11 @@ import EphemeralStore from '@store/ephemeral_store'; import ThreadPostList from './thread_post_list'; import type PostModel from '@typings/database/models/servers/post'; +import type {AvailableScreens} from '@typings/screens/navigation'; +import type {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view'; type ThreadProps = { - componentId: string; + componentId: AvailableScreens; rootPost?: PostModel; isInACall: boolean; }; @@ -42,7 +44,12 @@ const Thread = ({componentId, rootPost, isInACall}: ThreadProps) => { const [containerHeight, setContainerHeight] = useState(0); const rootId = rootPost?.id || ''; + const close = () => { + popTopScreen(componentId); + }; + useKeyboardTrackingPaused(postDraftRef, rootId, trackKeyboardForScreens); + useAndroidHardwareBackHandler(componentId, close); useEffect(() => { return () => { @@ -52,7 +59,7 @@ const Thread = ({componentId, rootPost, isInACall}: ThreadProps) => { useDidUpdate(() => { if (!rootPost) { - popTopScreen(componentId); + close(); } }, [componentId, rootPost]); diff --git a/app/screens/thread/thread_post_list/index.ts b/app/screens/thread/thread_post_list/index.ts index cdf3401fbd..81ecda79f7 100644 --- a/app/screens/thread/thread_post_list/index.ts +++ b/app/screens/thread/thread_post_list/index.ts @@ -3,7 +3,6 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; -import {AppStateStatus} from 'react-native'; import {of as of$} from 'rxjs'; import {switchMap} from 'rxjs/operators'; @@ -16,6 +15,7 @@ import ThreadPostList from './thread_post_list'; import type {WithDatabaseArgs} from '@typings/database/database'; import type PostModel from '@typings/database/models/servers/post'; +import type {AppStateStatus} from 'react-native'; type Props = WithDatabaseArgs & { forceQueryAfterAppState: AppStateStatus; diff --git a/app/screens/thread_options/options/mark_as_unread_option.tsx b/app/screens/thread_options/options/mark_as_unread_option.tsx index 9cc462d2ed..bb99285d35 100644 --- a/app/screens/thread_options/options/mark_as_unread_option.tsx +++ b/app/screens/thread_options/options/mark_as_unread_option.tsx @@ -5,15 +5,15 @@ import React, {useCallback} from 'react'; import {markThreadAsRead, markThreadAsUnread} from '@actions/remote/thread'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; import type ThreadModel from '@typings/database/models/servers/thread'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; teamId: string; thread: ThreadModel; } diff --git a/app/screens/thread_options/options/open_in_channel_option.tsx b/app/screens/thread_options/options/open_in_channel_option.tsx index b0df2b0339..a666c16d1e 100644 --- a/app/screens/thread_options/options/open_in_channel_option.tsx +++ b/app/screens/thread_options/options/open_in_channel_option.tsx @@ -6,13 +6,14 @@ import {useIntl} from 'react-intl'; import {showPermalink} from '@actions/remote/permalink'; import {BaseOption} from '@components/common_post_options'; -import {Screens} from '@constants'; import {useServerUrl} from '@context/server'; import {t} from '@i18n'; import {dismissBottomSheet} from '@screens/navigation'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type Props = { - bottomSheetId: typeof Screens[keyof typeof Screens]; + bottomSheetId: AvailableScreens; threadId: string; } const OpenInChannelOption = ({bottomSheetId, threadId}: Props) => { diff --git a/app/screens/user_profile/title/index.tsx b/app/screens/user_profile/title/index.tsx index f961c7e3a0..4253f7bc6d 100644 --- a/app/screens/user_profile/title/index.tsx +++ b/app/screens/user_profile/title/index.tsx @@ -98,8 +98,9 @@ const UserProfileTitle = ({ uri: imageUrl, width: 400, height: 400, + lastPictureUpdate: user.lastPictureUpdate, name: displayName, - mime_type: 'images/png', + mime_type: 'image/png', authorId: user.id, type: 'avatar', }; diff --git a/app/screens/user_profile/user_profile.tsx b/app/screens/user_profile/user_profile.tsx index e0f1eaf780..dcaf576faf 100644 --- a/app/screens/user_profile/user_profile.tsx +++ b/app/screens/user_profile/user_profile.tsx @@ -21,6 +21,7 @@ import UserProfileOptions, {OptionsType} from './options'; import UserProfileTitle from './title'; import type UserModel from '@typings/database/models/servers/user'; +import type {AvailableScreens} from '@typings/screens/navigation'; type Props = { channelId?: string; @@ -34,7 +35,7 @@ type Props = { isMilitaryTime: boolean; isSystemAdmin: boolean; isTeamAdmin: boolean; - location: string; + location: AvailableScreens; teamId: string; teammateDisplayName: string; user: UserModel; @@ -46,6 +47,7 @@ const TITLE_HEIGHT = 118; const OPTIONS_HEIGHT = 82; const SINGLE_OPTION_HEIGHT = 68; const LABEL_HEIGHT = 58; +const channelContextScreens: AvailableScreens[] = [Screens.CHANNEL, Screens.THREAD]; const UserProfile = ({ channelId, closeButtonId, currentUserId, enablePostIconOverride, enablePostUsernameOverride, @@ -56,7 +58,7 @@ const UserProfile = ({ const {formatMessage, locale} = useIntl(); const serverUrl = useServerUrl(); const {bottom} = useSafeAreaInsets(); - const channelContext = [Screens.CHANNEL, Screens.THREAD].includes(location); + const channelContext = channelContextScreens.includes(location); const showOptions: OptionsType = channelContext && !user.isBot ? 'all' : 'message'; const override = Boolean(userIconOverride || usernameOverride); const timezone = getUserTimezone(user); diff --git a/app/store/navigation_store.ts b/app/store/navigation_store.ts index 3681c26079..2f19fce4e3 100644 --- a/app/store/navigation_store.ts +++ b/app/store/navigation_store.ts @@ -1,19 +1,21 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import type {AvailableScreens} from '@typings/screens/navigation'; + class NavigationStore { - private screensInStack: string[] = []; - private modalsInStack: string[] = []; + private screensInStack: AvailableScreens[] = []; + private modalsInStack: AvailableScreens[] = []; private visibleTab = 'Home'; private tosOpen = false; - addModalToStack = (modalId: string) => { + addModalToStack = (modalId: AvailableScreens) => { this.removeModalFromStack(modalId); this.addScreenToStack(modalId); this.modalsInStack.unshift(modalId); }; - addScreenToStack = (screenId: string) => { + addScreenToStack = (screenId: AvailableScreens) => { this.removeScreenFromStack(screenId); this.screensInStack.unshift(screenId); }; @@ -36,21 +38,21 @@ class NavigationStore { isToSOpen = () => this.tosOpen; - popTo = (screenId: string) => { + popTo = (screenId: AvailableScreens) => { const index = this.screensInStack.indexOf(screenId); if (index > -1) { this.screensInStack.splice(0, index); } }; - removeScreenFromStack = (screenId: string) => { + removeScreenFromStack = (screenId: AvailableScreens) => { const index = this.screensInStack.indexOf(screenId); if (index > -1) { this.screensInStack.splice(index, 1); } }; - removeModalFromStack = (modalId: string) => { + removeModalFromStack = (modalId: AvailableScreens) => { const indexInStack = this.screensInStack.indexOf(modalId); if (indexInStack > -1) { // This removes all the screens that were on top of the modal @@ -78,7 +80,7 @@ class NavigationStore { * and can easily run forever if the screen is never prevesented. * @param screenId string */ - waitUntilScreenHasLoaded = async (screenId: string) => { + waitUntilScreenHasLoaded = async (screenId: AvailableScreens) => { let found = false; while (!found) { // eslint-disable-next-line no-await-in-loop @@ -94,7 +96,7 @@ class NavigationStore { * this function will run until the screen is in the top * @param screenId string */ - waitUntilScreenIsTop = async (screenId: string) => { + waitUntilScreenIsTop = async (screenId: AvailableScreens) => { let found = false; while (!found) { // eslint-disable-next-line no-await-in-loop @@ -111,7 +113,7 @@ class NavigationStore { * and can easily run forever if the screen is never removed. * @param screenId string */ - waitUntilScreensIsRemoved = async (screenId: string) => { + waitUntilScreensIsRemoved = async (screenId: AvailableScreens) => { let found = false; while (!found) { // eslint-disable-next-line no-await-in-loop diff --git a/app/utils/channel/index.ts b/app/utils/channel/index.ts index a87dd6b61d..d1ed84125b 100644 --- a/app/utils/channel/index.ts +++ b/app/utils/channel/index.ts @@ -1,6 +1,5 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Channel, General, Permissions} from '@constants'; import {t, DEFAULT_LOCALE} from '@i18n'; @@ -10,6 +9,7 @@ import {generateId} from '../general'; import {cleanUpUrlable} from '../url'; import type ChannelModel from '@typings/database/models/servers/channel'; +import type {IntlShape} from 'react-intl'; export function getDirectChannelName(id: string, otherId: string): string { let handle; diff --git a/app/utils/client_error.ts b/app/utils/client_error.ts index b7103e25fa..111e72cd23 100644 --- a/app/utils/client_error.ts +++ b/app/utils/client_error.ts @@ -1,10 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; - import {cleanUrlForLogging} from '@utils/url'; +import type {IntlShape} from 'react-intl'; + export class ClientError extends Error { details: Error; intl?: {defaultMessage?: string; id: string} | { defaultMessage?: string; id: string } | { id: string; defaultMessage?: string; values: any } | { id: string; defaultMessage?: string }; diff --git a/app/utils/deep_link/index.ts b/app/utils/deep_link/index.ts index 61c03acf62..6ae6080824 100644 --- a/app/utils/deep_link/index.ts +++ b/app/utils/deep_link/index.ts @@ -14,7 +14,7 @@ import DatabaseManager from '@database/manager'; import {DEFAULT_LOCALE, getTranslations} from '@i18n'; import {getActiveServerUrl} from '@queries/app/servers'; import {getCurrentUser, queryUsersByUsername} from '@queries/servers/user'; -import {dismissAllModalsAndPopToRoot, showModal} from '@screens/navigation'; +import {dismissAllModalsAndPopToRoot} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import NavigationStore from '@store/navigation_store'; import {errorBadChannel, errorUnkownUser} from '@utils/draft'; @@ -23,7 +23,10 @@ import {escapeRegex} from '@utils/markdown'; import {addNewServer} from '@utils/server'; import {removeProtocol} from '@utils/url'; -import type {DeepLinkChannel, DeepLinkDM, DeepLinkGM, DeepLinkPermalink, DeepLinkPlugin, DeepLinkWithData, LaunchProps} from '@typings/launch'; +import type {DeepLinkChannel, DeepLinkDM, DeepLinkGM, DeepLinkPermalink, DeepLinkWithData, LaunchProps} from '@typings/launch'; +import type {AvailableScreens} from '@typings/screens/navigation'; + +const deepLinkScreens: AvailableScreens[] = [Screens.HOME, Screens.CHANNEL, Screens.GLOBAL_THREADS, Screens.THREAD]; export async function handleDeepLink(deepLinkUrl: string, intlShape?: IntlShape, location?: string) { try { @@ -88,21 +91,25 @@ export async function handleDeepLink(deepLinkUrl: string, intlShape?: IntlShape, } case DeepLink.Permalink: { const deepLinkData = parsed.data as DeepLinkPermalink; - if (NavigationStore.hasModalsOpened() || ![Screens.HOME, Screens.CHANNEL, Screens.GLOBAL_THREADS, Screens.THREAD].includes(NavigationStore.getVisibleScreen())) { + if ( + NavigationStore.hasModalsOpened() || + !deepLinkScreens.includes(NavigationStore.getVisibleScreen()) + ) { await dismissAllModalsAndPopToRoot(); } showPermalink(existingServerUrl, deepLinkData.teamName, deepLinkData.postId); break; } case DeepLink.Plugin: { - const deepLinkData = parsed.data as DeepLinkPlugin; - showModal('PluginInternal', deepLinkData.id, {link: location}); + // https://mattermost.atlassian.net/browse/MM-49846 + // const deepLinkData = parsed.data as DeepLinkPlugin; + // showModal('PluginInternal', deepLinkData.id, {link: location}); break; } } return {error: false}; } catch (error) { - logError('Failed to open channel from deeplink', error); + logError('Failed to open channel from deeplink', error, location); return {error: true}; } } diff --git a/app/utils/document/index.ts b/app/utils/document/index.ts index 48f3a9df8e..ac8e723f80 100644 --- a/app/utils/document/index.ts +++ b/app/utils/document/index.ts @@ -1,9 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Alert} from 'react-native'; +import type {IntlShape} from 'react-intl'; + export function alertFailedToOpenDocument(file: FileInfo, intl: IntlShape) { Alert.alert( intl.formatMessage({ diff --git a/app/utils/draft/index.ts b/app/utils/draft/index.ts index ff95beee1f..d3760ea81f 100644 --- a/app/utils/draft/index.ts +++ b/app/utils/draft/index.ts @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {MessageDescriptor} from '@formatjs/intl/src/types'; import {Alert, AlertButton} from 'react-native'; import {General} from '@constants'; import {CODE_REGEX} from '@constants/autocomplete'; import {t} from '@i18n'; +import type {MessageDescriptor} from '@formatjs/intl/src/types'; import type {IntlShape} from 'react-intl'; type AlertCallback = (value?: string) => void; diff --git a/app/utils/emoji/helpers.ts b/app/utils/emoji/helpers.ts index 148d82e6b6..26ef3ff632 100644 --- a/app/utils/emoji/helpers.ts +++ b/app/utils/emoji/helpers.ts @@ -2,13 +2,13 @@ // See LICENSE.txt for license information. import emojiRegex from 'emoji-regex'; -import Fuse from 'fuse.js'; import SystemModel from '@database/models/server/system'; import {Emojis, EmojiIndicesByAlias, EmojiIndicesByUnicode} from '.'; import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; +import type Fuse from 'fuse.js'; const UNICODE_REGEX = /\p{Emoji}/u; diff --git a/app/utils/error_handling.ts b/app/utils/error_handling.ts index 3a17a1ff07..f2b612c7f9 100644 --- a/app/utils/error_handling.ts +++ b/app/utils/error_handling.ts @@ -10,7 +10,6 @@ import { import {DEFAULT_LOCALE, getTranslations, t} from '@i18n'; import {dismissAllModals} from '@screens/navigation'; -import {ClientError} from '@utils/client_error'; import {isBetaApp} from '@utils/general'; import { captureException, @@ -20,6 +19,8 @@ import { import {logWarning} from './log'; +import type {ClientError} from '@utils/client_error'; + class JavascriptAndNativeErrorHandler { initializeErrorHandling = () => { initializeSentry(); diff --git a/app/utils/file/file_picker/index.ts b/app/utils/file/file_picker/index.ts index 2cbfb6c4da..dcfbef5d03 100644 --- a/app/utils/file/file_picker/index.ts +++ b/app/utils/file/file_picker/index.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Alert, NativeModules, Platform, StatusBar} from 'react-native'; import AndroidOpenSettings from 'react-native-android-open-settings'; import DeviceInfo from 'react-native-device-info'; @@ -11,7 +10,9 @@ import Permissions from 'react-native-permissions'; import {dismissBottomSheet} from '@screens/navigation'; import {extractFileInfo, lookupMimeType} from '@utils/file'; -import {logError} from '@utils/log'; +import {logWarning} from '@utils/log'; + +import type {IntlShape} from 'react-intl'; const MattermostManaged = NativeModules.MattermostManaged; @@ -46,7 +47,7 @@ export default class FilePickerUtil { id: 'mobile.camera_photo_permission_denied_description', defaultMessage: 'Take photos and upload them to your server or save them to your device. Open Settings to grant {applicationName} read and write access to your camera.', - }), + }, {applicationName}), }, storage: { title: formatMessage( @@ -61,7 +62,7 @@ export default class FilePickerUtil { id: 'mobile.storage_permission_denied_description', defaultMessage: 'Upload files to your server. Open Settings to grant {applicationName} Read and Write access to files on this device.', - }), + }, {applicationName}), }, denied_ios: { title: formatMessage( @@ -76,7 +77,7 @@ export default class FilePickerUtil { id: 'mobile.ios.photos_permission_denied_description', defaultMessage: 'Upload photos and videos to your server or save them to your device. Open Settings to grant {applicationName} Read and Write access to your photo and video library.', - }), + }, {applicationName}), }, denied_android: { title: formatMessage( @@ -91,7 +92,7 @@ export default class FilePickerUtil { id: 'mobile.android.photos_permission_denied_description', defaultMessage: 'Upload photos to your server or save them to your device. Open Settings to grant {applicationName} Read and Write access to your photo library.', - }), + }, {applicationName}), }, }; @@ -117,7 +118,7 @@ export default class FilePickerUtil { private getFilesFromResponse = async (response: ImagePickerResponse): Promise => { if (!response?.assets?.length) { - logError('no assets in response'); + logWarning('no assets in response'); return []; } @@ -138,7 +139,7 @@ export default class FilePickerUtil { if (uri) { files.push({...file, fileName, uri, type, width: file.width, height: file.height}); } else { - logError('attaching file reponse return empty uri', file); + logWarning('attaching file reponse return empty uri', file); } } }))); @@ -187,40 +188,39 @@ export default class FilePickerUtil { }; private hasStoragePermission = async () => { - if (Platform.OS === 'ios') { - return true; - } + if (Platform.OS === 'android' && Platform.Version < 32) { + const storagePermission = Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE; + let permissionRequest; + const hasPermissionToStorage = await Permissions.check(storagePermission); + switch (hasPermissionToStorage) { + case Permissions.RESULTS.DENIED: + permissionRequest = await Permissions.request(storagePermission); + return permissionRequest === Permissions.RESULTS.GRANTED; + case Permissions.RESULTS.BLOCKED: { + const {title, text} = this.getPermissionDeniedMessage(); - const storagePermission = Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE; - let permissionRequest; - const hasPermissionToStorage = await Permissions.check(storagePermission); - switch (hasPermissionToStorage) { - case Permissions.RESULTS.DENIED: - permissionRequest = await Permissions.request(storagePermission); - return permissionRequest === Permissions.RESULTS.GRANTED; - break; - case Permissions.RESULTS.BLOCKED: { - const {title, text} = this.getPermissionDeniedMessage(); - - Alert.alert(title, text, [ - { - text: this.intl.formatMessage({ - id: 'mobile.permission_denied_dismiss', - defaultMessage: "Don't Allow", - }), - }, - { - text: this.intl.formatMessage({ - id: 'mobile.permission_denied_retry', - defaultMessage: 'Settings', - }), - onPress: () => AndroidOpenSettings.appDetailsSettings(), - }, - ]); - return false; + Alert.alert(title, text, [ + { + text: this.intl.formatMessage({ + id: 'mobile.permission_denied_dismiss', + defaultMessage: "Don't Allow", + }), + }, + { + text: this.intl.formatMessage({ + id: 'mobile.permission_denied_retry', + defaultMessage: 'Settings', + }), + onPress: () => AndroidOpenSettings.appDetailsSettings(), + }, + ]); + return false; + } + default: return true; } - default: return true; } + + return true; }; private buildUri = async (doc: DocumentPickerResponse) => { @@ -228,10 +228,14 @@ export default class FilePickerUtil { if (Platform.OS === 'android') { // For android we need to retrieve the realPath in case the file being imported is from the cloud - const newUri = await MattermostManaged.getFilePath(doc.uri); - uri = newUri?.filePath; - if (uri === undefined) { - return {doc: undefined}; + if (doc.fileCopyUri) { + uri = doc.fileCopyUri; + } else { + const newUri = await MattermostManaged.getFilePath(doc.uri); + uri = newUri?.filePath; + if (uri === undefined) { + return {doc: undefined}; + } } doc.uri = uri; @@ -272,7 +276,7 @@ export default class FilePickerUtil { if (hasPermission) { try { - const docResponse = (await DocumentPicker.pick({allowMultiSelection, type: [fileType]})); + const docResponse = (await DocumentPicker.pick({allowMultiSelection, type: [fileType], copyTo: 'cachesDirectory'})); const proDocs = docResponse.map(async (d: DocumentPickerResponse) => { const {doc} = await this.buildUri(d); return doc; @@ -302,7 +306,7 @@ export default class FilePickerUtil { launchImageLibrary(options, async (response: ImagePickerResponse) => { StatusBar.setHidden(false); if (response.errorMessage || response.didCancel) { - logError('Attach failed', response.errorMessage || (response.didCancel ? 'cancelled' : '')); + logWarning('Attach failed', response.errorMessage || (response.didCancel ? 'cancelled' : '')); return; } diff --git a/app/utils/file/index.ts b/app/utils/file/index.ts index 348a156181..8b1e124cce 100644 --- a/app/utils/file/index.ts +++ b/app/utils/file/index.ts @@ -1,16 +1,12 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {PastedFile} from '@mattermost/react-native-paste-input'; import Model from '@nozbe/watermelondb/Model'; import mimeDB from 'mime-db'; -import {IntlShape} from 'react-intl'; import {Alert, Platform} from 'react-native'; import AndroidOpenSettings from 'react-native-android-open-settings'; import DeviceInfo from 'react-native-device-info'; -import {DocumentPickerResponse} from 'react-native-document-picker'; import FileSystem from 'react-native-fs'; -import {Asset} from 'react-native-image-picker'; import Permissions, {PERMISSIONS} from 'react-native-permissions'; import {Files} from '@constants'; @@ -20,7 +16,11 @@ import {logError} from '@utils/log'; import {deleteEntititesFile, getIOSAppGroupDetails} from '@utils/mattermost_managed'; import {urlSafeBase64Encode} from '@utils/security'; +import type {PastedFile} from '@mattermost/react-native-paste-input'; import type FileModel from '@typings/database/models/servers/file'; +import type {IntlShape} from 'react-intl'; +import type {DocumentPickerResponse} from 'react-native-document-picker'; +import type {Asset} from 'react-native-image-picker'; const EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/; const CONTENT_DISPOSITION_REGEXP = /inline;filename=".*\.([a-z]+)";/i; @@ -477,52 +477,52 @@ export const fileExists = async (path: string) => { }; export const hasWriteStoragePermission = async (intl: IntlShape) => { - if (Platform.OS === 'ios') { - return true; - } - - const storagePermission = PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE; - let permissionRequest; - const hasPermissionToStorage = await Permissions.check(storagePermission); - switch (hasPermissionToStorage) { - case Permissions.RESULTS.DENIED: - permissionRequest = await Permissions.request(storagePermission); - return permissionRequest === Permissions.RESULTS.GRANTED; - case Permissions.RESULTS.BLOCKED: { - const applicationName = DeviceInfo.getApplicationName(); - const title = intl.formatMessage( - { - id: 'mobile.storage_permission_denied_title', + if (Platform.OS === 'android' && Platform.Version < 33) { + const storagePermission = PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE; + let permissionRequest; + const hasPermissionToStorage = await Permissions.check(storagePermission); + switch (hasPermissionToStorage) { + case Permissions.RESULTS.DENIED: + permissionRequest = await Permissions.request(storagePermission); + return permissionRequest === Permissions.RESULTS.GRANTED; + case Permissions.RESULTS.BLOCKED: { + const applicationName = DeviceInfo.getApplicationName(); + const title = intl.formatMessage( + { + id: 'mobile.storage_permission_denied_title', + defaultMessage: + '{applicationName} would like to access your files', + }, + {applicationName}, + ); + const text = intl.formatMessage({ + id: 'mobile.write_storage_permission_denied_description', defaultMessage: - '{applicationName} would like to access your files', - }, - {applicationName}, - ); - const text = intl.formatMessage({ - id: 'mobile.write_storage_permission_denied_description', - defaultMessage: - 'Save files to your device. Open Settings to grant {applicationName} write access to files on this device.', - }); + 'Save files to your device. Open Settings to grant {applicationName} write access to files on this device.', + }); - Alert.alert(title, text, [ - { - text: intl.formatMessage({ - id: 'mobile.permission_denied_dismiss', - defaultMessage: "Don't Allow", - }), - }, - { - text: intl.formatMessage({ - id: 'mobile.permission_denied_retry', - defaultMessage: 'Settings', - }), - onPress: () => AndroidOpenSettings.appDetailsSettings(), - }, - ]); - return false; + Alert.alert(title, text, [ + { + text: intl.formatMessage({ + id: 'mobile.permission_denied_dismiss', + defaultMessage: "Don't Allow", + }), + }, + { + text: intl.formatMessage({ + id: 'mobile.permission_denied_retry', + defaultMessage: 'Settings', + }), + onPress: () => AndroidOpenSettings.appDetailsSettings(), + }, + ]); + return false; + } + default: return true; } - default: return true; } + + return true; }; export const getAllFilesInCachesDirectory = async (serverUrl: string) => { diff --git a/app/utils/files.tsx b/app/utils/files.tsx index d8375da910..b100f6c37e 100644 --- a/app/utils/files.tsx +++ b/app/utils/files.tsx @@ -1,9 +1,10 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ChannelModel} from '@database/models/server'; import {fileToGalleryItem} from '@utils/gallery'; +import type ChannelModel from '@typings/database/models/servers/channel'; + export const getNumberFileMenuOptions = (canDownloadFiles: boolean, publicLinkEnabled: boolean) => { let numberItems = 1; numberItems += canDownloadFiles ? 1 : 0; @@ -42,3 +43,7 @@ export const getOrderedGalleryItems = (orderedFileInfos: FileInfo[]) => { return orderedFileInfos.map((f) => fileToGalleryItem(f, f.user_id)); }; +export const pathWithPrefix = (prefix: string, path: string) => { + const p = path.startsWith(prefix) ? '' : prefix; + return `${p}${path}`; +}; diff --git a/app/utils/gallery/index.ts b/app/utils/gallery/index.ts index 856886ee06..94f04f662d 100644 --- a/app/utils/gallery/index.ts +++ b/app/utils/gallery/index.ts @@ -28,7 +28,7 @@ export const clampVelocity = (velocity: number, minVelocity: number, maxVelocity return Math.max(Math.min(velocity, -minVelocity), -maxVelocity); }; -export const fileToGalleryItem = (file: FileInfo, authorId?: string): GalleryItemType => { +export const fileToGalleryItem = (file: FileInfo, authorId?: string, lastPictureUpdate = 0): GalleryItemType => { let type: GalleryItemType['type'] = 'file'; if (isVideo(file)) { type = 'video'; @@ -41,6 +41,7 @@ export const fileToGalleryItem = (file: FileInfo, authorId?: string): GalleryIte extension: file.extension, height: file.height, id: file.id || generateId('uid'), + lastPictureUpdate, mime_type: file.mime_type, name: file.name, posterUri: type === 'video' ? file.mini_preview : undefined, // set the video poster to the mini_preview @@ -105,10 +106,10 @@ export function measureItem(ref: React.RefObject, sharedValues: GalleryMana try { const measurements = measure(ref); - sharedValues.x.value = measurements.pageX; - sharedValues.y.value = measurements.pageY; - sharedValues.width.value = measurements.width; - sharedValues.height.value = measurements.height; + sharedValues.x.value = measurements?.pageX || 999999; + sharedValues.y.value = measurements?.pageY || 999999; + sharedValues.width.value = measurements?.width || 0; + sharedValues.height.value = measurements?.height || 0; } catch (err) { sharedValues.x.value = 999999; sharedValues.y.value = 999999; diff --git a/app/utils/integrations.ts b/app/utils/integrations.ts index 3cde2f69bd..7fe8092e07 100644 --- a/app/utils/integrations.ts +++ b/app/utils/integrations.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {KeyboardTypeOptions} from 'react-native'; +import type {KeyboardTypeOptions} from 'react-native'; type DialogError = { id: string; diff --git a/app/utils/markdown/index.ts b/app/utils/markdown/index.ts index ca0d283d54..486a80371f 100644 --- a/app/utils/markdown/index.ts +++ b/app/utils/markdown/index.ts @@ -30,6 +30,7 @@ export const getMarkdownTextStyles = makeStyleSheetFromTheme((theme: Theme) => { }, strong: { fontFamily: 'OpenSans-SemiBold', + fontWeight: '600', }, del: { textDecorationLine: 'line-through', @@ -213,30 +214,6 @@ export function escapeRegex(text: string) { return text.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); } -export function switchKeyboardForCodeBlocks(value: string, cursorPosition: number) { - if (Platform.OS === 'ios' && parseInt(Platform.Version, 10) >= 12) { - const regexForCodeBlock = /^```$(.*?)^```$|^```$(.*)/gms; - - const matches = []; - let nextMatch; - while ((nextMatch = regexForCodeBlock.exec(value)) !== null) { - matches.push({ - startOfMatch: regexForCodeBlock.lastIndex - nextMatch[0].length, - endOfMatch: regexForCodeBlock.lastIndex + 1, - }); - } - - const cursorIsInsideCodeBlock = matches.some((match) => cursorPosition >= match.startOfMatch && cursorPosition <= match.endOfMatch); - - // 'email-address' keyboardType prevents iOS emdash autocorrect - if (cursorIsInsideCodeBlock) { - return 'email-address'; - } - } - - return 'default'; -} - export const getMarkdownImageSize = ( isReplyPost: boolean, isTablet: boolean, diff --git a/app/utils/navigation/index.ts b/app/utils/navigation/index.ts index eb50c96081..7f813af833 100644 --- a/app/utils/navigation/index.ts +++ b/app/utils/navigation/index.ts @@ -1,14 +1,16 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Alert} from 'react-native'; import {Navigation, Options} from 'react-native-navigation'; import {Screens, ServerErrors} from '@constants'; import {isServerError} from '@utils/errors'; -export const appearanceControlledScreens = new Set([ +import type {AvailableScreens} from '@typings/screens/navigation'; +import type {IntlShape} from 'react-intl'; + +export const appearanceControlledScreens = new Set([ Screens.ONBOARDING, Screens.SERVER, Screens.LOGIN, diff --git a/app/utils/push_proxy.ts b/app/utils/push_proxy.ts index 999504742e..e207c9841e 100644 --- a/app/utils/push_proxy.ts +++ b/app/utils/push_proxy.ts @@ -1,12 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Alert} from 'react-native'; import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_RESPONSE_UNKNOWN, PUSH_PROXY_STATUS_NOT_AVAILABLE, PUSH_PROXY_STATUS_UNKNOWN, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy'; import EphemeralStore from '@store/ephemeral_store'; +import type {IntlShape} from 'react-intl'; + export function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) { switch (verification) { case PUSH_PROXY_RESPONSE_NOT_AVAILABLE: diff --git a/app/utils/sentry.ts b/app/utils/sentry.ts index 188a36cd43..4017a38be5 100644 --- a/app/utils/sentry.ts +++ b/app/utils/sentry.ts @@ -1,8 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {Database} from '@nozbe/watermelondb'; -import {Breadcrumb, Event} from '@sentry/types'; import {Platform} from 'react-native'; import {Navigation} from 'react-native-navigation'; @@ -15,6 +13,9 @@ import {isBetaApp} from '@utils/general'; import {ClientError} from './client_error'; import {logError, logWarning} from './log'; +import type {Database} from '@nozbe/watermelondb'; +import type {Breadcrumb, Event} from '@sentry/types'; + export const BREADCRUMB_UNCAUGHT_APP_ERROR = 'uncaught-app-error'; export const BREADCRUMB_UNCAUGHT_NON_ERROR = 'uncaught-non-error'; diff --git a/app/utils/server/index.ts b/app/utils/server/index.ts index debff00faf..b284076cdc 100644 --- a/app/utils/server/index.ts +++ b/app/utils/server/index.ts @@ -1,7 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {IntlShape} from 'react-intl'; import {Alert, AlertButton} from 'react-native'; import CompassIcon from '@components/compass_icon'; @@ -14,6 +13,7 @@ import {tryOpenURL} from '@utils/url'; import type ServersModel from '@typings/database/models/app/servers'; import type {DeepLinkWithData} from '@typings/launch'; +import type {IntlShape} from 'react-intl'; export function isSupportedServer(currentVersion: string) { return isMinimumServerVersion(currentVersion, SupportedServer.MAJOR_VERSION, SupportedServer.MIN_VERSION, SupportedServer.PATCH_VERSION); diff --git a/app/utils/snack_bar/index.ts b/app/utils/snack_bar/index.ts index 0ccbc70e54..62f8afdbec 100644 --- a/app/utils/snack_bar/index.ts +++ b/app/utils/snack_bar/index.ts @@ -4,10 +4,12 @@ import {Screens} from '@constants'; import {SNACK_BAR_TYPE} from '@constants/snack_bar'; import {showOverlay} from '@screens/navigation'; +import type {AvailableScreens} from '@typings/screens/navigation'; + type ShowSnackBarArgs = { barType: keyof typeof SNACK_BAR_TYPE; onAction?: () => void; - sourceScreen?: typeof Screens[keyof typeof Screens]; + sourceScreen?: AvailableScreens; }; export const showSnackBar = (passProps: ShowSnackBarArgs) => { diff --git a/app/utils/theme/index.ts b/app/utils/theme/index.ts index 519b3fcae4..e10f307037 100644 --- a/app/utils/theme/index.ts +++ b/app/utils/theme/index.ts @@ -10,9 +10,9 @@ import {Preferences} from '@constants'; import {MODAL_SCREENS_WITHOUT_BACK, SCREENS_AS_BOTTOM_SHEET, SCREENS_WITH_TRANSPARENT_BACKGROUND} from '@constants/screens'; import EphemeralStore from '@store/ephemeral_store'; import NavigationStore from '@store/navigation_store'; -import {NamedStyles} from '@typings/global/styles'; import {appearanceControlledScreens, mergeNavigationOptions} from '@utils/navigation'; +import type {NamedStyles} from '@typings/global/styles'; import type {Options} from 'react-native-navigation'; const rgbPattern = /^rgba?\((\d+),(\d+),(\d+)(?:,([\d.]+))?\)$/; diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 565aca508b..f7ee276f50 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -327,6 +327,28 @@ "intro.welcome.public": "Add some more team members to the channel or start a conversation below.", "invite_people_to_team.message": "Here’s a link to collaborate and communicate with us on Mattermost.", "invite_people_to_team.title": "Join the {team} team", + "invite.members.already_member": "This person is already a team member", + "invite.members.user_is_guest": "Contact your admin to make this guest a full member", + "invite.search.email_invite": "invite", + "invite.search.no_results": "No one found matching", + "invite.searchPlaceholder": "Type a name or email address…", + "invite.send_error": "Something went wrong while trying to send invitations. Please check your network connection and try again.", + "invite.send_invite": "Send", + "invite.sendInvitationsTo": "Send invitations to…", + "invite.shareLink": "Share link", + "invite.summary.done": "Done", + "invite.summary.email_invite": "An invitation email has been sent", + "invite.summary.error": "{invitationsCount, plural, one {Invitation} other {Invitations}} could not be sent successfully", + "invite.summary.member_invite": "Invited as a member of {teamDisplayName}", + "invite.summary.not_sent": "{notSentCount, plural, one {Invitation wasn’t} other {Invitations weren’t}} sent", + "invite.summary.report.notSent": "{count} {count, plural, one {invitation} other {invitations}} not sent", + "invite.summary.report.sent": "{count} successful {count, plural, one {invitation} other {invitations}}", + "invite.summary.sent": "Your {sentCount, plural, one {invitation has} other {invitations have}} been sent", + "invite.summary.smtp_failure": "SMTP is not configured in System Console", + "invite.summary.some_not_sent": "{notSentCount, plural, one {An invitation was} other {Some invitations were}} not sent", + "invite.summary.try_again": "Try again", + "invite.title": "Invite", + "invite.title.summary": "Invite summary", "join_team.error.group_error": "You need to be a member of a linked group to join this team.", "join_team.error.message": "There has been an error joining the team", "join_team.error.title": "Error joining a team", @@ -408,6 +430,7 @@ "mobile.calls_not_available_msg": "Please contact your System Admin to enable the feature.", "mobile.calls_not_available_option": "(Not available)", "mobile.calls_not_available_title": "Calls is not enabled", + "mobile.calls_not_connected": "You're not connected to a call in the current channel.", "mobile.calls_ok": "OK", "mobile.calls_okay": "Okay", "mobile.calls_open_channel": "Open Channel", @@ -423,6 +446,7 @@ "mobile.calls_see_logs": "See server logs", "mobile.calls_speaker": "Speaker", "mobile.calls_start_call": "Start Call", + "mobile.calls_start_call_exists": "A call is already ongoing in the channel.", "mobile.calls_stop_recording": "Stop Recording", "mobile.calls_unmute": "Unmute", "mobile.calls_viewing_screen": "You are viewing {name}'s screen", @@ -503,7 +527,9 @@ "mobile.login_options.sso_continue": "Continue with", "mobile.managed.blocked_by": "Blocked by {vendor}", "mobile.managed.exit": "Exit", - "mobile.managed.jailbreak": "Jailbroken devices are not trusted by {vendor}, please exit the app.", + "mobile.managed.jailbreak": "Jailbroken devices are not trusted by {vendor}.\n\nReason {reason}\n\n\n\nDebug info: {debug}\n\nPlease exit the app.", + "mobile.managed.jailbreak_no_debug_info": "Not available", + "mobile.managed.jailbreak_no_reason": "Not available", "mobile.managed.not_secured.android": "This device must be secured with a screen lock to use Mattermost.", "mobile.managed.not_secured.ios": "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Face ID & Passcode.", "mobile.managed.not_secured.ios.touchId": "This device must be secured with a passcode to use Mattermost.\n\nGo to Settings > Touch ID & Passcode.", diff --git a/assets/base/i18n/en_AU.json b/assets/base/i18n/en_AU.json index beef334f8e..0c43c80aaf 100644 --- a/assets/base/i18n/en_AU.json +++ b/assets/base/i18n/en_AU.json @@ -937,5 +937,7 @@ "connection_banner.connecting": "Connecting...", "skintone_selector.tooltip.title": "Choose your default skin tone", "skintone_selector.tooltip.description": "You can now choose the skin tone you prefer to use for your emojis.", - "default_skin_tone": "Default Skin Tone" + "default_skin_tone": "Default Skin Tone", + "mobile.calls_rec": "rec", + "mobile.calls_host": "host" } diff --git a/assets/base/i18n/nl.json b/assets/base/i18n/nl.json index 286cba2e26..c42c4df830 100644 --- a/assets/base/i18n/nl.json +++ b/assets/base/i18n/nl.json @@ -1,17 +1,17 @@ { "about.date": "Compilatiedatum:", - "about.enterpriseEditione1": "Enterprise-Editie", - "about.enterpriseEditionLearn": "Meer informatie over de Enterprise-Editie op ", + "about.enterpriseEditione1": "Enterprise-editie", + "about.enterpriseEditionLearn": "Meer informatie over de Enterprise-editie op ", "about.enterpriseEditionSt": "Moderne communicatie achter jouw eigen firewall.", "about.hash": "Compilatiehash:", "about.hashee": "EE Compilatiehash:", "about.teamEditionLearn": "Word lid van de Mattermost-gemeenschap op ", "about.teamEditionSt": "Alle team-communicatie op één plaats, doorzoekbaar en van overal bereikbaar.", "about.teamEditiont0": "Team Editie", - "about.teamEditiont1": "Enterprise Editie", + "about.teamEditiont1": "Enterprise-editie", "api.channel.add_guest.added": "{addedUsername} werd toegevoegd aan het kanaal als gast door {username}.", "api.channel.add_member.added": "{addedUsername} is toegevoegd aan het kanaal door {username}.", - "api.channel.guest_join_channel.post_and_forget": "{username} is toegetreden tot het kanaal als gast.", + "api.channel.guest_join_channel.post_and_forget": "{username} is toegetreden tot het kanaal als gastgebruiker.", "apps.error": "Fout: {error}", "apps.error.command.field_missing": "Verplichte velden ontbreken: `{fieldName}`.", "apps.error.command.same_channel": "Kanaal herhaald voor veld `{fieldName}`: `{option}`.", @@ -55,16 +55,16 @@ "apps.error.responses.unexpected_error": "Een onverwachte fout ontvangen.", "apps.error.responses.unknown_field_error": "Fout ontvangen voor een onbekend veld. Veldnaam: `{field}`. Fout:`{error}`.", "apps.error.responses.unknown_type": "Het app-antwoordtype wordt niet ondersteund. Type antwoord: {type}.", - "apps.error.unknown": "Er is een onbekende fout opgetreden.", + "apps.error.unknown": "Onbekende fout opgetreden.", "apps.suggestion.dynamic.error": "Dynamische selectiefout", "apps.suggestion.errors.parser_error": "Fout bij het parsen", "apps.suggestion.no_dynamic": "Geen gegevens ontvangen voor dynamische suggesties", "apps.suggestion.no_static": "Geen passende opties.", "apps.suggestion.no_suggestion": "Geen passende suggesties.", "archivedChannelMessage": "Je bekijkt een **gearchiveerd kanaal**. Er kunnen geen nieuwe berichten worden geplaatst.", - "camera_type.photo.option": "Foto maken", - "camera_type.video.option": "Video opnemen", - "center_panel.archived.closeChannel": "Kanaal sluiten", + "camera_type.photo.option": "Maak foto", + "camera_type.video.option": "Neem video op", + "center_panel.archived.closeChannel": "Sluit kanaal", "channel_info.header": "Kop:", "channel_loader.someone": "Iemand", "channel_modal.descriptionHelp": "Beschrijf het doel van dit kanaal.", @@ -124,10 +124,10 @@ "custom_status.suggestions.on_a_vacation": "Op vakantie", "custom_status.suggestions.out_for_lunch": "Lunch", "custom_status.suggestions.out_sick": "Ziek", - "custom_status.suggestions.working_from_home": "Thuiswerk", + "custom_status.suggestions.working_from_home": "Thuiswerken", "date_separator.today": "Vandaag", "date_separator.yesterday": "Gisteren", - "edit_post.editPost": "Bewerk het bericht...", + "edit_post.editPost": "Wijzig het bericht...", "edit_post.save": "Opslaan", "emoji_picker.activities": "Activiteiten", "emoji_picker.animals-nature": "Dieren & Natuur", @@ -155,19 +155,19 @@ "friendly_date.yearsAgo": "{count} {count, plural, one {jaar} other {jaren}} geleden", "friendly_date.yesterday": "Gisteren", "gallery.footer.channel_name": "Gedeeld in {channelName}", - "gallery.open_file": "Bestand openen", + "gallery.open_file": "Open bestand", "get_post_link_modal.title": "Kopieer link", - "global_threads.allThreads": "Al je draadjes", - "global_threads.emptyThreads.message": "Alle draadjes waarin je bent genoemd of waaraan jehebt deelgenomen, worden hier getoond, samen met alle threads die je hebt gevolgd.", + "global_threads.allThreads": "Al je chatgesprekken", + "global_threads.emptyThreads.message": "Alle chatgesprekken waarin je bent genoemd of waaraan je hebt deelgenomen, worden hier getoond, samen met alle threads die je hebt gevolgd.", "global_threads.emptyThreads.title": "Nog geen gevolgde draadjes", - "global_threads.emptyUnreads.message": "Het lijkt erop dat je weer helemaal mee bent.", - "global_threads.emptyUnreads.title": "Geen ongelezen draadjes", - "global_threads.markAllRead.cancel": "Annuleren", - "global_threads.markAllRead.markRead": "Als gelezen markeren", + "global_threads.emptyUnreads.message": "Zo te zien ben je helemaal bij.", + "global_threads.emptyUnreads.title": "Geen ongelezen chatgesprekken", + "global_threads.markAllRead.cancel": "Annuleer", + "global_threads.markAllRead.markRead": "Markeer als gelezen", "global_threads.markAllRead.message": "Dit zal alle ongelezen status verwijderen voor al je threads die hier getoond worden", "global_threads.markAllRead.title": "Weet je zeker dat je alle onderwerpen als gelezen wilt markeren?", "global_threads.options.mark_as_read": "Markeer als gelezen", - "global_threads.options.open_in_channel": "Openen in kanaal", + "global_threads.options.open_in_channel": "Open in kanaal", "global_threads.unreads": "Ongelezen", "last_users_message.added_to_channel.type": "is **aan het kanaal toegevoegd** door {actor}.", "last_users_message.added_to_team.type": "is **aan het team toegevoegd** door {actor}.", @@ -179,7 +179,7 @@ "last_users_message.others": "{numOthers} anderen ", "last_users_message.removed_from_channel.type": "werd **verwijderd uit het kanaal**.", "last_users_message.removed_from_team.type": "werd **verwijderd uit het team**.", - "login_mfa.tokenReq": "Geef een MFA token op", + "login_mfa.tokenReq": "Voer een MFA-token in", "login.email": "E-mail", "login.ldapUsername": "AD/LDAP Gebruikersnaam", "login.or": "of", @@ -188,30 +188,30 @@ "mobile.about.appVersion": "Appversie: {version} (Build {number})", "mobile.account.settings.save": "Opslaan", "mobile.action_menu.select": "Selecteer een optie", - "mobile.android.back_handler_exit": "Klik nogmaals op Terug om te sluiten", + "mobile.android.back_handler_exit": "Tik nogmaals op Terug om te sluiten", "mobile.android.photos_permission_denied_title": "{applicationName} wil toegang tot jouw foto's", "mobile.camera_photo_permission_denied_title": "{applicationName} wil toegang tot jouw camera", "mobile.channel_info.alertNo": "Nee", "mobile.channel_info.alertYes": "Ja", "mobile.commands.error_title": "Fout bij uitvoeren van opdracht", "mobile.components.select_server_view.connect": "Verbinden", - "mobile.components.select_server_view.enterServerUrl": "Server-URL opgeven", + "mobile.components.select_server_view.enterServerUrl": "Voer server-url in", "mobile.components.select_server_view.proceed": "Verdergaan", "mobile.create_channel": "Aanmaken", "mobile.custom_status.choose_emoji": "Kies een emoticon", "mobile.custom_status.clear_after": "Wis na", "mobile.custom_status.modal_confirm": "Klaar", "mobile.display_settings.theme": "Thema", - "mobile.document_preview.failed_description": "Er is een fout opgetreden tijdens het openen van het document. Zorg ervoor dat je een {fileType} - viewer geïnstalleerd en probeer het opnieuw. \n", - "mobile.document_preview.failed_title": "Openen van document is mislukt", - "mobile.downloader.disabled_description": "File downloads zijn uitgeschakeld op deze server. Neem contact op met uw Systeembeheerder voor meer informatie.\n", + "mobile.document_preview.failed_description": "Er is een fout opgetreden tijdens het openen van het document. Zorg ervoor dat je een {fileType}-viewer geïnstalleerd en probeer het opnieuw.\n", + "mobile.document_preview.failed_title": "Openen document mislukt", + "mobile.downloader.disabled_description": "File downloads zijn uitgeschakeld op deze server. Neem contact op met je systeembeheerder voor meer info.\n", "mobile.downloader.disabled_title": "Downloaden uitgeschakeld", - "mobile.downloader.failed_description": "Er is een fout opgetreden tijdens het downloaden van het bestand. Controleer uw internetverbinding en probeer het opnieuw.\n", + "mobile.downloader.failed_description": "Er is een fout opgetreden tijdens het downloaden van het bestand. Controleer je internetverbinding en probeer het nog eens.\n", "mobile.downloader.failed_title": "Downloaden mislukt", - "mobile.edit_channel": "Opslaan", + "mobile.edit_channel": "Bewaren", "mobile.edit_post.title": "Bericht bewerken", "mobile.error_handler.button": "Opnieuw starten", - "mobile.error_handler.description": "\nTik op opnieuw starten om de app opnieuw te openen. Nadat deze opnieuw is opgestart, kunt je het probleem melden in het menu instellingen.\n", + "mobile.error_handler.description": "\nTik op opnieuw starten om de app opnieuw te openen. Nadat deze opnieuw is opgestart, kunt je het probleem melden in het menu Instellingen.\n", "mobile.error_handler.title": "Onvoorziene fout opgetreden", "mobile.file_upload.disabled2": "Bestanden opladen van op mobiele toestellen is uitgeschakeld.", "mobile.file_upload.max_warning": "Uploads beperkt tot maximaal {count} bestanden.", @@ -225,16 +225,16 @@ "mobile.managed.blocked_by": "Geblokkeerd door {vendor}", "mobile.managed.exit": "Afsluiten", "mobile.managed.jailbreak": "Jailbroken apparaten worden niet vertrouwd door {vendor}, sluit de app af.", - "mobile.managed.not_secured.android": "Dit apparaat moet beveiligd zijn met een schermvergrendeling om Mattermost te gebruiken.", - "mobile.managed.not_secured.ios": "Dit apparaat moet worden beveiligd met een toegangscode om Mattermost te gebruiken.\n\nGa naar Instellingen > Face ID & Wachtwoord.", - "mobile.managed.not_secured.ios.touchId": "Dit apparaat moet worden beveiligd met een toegangscode om Mattermost te gebruiken.\n\nGa naar Instellingen > Touch ID & Wachtwoord.", + "mobile.managed.not_secured.android": "Dit apparaat moet eerst beveiligd worden met een schermvergrendeling, zodat je Mattermost kunt gebruiken.", + "mobile.managed.not_secured.ios": "Dit apparaat moet worden beveiligd met een toegangscode om Mattermost te gebruiken.\n\nGa naar Instellingen > Biometrie en wachtwoord.", + "mobile.managed.not_secured.ios.touchId": "Dit apparaat moet worden beveiligd met een toegangscode om Mattermost te gebruiken.\n\nGa naar Instellingen > Vingerafruk-id en wachtwoord.", "mobile.managed.secured_by": "Beveiligd door {vendor}", "mobile.managed.settings": "Ga naar instellingen", - "mobile.markdown.code.copy_code": "Kopieer Code", + "mobile.markdown.code.copy_code": "Kopieer code", "mobile.markdown.code.plusMoreLines": "+{count, number} meer {count, plural, one {line} other {lines}}", "mobile.markdown.image.too_large": "Afbeelding overschrijdt de maximumgrootte van {maxWidth} op {maxHeight}:", "mobile.markdown.link.copy_url": "Kopieer URL", - "mobile.mention.copy_mention": "Kopieer Vermelding", + "mobile.mention.copy_mention": "Kopieer vermelding", "mobile.message_length.message": "Je huidige bericht is te lang. Huidige aantal tekens: {count}/{max}", "mobile.message_length.message_split_left": "Bericht overschrijdt het maximum aantal karakters", "mobile.message_length.title": "Berichtlengte", @@ -252,7 +252,7 @@ "mobile.post_info.reply": "Antwoord", "mobile.post_info.unpin": "Losmaken van Kanaal", "mobile.post_pre_header.pinned": "Vastgemaakt", - "mobile.post_textbox.entire_channel_here.message": "Door @here te gebruiken ga je berichten sturen naar maximaal {totalMembers, number} {totalMembers, plural, one {persoon} other {mensen}}.. Weet je zeker dat je dit wilt doen?", + "mobile.post_textbox.entire_channel_here.message": "Door @here te gebruiken ga je berichten sturen naar maximaal {totalMembers, number} {totalMembers, plural, one {persoon} other {mensen}}. Weet je zeker dat je dit wilt doen?", "mobile.post_textbox.entire_channel_here.message.with_timezones": "Bij gebruik van @all of @channel verstuur je meldingen naar {totalMembers, number} {totalMembers, plural, one {persoon} other {mensen}} in {timezones, number} {timezones, plural, one {tijdzone} other {tijdzones}}. Weet je zeker dat je dit wil doen?", "mobile.post_textbox.entire_channel.cancel": "Annuleren", "mobile.post_textbox.entire_channel.confirm": "Bevestigen", @@ -264,12 +264,12 @@ "mobile.post_textbox.uploadFailedTitle": "Bijlagefout", "mobile.post.cancel": "Annuleren", "mobile.post.delete_question": "Weet je zeker dat je deze bericht wil wissen?", - "mobile.post.delete_title": "Verwijder Bericht", - "mobile.post.failed_delete": "Verwijder Bericht", - "mobile.post.failed_retry": "Probeer Opnieuw", + "mobile.post.delete_title": "Verwijder bericht", + "mobile.post.failed_delete": "Verwijder bericht", + "mobile.post.failed_retry": "Probeer opnieuw", "mobile.privacy_link": "Privacybeleid", "mobile.push_notification_reply.button": "Verzenden", - "mobile.push_notification_reply.placeholder": "Schrijf een antwoord...", + "mobile.push_notification_reply.placeholder": "Schrijf een reactie...", "mobile.push_notification_reply.title": "Antwoord", "mobile.rename_channel.display_name_maxLength": "Kanaalnaam moet kleiner zijn dan {maxLength, number} tekens", "mobile.rename_channel.display_name_minLength": "Kanaalnaam moet {minLength, number} of meer tekens zijn", @@ -282,8 +282,8 @@ "mobile.routes.custom_status": "Een aangepaste status instellen", "mobile.routes.table": "Tabel", "mobile.routes.user_profile": "Profiel", - "mobile.search.jump": "Naar recente berichten gaan", - "mobile.server_link.error.text": "De link is niet gevonden op deze server.", + "mobile.search.jump": "Ga naar recente berichten", + "mobile.server_link.error.text": "De link werd niet gevonden op deze server.", "mobile.server_link.error.title": "Foute Link", "mobile.server_link.unreachable_channel.error": "Deze link behoort tot een gewist kanaal of tot een kanaal waartoe je geen toegang hebt.", "mobile.server_link.unreachable_team.error": "Deze link behoort tot een gewist team of tot een team waartoe je geen toegang hebt.", @@ -461,8 +461,8 @@ "intro.townsquare": "Welkom op {name}. Iedereen wordt automatisch lid van dit kanaal als ze bij het team komen.", "intro.public_channel": "Publiek kanaal", "intro.private_channel": "Privé-kanaal", - "intro.group_message": "Dit is het begin van jouw gesprek met deze groep. Berichten en bestanden die hier gedeeld worden, worden aan niemand buiten de groep getoond.", - "intro.direct_message": "Dit is het begin van jouw gesprek met {teammate}. Berichten en bestanden die hier gedeeld worden, worden aan niemand anders getoond.", + "intro.group_message": "Dit is het begin van je gesprek met deze groep. Berichten en bestanden die hier gedeeld worden, worden aan niemand buiten de groep getoond.", + "intro.direct_message": "Dit is het begin van je gesprek met {teammate}. Berichten en bestanden die hier gedeeld worden, worden aan niemand anders getoond.", "intro.created_by": "gemaakt door {creator} op {date}.", "intro.channel_info": "Info", "intro.add_people": "Mensen toevoegen", @@ -590,7 +590,7 @@ "channel_modal.headerHelp": "Specificeer tekst die in de koptekst van het kanaal moet verschijnen naast de naam van het kanaal. Neem bijvoorbeeld veelgebruikte links op door linktekst [Linktitel](http://voorbeeld.nl) te typen.", "channel_modal.headerEx": "Markdown gebruiken om koptekst op te maken", "channel_list.find_channels": "Kanalen zoeken...", - "mobile.post_pre_header.saved": "Bewaard", + "mobile.post_pre_header.saved": "Opgeslagen", "mobile.post_pre_header.pinned_saved": "Vastgemaakt en bewaard", "mobile.post_info.unsave": "Niet langer bewaren", "mobile.post_info.save": "Bewaren", @@ -727,7 +727,7 @@ "server.tutorial.swipe": "Veeg naar links op een server om meer acties te zien", "server.remove.alert_title": "Weet je zeker dat je {displayName} wilt verwijderen?", "server.remove.alert_description": "Dit zal de server verwijderen uit jouw lijst van servers. Alle bijbehorende gegevens worden verwijderd", - "server.logout.alert_title": "Weet je zeker dat je je wilt afmelden bij {displayName}?", + "server.logout.alert_title": "Weet je zeker dat je wilt uitloggen bij {displayName}?", "server.logout.alert_description": "Alle bijbehorende gegevens worden verwijderd", "server_list.push_proxy_unknown": "Meldingen konden niet worden ontvangen van deze server vanwege de configuratie. Log uit en log opnieuw in om het opnieuw te proberen.", "server_list.push_proxy_error": "Meldingen kunnen niet worden ontvangen van deze server vanwege de configuratie. Neem contact op met jouw systeembeheerder.", @@ -842,7 +842,7 @@ "notification_settings.auto_responder.message": "Bericht", "mobile.onboarding.sign_in_to_get_started": "Meld je aan om van start te gaan", "mobile.onboarding.sign_in": "Aanmelden", - "mobile.onboarding.next": "Volgende", + "mobile.onboarding.next": "Ga verder", "mobile.integration_selector.loading_options": "Opties aan het laden...", "mobile.integration_selector.loading_channels": "Kanalen aan het laden...", "mobile.custom_list.no_results": "Geen resultaten", @@ -905,7 +905,7 @@ "share_extension.max_resolution": "Afbeelding overschrijdt de maximum afmeting van 7680 x 4320 px", "share_extension.file_limit.single": "Het bestand moet kleiner zijn dan {size}", "share_extension.file_limit.multiple": "Elk bestand moet minder dan {size}", - "share_extension.count_limit": "Je kan alleen {count, number} {count, plural, one {bestand} other {bestanden}} delen op deze server", + "share_extension.count_limit": "Je kan slechts {count, number} {count, plural, one {bestand} other {bestanden}} delen op deze server", "share_extension.channel_label": "Kanaal", "share_extension.channel_error": "Je bent geen lid van een team op de geselecteerde server. Selecteer een andere server of open Mattermost om lid te worden van een team.", "settings.advanced.delete_message.confirmation": "\nDit zal alle bestanden verwijderen die via de app voor deze server zijn gedownload. Gelieve te bevestigen om verder te gaan.\n", diff --git a/assets/base/i18n/sv.json b/assets/base/i18n/sv.json index 0f5135cad0..59fa977bbc 100644 --- a/assets/base/i18n/sv.json +++ b/assets/base/i18n/sv.json @@ -936,5 +936,8 @@ "user_status.away": "Tillfälligt borta", "mobile.camera_type.title": "Alternativ för kameran", "join_team.error.title": "Fel vid anslutning till teamet", - "join_team.error.message": "Det har uppstått ett fel när du skulle anslutas till teamet" + "join_team.error.message": "Det har uppstått ett fel när du skulle anslutas till teamet", + "skintone_selector.tooltip.title": "Välj standard-hudton", + "skintone_selector.tooltip.description": "Du kan nu välja vilken hudton du vill använda för dina emojis.", + "default_skin_tone": "Standard hudton" } diff --git a/assets/base/i18n/tr.json b/assets/base/i18n/tr.json index c03a78b140..bed103a98a 100644 --- a/assets/base/i18n/tr.json +++ b/assets/base/i18n/tr.json @@ -876,5 +876,68 @@ "join_team.error.title": "Bir takıma katılınırken sorun çıktı", "join_team.error.message": "Takıma katılınırken bir sorun çıktı", "join_team.error.group_error": "Bu takıma katılmak için ilişkilendirilmiş bir grubun üyesi olmalısınız.", - "connection_banner.connecting": "Bağlantı kuruluyor..." + "connection_banner.connecting": "Bağlantı kuruluyor...", + "share_extension.file_limit.single": "Dosya {size} boyutundan küçük olmalıdır", + "share_extension.file_limit.multiple": "Her bir dosya {size} boyutundan küçük olmalıdır", + "share_extension.count_limit": "Bu sunucuda yalnızca {count, number} {count, plural, one {dosya} other {dosya}} paylaşabilirsiniz", + "share_extension.channel_label": "Kanal", + "share_extension.channel_error": "Seçilmiş sunucuda bir takımın üyesi değilsiniz. Başka bir sunucu seçin ya da bir takıma katılmak için Mattermost uygulamasını açın.", + "settings.advanced.delete_message.confirmation": "\nBu işlem, bu sunucuya uygulama ile indirilmiş tüm dosyaları siler. Lütfen ilerlemek istiyorsanız onaylayın.\n", + "settings.advanced.delete_data": "Yerel dosyaları sil", + "settings.advanced.delete": "Sil", + "settings.advanced.cancel": "İptal", + "rate.title": "Mattermost hoşunuza gidiyor mu?", + "rate.subtitle": "Ne düşündüğünüzü bize iletin.", + "rate.error.title": "Hata", + "rate.error.text": "Gözden geçirme penceresi açılırken bir sorun çıktı.", + "rate.dont_ask_again": "Bir daha sorma", + "rate.button.yes": "Bayıldım!", + "rate.button.needs_work": "Çalışma gerektiriyor", + "post_priority.picker.title": "İleti önceliği", + "post_priority.picker.label.urgent": "Acil", + "post_priority.picker.label.standard": "Standart", + "post_priority.picker.label.important": "Önemli", + "post_priority.picker.beta": "BETA", + "onboaring.welcome_description": "Mattermost, geliştiriciler arasında işbirliği sağlamayı amaçlayan açık kaynaklı bir platformdur. Güvenlidir, esnektir ve araçlarınızla bütünleşik çalışır.", + "onboarding.welcome": "Hoş geldiniz", + "onboarding.realtime_collaboration_description": "Kalıcı kanallar, doğrudan iletişim ve dosya paylaşımı sorunsuz bir şekilde çalışır. Böylece nerede olursanız olun bağlantıda kalabilirsiniz.", + "onboarding.realtime_collaboration": "Gerçek zamanlı işbirliği yapın", + "onboarding.integrations_description": "Ortak geliştirme süreçlerine uygun, sıkı bir şekilde bütünleştirilmiş ürün çözümleriyle sohbetin ötesine geçin.", + "onboarding.calls_description": "Yazmak yeterince hızlı olmadığında, tek bir dokunuşla kanal tabanlı sohbetten güvenli sesli aramaya geçin.", + "onboarding.calls": "güvenli sesli çağrılar hemen başlatılsın", + "default_skin_tone": "Varsayılan cilt tonu", + "terms_of_service.acceptButton": "Kabul et", + "terms_of_service.terms_declined.text": "Bu sunucuya erişmek için hizmet koşullarını kabul etmelisiniz. Ayrıntılı bilgi almak için sistem yöneticinizle görüşün. Şimdi oturumunuz kapatılacak. Hizmet koşullarını kabul etmek için yeniden oturum açın.", + "video.download_description": "Oynatmak için bu görüntüyü indirmelisiniz.", + "user.edit_profile.profile_photo.change_photo": "Profil fotoğrafını değiştir", + "user_status.title": "Durum", + "user_status.online": "Çevrimiçi", + "user_status.offline": "Çevrimdışı", + "user_status.dnd": "Rahatsız etmeyin", + "user_status.away": "Uzakta", + "thread.loadingReplies": "Yanıtlar yükleniyor...", + "terms_of_service.title": "Hizmet koşulları", + "terms_of_service.terms_declined.title": "Hizmet koşullarını kabul etmelisiniz", + "terms_of_service.terms_declined.ok": "Tamam", + "terms_of_service.error.title": "Hizmet koşulları alınamadı.", + "terms_of_service.error.retry": "Yeniden dene", + "terms_of_service.error.logout": "Oturumu kapat", + "terms_of_service.error.description": "Hizmet koşulları sunucudan alınamadı.", + "terms_of_service.decline": "Reddet", + "terms_of_service.api_error": "İstek yerine getirilemedi. Sorun sürerse sistem yöneticiniz ile görüşün.", + "terms_of_service.alert_retry": "Yeniden dene", + "terms_of_service.alert_cancel": "İptal", + "skintone_selector.tooltip.title": "Varsayılan cilt tonunuzu seçin", + "skintone_selector.tooltip.description": "Artık emojilerinizde kullanmak istediğiniz cilt tonunu seçebilirsiniz.", + "share_feedback.title": "Görüşlerinizi paylaşır mısınız?", + "share_feedback.subtitle": "Deneyiminizi nasıl daha iyi yapabileceğimizi duymak isteriz.", + "share_feedback.button.yes": "Evet", + "share_feedback.button.no": "Hayır, teşekkürler", + "share_extension.upload_disabled": "Seçilmiş sunucu için dosya yükleme özelliği devre dışı bırakılmış", + "share_extension.share_screen.title": "Mattermost ile paylaş", + "share_extension.servers_screen.title": "Sunucu seçin", + "share_extension.server_label": "Sunucu", + "share_extension.multiple_label": "{count, number} ek dosya", + "share_extension.message": "Bir ileti yazın (isteğe bağlı)", + "share_extension.max_resolution": "Görsel olabilecek en büyük 7680 x 4320 piksel boyutundan büyük" } diff --git a/assets/base/i18n/uk.json b/assets/base/i18n/uk.json index 32f4fe7b88..040a971181 100644 --- a/assets/base/i18n/uk.json +++ b/assets/base/i18n/uk.json @@ -251,5 +251,22 @@ "user.settings.general.lastName": "Прізвище", "user.settings.general.nickname": "Псевдонім", "user.settings.general.position": "Посада", - "user.settings.general.username": "Ім'я користувача" + "user.settings.general.username": "Ім'я користувача", + "alert.push_proxy_error.title": "Сповіщення не можуть бути отримані з цього сервера", + "alert.push_proxy_error.description": "Через конфігурацію цього сервера сповіщення не можуть надходити в мобільний додаток. Щоб отримати додаткову інформацію, зверніться до свого системного адміністратора.", + "alert.channel_deleted.title": "Канал заархівований", + "alert.channel_deleted.description": "Канал {displayName} був заархівований.", + "account.your_profile": "Ваш профіль", + "account.settings": "Налаштування", + "account.logout_from": "Вийти з {serverName}", + "account.logout": "Вийти", + "announcment_banner.okay": "Добре", + "announcment_banner.dismiss": "Відхилити оголошення", + "alert.removed_from_team.title": "Видалено з команди", + "alert.removed_from_team.description": "Вас було видалино з команди {displayName}.", + "alert.removed_from_channel.title": "Видалено з каналу", + "alert.removed_from_channel.description": "Вас видалили з каналу {displayName}.", + "alert.push_proxy.button": "Добре", + "alert.push_proxy_unknown.title": "Сповіщення не може бути отримано з цього сервера", + "alert.push_proxy_unknown.description": "З невідомих причин цей сервер не зміг отримати push-нотифікацію. Це буде зроблено знову під час наступного підключення." } diff --git a/detox/e2e/support/ui/screen/index.ts b/detox/e2e/support/ui/screen/index.ts index 891e6d90b6..99497dda6c 100644 --- a/detox/e2e/support/ui/screen/index.ts +++ b/detox/e2e/support/ui/screen/index.ts @@ -23,6 +23,7 @@ import EmojiPickerScreen from './emoji_picker'; import FindChannelsScreen from './find_channels'; import GlobalThreadsScreen from './global_threads'; import HomeScreen from './home'; +import Invite from './invite'; import LoginScreen from './login'; import MentionNotificationSettingsScreen from './mention_notification_settings'; import NotificationSettingsScreen from './notification_settings'; @@ -69,6 +70,7 @@ export { FindChannelsScreen, GlobalThreadsScreen, HomeScreen, + Invite, LoginScreen, MentionNotificationSettingsScreen, NotificationSettingsScreen, diff --git a/detox/e2e/support/ui/screen/invite.ts b/detox/e2e/support/ui/screen/invite.ts new file mode 100644 index 0000000000..3962618fbf --- /dev/null +++ b/detox/e2e/support/ui/screen/invite.ts @@ -0,0 +1,127 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {ChannelListScreen} from '@support/ui/screen'; +import {timeouts, wait} from '@support/utils'; +import {expect} from 'detox'; + +class InviteScreen { + testID = { + inviteScreen: 'invite.screen', + screenSummary: 'invite.screen.summary', + screenSelection: 'invite.screen.selection', + closeButton: 'invite.close.button', + sendButton: 'invite.send.button', + teamIcon: 'invite.team_icon', + teamDisplayName: 'invite.team_display_name', + serverDisplayName: 'invite.server_display_name', + shareLinkButton: 'invite.share_link.button', + searchBarTitle: 'invite.search_bar_title', + searchBarInput: 'invite.search_bar_input', + selectedItems: 'invite.selected_items', + selectedItemPrefix: 'invite.selected_item', + searchList: 'invite.search_list', + searchListItemPrefix: 'invite.search_list_item.', + searchListTextItemPrefix: 'invite.search_list_text_item', + searchListUserItemPrefix: 'invite.search_list_user_item', + searchListNoResultsPrefix: 'invite.search_list_no_results', + summaryReportPrefix: 'invite.summary_report', + summaryReportTextItemPrefix: 'invite.summary_report.text_item', + summaryReportUserItemPrefix: 'invite.summary_report.user_item', + }; + + inviteScreen = element(by.id(this.testID.inviteScreen)); + screenSummary = element(by.id(this.testID.screenSummary)); + screenSelection = element(by.id(this.testID.screenSelection)); + closeButton = element(by.id(this.testID.closeButton)); + sendButton = element(by.id(this.testID.sendButton)); + teamIcon = element(by.id(this.testID.teamIcon)); + teamDisplayName = element(by.id(this.testID.teamDisplayName)); + serverDisplayName = element(by.id(this.testID.serverDisplayName)); + shareLinkButton = element(by.id(this.testID.shareLinkButton)); + searchBarTitle = element(by.id(this.testID.searchBarTitle)); + searchBarInput = element(by.id(this.testID.searchBarInput)); + selectedItems = element(by.id(this.testID.selectedItems)); + selectedItemPrefix = element(by.id(this.testID.selectedItemPrefix)); + searchList = element(by.id(this.testID.searchList)); + searchListItemPrefix = element(by.id(this.testID.searchListItemPrefix)); + searchListTextItemPrefix = element(by.id(this.testID.searchListTextItemPrefix)); + searchListUserItemPrefix = element(by.id(this.testID.searchListUserItemPrefix)); + searchListNoResultsPrefix = element(by.id(this.testID.searchListNoResultsPrefix)); + summaryReportTextItemPrefix = element(by.id(this.testID.summaryReportTextItemPrefix)); + summaryReportUserItemPrefix = element(by.id(this.testID.summaryReportUserItemPrefix)); + + getSearchListTextItem = (id: string) => { + return element(by.id(`${this.testID.searchListTextItemPrefix}.${id}`)); + }; + + getSearchListTextItemText = (id: string) => { + return element(by.id(`${this.testID.searchListTextItemPrefix}.text.${id}`)); + }; + + getSearchListUserItem = (id: string) => { + return element(by.id(`${this.testID.searchListUserItemPrefix}.${id}`)); + }; + + getSearchListUserItemText = (id: string) => { + return element(by.id(`${this.testID.searchListUserItemPrefix}.${id}.username`)); + }; + + getSearchListNoResults = (id: string) => { + return element(by.id(`${this.testID.searchListNoResultsPrefix}.${id}`)); + }; + + getSearchListNoResultsText = (id: string) => { + return element(by.id(`${this.testID.searchListNoResultsPrefix}.text.${id}`)); + }; + + getSelectedItem = (id: string) => { + return element(by.id(`${this.testID.selectedItemPrefix}.${id}`)); + }; + + getSummaryReportSent = () => { + return element(by.id(`${this.testID.summaryReportPrefix}.sent`)); + }; + + getSummaryReportNotSent = () => { + return element(by.id(`${this.testID.summaryReportPrefix}.not_sent`)); + }; + + getSummaryReportTextItem = (id: string) => { + return element(by.id(`${this.testID.summaryReportTextItemPrefix}.${id}`)); + }; + + getSummaryReportTextItemText = (id: string) => { + return element(by.id(`${this.testID.summaryReportTextItemPrefix}.text.${id}`)); + }; + + getSummaryReportUserItem = (id: string) => { + return element(by.id(`${this.testID.summaryReportUserItemPrefix}.${id}`)); + }; + + getSummaryReportUserItemText = (id: string) => { + return element(by.id(`${this.testID.summaryReportUserItemPrefix}.${id}.username`)); + }; + + toBeVisible = async () => { + await waitFor(this.inviteScreen).toExist().withTimeout(timeouts.TEN_SEC); + + return this.inviteScreen; + }; + + open = async () => { + await ChannelListScreen.headerPlusButton.tap(); + await wait(timeouts.ONE_SEC); + await ChannelListScreen.invitePeopleToTeamItem.tap(); + + return this.toBeVisible(); + }; + + close = async () => { + await this.closeButton.tap(); + await expect(this.inviteScreen).not.toBeVisible(); + }; +} + +const inviteScreen = new InviteScreen(); +export default inviteScreen; diff --git a/detox/e2e/support/ui/screen/server.ts b/detox/e2e/support/ui/screen/server.ts index 61f5966fbb..6bac98f927 100644 --- a/detox/e2e/support/ui/screen/server.ts +++ b/detox/e2e/support/ui/screen/server.ts @@ -45,6 +45,7 @@ class ServerScreen { connectToServer = async (serverUrl: string, serverDisplayName: string) => { await this.toBeVisible(); await this.serverUrlInput.replaceText(serverUrl); + await this.serverUrlInput.tapReturnKey(); await this.serverDisplayNameInput.replaceText(serverDisplayName); await this.connectButton.tap(); }; diff --git a/detox/e2e/test/teams/invite_people.e2e.ts b/detox/e2e/test/teams/invite_people.e2e.ts index f325701d7e..fc0faeaeaf 100644 --- a/detox/e2e/test/teams/invite_people.e2e.ts +++ b/detox/e2e/test/teams/invite_people.e2e.ts @@ -7,32 +7,34 @@ // - Use element testID when selecting an element. Create one if none. // ******************************************************************* -import {Setup} from '@support/server_api'; +import {Setup, User} from '@support/server_api'; import { serverOneUrl, siteOneUrl, } from '@support/test_config'; import { ChannelListScreen, + Invite, HomeScreen, LoginScreen, ServerScreen, } from '@support/ui/screen'; -import {isIos, timeouts, wait} from '@support/utils'; +import {isIos, timeouts} from '@support/utils'; import {expect} from 'detox'; function systemDialog(label: string) { - if (device.getPlatform() === 'ios') { + if (isIos()) { return element(by.label(label)).atIndex(0); } return element(by.text(label)); } -describe('Teams - Invite people', () => { +describe('Teams - Invite', () => { const serverOneDisplayName = 'Server 1'; let testTeam: any; let testUser: any; + let testUser1: any; beforeAll(async () => { const {team, user} = await Setup.apiInit(siteOneUrl); @@ -40,38 +42,208 @@ describe('Teams - Invite people', () => { testTeam = team; testUser = user; + const {user: user1} = await User.apiCreateUser(siteOneUrl, {prefix: 'i'}); + + testUser1 = user1; + // # Log in to server await ServerScreen.connectToServer(serverOneUrl, serverOneDisplayName); await LoginScreen.login(testUser); }); beforeEach(async () => { + await device.reloadReactNative(); + // * Verify on channel list screen await ChannelListScreen.toBeVisible(); + + // # Open invite screen + await Invite.open(); }); afterAll(async () => { + // # Close invite screen + await Invite.close(); + // # Log out await HomeScreen.logout(); }); + it('MM-T5360 - should open the invite screen', async () => { + // * Verify invite screen Header buttons + await expect(Invite.closeButton).toBeVisible(); + await expect(Invite.sendButton).toBeVisible(); + + // * Verify Team data + await expect(Invite.teamDisplayName).toHaveText(testTeam.display_name); + await expect(Invite.teamIcon).toBeVisible(); + + // * Verify default Selection + await expect(Invite.screenSelection).toBeVisible(); + + // * Verify Server data + await expect(Invite.serverDisplayName).toHaveText(serverOneDisplayName); + + // * Verify Share Link + await expect(Invite.shareLinkButton).toBeVisible(); + + // * Verify Search bar + await expect(Invite.searchBarTitle).toBeVisible(); + await expect(Invite.searchBarInput).toBeVisible(); + }); + it('MM-T5221 - should be able to share a URL invite to the team', async () => { - // # Open plus menu - await ChannelListScreen.headerPlusButton.tap(); - - // * Verify invite people to team item is available - await wait(timeouts.ONE_SEC); - await expect(ChannelListScreen.invitePeopleToTeamItem).toExist(); - - // # Tap on invite people to team item - await ChannelListScreen.invitePeopleToTeamItem.tap(); + // # Tap on Share link + await Invite.shareLinkButton.tap(); if (isIos()) { + const dialog = systemDialog(`Join the ${testTeam.display_name} team`); + // * Verify share dialog is open - await expect(systemDialog(`Join the ${testTeam.display_name} team`)).toExist(); + await expect(dialog).toExist(); // # Close share dialog - await device.reloadReactNative(); + await dialog.swipe('down'); } }); + + it('MM-T5361 - should show no results item in search list', async () => { + const noUser = 'qwertyuiop'; + + // # Search for a non existent user + await Invite.searchBarInput.replaceText(noUser); + + // * Validate no results item in search list + await expect(Invite.getSearchListNoResults(noUser)).toBeVisible(); + await expect(Invite.getSearchListNoResultsText(noUser)).toHaveText(noUser); + }); + + it('MM-T5362 - should be able to send email invite', async () => { + const noUserEmailFormat = 'qwerty@ui.op'; + + // # Search for a non existent user with email format + await Invite.searchBarInput.replaceText(noUserEmailFormat); + + // * Validate email invite item in search list + await expect(Invite.getSearchListTextItem(noUserEmailFormat)).toBeVisible(); + await expect(Invite.getSearchListTextItemText(noUserEmailFormat)).toHaveText(noUserEmailFormat); + + // # Select email invite item + await Invite.getSearchListTextItem(noUserEmailFormat).tap(); + await expect(Invite.getSearchListTextItem(noUserEmailFormat)).not.toBeVisible(); + + // * Validate email invite is added to selected items + await expect(Invite.getSelectedItem(noUserEmailFormat)).toBeVisible(); + + // # Send invitation + await Invite.sendButton.tap(); + + // * Validate summary report sent + await expect(Invite.screenSummary).toBeVisible(); + await expect(Invite.getSummaryReportSent()).toBeVisible(); + await expect(Invite.getSummaryReportNotSent()).not.toExist(); + await expect(Invite.getSummaryReportTextItem(noUserEmailFormat)).toBeVisible(); + await expect(Invite.getSummaryReportTextItemText(noUserEmailFormat)).toHaveText(noUserEmailFormat); + }); + + it('MM-T5363 - should be able to send user invite', async () => { + const username = ` @${testUser1.username}`; + + // # Search for a existent user + await Invite.searchBarInput.replaceText(testUser1.username); + + // * Validate user item in search list + await expect(Invite.getSearchListUserItem(testUser1.id)).toBeVisible(); + await expect(Invite.getSearchListUserItemText(testUser1.id)).toHaveText(username); + + // # Select user item + await Invite.getSearchListUserItem(testUser1.id).tap(); + await expect(Invite.getSearchListUserItem(testUser1.id)).not.toBeVisible(); + + // * Validate user is added to selected items + await expect(Invite.getSelectedItem(testUser1.id)).toBeVisible(); + + // # Send invitation + await Invite.sendButton.tap(); + + // * Validate summary report sent + await expect(Invite.screenSummary).toBeVisible(); + await expect(Invite.getSummaryReportSent()).toBeVisible(); + await expect(Invite.getSummaryReportNotSent()).not.toExist(); + await expect(Invite.getSummaryReportUserItem(testUser1.id)).toBeVisible(); + await expect(Invite.getSummaryReportUserItemText(testUser1.id)).toHaveText(username); + }); + + it('MM-T5364 - should not be able to send user invite to user already in team', async () => { + const username = ` @${testUser1.username}`; + + // # Search for a existent user already in team + await Invite.searchBarInput.replaceText(testUser1.username); + + // * Validate user item in search list + await expect(Invite.getSearchListUserItem(testUser1.id)).toBeVisible(); + + // # Select user item + await Invite.getSearchListUserItem(testUser1.id).tap(); + + // * Validate user is added to selected items + await expect(Invite.getSelectedItem(testUser1.id)).toBeVisible(); + + // # Send invitation + await Invite.sendButton.tap(); + + // * Validate summary report not sent + await expect(Invite.screenSummary).toBeVisible(); + await expect(Invite.getSummaryReportSent()).not.toExist(); + await expect(Invite.getSummaryReportNotSent()).toBeVisible(); + await expect(Invite.getSummaryReportUserItem(testUser1.id)).toBeVisible(); + await expect(Invite.getSummaryReportUserItemText(testUser1.id)).toHaveText(username); + }); + + it('MM-T5365 - should handle both sent and not sent invites', async () => { + const {user: testUser2} = await User.apiCreateUser(siteOneUrl, {prefix: 'i'}); + + const username1 = ` @${testUser1.username}`; + const username2 = ` @${testUser2.username}`; + + // # Search for a existent user + await Invite.searchBarInput.replaceText(testUser2.username); + + // * Validate user item in search list + await expect(Invite.getSearchListUserItem(testUser2.id)).toBeVisible(); + + // # Select user item + await Invite.getSearchListUserItem(testUser2.id).tap(); + + // * Validate user is added to selected items + await expect(Invite.getSelectedItem(testUser2.id)).toBeVisible(); + + // # Search for a existent user already in team + await Invite.searchBarInput.replaceText(testUser1.username); + + // # Wait for user item in search list + await waitFor(Invite.getSearchListUserItem(testUser1.id)).toExist().withTimeout(timeouts.TWO_SEC); + + // # Select user item + await Invite.getSearchListUserItem(testUser1.id).tap(); + + // * Validate user is added to selected items + await expect(Invite.getSelectedItem(testUser1.id)).toBeVisible(); + + // # Send invitation + await Invite.sendButton.tap(); + + // * Validate summary + await expect(Invite.screenSummary).toBeVisible(); + + // * Validate summary report not sent + await expect(Invite.getSummaryReportNotSent()).toBeVisible(); + await expect(Invite.getSummaryReportUserItem(testUser1.id)).toBeVisible(); + await expect(Invite.getSummaryReportUserItemText(testUser1.id)).toHaveText(username1); + + // * Validate summary report sent + await expect(Invite.getSummaryReportSent()).toBeVisible(); + await expect(Invite.getSummaryReportUserItem(testUser2.id)).toBeVisible(); + await expect(Invite.getSummaryReportUserItemText(testUser2.id)).toHaveText(username2); + }); }); diff --git a/detox/package-lock.json b/detox/package-lock.json index e61e8d934d..76fb4b4799 100644 --- a/detox/package-lock.json +++ b/detox/package-lock.json @@ -11,17 +11,17 @@ "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", "@jest/test-sequencer": "29.3.1", - "@types/jest": "29.2.5", + "@types/jest": "29.2.6", "@types/tough-cookie": "4.0.2", "@types/uuid": "9.0.0", - "aws-sdk": "2.1286.0", - "axios": "1.2.2", + "aws-sdk": "2.1297.0", + "axios": "1.2.3", "axios-cookiejar-support": "4.0.6", "babel-jest": "29.3.1", - "babel-plugin-module-resolver": "4.1.0", + "babel-plugin-module-resolver": "5.0.0", "client-oauth2": "4.3.3", "deepmerge": "4.2.2", - "detox": "20.1.1", + "detox": "20.1.2", "form-data": "4.0.0", "jest": "29.3.1", "jest-circus": "29.3.1", @@ -35,7 +35,7 @@ "sanitize-filename": "1.6.3", "shelljs": "0.8.5", "tough-cookie": "4.1.2", - "ts-jest": "29.0.3", + "ts-jest": "29.0.5", "tslib": "2.4.1", "typescript": "4.9.4", "uuid": "9.0.0", @@ -2612,9 +2612,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.6.tgz", + "integrity": "sha512-XEUC/Tgw3uMh6Ho8GkUtQ2lPhY5Fmgyp3TdlkTJs1W9VgNxs+Ow/x3Elh8lHQKqCbZL0AubQuqWjHVT033Hhrw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -2792,9 +2792,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1286.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1286.0.tgz", - "integrity": "sha512-CvkCD1+NSk2MPOutD2hEPhXDET/79w/gd9a359QWb9Ja0Fd4vVFXPkhlm1DTGzuwqFKGinpCMxDP4md7QPsVvw==", + "version": "2.1297.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1297.0.tgz", + "integrity": "sha512-hZbG8tfluU2ijCCBQnQzCiPbArFtaWqAUFAWAGZ0+Df7OzTm7ya9fLYV3j3L6p2PacAyAuxXaeMbgMHlHi/D3w==", "dev": true, "dependencies": { "buffer": "4.9.2", @@ -2841,9 +2841,9 @@ } }, "node_modules/axios": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", - "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -2993,19 +2993,59 @@ } }, "node_modules/babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", + "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", "dev": true, "dependencies": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", + "find-babel-config": "^2.0.0", + "glob": "^8.0.3", "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "reselect": "^4.1.7", + "resolve": "^1.22.1" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 16" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/babel-plugin-polyfill-corejs2": { @@ -3651,9 +3691,9 @@ } }, "node_modules/detox": { - "version": "20.1.1", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.1.tgz", - "integrity": "sha512-0ieeWAyo2f3YKeFwm7KCz4lBkCJIydyqzCQVN1sw/ZU9x9Qc8kz+itKAEiH4DHUlLkb4YLzfEbAXfO09wvrQ3w==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.2.tgz", + "integrity": "sha512-SGxLyuzE8TjIc4Lg49YKD0buj3JLaX+KtprSeFvn7ZTdWd4fH6o5Szd4KM21uBSpnYEEgXTgiCypPQst6dt5mQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -3669,7 +3709,7 @@ "glob": "^8.0.3", "ini": "^1.3.4", "json-cycle": "^1.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "multi-sort-stream": "^1.0.3", "multipipe": "^4.0.0", "node-ipc": "^9.2.1", @@ -4163,25 +4203,25 @@ } }, "node_modules/find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", + "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", "dev": true, "dependencies": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" + "json5": "^2.1.1", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=16.0.0" } }, - "node_modules/find-babel-config/node_modules/json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", + "node_modules/find-babel-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=8" } }, "node_modules/find-up": { @@ -7445,9 +7485,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -8525,9 +8565,9 @@ "dev": true }, "node_modules/reselect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", - "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==", "dev": true }, "node_modules/resolve": { @@ -9211,15 +9251,15 @@ "dev": true }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -11674,9 +11714,9 @@ } }, "@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.6.tgz", + "integrity": "sha512-XEUC/Tgw3uMh6Ho8GkUtQ2lPhY5Fmgyp3TdlkTJs1W9VgNxs+Ow/x3Elh8lHQKqCbZL0AubQuqWjHVT033Hhrw==", "dev": true, "requires": { "expect": "^29.0.0", @@ -11823,9 +11863,9 @@ "dev": true }, "aws-sdk": { - "version": "2.1286.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1286.0.tgz", - "integrity": "sha512-CvkCD1+NSk2MPOutD2hEPhXDET/79w/gd9a359QWb9Ja0Fd4vVFXPkhlm1DTGzuwqFKGinpCMxDP4md7QPsVvw==", + "version": "2.1297.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1297.0.tgz", + "integrity": "sha512-hZbG8tfluU2ijCCBQnQzCiPbArFtaWqAUFAWAGZ0+Df7OzTm7ya9fLYV3j3L6p2PacAyAuxXaeMbgMHlHi/D3w==", "dev": true, "requires": { "buffer": "4.9.2", @@ -11865,9 +11905,9 @@ } }, "axios": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", - "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", "dev": true, "requires": { "follow-redirects": "^1.15.0", @@ -11976,16 +12016,49 @@ } }, "babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", + "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", "dev": true, "requires": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", + "find-babel-config": "^2.0.0", + "glob": "^8.0.3", "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "reselect": "^4.1.7", + "resolve": "^1.22.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "babel-plugin-polyfill-corejs2": { @@ -12459,9 +12532,9 @@ "dev": true }, "detox": { - "version": "20.1.1", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.1.tgz", - "integrity": "sha512-0ieeWAyo2f3YKeFwm7KCz4lBkCJIydyqzCQVN1sw/ZU9x9Qc8kz+itKAEiH4DHUlLkb4YLzfEbAXfO09wvrQ3w==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.2.tgz", + "integrity": "sha512-SGxLyuzE8TjIc4Lg49YKD0buj3JLaX+KtprSeFvn7ZTdWd4fH6o5Szd4KM21uBSpnYEEgXTgiCypPQst6dt5mQ==", "dev": true, "requires": { "ajv": "^8.6.3", @@ -12476,7 +12549,7 @@ "glob": "^8.0.3", "ini": "^1.3.4", "json-cycle": "^1.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "multi-sort-stream": "^1.0.3", "multipipe": "^4.0.0", "node-ipc": "^9.2.1", @@ -12859,19 +12932,19 @@ } }, "find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", + "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", "dev": true, "requires": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" + "json5": "^2.1.1", + "path-exists": "^4.0.0" }, "dependencies": { - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==", + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true } } @@ -15285,9 +15358,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsonfile": { @@ -16111,9 +16184,9 @@ "dev": true }, "reselect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz", - "integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==", "dev": true }, "resolve": { @@ -16622,15 +16695,15 @@ "dev": true }, "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "requires": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", diff --git a/detox/package.json b/detox/package.json index e91b122073..ae83b4aafc 100644 --- a/detox/package.json +++ b/detox/package.json @@ -9,17 +9,17 @@ "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", "@jest/test-sequencer": "29.3.1", - "@types/jest": "29.2.5", + "@types/jest": "29.2.6", "@types/tough-cookie": "4.0.2", "@types/uuid": "9.0.0", - "aws-sdk": "2.1286.0", - "axios": "1.2.2", + "aws-sdk": "2.1297.0", + "axios": "1.2.3", "axios-cookiejar-support": "4.0.6", "babel-jest": "29.3.1", - "babel-plugin-module-resolver": "4.1.0", + "babel-plugin-module-resolver": "5.0.0", "client-oauth2": "4.3.3", "deepmerge": "4.2.2", - "detox": "20.1.1", + "detox": "20.1.2", "form-data": "4.0.0", "jest": "29.3.1", "jest-circus": "29.3.1", @@ -33,7 +33,7 @@ "sanitize-filename": "1.6.3", "shelljs": "0.8.5", "tough-cookie": "4.1.2", - "ts-jest": "29.0.3", + "ts-jest": "29.0.5", "tslib": "2.4.1", "typescript": "4.9.4", "uuid": "9.0.0", diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 63a4161ab0..fad38e7460 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -667,6 +667,7 @@ platform :android do package_id = ENV['MAIN_APP_IDENTIFIER'] || 'com.mattermost.rnbeta' android_change_package_identifier(newIdentifier: package_id, manifest: './android/app/src/main/AndroidManifest.xml') android_update_application_id(app_folder_name: 'android/app', application_id: package_id) + android_update_namespace(app_folder_name: 'android/app', namespace: package_id) app_scheme = ENV['APP_SCHEME'] || 'mattermost' find_replace_string( @@ -693,12 +694,6 @@ platform :android do sh "mv .#{beta_dir}* .#{release_dir}" - find_replace_string( - path_to_file: './android/app/BUCK', - old_string: 'package com.mattermost.rnbeta;', - new_string: "package #{package_id};" - ) - Dir.glob(".#{release_dir}*.java") do |item| find_replace_string( path_to_file: item[1..-1], diff --git a/fastlane/Gemfile.lock b/fastlane/Gemfile.lock index 8f0e2da226..5ca22a121f 100644 --- a/fastlane/Gemfile.lock +++ b/fastlane/Gemfile.lock @@ -8,16 +8,16 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.683.0) - aws-sdk-core (3.168.4) + aws-partitions (1.695.0) + aws-sdk-core (3.169.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.61.0) + aws-sdk-kms (1.62.0) aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.117.2) + aws-sdk-s3 (1.118.0) aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) @@ -36,8 +36,8 @@ GEM unf (>= 0.0.5, < 1.0.0) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.95.0) - faraday (1.10.2) + excon (0.97.1) + faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -113,7 +113,7 @@ GEM gh_inspector (1.1.3) google-apis-androidpublisher_v3 (0.32.0) google-apis-core (>= 0.9.1, < 2.a) - google-apis-core (0.9.2) + google-apis-core (0.9.5) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -159,19 +159,19 @@ GEM memoist (0.16.2) mini_magick (4.12.0) mini_mime (1.1.2) - mini_portile2 (2.8.0) + mini_portile2 (2.8.1) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) naturally (2.2.1) - nokogiri (1.13.10) + nokogiri (1.14.0) mini_portile2 (~> 2.8.0) racc (~> 1.4) optparse (0.1.1) os (1.1.4) plist (3.6.0) public_suffix (5.0.1) - racc (1.6.1) + racc (1.6.2) rake (13.0.6) representable (3.2.0) declarative (< 0.1.0) diff --git a/fastlane/actions/android_update_namespace.rb b/fastlane/actions/android_update_namespace.rb new file mode 100644 index 0000000000..e0b0eecb49 --- /dev/null +++ b/fastlane/actions/android_update_namespace.rb @@ -0,0 +1,110 @@ +# rubocop:disable Style/CaseEquality +# rubocop:disable Style/MultilineTernaryOperator +# rubocop:disable Style/NestedTernaryOperator + +require 'tempfile' +require 'fileutils' + +module Fastlane + module Actions + class AndroidUpdateNamespaceAction < Action + def self.run(params) + app_folder_name ||= params[:app_folder_name] + UI.message("The update_namespace plugin is looking inside your project folder (#{app_folder_name})!") + + new_namespace ||= params[:namespace] + UI.message("new namespace = #{new_namespace}") + + temp_file = Tempfile.new('fastlaneUpdateNamespace') + foundNamespace = "false" + Dir.glob("#{app_folder_name}/build.gradle") do |path| + UI.message(" -> Found a build.gradle file at path: (#{path})!") + begin + temp_file = Tempfile.new('fastlaneUpdateNamespace') + File.open(path, 'r') do |file| + file.each_line do |line| + if line.include? "namespace " and foundNamespace=="false" + + applicationComponents = line.strip.split(' ') + namespace = applicationComponents[1].tr("\"","") + line.replace line.sub(namespace, new_namespace.to_s) + foundNamespace = "true" + temp_file.puts line + else + temp_file.puts line + end + end + + if foundNamespace=="true" + break + end + file.close + end + temp_file.rewind + temp_file.close + FileUtils.mv(temp_file.path, path) + temp_file.unlink + ensure + if foundNamespace=="true" + + break + end + + end + end + + + if new_namespace.empty? + UI.user_error!("Impossible to update the namespace in the current project folder #{app_folder_name} 😭") + else + # Store the version name in the shared hash + Actions.lane_context["ANDROID_NAMESPACE"]=new_namespace + UI.success("☝️ namespace has been changed to #{new_namespace}") + end + + return new_namespace + end + + def self.description + "Update the namespace of your android project." + end + + def self.authors + ["Elias Nahum"] + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :app_folder_name, + env_name: "APPLICATIONID_APP_FOLDER_NAME", + description: "The name of the application source folder in the Android project (default: app)", + optional: true, + type: String, + default_value:"app"), + FastlaneCore::ConfigItem.new(key: :namespace, + env_name: "NAMESPACE_VALUE", + description: "Change to a specific namespace", + optional: false, + type: String, + default_value: '') + ] + end + + def self.output + [ + ['ANDROID_NAMESPACE', 'The new namespace of the project'] + ] + end + + def self.is_supported?(platform) + [:android].include?(platform) + end + end + end +end + + + +# rubocop:enable Style/CaseEquality +# rubocop:enable Style/MultilineTernaryOperator +# rubocop:enable Style/NestedTernaryOperator diff --git a/index.ts b/index.ts index 1b0b597d17..69fbefa2df 100644 --- a/index.ts +++ b/index.ts @@ -3,10 +3,10 @@ import TurboLogger from '@mattermost/react-native-turbo-log'; import {LogBox, Platform} from 'react-native'; +import ViewReactNativeStyleAttributes from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes'; import {RUNNING_E2E} from 'react-native-dotenv'; import 'react-native-gesture-handler'; import {Navigation} from 'react-native-navigation'; -import ViewReactNativeStyleAttributes from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes'; import {initialize, start} from './app/init/app'; import setFontFamily from './app/utils/font_family'; @@ -26,9 +26,6 @@ TurboLogger.configure({ if (__DEV__) { LogBox.ignoreLogs([ - '`-[RCTRootView cancelTouches]`', - 'scaleY', - "[react-native-gesture-handler] Seems like you're using an old API with gesture components, check out new Gestures system!", 'new NativeEventEmitter', ]); diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index 958371b43e..638d652ec1 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -921,7 +921,7 @@ "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/hermes.framework/hermes", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( @@ -1116,7 +1116,7 @@ CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 452; + CURRENT_PROJECT_VERSION = 453; DEVELOPMENT_TEAM = UQ8HT4Q2XM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = ( @@ -1160,7 +1160,7 @@ CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 452; + CURRENT_PROJECT_VERSION = 453; DEVELOPMENT_TEAM = UQ8HT4Q2XM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = ( @@ -1303,7 +1303,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 452; + CURRENT_PROJECT_VERSION = 453; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = UQ8HT4Q2XM; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1354,7 +1354,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 452; + CURRENT_PROJECT_VERSION = 453; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = UQ8HT4Q2XM; GCC_C_LANGUAGE_STANDARD = gnu11; diff --git a/ios/Mattermost.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Mattermost.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c5ea..ff23ebc817 100644 --- a/ios/Mattermost.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/ios/Mattermost.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -2,6 +2,8 @@ + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + PreviewsEnabled diff --git a/ios/Mattermost/AppDelegate.h b/ios/Mattermost/AppDelegate.h index 52ab11b46d..37ec94b47f 100644 --- a/ios/Mattermost/AppDelegate.h +++ b/ios/Mattermost/AppDelegate.h @@ -1,10 +1,9 @@ -#import +#import #import #import "RNNotifications.h" -@interface AppDelegate : UIResponder +@interface AppDelegate : RCTAppDelegate -@property (nonatomic, strong) UIWindow *window; @property(nonatomic,assign)BOOL allowRotation; @end diff --git a/ios/Mattermost/AppDelegate.mm b/ios/Mattermost/AppDelegate.mm index cda7f23962..c35997300f 100644 --- a/ios/Mattermost/AppDelegate.mm +++ b/ios/Mattermost/AppDelegate.mm @@ -3,9 +3,7 @@ #import #import -#import #import -#import #import #import @@ -15,26 +13,6 @@ #import "Mattermost-Swift.h" #import -#if RCT_NEW_ARCH_ENABLED -#import -#import -#import -#import -#import -#import -#import - -static NSString *const kRNConcurrentRoot = @"concurrentRoot"; - -@interface AppDelegate () { - RCTTurboModuleManager *_turboModuleManager; - RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; - std::shared_ptr _reactNativeConfig; - facebook::react::ContextContainer::Shared _contextContainer; -} -@end -#endif - @implementation AppDelegate NSString* const NOTIFICATION_MESSAGE_ACTION = @"message"; @@ -50,8 +28,6 @@ NSString* const NOTIFICATION_TEST_ACTION = @"test"; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - RCTAppSetupPrepareApp(application); - if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) { _allowRotation = YES; @@ -75,25 +51,11 @@ NSString* const NOTIFICATION_TEST_ACTION = @"test"; [RNNotifications startMonitorNotifications]; - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - if (@available(iOS 13.0, *)) { - self.window.backgroundColor = [UIColor systemBackgroundColor]; - } else { - self.window.backgroundColor = [UIColor whiteColor]; - } - [self.window makeKeyWindow]; - - RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; - - #if RCT_NEW_ARCH_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); - _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; - bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; - #endif - - [ReactNativeNavigation bootstrapWithBridge:bridge]; + self.moduleName = @"Mattermost"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + [ReactNativeNavigation bootstrapWithDelegate:self launchOptions:launchOptions]; os_log(OS_LOG_DEFAULT, "Mattermost started!!"); @@ -250,6 +212,7 @@ RNHWKeyboardEvent *hwKeyEvent = nil; // Switch this bool to turn on and off the concurrent root return false; } + - (NSDictionary *)prepareInitialProps { NSMutableDictionary *initProps = [NSMutableDictionary new]; @@ -268,35 +231,4 @@ RNHWKeyboardEvent *hwKeyEvent = nil; #endif } -#if RCT_NEW_ARCH_ENABLED -#pragma mark - RCTCxxBridgeDelegate -- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge -{ - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); -} -#pragma mark RCTTurboModuleManagerDelegate -- (Class)getModuleClassFromName:(const char *)name -{ - return RCTCoreModulesClassProvider(name); -} -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker -{ - return nullptr; -} -- (std::shared_ptr)getTurboModule:(const std::string &)name - initParams: - (const facebook::react::ObjCTurboModule::InitParams &)params -{ - return nullptr; -} -- (id)getModuleInstanceFromClass:(Class)moduleClass -{ - return RCTAppSetupDefaultModuleFromClass(moduleClass); -} -#endif - @end diff --git a/ios/Mattermost/Info.plist b/ios/Mattermost/Info.plist index b92fded1b0..e8483614ce 100644 --- a/ios/Mattermost/Info.plist +++ b/ios/Mattermost/Info.plist @@ -37,7 +37,7 @@ CFBundleVersion - 452 + 453 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS @@ -83,6 +83,10 @@ Upload photos and videos from your device to $(PRODUCT_NAME) NSSpeechRecognitionUsageDescription Send voice messages to $(PRODUCT_NAME) + NSUserActivityTypes + + INSendMessageIntent + UIAppFonts OpenSans-Bold.ttf @@ -113,23 +117,21 @@ armv7 UIRequiresFullScreen - + UISupportedInterfaceOrientations - UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait UISupportedInterfaceOrientations~ipad - UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown UIViewControllerBasedStatusBarAppearance - NSUserActivityTypes - - INSendMessageIntent - diff --git a/ios/MattermostShare/Info.plist b/ios/MattermostShare/Info.plist index 597ef229c3..80d2594e0e 100644 --- a/ios/MattermostShare/Info.plist +++ b/ios/MattermostShare/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 2.0.0 CFBundleVersion - 452 + 453 UIAppFonts OpenSans-Bold.ttf diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index 9085909595..6eaa7947d9 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 2.0.0 CFBundleVersion - 452 + 453 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile b/ios/Podfile index a740aa8fab..0c70352b4f 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,8 +1,24 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, '12.4' -install! 'cocoapods', :deterministic_uuids => false +platform :ios, min_ios_version_supported +prepare_react_native_project! + +# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. +# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded +# +# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` +# ```js +# module.exports = { +# dependencies: { +# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), +# ``` +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end target 'Mattermost' do # Pods for Mattermost @@ -23,7 +39,7 @@ target 'Mattermost' do # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. - :flipper_configuration => FlipperConfiguration.enabled, + :flipper_configuration => flipper_config, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) @@ -34,6 +50,7 @@ target 'Mattermost' do pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications" pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary" pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi', :modular_headers => true + pod 'React-jsc', :path => '../node_modules/react-native/ReactCommon/jsc', :modular_headers => true pod 'simdjson', path: '../node_modules/@nozbe/simdjson' # TODO: Remove this once upstream PR https://github.com/daltoniam/Starscream/pull/871 is merged @@ -53,16 +70,4 @@ post_install do |installer| puts 'Patching Alamofire to include X-Uncompressed-Content-Length to measure download progress' %x(patch Pods/Alamofire/Source/SessionDelegate.swift < patches/SessionDelegate.patch) - installer.pods_project.targets.each do |target| - if target.name != "RCT-Folly" - target.build_configurations.each do |config| - config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' - end - end - if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle" - target.build_configurations.each do |config| - config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' - end - end - end end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ddd55e7aad..28a3a4b73f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -8,14 +8,14 @@ PODS: - CocoaLumberjack/Core (= 3.8.0) - CocoaLumberjack/Core (3.8.0) - DoubleConversion (1.1.6) - - FBLazyVector (0.70.6) - - FBReactNativeSpec (0.70.6): + - FBLazyVector (0.71.1) + - FBReactNativeSpec (0.71.1): - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.70.6) - - RCTTypeSafety (= 0.70.6) - - React-Core (= 0.70.6) - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) + - RCTRequired (= 0.71.1) + - RCTTypeSafety (= 0.71.1) + - React-Core (= 0.71.1) + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) - Flipper (0.125.0): - Flipper-Folly (~> 2.6) - Flipper-RSocket (~> 1.4) @@ -79,7 +79,9 @@ PODS: - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) - - hermes-engine (0.70.6) + - hermes-engine (0.71.1): + - hermes-engine/Pre-built (= 0.71.1) + - hermes-engine/Pre-built (0.71.1) - HMSegmentedControl (1.5.6) - jail-monkey (2.8.0): - React-Core @@ -93,8 +95,9 @@ PODS: - libwebp/mux (1.2.4): - libwebp/demux - libwebp/webp (1.2.4) - - mattermost-react-native-turbo-log (0.2.1): + - mattermost-react-native-turbo-log (0.2.2): - CocoaLumberjack + - RCT-Folly (= 2021.07.22.00) - React-Core - OpenSSL-Universal (1.1.1100) - Permission-Camera (3.6.1): @@ -122,218 +125,216 @@ PODS: - fmt (~> 6.2.1) - glog - libevent - - RCTRequired (0.70.6) - - RCTTypeSafety (0.70.6): - - FBLazyVector (= 0.70.6) - - RCTRequired (= 0.70.6) - - React-Core (= 0.70.6) - - React (0.70.6): - - React-Core (= 0.70.6) - - React-Core/DevSupport (= 0.70.6) - - React-Core/RCTWebSocket (= 0.70.6) - - React-RCTActionSheet (= 0.70.6) - - React-RCTAnimation (= 0.70.6) - - React-RCTBlob (= 0.70.6) - - React-RCTImage (= 0.70.6) - - React-RCTLinking (= 0.70.6) - - React-RCTNetwork (= 0.70.6) - - React-RCTSettings (= 0.70.6) - - React-RCTText (= 0.70.6) - - React-RCTVibration (= 0.70.6) - - React-bridging (0.70.6): - - RCT-Folly (= 2021.07.22.00) - - React-jsi (= 0.70.6) - - React-callinvoker (0.70.6) - - React-Codegen (0.70.6): - - FBReactNativeSpec (= 0.70.6) - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.70.6) - - RCTTypeSafety (= 0.70.6) - - React-Core (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-Core (0.70.6): + - RCTRequired (0.71.1) + - RCTTypeSafety (0.71.1): + - FBLazyVector (= 0.71.1) + - RCTRequired (= 0.71.1) + - React-Core (= 0.71.1) + - React (0.71.1): + - React-Core (= 0.71.1) + - React-Core/DevSupport (= 0.71.1) + - React-Core/RCTWebSocket (= 0.71.1) + - React-RCTActionSheet (= 0.71.1) + - React-RCTAnimation (= 0.71.1) + - React-RCTBlob (= 0.71.1) + - React-RCTImage (= 0.71.1) + - React-RCTLinking (= 0.71.1) + - React-RCTNetwork (= 0.71.1) + - React-RCTSettings (= 0.71.1) + - React-RCTText (= 0.71.1) + - React-RCTVibration (= 0.71.1) + - React-callinvoker (0.71.1) + - React-Codegen (0.71.1): + - FBReactNativeSpec + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.70.6) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-Core/Default (= 0.71.1) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/CoreModulesHeaders (0.70.6): + - React-Core/CoreModulesHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/Default (0.70.6): + - React-Core/Default (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/DevSupport (0.70.6): + - React-Core/DevSupport (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.70.6) - - React-Core/RCTWebSocket (= 0.70.6) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-jsinspector (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-Core/Default (= 0.71.1) + - React-Core/RCTWebSocket (= 0.71.1) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-jsinspector (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTActionSheetHeaders (0.70.6): + - React-Core/RCTActionSheetHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTAnimationHeaders (0.70.6): + - React-Core/RCTAnimationHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTBlobHeaders (0.70.6): + - React-Core/RCTBlobHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTImageHeaders (0.70.6): + - React-Core/RCTImageHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTLinkingHeaders (0.70.6): + - React-Core/RCTLinkingHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTNetworkHeaders (0.70.6): + - React-Core/RCTNetworkHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTSettingsHeaders (0.70.6): + - React-Core/RCTSettingsHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTTextHeaders (0.70.6): + - React-Core/RCTTextHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTVibrationHeaders (0.70.6): + - React-Core/RCTVibrationHeaders (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-Core/RCTWebSocket (0.70.6): + - React-Core/RCTWebSocket (0.71.1): - glog - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.70.6) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-Core/Default (= 0.71.1) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-perflogger (= 0.71.1) - Yoga - - React-CoreModules (0.70.6): + - React-CoreModules (0.71.1): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.6) - - React-Codegen (= 0.70.6) - - React-Core/CoreModulesHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - React-RCTImage (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-cxxreact (0.70.6): + - RCTTypeSafety (= 0.71.1) + - React-Codegen (= 0.71.1) + - React-Core/CoreModulesHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - React-RCTImage (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-cxxreact (0.71.1): - boost (= 1.76.0) - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsinspector (= 0.70.6) - - React-logger (= 0.70.6) - - React-perflogger (= 0.70.6) - - React-runtimeexecutor (= 0.70.6) - - React-hermes (0.70.6): + - React-callinvoker (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsinspector (= 0.71.1) + - React-logger (= 0.71.1) + - React-perflogger (= 0.71.1) + - React-runtimeexecutor (= 0.71.1) + - React-hermes (0.71.1): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2021.07.22.00) - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-jsiexecutor (= 0.70.6) - - React-jsinspector (= 0.70.6) - - React-perflogger (= 0.70.6) - - React-jsi (0.70.6): + - React-cxxreact (= 0.71.1) + - React-jsiexecutor (= 0.71.1) + - React-jsinspector (= 0.71.1) + - React-perflogger (= 0.71.1) + - React-jsc (0.71.1): + - React-jsc/Fabric (= 0.71.1) + - React-jsi (= 0.71.1) + - React-jsc/Fabric (0.71.1): + - React-jsi (= 0.71.1) + - React-jsi (0.71.1): - boost (= 1.76.0) - DoubleConversion - glog + - hermes-engine - RCT-Folly (= 2021.07.22.00) - - React-jsi/Default (= 0.70.6) - - React-jsi/Default (0.70.6): - - boost (= 1.76.0) + - React-jsiexecutor (0.71.1): - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.70.6): - - DoubleConversion - - glog - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-perflogger (= 0.70.6) - - React-jsinspector (0.70.6) - - React-logger (0.70.6): + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-perflogger (= 0.71.1) + - React-jsinspector (0.71.1) + - React-logger (0.71.1): - glog - react-native-background-timer (2.4.1): - React-Core - - react-native-cameraroll (5.2.1): + - react-native-cameraroll (5.2.2): - React-Core - react-native-cookies (6.2.1): - React-Core @@ -341,33 +342,34 @@ PODS: - React-Core - react-native-document-picker (8.1.3): - React-Core - - react-native-emm (1.3.3): + - react-native-emm (1.3.4): - React-Core - react-native-hw-keyboard-event (0.0.4): - React - - react-native-image-picker (4.10.3): + - react-native-image-picker (5.0.1): - React-Core - react-native-in-app-review (4.2.1): - React-Core - react-native-netinfo (9.3.7): - React-Core - - react-native-network-client (1.0.2): + - react-native-network-client (1.1.0): - Alamofire (~> 5.6.4) - React-Core - Starscream (~> 4.0.4) - SwiftyJSON (~> 5.0) - react-native-notifications (4.3.3): - React-Core - - react-native-paste-input (0.5.2): + - react-native-paste-input (0.6.0): - React-Core - Swime (= 3.0.6) - - react-native-safe-area-context (4.4.1): + - react-native-safe-area-context (4.5.0): - RCT-Folly - RCTRequired - RCTTypeSafety - React-Core - ReactCommon/turbomodule/core - - react-native-turbo-mailer (0.2.0): + - react-native-turbo-mailer (0.2.3): + - RCT-Folly (= 2021.07.22.00) - React-Core - react-native-video (5.2.1): - React-Core @@ -378,92 +380,107 @@ PODS: - React - react-native-webview (11.26.0): - React-Core - - React-perflogger (0.70.6) - - React-RCTActionSheet (0.70.6): - - React-Core/RCTActionSheetHeaders (= 0.70.6) - - React-RCTAnimation (0.70.6): + - React-perflogger (0.71.1) + - React-RCTActionSheet (0.71.1): + - React-Core/RCTActionSheetHeaders (= 0.71.1) + - React-RCTAnimation (0.71.1): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.6) - - React-Codegen (= 0.70.6) - - React-Core/RCTAnimationHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-RCTBlob (0.70.6): + - RCTTypeSafety (= 0.71.1) + - React-Codegen (= 0.71.1) + - React-Core/RCTAnimationHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-RCTAppDelegate (0.71.1): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - ReactCommon/turbomodule/core + - React-RCTBlob (0.71.1): - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.70.6) - - React-Core/RCTBlobHeaders (= 0.70.6) - - React-Core/RCTWebSocket (= 0.70.6) - - React-jsi (= 0.70.6) - - React-RCTNetwork (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-RCTImage (0.70.6): + - React-Codegen (= 0.71.1) + - React-Core/RCTBlobHeaders (= 0.71.1) + - React-Core/RCTWebSocket (= 0.71.1) + - React-jsi (= 0.71.1) + - React-RCTNetwork (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-RCTImage (0.71.1): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.6) - - React-Codegen (= 0.70.6) - - React-Core/RCTImageHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - React-RCTNetwork (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-RCTLinking (0.70.6): - - React-Codegen (= 0.70.6) - - React-Core/RCTLinkingHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-RCTNetwork (0.70.6): + - RCTTypeSafety (= 0.71.1) + - React-Codegen (= 0.71.1) + - React-Core/RCTImageHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - React-RCTNetwork (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-RCTLinking (0.71.1): + - React-Codegen (= 0.71.1) + - React-Core/RCTLinkingHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-RCTNetwork (0.71.1): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.6) - - React-Codegen (= 0.70.6) - - React-Core/RCTNetworkHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-RCTSettings (0.70.6): + - RCTTypeSafety (= 0.71.1) + - React-Codegen (= 0.71.1) + - React-Core/RCTNetworkHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-RCTSettings (0.71.1): - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.70.6) - - React-Codegen (= 0.70.6) - - React-Core/RCTSettingsHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-RCTText (0.70.6): - - React-Core/RCTTextHeaders (= 0.70.6) - - React-RCTVibration (0.70.6): + - RCTTypeSafety (= 0.71.1) + - React-Codegen (= 0.71.1) + - React-Core/RCTSettingsHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-RCTText (0.71.1): + - React-Core/RCTTextHeaders (= 0.71.1) + - React-RCTVibration (0.71.1): - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.70.6) - - React-Core/RCTVibrationHeaders (= 0.70.6) - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (= 0.70.6) - - React-runtimeexecutor (0.70.6): - - React-jsi (= 0.70.6) - - ReactCommon/turbomodule/core (0.70.6): + - React-Codegen (= 0.71.1) + - React-Core/RCTVibrationHeaders (= 0.71.1) + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/core (= 0.71.1) + - React-runtimeexecutor (0.71.1): + - React-jsi (= 0.71.1) + - ReactCommon/turbomodule/bridging (0.71.1): - DoubleConversion - glog - RCT-Folly (= 2021.07.22.00) - - React-bridging (= 0.70.6) - - React-callinvoker (= 0.70.6) - - React-Core (= 0.70.6) - - React-cxxreact (= 0.70.6) - - React-jsi (= 0.70.6) - - React-logger (= 0.70.6) - - React-perflogger (= 0.70.6) + - React-callinvoker (= 0.71.1) + - React-Core (= 0.71.1) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-logger (= 0.71.1) + - React-perflogger (= 0.71.1) + - ReactCommon/turbomodule/core (0.71.1): + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.1) + - React-Core (= 0.71.1) + - React-cxxreact (= 0.71.1) + - React-jsi (= 0.71.1) + - React-logger (= 0.71.1) + - React-perflogger (= 0.71.1) - ReactNativeExceptionHandler (2.10.10): - React-Core - ReactNativeIncallManager (4.0.0): - React-Core - ReactNativeKeyboardTrackingView (5.7.0): - React - - ReactNativeNavigation (7.30.6): + - ReactNativeNavigation (7.31.1): - HMSegmentedControl - React-Core - React-RCTImage - React-RCTText - - ReactNativeNavigation/Core (= 7.30.6) - - ReactNativeNavigation/Core (7.30.6): + - ReactNativeNavigation/Core (= 7.31.1) + - ReactNativeNavigation/Core (7.31.1): - HMSegmentedControl - React-Core - React-RCTImage - React-RCTText - RNCClipboard (1.11.1): - React-Core - - RNDateTimePicker (6.7.1): + - RNDateTimePicker (6.7.3): - React-Core - RNDeviceInfo (10.3.0): - React-Core @@ -475,7 +492,7 @@ PODS: - React-Core - RNFS (2.20.0): - React-Core - - RNGestureHandler (2.8.0): + - RNGestureHandler (2.9.0): - React-Core - RNKeychain (8.1.1): - React-Core @@ -485,7 +502,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (2.13.0): + - RNReanimated (2.14.4): - DoubleConversion - FBLazyVector - FBReactNativeSpec @@ -512,18 +529,18 @@ PODS: - React-RCTText - ReactCommon/turbomodule/core - Yoga - - RNRudderSdk (1.0.0): + - RNRudderSdk (1.5.2): - React - Rudder (~> 1.6.0) - - RNScreens (3.18.2): + - RNScreens (3.19.0): - React-Core - React-RCTImage - - RNSentry (4.12.0): + - RNSentry (4.13.0): - React-Core - - Sentry/HybridSDK (= 7.31.3) + - Sentry/HybridSDK (= 7.31.5) - RNShare (8.1.0): - React-Core - - RNSVG (13.6.0): + - RNSVG (13.7.0): - React-Core - RNVectorIcons (9.2.0): - React-Core @@ -534,13 +551,13 @@ PODS: - SDWebImageWebPCoder (0.8.5): - libwebp (~> 1.0) - SDWebImage/Core (~> 5.10) - - Sentry/HybridSDK (7.31.3) + - Sentry/HybridSDK (7.31.5) - simdjson (1.0.0) - SocketRocket (0.6.0) - Starscream (4.0.4) - SwiftyJSON (5.0.1) - Swime (3.0.6) - - WatermelonDB (0.24.0): + - WatermelonDB (0.25.1): - React - React-jsi - Yoga (1.14.0) @@ -575,7 +592,7 @@ DEPENDENCIES: - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - - hermes-engine (from `../node_modules/react-native/sdks/hermes/hermes-engine.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - jail-monkey (from `../node_modules/jail-monkey`) - libevent (~> 2.1.12) - "mattermost-react-native-turbo-log (from `../node_modules/@mattermost/react-native-turbo-log`)" @@ -588,7 +605,6 @@ DEPENDENCIES: - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - React (from `../node_modules/react-native/`) - - React-bridging (from `../node_modules/react-native/ReactCommon`) - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) @@ -597,6 +613,7 @@ DEPENDENCIES: - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-jsc (from `../node_modules/react-native/ReactCommon/jsc`) - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) @@ -622,6 +639,7 @@ DEPENDENCIES: - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) @@ -700,7 +718,7 @@ EXTERNAL SOURCES: glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: - :podspec: "../node_modules/react-native/sdks/hermes/hermes-engine.podspec" + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" jail-monkey: :path: "../node_modules/jail-monkey" mattermost-react-native-turbo-log: @@ -721,8 +739,6 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/TypeSafety" React: :path: "../node_modules/react-native/" - React-bridging: - :path: "../node_modules/react-native/ReactCommon" React-callinvoker: :path: "../node_modules/react-native/ReactCommon/callinvoker" React-Codegen: @@ -735,6 +751,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/cxxreact" React-hermes: :path: "../node_modules/react-native/ReactCommon/hermes" + React-jsc: + :path: "../node_modules/react-native/ReactCommon/jsc" React-jsi: :path: "../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: @@ -785,6 +803,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/ActionSheetIOS" React-RCTAnimation: :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" React-RCTBlob: :path: "../node_modules/react-native/Libraries/Blob" React-RCTImage: @@ -864,13 +884,13 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Alamofire: 4e95d97098eacb88856099c4fc79b526a299e48c - boost: a7c83b31436843459a1961bfd74b96033dc77234 + boost: 57d2868c099736d80fcd648bf211b4431e51a558 BVLinearGradient: 34a999fda29036898a09c6a6b728b0b4189e1a44 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 CocoaLumberjack: 78abfb691154e2a9df8ded4350d504ee19d90732 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 - FBLazyVector: 48289402952f4f7a4e235de70a9a590aa0b79ef4 - FBReactNativeSpec: dd1186fd05255e3457baa2f4ca65e94c2cd1e3ac + FBLazyVector: ad72713385db5289b19f1ead07e8e4aa26dcb01d + FBReactNativeSpec: df2602c11e33d310433496e28a48b4b2be652a61 Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 @@ -882,97 +902,98 @@ SPEC CHECKSUMS: FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - hermes-engine: 2af7b7a59128f250adfd86f15aa1d5a2ecd39995 + hermes-engine: 922ccd744f50d9bfde09e9677bf0f3b562ea5fb9 HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352 jail-monkey: a71b35d482a70ecba844a90f002994012cf12a5d libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef - mattermost-react-native-turbo-log: bc61d03ab49480cd03a68dd85e816910d941c82f + mattermost-react-native-turbo-log: 3c56c4e6e1d706b70d652e5509d1254eef914153 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c Permission-Camera: bf6791b17c7f614b6826019fcfdcc286d3a107f6 Permission-Microphone: 48212dd4d28025d9930d583e3c7a56da7268665c Permission-Notifications: 150484ae586eb9be4e32217582a78350a9bb31c3 Permission-PhotoLibrary: 5b34ca67279f7201ae109cef36f9806a6596002d - RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda - RCTRequired: e1866f61af7049eb3d8e08e8b133abd38bc1ca7a - RCTTypeSafety: 27c2ac1b00609a432ced1ae701247593f07f901e - React: bb3e06418d2cc48a84f9666a576c7b38e89cd7db - React-bridging: 572502ec59c9de30309afdc4932e278214288913 - React-callinvoker: 6b708b79c69f3359d42f1abb4663f620dbd4dadf - React-Codegen: 74e1cd7cee692a8b983c18df3274b5e749de07c8 - React-Core: b587d0a624f9611b0e032505f3d6f25e8daa2bee - React-CoreModules: c6ff48b985e7aa622e82ca51c2c353c7803eb04e - React-cxxreact: ade3d9e63c599afdead3c35f8a8bd12b3da6730b - React-hermes: ed09ae33512bbb8d31b2411778f3af1a2eb681a1 - React-jsi: 5a3952e0c6d57460ad9ee2c905025b4c28f71087 - React-jsiexecutor: b4a65947391c658450151275aa406f2b8263178f - React-jsinspector: 60769e5a0a6d4b32294a2456077f59d0266f9a8b - React-logger: 1623c216abaa88974afce404dc8f479406bbc3a0 + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: fd4d923b964658aa0c4091a32c8b2004c6d9e3a6 + RCTTypeSafety: c276d85975bde3d8448907235c70bf0da257adfd + React: e481a67971af1ce9639c9f746b753dd0e84ca108 + React-callinvoker: 1051c04a94fa9d243786b86380606bad701a3b31 + React-Codegen: 14b1e716d361d5ad95e0ce1a338f3fa0733a98b5 + React-Core: 698fc3baecb80d511d987475a16d036cec6d287f + React-CoreModules: 59245305f41ff0adfeac334acc0594dea4585a7c + React-cxxreact: 49accd2954b0f532805dbcd1918fa6962f32f247 + React-hermes: d068733294581a085e95b6024e8d951b005e26d3 + React-jsc: b4246f1eed2b9addf2edc93b0462c1b4e55fc1d6 + React-jsi: 122b9bce14f4c6c7cb58f28f87912cfe091885fa + React-jsiexecutor: 60cf272aababc5212410e4249d17cea14fc36caa + React-jsinspector: ff56004b0c974b688a6548c156d5830ad751ae07 + React-logger: 60a0b5f8bed667ecf9e24fecca1f30d125de6d75 react-native-background-timer: 17ea5e06803401a379ebf1f20505b793ac44d0fe - react-native-cameraroll: f94bf9f46c998963ecd2bb6e9a3f9cca59b6d9f1 + react-native-cameraroll: 71d68167beb6fc7216aa564abb6d86f1d666a2c6 react-native-cookies: f54fcded06bb0cda05c11d86788020b43528a26c react-native-create-thumbnail: e022bcdcba8a0b4529a50d3fa1a832ec921be39d react-native-document-picker: 958e2bc82e128be69055be261aeac8d872c8d34c - react-native-emm: c5b7dcffde34ce345fd0c16d66b587e611a3d31f + react-native-emm: 8439515a27ad8723dfd37f554ea6c944882a49bc react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53 - react-native-image-picker: 60f4246eb5bb7187fc15638a8c1f13abd3820695 + react-native-image-picker: 8cb4280e2c1efc3daeb2d9d597f9429a60472e40 react-native-in-app-review: a073f67c5f3392af6ea7fb383217cdb1aa2aa726 react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983 - react-native-network-client: ce464b9d413872f1b0c36852a44d66b1a45a9dce + react-native-network-client: 88b7ef8ef937352db3cfdbea939dc55397c64b9f react-native-notifications: 83b4fd4a127a6c918fc846cae90da60f84819e44 - react-native-paste-input: 88709b4fd586ea8cc56ba5e2fc4cdfe90597730c - react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a - react-native-turbo-mailer: 226fc3533d16500fb4ad08cf8ab2cfc7bb1ef593 + react-native-paste-input: 5182843692fd2ec72be50f241a38a49796e225d7 + react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc + react-native-turbo-mailer: fa3f18b5a274fa32ebe43af125caf041f7cc4cbf react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253 react-native-webrtc: 86d841823e66d68cc1f86712db1c2956056bf0c2 react-native-webview: 994b9f8fbb504d6314dc40d83f94f27c6831b3bf - React-perflogger: 8c79399b0500a30ee8152d0f9f11beae7fc36595 - React-RCTActionSheet: 7316773acabb374642b926c19aef1c115df5c466 - React-RCTAnimation: 5341e288375451297057391227f691d9b2326c3d - React-RCTBlob: b0615fc2daf2b5684ade8fadcab659f16f6f0efa - React-RCTImage: 6487b9600f268ecedcaa86114d97954d31ad4750 - React-RCTLinking: c8018ae9ebfefcec3839d690d4725f8d15e4e4b3 - React-RCTNetwork: 8aa63578741e0fe1205c28d7d4b40dbfdabce8a8 - React-RCTSettings: d00c15ad369cd62242a4dfcc6f277912b4a84ed3 - React-RCTText: f532e5ca52681ecaecea452b3ad7a5b630f50d75 - React-RCTVibration: c75ceef7aa60a33b2d5731ebe5800ddde40cefc4 - React-runtimeexecutor: 15437b576139df27635400de0599d9844f1ab817 - ReactCommon: 349be31adeecffc7986a0de875d7fb0dcf4e251c + React-perflogger: ec8eef2a8f03ecfa6361c2c5fb9197ef4a29cc85 + React-RCTActionSheet: a0c023b86cf4c862fa9c4eb0f6f91fbe878fb2de + React-RCTAnimation: 168d53718c74153947c0109f55900faa64d79439 + React-RCTAppDelegate: a8efbab128b34aa07a9491c85a41401210b1bec5 + React-RCTBlob: 9bcbfc893bfda9f6b2eb016329d38c0f6366d31a + React-RCTImage: 3fcd4570b4b0f1ac2f4b4b6308dba33ce66c5b50 + React-RCTLinking: 1edb8e1bb3fc39bf9e13c63d6aaaa3f0c3d18683 + React-RCTNetwork: 500a79e0e0f67678077df727fabba87a55c043e1 + React-RCTSettings: cc4414eb84ad756d619076c3999fecbf12896d6f + React-RCTText: 2a34261f3da6e34f47a62154def657546ebfa5e1 + React-RCTVibration: 49d531ec8498e0afa2c9b22c2205784372e3d4f3 + React-runtimeexecutor: 311feb67600774723fe10eb8801d3138cae9ad67 + ReactCommon: 03be76588338a27a88d103b35c3c44a3fd43d136 ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60 ReactNativeIncallManager: b169b57d3064d8f62478f8fc3c485da6c75045d1 ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306 - ReactNativeNavigation: 44df9a6347dc583deac3a09b171e2e1b4905a9d6 + ReactNativeNavigation: c3e1e813b46d4c7219949cfbb67feb90b8315058 RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd - RNDateTimePicker: 0530a73a6f3a1a85814cbde0802736993b9e675e + RNDateTimePicker: 00247f26c34683c80be94207f488f6f13448586e RNDeviceInfo: 4701f0bf2a06b34654745053db0ce4cb0c53ada7 RNFastImage: 0ee8f7e39df8190d3ca3a5b0c4ea0109c0ff132e RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592 RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 - RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3 + RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39 RNKeychain: ff836453cba46938e0e9e4c22e43d43fa2c90333 RNLocalize: 0df7970cfc60389f00eb62fd7c097dc75af3fb4f RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a - RNRudderSdk: 14c176adb1557f3832cb385fcd14250f76a7e268 - RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d - RNSentry: 4c09f4dd9740cb9b33e94303de5b6d0dbeb0737d + RNReanimated: cc5e3aa479cb9170bcccf8204291a6950a3be128 + RNRudderSdk: 07f732edfe473ef67b8cc6ad1800ddb81b78286f + RNScreens: ea4cd3a853063cda19a4e3c28d2e52180c80f4eb + RNSentry: acebe4104a6f5915ae871eb59dc73f13dcc92ef7 RNShare: 48b3113cd089a2be8ff0515c3ae7a46a4db8a76b - RNSVG: 3a79c0c4992213e4f06c08e62730c5e7b9e4dc17 + RNSVG: d787d64ca06b9158e763ad2638a8c4edce00782a RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8 Rudder: 7c080303528ea612f58c9f9e8fcfab92b5dbcca8 SDWebImage: a47aea9e3d8816015db4e523daff50cfd294499d SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d - Sentry: 08884c523575ec0f6690d94ed3ccb0246a1600bf + Sentry: 4c9babff9034785067c896fd580b1f7de44da020 simdjson: c96317b3a50dff3468a42f586ab7ed22c6ab2fd9 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9 SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b - WatermelonDB: baec390a1039dcebeee959218900c978af3407c9 - Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc + WatermelonDB: cce0b748ccbd7a71c161e8545b5f6357a0945be1 + Yoga: 921eb014669cf9c718ada68b08d362517d564e0c YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 96049f4170c9cafd0ff121db4444b3f46f51bc97 +PODFILE CHECKSUM: 9f76739ed16bbdc0f4b1049ecb366fb5d23a0f3a COCOAPODS: 1.11.3 diff --git a/package-lock.json b/package-lock.json index 91620ba23c..96813a4582 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,24 +18,24 @@ "@formatjs/intl-relativetimeformat": "11.1.8", "@gorhom/bottom-sheet": "4.4.5", "@mattermost/compass-icons": "0.1.35", - "@mattermost/react-native-emm": "1.3.3", - "@mattermost/react-native-network-client": "1.0.2", - "@mattermost/react-native-paste-input": "0.5.2", - "@mattermost/react-native-turbo-log": "0.2.1", - "@mattermost/react-native-turbo-mailer": "0.2.0", + "@mattermost/react-native-emm": "1.3.4", + "@mattermost/react-native-network-client": "1.1.0", + "@mattermost/react-native-paste-input": "0.6.0", + "@mattermost/react-native-turbo-log": "0.2.2", + "@mattermost/react-native-turbo-mailer": "0.2.3", "@msgpack/msgpack": "2.8.0", - "@nozbe/watermelondb": "0.24.0", + "@nozbe/watermelondb": "0.25.1", "@nozbe/with-observables": "1.4.1", - "@react-native-camera-roll/camera-roll": "5.2.1", + "@react-native-camera-roll/camera-roll": "5.2.2", "@react-native-clipboard/clipboard": "1.11.1", - "@react-native-community/datetimepicker": "6.7.1", + "@react-native-community/datetimepicker": "6.7.3", "@react-native-community/netinfo": "9.3.7", "@react-native-cookies/cookies": "6.2.1", - "@react-navigation/bottom-tabs": "6.5.2", - "@react-navigation/native": "6.1.1", - "@react-navigation/stack": "6.3.10", - "@rudderstack/rudder-sdk-react-native": "1.5.1", - "@sentry/react-native": "4.12.0", + "@react-navigation/bottom-tabs": "6.5.3", + "@react-navigation/native": "6.1.2", + "@react-navigation/stack": "6.3.11", + "@rudderstack/rudder-sdk-react-native": "1.5.2", + "@sentry/react-native": "4.13.0", "@stream-io/flat-list-mvcp": "0.10.2", "base-64": "1.0.0", "commonmark": "npm:@mattermost/commonmark@0.30.1-0", @@ -52,7 +52,7 @@ "react": "18.2.0", "react-freeze": "1.0.3", "react-intl": "6.2.5", - "react-native": "0.70.6", + "react-native": "0.71.1", "react-native-android-open-settings": "1.3.0", "react-native-animated-numbers": "0.4.1", "react-native-background-timer": "2.4.1", @@ -67,10 +67,10 @@ "react-native-fast-image": "8.6.3", "react-native-file-viewer": "2.1.5", "react-native-fs": "2.20.0", - "react-native-gesture-handler": "2.8.0", + "react-native-gesture-handler": "2.9.0", "react-native-haptic-feedback": "1.14.0", "react-native-hw-keyboard-event": "0.0.4", - "react-native-image-picker": "4.10.3", + "react-native-image-picker": "5.0.1", "react-native-in-app-review": "4.2.1", "react-native-incall-manager": "github:cpoile/react-native-incall-manager", "react-native-keyboard-aware-scroll-view": "0.9.5", @@ -79,19 +79,19 @@ "react-native-linear-gradient": "2.6.2", "react-native-localize": "2.2.4", "react-native-math-view": "3.9.5", - "react-native-navigation": "7.30.6", + "react-native-navigation": "7.31.1", "react-native-notifications": "4.3.3", "react-native-permissions": "3.6.1", - "react-native-reanimated": "2.13.0", - "react-native-safe-area-context": "4.4.1", - "react-native-screens": "3.18.2", + "react-native-reanimated": "2.14.4", + "react-native-safe-area-context": "4.5.0", + "react-native-screens": "3.19.0", "react-native-section-list-get-item-layout": "2.2.3", "react-native-shadow-2": "7.0.6", "react-native-share": "8.1.0", - "react-native-svg": "13.6.0", + "react-native-svg": "13.7.0", "react-native-vector-icons": "9.2.0", "react-native-video": "5.2.1", - "react-native-walkthrough-tooltip": "1.4.0", + "react-native-walkthrough-tooltip": "1.5.0", "react-native-webrtc": "github:mattermost/react-native-webrtc", "react-native-webview": "11.26.0", "react-syntax-highlighter": "15.5.0", @@ -107,13 +107,13 @@ "@babel/core": "7.20.12", "@babel/eslint-parser": "7.19.1", "@babel/plugin-proposal-class-properties": "7.18.6", - "@babel/plugin-proposal-decorators": "7.20.7", + "@babel/plugin-proposal-decorators": "7.20.13", "@babel/plugin-transform-flow-strip-types": "7.19.0", "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", "@babel/preset-typescript": "7.18.6", "@babel/register": "7.18.9", - "@babel/runtime": "7.20.7", + "@babel/runtime": "7.20.13", "@react-native-community/eslint-config": "3.2.0", "@testing-library/react-hooks": "8.0.1", "@testing-library/react-native": "11.5.0", @@ -121,12 +121,11 @@ "@types/commonmark": "0.27.5", "@types/commonmark-react-renderer": "4.3.1", "@types/deep-equal": "1.0.1", - "@types/jest": "29.2.5", + "@types/jest": "29.2.6", "@types/lodash": "4.14.191", "@types/mime-db": "1.43.1", "@types/querystringify": "2.0.0", - "@types/react": "18.0.26", - "@types/react-native": "0.70.8", + "@types/react": "18.0.27", "@types/react-native-background-timer": "2.0.0", "@types/react-native-button": "3.0.1", "@types/react-native-dotenv": "0.2.0", @@ -141,36 +140,36 @@ "@types/tough-cookie": "4.0.2", "@types/url-parse": "1.4.8", "@types/uuid": "9.0.0", - "@typescript-eslint/eslint-plugin": "5.48.0", - "@typescript-eslint/parser": "5.48.0", - "axios": "1.2.2", + "@typescript-eslint/eslint-plugin": "5.49.0", + "@typescript-eslint/parser": "5.49.0", + "axios": "1.2.3", "axios-cookiejar-support": "4.0.6", "babel-jest": "29.3.1", "babel-loader": "9.1.2", - "babel-plugin-module-resolver": "4.1.0", + "babel-plugin-module-resolver": "5.0.0", "deep-freeze": "0.0.1", - "detox": "20.1.1", - "eslint": "8.31.0", + "detox": "20.1.2", + "eslint": "8.32.0", "eslint-plugin-header": "3.1.1", - "eslint-plugin-import": "2.26.0", + "eslint-plugin-import": "2.27.5", "eslint-plugin-jest": "27.2.1", - "eslint-plugin-react": "7.31.11", + "eslint-plugin-react": "7.32.1", "eslint-plugin-react-hooks": "4.6.0", "husky": "8.0.3", "isomorphic-fetch": "3.0.0", "jest": "29.3.1", "jest-cli": "29.3.1", "jetifier": "2.0.0", - "metro-react-native-babel-preset": "0.73.7", + "metro-react-native-babel-preset": "0.74.1", "mmjstool": "github:mattermost/mattermost-utilities#010f456ea8be5beebafdb8776177cba515c1969e", "mock-async-storage": "2.2.0", - "nock": "13.2.9", + "nock": "13.3.0", "patch-package": "6.5.1", "react-devtools-core": "4.27.1", "react-native-svg-transformer": "1.0.0", "react-test-renderer": "18.2.0", "tough-cookie": "4.1.2", - "ts-jest": "29.0.3", + "ts-jest": "29.0.5", "typescript": "4.9.4", "underscore": "1.13.6", "util": "0.12.5", @@ -376,9 +375,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz", - "integrity": "sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", @@ -386,6 +385,7 @@ "@babel/helper-member-expression-to-functions": "^7.20.7", "@babel/helper-optimise-call-expression": "^7.18.6", "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", "@babel/helper-split-export-declaration": "^7.18.6" }, "engines": { @@ -580,11 +580,11 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", - "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "dependencies": { - "@babel/types": "^7.18.9" + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -755,12 +755,12 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.7.tgz", - "integrity": "sha512-JB45hbUweYpwAGjkiM7uCyXMENH2lG+9r3G2E+ttc2PRXAoEkpfd/KW5jDg4j8RS6tLtTG1jZi9LbHZVSfs1/A==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.13.tgz", + "integrity": "sha512-7T6BKHa9Cpd7lCueHBBzP0nkXNina+h5giOZw+a8ZpMfPFY19VjJAjIxyFHuWkhCWgL6QMqRiY/wB1fLXzm6Mw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-create-class-features-plugin": "^7.20.12", "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-replace-supers": "^7.20.7", "@babel/helper-split-export-declaration": "^7.18.6", @@ -2044,9 +2044,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -2686,108 +2686,20 @@ } }, "node_modules/@jest/create-cache-key-function": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", - "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.3.1.tgz", + "integrity": "sha512-4i+E+E40gK13K78ffD/8cy4lSSqeWwyXeTZoq16tndiCP12hC8uQsPJdIu5C6Kf22fD8UbBk71so7s/6VwpUOQ==", "dependencies": { - "@jest/types": "^27.5.1" + "@jest/types": "^29.3.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@jest/create-cache-key-function/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/create-cache-key-function/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/environment": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", - "dev": true, "dependencies": { "@jest/fake-timers": "^29.3.1", "@jest/types": "^29.3.1", @@ -2827,7 +2739,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", - "dev": true, "dependencies": { "@jest/types": "^29.3.1", "@sinonjs/fake-timers": "^9.1.2", @@ -2981,7 +2892,6 @@ "version": "29.0.0", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -3157,7 +3067,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dev": true, "dependencies": { "@jest/schemas": "^29.0.0", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3174,7 +3083,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3189,7 +3097,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3205,7 +3112,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -3216,14 +3122,12 @@ "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3232,7 +3136,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -3273,8 +3176,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -3331,21 +3232,21 @@ "integrity": "sha512-qCZjvU6Vsl7cg/0urrq8ItK5CXnt3DqjFq/w9mBpWuem/YhMWLMVBoSuASAx9S2HV7Vr/iMdsMGWH/4qXkXCBg==" }, "node_modules/@mattermost/react-native-emm": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-emm/-/react-native-emm-1.3.3.tgz", - "integrity": "sha512-mOPlp3C0ba1XOANTYi3i2dL9gBdQLoJZ4zvOzhqYeg5FQXBXXoJomPKAzxJH27aX3k92bu+U0BmEbnKIitKKEA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-emm/-/react-native-emm-1.3.4.tgz", + "integrity": "sha512-xdFPfAH3d9pa1og6rr+kHCWlLYMnHe7kY1IxIjhvfZ28ElNExjOhOF7JOL/s4RUvk8bZS7H72+ldRYZ6ERHlWw==", "peerDependencies": { "react": "*", "react-native": "*" } }, "node_modules/@mattermost/react-native-network-client": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-network-client/-/react-native-network-client-1.0.2.tgz", - "integrity": "sha512-ywVxTKPT1A8eEccPpCrHXYqO9BvvEx+xdecn/VILUDeEIfpOVETLh5952SQjoc3PP0RRME0bv92+fzoxiOZ4YQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-network-client/-/react-native-network-client-1.1.0.tgz", + "integrity": "sha512-iZemjWqUaGkfSY+7Ve+m6MUJc8blUOzHoY9J5miKjez7QPiknYGMIdVFMYAiuO9jUtgQ4XSG7/nENqYR5jSwCg==", "dependencies": { "validator": "13.7.0", - "zod": "3.19.1" + "zod": "3.20.2" }, "peerDependencies": { "react": "*", @@ -3353,11 +3254,11 @@ } }, "node_modules/@mattermost/react-native-paste-input": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-paste-input/-/react-native-paste-input-0.5.2.tgz", - "integrity": "sha512-aQdLUidSAbWPLXWmwM1x8AhnZIO4EN5uWx813/G3+mL8kWD7mpXrQEvMpcdtKWatD705kCyKZkvnNY4yjq0TkA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-paste-input/-/react-native-paste-input-0.6.0.tgz", + "integrity": "sha512-Hy4w8RaiiXl2AKcLXT0FjJJsh4FXtLiWCxfh6zaBtCkx7jsr4d9xwJ/zqrnjv0jkG7XbRUCp40dgNBpWYZ1pyQ==", "dependencies": { - "deprecated-react-native-prop-types": "^2.3.0" + "semver": "7.3.8" }, "peerDependencies": { "react": "*", @@ -3365,18 +3266,18 @@ } }, "node_modules/@mattermost/react-native-turbo-log": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-log/-/react-native-turbo-log-0.2.1.tgz", - "integrity": "sha512-c5Wx82gYLEUY70lIoA3jWg2sWo+l/Ah8vAfvu2cYkGnX4NArB/NKWnC4GWaclDSuNO4Tm5DrXgFeSqqArs7IJQ==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-log/-/react-native-turbo-log-0.2.2.tgz", + "integrity": "sha512-UjatbzMyB3jp/tAI1B8lmqZtF8om103hzUAlRVnUIPvzDQl5u2OtiwkwdYlnyN1P72WiIKhNcx7W+NZO0/wjyg==", "peerDependencies": { "react": "*", "react-native": "*" } }, "node_modules/@mattermost/react-native-turbo-mailer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-mailer/-/react-native-turbo-mailer-0.2.0.tgz", - "integrity": "sha512-KMrEkMa30zjFv8ofvQsE1c1ln+8ntGDKJWDjScK02jvN3rtD8jMz1derz1py8tbDU9uU2nQPqWu4lP4b3g27Tw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-mailer/-/react-native-turbo-mailer-0.2.3.tgz", + "integrity": "sha512-m49wYLOx6TCiv5IDZKNAzhY8hnib+CgZ31jenR5rMiEmykmnI4VIyan1nNcPTyZPRGGmBb4UYzrcPd3hdIaOSg==", "engines": { "node": ">= 16.0.0" }, @@ -3455,33 +3356,20 @@ "integrity": "sha512-wKTFGvgf5V+bYlhXdukOWKH0XgdG0NmUQwLWG7w5Yk4EUeQS29D5uWPCeWT1Ac/NzDKuHsYP6KVOJDbJSauAAg==" }, "node_modules/@nozbe/watermelondb": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@nozbe/watermelondb/-/watermelondb-0.24.0.tgz", - "integrity": "sha512-CPCsRLQY2Lyq1MwUeK6zDsjfMKpW2KWYQJlF+ijGeKWv84xND0QC6a6EBWWiflvcdAwLSuGclojoah1HZYfs0g==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@nozbe/watermelondb/-/watermelondb-0.25.1.tgz", + "integrity": "sha512-Yd4gXttVlfl2e8rDsduTmPWgZWidaVAMpDcJr1fmsmHJQnNWdYRR+1V07Io4muNMSSq7rdn0Yl8GHNpNzN+rfQ==", "dependencies": { "@babel/runtime": "^7.11.2", "@nozbe/simdjson": "1.0.0", "@nozbe/sqlite": "3.36.0", - "@nozbe/with-observables": "1.4.0", + "@nozbe/with-observables": "1.4.1", "hoist-non-react-statics": "^3.3.2", - "lokijs": "npm:@nozbe/lokijs@1.5.12-wmelon4", - "rxjs": "^7.3.0", + "lokijs": "npm:@nozbe/lokijs@1.5.12-wmelon6", + "rxjs": "^7.4.0", "sql-escape-string": "^1.1.0" } }, - "node_modules/@nozbe/watermelondb/node_modules/@nozbe/with-observables": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@nozbe/with-observables/-/with-observables-1.4.0.tgz", - "integrity": "sha512-vzc0QiYcXK/GmflBGBXTs02ayL25e1l4Cr9aYgSuYCZVqpyMfep9xp89RygNbiibAfVLbgEUa7thxlm3jw8hFw==", - "dependencies": { - "hoist-non-react-statics": "^3.3.2" - }, - "peerDependencies": { - "@types/hoist-non-react-statics": "^3.3.1", - "@types/react": "^16.9.23||^17", - "react": "^16.4.2||^17" - } - }, "node_modules/@nozbe/with-observables": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@nozbe/with-observables/-/with-observables-1.4.1.tgz", @@ -3496,9 +3384,9 @@ } }, "node_modules/@react-native-camera-roll/camera-roll": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.1.tgz", - "integrity": "sha512-axWwlLj/3E5PIjXcN2y2XZzK/hYTx73kDlQJpHpcurejmQR9sU22w3cs+YltaNkZGl3y7Eu/LbiPEkGIwNVQow==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.2.tgz", + "integrity": "sha512-LVzUX1KdKvOXJGiV/9tlkDyDSOEjvAzuiV8OkSUD13TXN/Tk5u2KVHTYRYJz5pmXanLN2dmEamctJcqKCeXYxg==", "peerDependencies": { "react-native": ">=0.59" } @@ -3513,21 +3401,21 @@ } }, "node_modules/@react-native-community/cli": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.3.2.tgz", - "integrity": "sha512-IAW4X0vmX/xozNpp/JVZaX7MrC85KV0OP2DF4o7lNGOfpUhzJAEWqTfkxFYS+VsRjZHDve4wSTiGIuXwE7FG1w==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.1.3.tgz", + "integrity": "sha512-kzh6bYLGN1q1q0IiczKSP1LTrovFeVzppYRTKohPI9VdyZwp7b5JOgaQMB/Ijtwm3MxBDrZgV9AveH/eUmUcKQ==", "dependencies": { - "@react-native-community/cli-clean": "^9.2.1", - "@react-native-community/cli-config": "^9.2.1", - "@react-native-community/cli-debugger-ui": "^9.0.0", - "@react-native-community/cli-doctor": "^9.3.0", - "@react-native-community/cli-hermes": "^9.3.1", - "@react-native-community/cli-plugin-metro": "^9.2.1", - "@react-native-community/cli-server-api": "^9.2.1", - "@react-native-community/cli-tools": "^9.2.1", - "@react-native-community/cli-types": "^9.1.0", + "@react-native-community/cli-clean": "^10.1.1", + "@react-native-community/cli-config": "^10.1.1", + "@react-native-community/cli-debugger-ui": "^10.0.0", + "@react-native-community/cli-doctor": "^10.1.1", + "@react-native-community/cli-hermes": "^10.1.3", + "@react-native-community/cli-plugin-metro": "^10.1.1", + "@react-native-community/cli-server-api": "^10.1.1", + "@react-native-community/cli-tools": "^10.1.1", + "@react-native-community/cli-types": "^10.0.0", "chalk": "^4.1.2", - "commander": "^9.4.0", + "commander": "^9.4.1", "execa": "^1.0.0", "find-up": "^4.1.0", "fs-extra": "^8.1.0", @@ -3543,11 +3431,11 @@ } }, "node_modules/@react-native-community/cli-clean": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-9.2.1.tgz", - "integrity": "sha512-dyNWFrqRe31UEvNO+OFWmQ4hmqA07bR9Ief/6NnGwx67IO9q83D5PEAf/o96ML6jhSbDwCmpPKhPwwBbsyM3mQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-10.1.1.tgz", + "integrity": "sha512-iNsrjzjIRv9yb5y309SWJ8NDHdwYtnCpmxZouQDyOljUdC9MwdZ4ChbtA4rwQyAwgOVfS9F/j56ML3Cslmvrxg==", "dependencies": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "execa": "^1.0.0", "prompts": "^2.4.0" @@ -3696,17 +3584,63 @@ } }, "node_modules/@react-native-community/cli-config": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-9.2.1.tgz", - "integrity": "sha512-gHJlBBXUgDN9vrr3aWkRqnYrPXZLztBDQoY97Mm5Yo6MidsEpYo2JIP6FH4N/N2p1TdjxJL4EFtdd/mBpiR2MQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-10.1.1.tgz", + "integrity": "sha512-p4mHrjC+s/ayiNVG6T35GdEGdP6TuyBUg5plVGRJfTl8WT6LBfLYLk+fz/iETrEZ/YkhQIsQcEUQC47MqLNHog==", "dependencies": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", + "chalk": "^4.1.2", "cosmiconfig": "^5.1.0", "deepmerge": "^3.2.0", "glob": "^7.1.3", "joi": "^17.2.1" } }, + "node_modules/@react-native-community/cli-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/@react-native-community/cli-config/node_modules/deepmerge": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", @@ -3715,22 +3649,41 @@ "node": ">=0.10.0" } }, + "node_modules/@react-native-community/cli-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native-community/cli-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@react-native-community/cli-debugger-ui": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-9.0.0.tgz", - "integrity": "sha512-7hH05ZwU9Tp0yS6xJW0bqcZPVt0YCK7gwj7gnRu1jDNN2kughf6Lg0Ys29rAvtZ7VO1PK5c1O+zs7yFnylQDUA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-10.0.0.tgz", + "integrity": "sha512-8UKLcvpSNxnUTRy8CkCl27GGLqZunQ9ncGYhSrWyKrU9SWBJJGeZwi2k2KaoJi5FvF2+cD0t8z8cU6lsq2ZZmA==", "dependencies": { "serve-static": "^1.13.1" } }, "node_modules/@react-native-community/cli-doctor": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-9.3.0.tgz", - "integrity": "sha512-/fiuG2eDGC2/OrXMOWI5ifq4X1gdYTQhvW2m0TT5Lk1LuFiZsbTCp1lR+XILKekuTvmYNjEGdVpeDpdIWlXdEA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-10.1.1.tgz", + "integrity": "sha512-9uvUhr6aJu4C7pCTsD9iRS/38tx1mzIrWuEQoh2JffTXg9MOq4jesvobkyKFRD90nOvqunEvfpnWnRdWcZO0Wg==", "dependencies": { - "@react-native-community/cli-config": "^9.2.1", - "@react-native-community/cli-platform-ios": "^9.3.0", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-config": "^10.1.1", + "@react-native-community/cli-platform-ios": "^10.1.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "command-exists": "^1.2.8", "envinfo": "^7.7.2", @@ -3916,12 +3869,12 @@ } }, "node_modules/@react-native-community/cli-hermes": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-9.3.1.tgz", - "integrity": "sha512-Mq4PK8m5YqIdaVq5IdRfp4qK09aVO+aiCtd6vjzjNUgk1+1X5cgUqV6L65h4N+TFJYJHcp2AnB+ik1FAYXvYPQ==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-10.1.3.tgz", + "integrity": "sha512-uYl8MLBtuu6bj0tDUzVGf30nK5i9haBv7F0u+NCOq31+zVjcwiUplrCuLorb2dMLMF+Fno9wDxi66W9MxoW4nA==", "dependencies": { - "@react-native-community/cli-platform-android": "^9.3.1", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-platform-android": "^10.1.3", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "hermes-profile-transformer": "^0.0.6", "ip": "^1.1.5" @@ -3992,17 +3945,15 @@ } }, "node_modules/@react-native-community/cli-platform-android": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-9.3.1.tgz", - "integrity": "sha512-m0bQ6Twewl7OEZoVf79I2GZmsDqh+Gh0bxfxWgwxobsKDxLx8/RNItAo1lVtTCgzuCR75cX4EEO8idIF9jYhew==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-10.1.3.tgz", + "integrity": "sha512-8YZEpBL6yd9l4CIoFcLOgrV8x2GDujdqrdWrNsNERDAbsiFwqAQvfjyyb57GAZVuEPEJCoqUlGlMCwOh3XQb9A==", "dependencies": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "execa": "^1.0.0", - "fs-extra": "^8.1.0", "glob": "^7.1.3", - "logkitty": "^0.7.1", - "slash": "^3.0.0" + "logkitty": "^0.7.1" } }, "node_modules/@react-native-community/cli-platform-android/node_modules/ansi-styles": { @@ -4082,19 +4033,6 @@ "node": ">=6" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/@react-native-community/cli-platform-android/node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -4149,14 +4087,6 @@ "semver": "bin/semver" } }, - "node_modules/@react-native-community/cli-platform-android/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, "node_modules/@react-native-community/cli-platform-android/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4169,11 +4099,11 @@ } }, "node_modules/@react-native-community/cli-platform-ios": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.3.0.tgz", - "integrity": "sha512-nihTX53BhF2Q8p4B67oG3RGe1XwggoGBrMb6vXdcu2aN0WeXJOXdBLgR900DAA1O8g7oy1Sudu6we+JsVTKnjw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.1.1.tgz", + "integrity": "sha512-EB9/L8j1LqrqyfJtLRixU+d8FIP6Pr83rEgUgXgya/u8wk3h/bvX70w+Ff2skwjdPLr5dLUQ/n5KFX4r3bsNmA==", "dependencies": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "execa": "^1.0.0", "glob": "^7.1.3", @@ -4323,19 +4253,20 @@ } }, "node_modules/@react-native-community/cli-plugin-metro": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.2.1.tgz", - "integrity": "sha512-byBGBH6jDfUvcHGFA45W/sDwMlliv7flJ8Ns9foCh3VsIeYYPoDjjK7SawE9cPqRdMAD4SY7EVwqJnOtRbwLiQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-10.1.1.tgz", + "integrity": "sha512-wEp47le4mzlelDF5sfkaaujUDYcuLep5HZqlcMx7PkL7BA3/fSHdDo1SblqaLgZ1ca6vFU+kfbHueLDct+xwFg==", "dependencies": { - "@react-native-community/cli-server-api": "^9.2.1", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-server-api": "^10.1.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", - "metro": "0.72.3", - "metro-config": "0.72.3", - "metro-core": "0.72.3", - "metro-react-native-babel-transformer": "0.72.3", - "metro-resolver": "0.72.3", - "metro-runtime": "0.72.3", + "execa": "^1.0.0", + "metro": "0.73.7", + "metro-config": "0.73.7", + "metro-core": "0.73.7", + "metro-react-native-babel-transformer": "0.73.7", + "metro-resolver": "0.73.7", + "metro-runtime": "0.73.7", "readline": "^1.3.0" } }, @@ -4384,6 +4315,49 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@react-native-community/cli-plugin-metro/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4392,6 +4366,41 @@ "node": ">=8" } }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@react-native-community/cli-plugin-metro/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/@react-native-community/cli-plugin-metro/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -4404,12 +4413,12 @@ } }, "node_modules/@react-native-community/cli-server-api": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-9.2.1.tgz", - "integrity": "sha512-EI+9MUxEbWBQhWw2PkhejXfkcRqPl+58+whlXJvKHiiUd7oVbewFs0uLW0yZffUutt4FGx6Uh88JWEgwOzAdkw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-10.1.1.tgz", + "integrity": "sha512-NZDo/wh4zlm8as31UEBno2bui8+ufzsZV+KN7QjEJWEM0levzBtxaD+4je0OpfhRIIkhaRm2gl/vVf7OYAzg4g==", "dependencies": { - "@react-native-community/cli-debugger-ui": "^9.0.0", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-debugger-ui": "^10.0.0", + "@react-native-community/cli-tools": "^10.1.1", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.0", @@ -4435,9 +4444,9 @@ } }, "node_modules/@react-native-community/cli-server-api/node_modules/@types/yargs": { - "version": "15.0.14", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "version": "15.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", + "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", "dependencies": { "@types/yargs-parser": "*" } @@ -4526,9 +4535,9 @@ } }, "node_modules/@react-native-community/cli-tools": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-9.2.1.tgz", - "integrity": "sha512-bHmL/wrKmBphz25eMtoJQgwwmeCylbPxqFJnFSbkqJPXQz3ManQ6q/gVVMqFyz7D3v+riaus/VXz3sEDa97uiQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-10.1.1.tgz", + "integrity": "sha512-+FlwOnZBV+ailEzXjcD8afY2ogFEBeHOw/8+XXzMgPaquU2Zly9B+8W089tnnohO3yfiQiZqkQlElP423MY74g==", "dependencies": { "appdirsjs": "^1.2.4", "chalk": "^4.1.2", @@ -4698,9 +4707,9 @@ } }, "node_modules/@react-native-community/cli-types": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-9.1.0.tgz", - "integrity": "sha512-KDybF9XHvafLEILsbiKwz5Iobd+gxRaPyn4zSaAerBxedug4er5VUWa8Szy+2GeYKZzMh/gsb1o9lCToUwdT/g==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-10.0.0.tgz", + "integrity": "sha512-31oUM6/rFBZQfSmDQsT1DX/5fjqfxg7sf2u8kTPJK7rXVya5SRpAMaCXsPAG0omsmJxXt+J9HxUi3Ic+5Ux5Iw==", "dependencies": { "joi": "^17.2.1" } @@ -4751,9 +4760,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@react-native-community/cli/node_modules/commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "engines": { "node": "^12.20.0 || >=14" } @@ -4877,9 +4886,9 @@ } }, "node_modules/@react-native-community/datetimepicker": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-6.7.1.tgz", - "integrity": "sha512-NPW1YITG7N+3TsqXc4LZV3c5IEpTD5iX18r0bvFsHdIblo5qi0ykpeK3TffmMM5gbTjgKJ4DNVHOjLiWKxFUxw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-6.7.3.tgz", + "integrity": "sha512-fXWbEdHMLW/e8cts3snEsbOTbnFXfUHeO2pkiDFX3fWpFoDtUrRWvn50xbY13IJUUKHDhoJ+mj24nMRVIXfX1A==", "dependencies": { "invariant": "^2.2.4" } @@ -4964,9 +4973,9 @@ "integrity": "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ==" }, "node_modules/@react-native/normalize-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.0.0.tgz", - "integrity": "sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz", + "integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==" }, "node_modules/@react-native/polyfills": { "version": "2.0.0", @@ -4974,11 +4983,11 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" }, "node_modules/@react-navigation/bottom-tabs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.2.tgz", - "integrity": "sha512-iN3B1cgXdo64lqXdsTsCjN7n+5ILYKRexAu0VtW6EO8E6Z/0obK5JcCEropSiimRqVRs0kyuYj3F94Oth+hMrw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.3.tgz", + "integrity": "sha512-ZA2Ko9fNwNaaSNn7738KpEk8Doi+yjRfTg8Wb/WvduIaK/28qNLAYWBCUEVjBC55y/9zJOzwc4R8Av2J2MG/4g==", "dependencies": { - "@react-navigation/elements": "^1.3.12", + "@react-navigation/elements": "^1.3.13", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -5019,9 +5028,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@react-navigation/core": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.5.tgz", - "integrity": "sha512-wcde35HeOM5r2P25EwLQZyJ1yhXDGKuWpnKfsSI1xrgYIvWdYi3j/yGnwgNGDelCmtUt1Fyk2pmOv8sEku9KkA==", + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.6.tgz", + "integrity": "sha512-6zaAgUT5k4vhJlddUk2l52RZyMkMelHdrRv1cL57ALi2RZzERdgmbiMKhJerxFLn9S8E3PUe8vwxHzjHOZKG4w==", "dependencies": { "@react-navigation/routers": "^6.1.6", "escape-string-regexp": "^4.0.0", @@ -5035,9 +5044,9 @@ } }, "node_modules/@react-navigation/elements": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.12.tgz", - "integrity": "sha512-iVcLIYg/XJk1p6X1rSFhNhCjAJ3ORqNT2/bJqw7I/liujeJAoz1oZ5JDoEcZaA0wMDts1txxLuqAYJmhCgU2aA==", + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.13.tgz", + "integrity": "sha512-LqqK5s2ZfYHn2cQ376jC5V9dQztLH5ixkkJj9WR7JY2g4SghDd39WJhL3Jillw1Mu3F3b9sZwvAK+QkXhnDeAA==", "peerDependencies": { "@react-navigation/native": "^6.0.0", "react": "*", @@ -5046,11 +5055,11 @@ } }, "node_modules/@react-navigation/native": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.1.tgz", - "integrity": "sha512-iIozx9c66EjSFyzKrZPixnk6vBuivYXp0jmbKCJXNIa7MY+8OLx9CXj/+1py/l/OGlXDhI6jiUWWetOfOtMaBQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.2.tgz", + "integrity": "sha512-qLUe0asHofr5EhxKjvUBJ9DrPPmR4535IEwmW3oU4DRb3cLbNysjajJKHL8kcYtqPvn9Bx9QZG2x0PMb2vN23A==", "dependencies": { - "@react-navigation/core": "^6.4.5", + "@react-navigation/core": "^6.4.6", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.1.23" @@ -5069,11 +5078,11 @@ } }, "node_modules/@react-navigation/stack": { - "version": "6.3.10", - "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.10.tgz", - "integrity": "sha512-mghQpCbGBI9jpwYmhXDI5drGOxz6F9hLxQgLeu1IsTSA9767Edov7TDt5n/PTJqhpOru7/xoNMs4yhp9ykVhng==", + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.11.tgz", + "integrity": "sha512-GWOAyJfPEsjVwDWec1ERwWL5LvManJucCRUZetJqCBs4/mV7HXEt2x6l3SMitHxH1+K+9XuYXI+wBTbK1WDYOA==", "dependencies": { - "@react-navigation/elements": "^1.3.12", + "@react-navigation/elements": "^1.3.13", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -5115,35 +5124,24 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@rudderstack/rudder-sdk-react-native": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.5.1.tgz", - "integrity": "sha512-nyacl2EpJ3l2NBMm7YhijyjD1jIk0GeBpBgFMZavMdAChA+Ak7sl+quKOfewYHLuFf/g2xh07p4ULLQpLqBpZw==", - "dependencies": { - "@babel/runtime": "^7.7.7", - "@types/async-lock": "^1.1.3", - "@types/react-native": "^0.62.2", - "async-lock": "^1.3.0" - }, + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.5.2.tgz", + "integrity": "sha512-M6dqOHqmbDzFE3R+TfjA0AppQfS8TSuv+qLtiq57V47zlLlkusszfZvHLQ8O63iTi5XsVciO1oTyj2ZCLtJUHA==", "peerDependencies": { - "react-native": ">=0.41.2 <=0.69.3" - } - }, - "node_modules/@rudderstack/rudder-sdk-react-native/node_modules/@types/react-native": { - "version": "0.62.18", - "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.18.tgz", - "integrity": "sha512-7QfU8EzIYxYqeXpPf8QNv2xi8hrePlgTbRATRo+plRSdVfJu7N6sAXqrFxKJp6bGLvp82GV1gczl93gqiAfXPA==", - "dependencies": { - "@types/react": "*" + "async-lock": "1.4.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "^0.41.2" } }, "node_modules/@sentry/browser": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.26.0.tgz", - "integrity": "sha512-S6uW+Ni2VLGHUV9eAUtTy5QEvqKeOhcnWnv+2yTGDtQCJ0SuHfXRCM7ASAQYBiKffZqIFc9Z2XNU/2cuWcXJmw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.29.0.tgz", + "integrity": "sha512-Af+dIcntaw405Wt7myDOMGDxiszfy4aBdshrEKYbGgcfHjgXBIdF3iKlNatvl6nrOm+IOVuKgSpCLOr2hiCwzw==", "dependencies": { - "@sentry/core": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/replay": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "engines": { @@ -5191,12 +5189,12 @@ } }, "node_modules/@sentry/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.26.0.tgz", - "integrity": "sha512-ydi236ZoP/xpvLdf7B8seKjCcGc5Z+q9c14tHCFusplPZgLSXcYpiiLIDWmF7OAXO89sSbb1NaFt9YB0LkYdLQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.29.0.tgz", + "integrity": "sha512-+e9aIp2ljtT4EJq3901z6TfEVEeqZd5cWzbKEuQzPn2UO6If9+Utd7kY2Y31eQYb4QnJgZfiIEz1HonuYY6zqQ==", "dependencies": { - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "engines": { @@ -5209,13 +5207,13 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@sentry/hub": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.26.0.tgz", - "integrity": "sha512-djAMuA4/Jy28dOSy9z5ccXBDyYk1N9m0ljle+dKqjfJwv440tCGyoxm2arqJFHbXvqwJTt2Giv8ASR4uGD1UNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.29.0.tgz", + "integrity": "sha512-nIV2NtTn16VukTtWFhROHJ35NyUIXgEGtesG8a1i7D4iRSvkfLkLrQ9i6D0BAE2huqKqQemO3zGEPR00szqsiA==", "dependencies": { - "@sentry/core": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "engines": { @@ -5228,12 +5226,12 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@sentry/integrations": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.26.0.tgz", - "integrity": "sha512-5tyBA5BnZEuosSIvBP7mJz66xJaZTb/k1EzHEc0hR2Mw8QpLgMneDZBfi4vdbhxtGpJKC/gURoUGZf9hpwW+DA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.29.0.tgz", + "integrity": "sha512-BkZe3ALij320VtC5bNkeSz3OUhT9oxZsj2lf5rCuRFqcqw4tvVNADF/Y98mf0L4VCy582M9MlNXmwfewJjxGOA==", "dependencies": { - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "localforage": "^1.8.1", "tslib": "^1.9.3" }, @@ -5247,13 +5245,13 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@sentry/react": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.26.0.tgz", - "integrity": "sha512-v5XKpG1PF4qnWvG8E0N1kcUk74lTp+TDfKx5x996NIja2oOTp/JL9V0Q+lAMlB1EKgJuxLe92IeqD5/DTtzE7A==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.29.0.tgz", + "integrity": "sha512-pJ138QTChfAiYzFrCgycBgXrAVARV6TdVvLB8z/HsqbHzPq17RhyF9M1xPE4ffeLDQAEuSudwED9CLOpJqKnAw==", "dependencies": { - "@sentry/browser": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/browser": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "hoist-non-react-statics": "^3.3.2", "tslib": "^1.9.3" }, @@ -5265,19 +5263,19 @@ } }, "node_modules/@sentry/react-native": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-4.12.0.tgz", - "integrity": "sha512-KBRXXqqGg67oqhtGzZQ8Ls4rxxUozDyL8tMLmRLk//bkSWBC6XslyjkZkQrB1VZsv2ikEYCUgyAP7fzcj6Bbig==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-4.13.0.tgz", + "integrity": "sha512-CxQd5jWPKEPgR1SH5ppf555h7DMhSBZMU3eSZ/VNT+BocgzxxBnf/tcJj92+gpwrzt2m7MiZ3uDfyfQOgyMc8Q==", "dependencies": { - "@sentry/browser": "7.26.0", + "@sentry/browser": "7.29.0", "@sentry/cli": "1.74.4", - "@sentry/core": "7.26.0", - "@sentry/hub": "7.26.0", - "@sentry/integrations": "7.26.0", - "@sentry/react": "7.26.0", - "@sentry/tracing": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/hub": "7.29.0", + "@sentry/integrations": "7.29.0", + "@sentry/react": "7.29.0", + "@sentry/tracing": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "@sentry/wizard": "1.4.0" }, "peerDependencies": { @@ -5290,14 +5288,30 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/@sentry/tracing": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.26.0.tgz", - "integrity": "sha512-UK8EiXxJrDTWD82Oasj2WP/QuQ+wzPlg74vYmxl1ie/LRs6C6wHkilBZwDV9HnDdqAqSjl0al8oBa075lK+U3Q==", + "node_modules/@sentry/replay": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.29.0.tgz", + "integrity": "sha512-Gw7HgviJQu6pX5RFQGVY38Av4qFn9otrZdwSSl/QK5hIyg6yhlh5h7U0ydZkrYYGiW6Z6SYYRpEWCJc/Wbh+ZQ==", "dependencies": { - "@sentry/core": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@sentry/browser": ">=7.24.0" + } + }, + "node_modules/@sentry/tracing": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.29.0.tgz", + "integrity": "sha512-MAN/G6XROtRhzo/KDjddb6VJn/Q1TaPLwdyj9vvfkUkBNtlt5k16oXp+u7eHWX0uujER9wnZtj2ivXaPeqq0VA==", + "dependencies": { + "@sentry/core": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "engines": { @@ -5310,19 +5324,19 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@sentry/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.26.0.tgz", - "integrity": "sha512-U2s0q3ALwWFdHJBgn8nrG9bCTJZ3hAqL/I2Si4Mf0ZWnJ/KTJKbtyrputHr8wMbHvX0NZTJGTxFVUO46J+GBRA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.29.0.tgz", + "integrity": "sha512-DmoEpoqHPty3VxqubS/5gxarwebHRlcBd/yuno+PS3xy++/i9YPjOWLZhU2jYs1cW68M9R6CcCOiC9f2ckJjdw==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.26.0.tgz", - "integrity": "sha512-nIC1PRyoMBi4QB7XNCWaPDqaQbPayMwAvUm6W3MC5bHPfVZmmFt+3sLZQKUD/E0NeQnJ3vTyPewPF/LfxLOE5A==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.29.0.tgz", + "integrity": "sha512-ICcBwTiBGK8NQA8H2BJo0JcMN6yCeKLqNKNMVampRgS6wSfSk1edvcTdhRkW3bSktIGrIPZrKskBHyMwDGF2XQ==", "dependencies": { - "@sentry/types": "7.26.0", + "@sentry/types": "7.29.0", "tslib": "^1.9.3" }, "engines": { @@ -5369,9 +5383,9 @@ } }, "node_modules/@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" }, "node_modules/@sideway/pinpoint": { "version": "2.0.0", @@ -5381,14 +5395,12 @@ "node_modules/@sinclair/typebox": { "version": "0.24.44", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz", - "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==", - "dev": true + "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==" }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, "dependencies": { "type-detect": "4.0.8" } @@ -5397,7 +5409,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" } @@ -5758,11 +5769,6 @@ "node": ">=10.13.0" } }, - "node_modules/@types/async-lock": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/async-lock/-/async-lock-1.1.3.tgz", - "integrity": "sha512-UpeDcjGKsYEQMeqEbfESm8OWJI305I7b9KE4ji3aBjoKWyN5CTdn8izcA1FM1DVDne30R5fNEnIy89vZw5LXJQ==" - }, "node_modules/@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -5892,11 +5898,6 @@ "hoist-non-react-statics": "^3.3.0" } }, - "node_modules/@types/invariant": { - "version": "2.2.35", - "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.35.tgz", - "integrity": "sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==" - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -5919,9 +5920,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.6.tgz", + "integrity": "sha512-XEUC/Tgw3uMh6Ho8GkUtQ2lPhY5Fmgyp3TdlkTJs1W9VgNxs+Ow/x3Elh8lHQKqCbZL0AubQuqWjHVT033Hhrw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -5981,9 +5982,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", + "version": "18.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", + "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -6097,8 +6098,7 @@ "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, "node_modules/@types/tinycolor2": { "version": "1.4.3", @@ -6133,7 +6133,6 @@ "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dev": true, "dependencies": { "@types/yargs-parser": "*" } @@ -6144,14 +6143,14 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz", - "integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.49.0.tgz", + "integrity": "sha512-IhxabIpcf++TBaBa1h7jtOWyon80SXPRLDq0dVz5SLFC/eW6tofkw/O7Ar3lkx5z5U6wzbKDrl2larprp5kk5Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.48.0", - "@typescript-eslint/type-utils": "5.48.0", - "@typescript-eslint/utils": "5.48.0", + "@typescript-eslint/scope-manager": "5.49.0", + "@typescript-eslint/type-utils": "5.49.0", + "@typescript-eslint/utils": "5.49.0", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -6177,14 +6176,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz", - "integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.49.0.tgz", + "integrity": "sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.48.0", - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/typescript-estree": "5.48.0", + "@typescript-eslint/scope-manager": "5.49.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/typescript-estree": "5.49.0", "debug": "^4.3.4" }, "engines": { @@ -6204,9 +6203,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6217,13 +6216,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", - "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz", + "integrity": "sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6244,12 +6243,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6270,13 +6269,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz", - "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.49.0.tgz", + "integrity": "sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0" + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6287,9 +6286,9 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6300,12 +6299,12 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6326,13 +6325,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz", - "integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.49.0.tgz", + "integrity": "sha512-eUgLTYq0tR0FGU5g1YHm4rt5H/+V2IPVkP0cBmbhRyEmyGe4XvJ2YJ6sYTmONfjmdMqyMLad7SB8GvblbeESZA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.0", - "@typescript-eslint/utils": "5.48.0", + "@typescript-eslint/typescript-estree": "5.49.0", + "@typescript-eslint/utils": "5.49.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -6353,9 +6352,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6366,13 +6365,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", - "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz", + "integrity": "sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6393,12 +6392,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6459,16 +6458,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz", - "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.49.0.tgz", + "integrity": "sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.0", - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/typescript-estree": "5.48.0", + "@typescript-eslint/scope-manager": "5.49.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/typescript-estree": "5.49.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -6485,9 +6484,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6498,13 +6497,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", - "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz", + "integrity": "sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6525,12 +6524,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -6825,7 +6824,6 @@ "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -7108,14 +7106,15 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7198,9 +7197,10 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "node_modules/async-lock": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.0.tgz", - "integrity": "sha512-8A7SkiisnEgME2zEedtDYPxUPzdv3x//E7n5IFktPAtMYSEAV7eNJF0rMwrVyUFj6d/8rgajLantbjcNRQYXIg==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==", + "peer": true }, "node_modules/asynckit": { "version": "0.4.0", @@ -7240,9 +7240,9 @@ } }, "node_modules/axios": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", - "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", "dev": true, "dependencies": { "follow-redirects": "^1.15.0", @@ -7479,19 +7479,76 @@ } }, "node_modules/babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", + "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", "dev": true, "dependencies": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", + "find-babel-config": "^2.0.0", + "glob": "^8.0.3", "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "reselect": "^4.1.7", + "resolve": "^1.22.1" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 16" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-module-resolver/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/babel-plugin-polyfill-corejs2": { @@ -8956,9 +9013,9 @@ } }, "node_modules/detox": { - "version": "20.1.1", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.1.tgz", - "integrity": "sha512-0ieeWAyo2f3YKeFwm7KCz4lBkCJIydyqzCQVN1sw/ZU9x9Qc8kz+itKAEiH4DHUlLkb4YLzfEbAXfO09wvrQ3w==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.2.tgz", + "integrity": "sha512-SGxLyuzE8TjIc4Lg49YKD0buj3JLaX+KtprSeFvn7ZTdWd4fH6o5Szd4KM21uBSpnYEEgXTgiCypPQst6dt5mQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -8974,7 +9031,7 @@ "glob": "^8.0.3", "ini": "^1.3.4", "json-cycle": "^1.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "multi-sort-stream": "^1.0.3", "multipipe": "^4.0.0", "node-ipc": "^9.2.1", @@ -9496,9 +9553,9 @@ } }, "node_modules/eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", + "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.4.1", @@ -9564,13 +9621,14 @@ } }, "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==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -9582,17 +9640,38 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" }, "engines": { "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, "node_modules/eslint-module-utils/node_modules/debug": { @@ -9604,64 +9683,6 @@ "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-plugin-eslint-comments": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", @@ -9717,23 +9738,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -9744,12 +9767,12 @@ } }, "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==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -9764,11 +9787,31 @@ "node": ">=0.10.0" } }, - "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/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-jest": { "version": "27.2.1", @@ -9816,9 +9859,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.1.tgz", + "integrity": "sha512-vOjdgyd0ZHBXNsmvU+785xY8Bfe57EFbTYYk8XrROzWpr9QBvpjITvAXt9xqcE6+8cjR/g1+mfumPToxsl1www==", "dev": true, "dependencies": { "array-includes": "^3.1.6", @@ -9833,7 +9876,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -9888,13 +9931,17 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10892,25 +10939,25 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", + "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", "dev": true, "dependencies": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" + "json5": "^2.1.1", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=16.0.0" } }, - "node_modules/find-babel-config/node_modules/json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "node_modules/find-babel-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=8" } }, "node_modules/find-cache-dir": { @@ -11029,9 +11076,9 @@ "dev": true }, "node_modules/flow-parser": { - "version": "0.121.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz", - "integrity": "sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==", + "version": "0.185.2", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.185.2.tgz", + "integrity": "sha512-2hJ5ACYeJCzNtiVULov6pljKOLygy0zddoqSI1fFetM+XRPpRshFdGEijtqlamA1XwyZ+7rhryI6FQFzvtLWUQ==", "engines": { "node": ">=0.4.0" } @@ -12175,9 +12222,9 @@ "dev": true }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { "has": "^1.0.3" }, @@ -13377,7 +13424,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", - "dev": true, "dependencies": { "@jest/environment": "^29.3.1", "@jest/fake-timers": "^29.3.1", @@ -13526,7 +13572,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.3.1", @@ -13546,7 +13591,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -13561,7 +13605,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13577,7 +13620,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -13588,14 +13630,12 @@ "node_modules/jest-message-util/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-message-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -13604,7 +13644,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "engines": { "node": ">=8" } @@ -13613,7 +13652,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -13625,7 +13663,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", - "dev": true, "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -14133,7 +14170,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dev": true, "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -14150,7 +14186,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -14165,7 +14200,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14181,7 +14215,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -14192,14 +14225,12 @@ "node_modules/jest-util/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -14208,7 +14239,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -14873,14 +14903,6 @@ "node": ">=0.10.0" } }, - "node_modules/klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", - "optionalDependencies": { - "graceful-fs": "^4.1.9" - } - }, "node_modules/klaw-sync": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", @@ -15223,9 +15245,9 @@ }, "node_modules/lokijs": { "name": "@nozbe/lokijs", - "version": "1.5.12-wmelon4", - "resolved": "https://registry.npmjs.org/@nozbe/lokijs/-/lokijs-1.5.12-wmelon4.tgz", - "integrity": "sha512-3sYrhLI2GkdXW/VOi1w6D2tENxxL+n1LJHRIAkaSCoehTVDiysAjxa/1GQq7gb7T4CFxJ+brMGvSx0sugEwqjQ==" + "version": "1.5.12-wmelon6", + "resolved": "https://registry.npmjs.org/@nozbe/lokijs/-/lokijs-1.5.12-wmelon6.tgz", + "integrity": "sha512-GXsaqY8qTJ6xdCrGyno2t+ON2aj6PrUDdvhbrkxK/0Fp12C4FGvDg1wS+voLU9BANYHEnr7KRWfItDZnQkjoAg==" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -15355,17 +15377,17 @@ } }, "node_modules/metro": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.72.3.tgz", - "integrity": "sha512-Hb3xTvPqex8kJ1hutQNZhQadUKUwmns/Du9GikmWKBFrkiG3k3xstGAyO5t5rN9JSUEzQT6y9SWzSSOGogUKIg==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.73.7.tgz", + "integrity": "sha512-pkRqFhuGUvkiu8HxKPUQelbCuyy6te6okMssTyLzQwsKilNLK4YMI2uD6PHnypg5SiMJ58lwfqkp/t5w72jEvw==", "dependencies": { "@babel/code-frame": "^7.0.0", - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", - "@babel/parser": "^7.14.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", "@babel/template": "^7.0.0", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", "absolute-path": "^0.0.0", "accepts": "^1.3.7", "async": "^3.2.2", @@ -15375,92 +15397,81 @@ "debug": "^2.2.0", "denodeify": "^1.2.1", "error-stack-parser": "^2.0.6", - "fs-extra": "^1.0.0", "graceful-fs": "^4.2.4", "hermes-parser": "0.8.0", "image-size": "^0.6.0", "invariant": "^2.2.4", "jest-worker": "^27.2.0", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.72.3", - "metro-cache": "0.72.3", - "metro-cache-key": "0.72.3", - "metro-config": "0.72.3", - "metro-core": "0.72.3", - "metro-file-map": "0.72.3", - "metro-hermes-compiler": "0.72.3", - "metro-inspector-proxy": "0.72.3", - "metro-minify-uglify": "0.72.3", - "metro-react-native-babel-preset": "0.72.3", - "metro-resolver": "0.72.3", - "metro-runtime": "0.72.3", - "metro-source-map": "0.72.3", - "metro-symbolicate": "0.72.3", - "metro-transform-plugins": "0.72.3", - "metro-transform-worker": "0.72.3", + "metro-babel-transformer": "0.73.7", + "metro-cache": "0.73.7", + "metro-cache-key": "0.73.7", + "metro-config": "0.73.7", + "metro-core": "0.73.7", + "metro-file-map": "0.73.7", + "metro-hermes-compiler": "0.73.7", + "metro-inspector-proxy": "0.73.7", + "metro-minify-terser": "0.73.7", + "metro-minify-uglify": "0.73.7", + "metro-react-native-babel-preset": "0.73.7", + "metro-resolver": "0.73.7", + "metro-runtime": "0.73.7", + "metro-source-map": "0.73.7", + "metro-symbolicate": "0.73.7", + "metro-transform-plugins": "0.73.7", + "metro-transform-worker": "0.73.7", "mime-types": "^2.1.27", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", - "rimraf": "^2.5.4", + "rimraf": "^3.0.2", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "strip-ansi": "^6.0.0", "temp": "0.8.3", "throat": "^5.0.0", "ws": "^7.5.1", - "yargs": "^15.3.1" + "yargs": "^17.5.1" }, "bin": { "metro": "src/cli.js" } }, "node_modules/metro-babel-transformer": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.72.3.tgz", - "integrity": "sha512-PTOR2zww0vJbWeeM3qN90WKENxCLzv9xrwWaNtwVlhcV8/diNdNe82sE1xIxLFI6OQuAVwNMv1Y7VsO2I7Ejrw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.73.7.tgz", + "integrity": "sha512-s7UVkwovGTEXYEQrv5hcmSBbFJ9s9lhCRNMScn4Itgj3UMdqRr9lU8DXKEFlJ7osgRxN6n5+eXqcvhE4B1H1VQ==", "dependencies": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.20.0", "hermes-parser": "0.8.0", - "metro-source-map": "0.72.3", + "metro-source-map": "0.73.7", "nullthrows": "^1.1.1" } }, "node_modules/metro-cache": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.72.3.tgz", - "integrity": "sha512-++eyZzwkXvijWRV3CkDbueaXXGlVzH9GA52QWqTgAOgSHYp5jWaDwLQ8qpsMkQzpwSyIF4LLK9aI3eA7Xa132A==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.73.7.tgz", + "integrity": "sha512-CPPgI+i9yVzOEDCdmEEZ67JgOvZyNDs8kStmGUFgDuLSjj3//HhkqT5XyfWjGeH6KmyGiS8ip3cgLOVn3IsOSA==", "dependencies": { - "metro-core": "0.72.3", - "rimraf": "^2.5.4" + "metro-core": "0.73.7", + "rimraf": "^3.0.2" } }, "node_modules/metro-cache-key": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.72.3.tgz", - "integrity": "sha512-kQzmF5s3qMlzqkQcDwDxrOaVxJ2Bh6WRXWdzPnnhsq9LcD3B3cYqQbRBS+3tSuXmathb4gsOdhWslOuIsYS8Rg==" - }, - "node_modules/metro-cache/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.73.7.tgz", + "integrity": "sha512-GngYzrHwZU9U0Xl81H4aq9Tn5cjQyU12v9/flB0hzpeiYO5A89TIeilb4Kg8jtfC6JcmmsdK9nxYIGEq7odHhQ==" }, "node_modules/metro-config": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.72.3.tgz", - "integrity": "sha512-VEsAIVDkrIhgCByq8HKTWMBjJG6RlYwWSu1Gnv3PpHa0IyTjKJtB7wC02rbTjSaemcr82scldf2R+h6ygMEvsw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.73.7.tgz", + "integrity": "sha512-pD/F+vK3u37cbj1skYmI6cUsEEscqNRtW2KlDKu1m+n8nooDB2oGTOZatlS5WQa7Ga6jYQRydftlq4CLDexAfA==", "dependencies": { "cosmiconfig": "^5.0.5", "jest-validate": "^26.5.2", - "metro": "0.72.3", - "metro-cache": "0.72.3", - "metro-core": "0.72.3", - "metro-runtime": "0.72.3" + "metro": "0.73.7", + "metro-cache": "0.73.7", + "metro-core": "0.73.7", + "metro-runtime": "0.73.7" } }, "node_modules/metro-config/node_modules/@jest/types": { @@ -15479,9 +15490,9 @@ } }, "node_modules/metro-config/node_modules/@types/yargs": { - "version": "15.0.14", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "version": "15.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", + "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", "dependencies": { "@types/yargs-parser": "*" } @@ -15605,18 +15616,18 @@ } }, "node_modules/metro-core": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.72.3.tgz", - "integrity": "sha512-KuYWBMmLB4+LxSMcZ1dmWabVExNCjZe3KysgoECAIV+wyIc2r4xANq15GhS94xYvX1+RqZrxU1pa0jQ5OK+/6A==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.73.7.tgz", + "integrity": "sha512-H7j1Egj1VnNnsSYf9ZKv0SRwijgtRKIcaGNQq/T+er73vqqb4kR9H+2VIJYPXi6R8lT+QLIMfs6CWSUHAJUgtg==", "dependencies": { "lodash.throttle": "^4.1.1", - "metro-resolver": "0.72.3" + "metro-resolver": "0.73.7" } }, "node_modules/metro-file-map": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.72.3.tgz", - "integrity": "sha512-LhuRnuZ2i2uxkpFsz1XCDIQSixxBkBG7oICAFyLyEMDGbcfeY6/NexphfLdJLTghkaoJR5ARFMiIxUg9fIY/pA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.73.7.tgz", + "integrity": "sha512-BYaCo2e/4FMN4nOajeN+Za5cPfecfikzUYuFWWMyLAmHU6dj7B+PFkaJ4OEJO3vmRoeq5vMOmhpKXgysYbNXJg==", "dependencies": { "abort-controller": "^3.0.0", "anymatch": "^3.0.3", @@ -15629,10 +15640,11 @@ "jest-util": "^27.2.0", "jest-worker": "^27.2.0", "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", "walker": "^1.0.7" }, "optionalDependencies": { - "fsevents": "^2.1.2" + "fsevents": "^2.3.2" } }, "node_modules/metro-file-map/node_modules/@jest/types": { @@ -15651,9 +15663,9 @@ } }, "node_modules/metro-file-map/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", "dependencies": { "@types/yargs-parser": "*" } @@ -15787,64 +15799,37 @@ } }, "node_modules/metro-hermes-compiler": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.72.3.tgz", - "integrity": "sha512-QWDQASMiXNW3j8uIQbzIzCdGYv5PpAX/ZiF4/lTWqKRWuhlkP4auhVY4eqdAKj5syPx45ggpjkVE0p8hAPDZYg==" + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.73.7.tgz", + "integrity": "sha512-F8PlJ8mWEEumGNH3eMRA3gjgP70ZvH4Ex5F1KY6ofD/gpn7w5HJHSPTeVw8gtUb1pYLN4nevptpyXGg04Jfcog==" }, "node_modules/metro-inspector-proxy": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.72.3.tgz", - "integrity": "sha512-UPFkaq2k93RaOi+eqqt7UUmqy2ywCkuxJLasQ55+xavTUS+TQSyeTnTczaYn+YKw+izLTLllGcvqnQcZiWYhGw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.73.7.tgz", + "integrity": "sha512-TsAtQeKr9X7NaQHlpshu+ZkGWlPi5fFKNqieLkfqvT1oXN4PQF/4q38INyiZtWLPvoUzTR6PRnm4pcUbJ7+Nzg==", "dependencies": { "connect": "^3.6.5", "debug": "^2.2.0", "ws": "^7.5.1", - "yargs": "^15.3.1" + "yargs": "^17.5.1" }, "bin": { "metro-inspector-proxy": "src/cli.js" } }, - "node_modules/metro-inspector-proxy/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/metro-inspector-proxy/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/metro-inspector-proxy/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=12" } }, - "node_modules/metro-inspector-proxy/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/metro-inspector-proxy/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -15853,14 +15838,6 @@ "ms": "2.0.0" } }, - "node_modules/metro-inspector-proxy/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/metro-inspector-proxy/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -15892,70 +15869,117 @@ "node": ">=8" } }, - "node_modules/metro-inspector-proxy/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/metro-inspector-proxy/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, "node_modules/metro-inspector-proxy/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/metro-inspector-proxy/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "engines": { - "node": ">=6" + "node": ">=12" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.73.7.tgz", + "integrity": "sha512-gbv1fmMOZm6gJ6dQoD+QktlCi2wk6nlTR8j8lQCjeeXGbs6O9e5XLWNPOexHqo7S69bdbohEnfZnLJFcxgHeNw==", + "dependencies": { + "terser": "^5.15.0" } }, "node_modules/metro-minify-uglify": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.72.3.tgz", - "integrity": "sha512-dPXqtMI8TQcj0g7ZrdhC8X3mx3m3rtjtMuHKGIiEXH9CMBvrET8IwrgujQw2rkPcXiSiX8vFDbGMIlfxefDsKA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.73.7.tgz", + "integrity": "sha512-DmDCzfdbaPExQuQ7NQozCNOSOAgp5Ux9kWzmKAT8seQ38/3NtUepW+PTgxXIHmwNjJV4oHsHwlBlTwJmYihKXg==", "dependencies": { "uglify-es": "^3.1.9" } }, "node_modules/metro-react-native-babel-preset": { + "version": "0.74.1", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.74.1.tgz", + "integrity": "sha512-DjsG9nqm5C7cjB2SlgbcNJOn9y5MBUd3bRlCfnoj8CxAeGTGkS+yXd183lHR3C1bhmQNjuUE0abzzpE1CFh6JQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.20.0", + "@babel/plugin-proposal-async-generator-functions": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.18.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "react-refresh": "^0.4.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/metro-react-native-babel-transformer": { + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.7.tgz", + "integrity": "sha512-73HW8betjX+VPm3iqsMBe8F/F2Tt+hONO6YJwcF7FonTqQYW1oTz0dOp0dClZGfHUXxpJBz6Vuo7J6TpdzDD+w==", + "dependencies": { + "@babel/core": "^7.20.0", + "babel-preset-fbjs": "^3.4.0", + "hermes-parser": "0.8.0", + "metro-babel-transformer": "0.73.7", + "metro-react-native-babel-preset": "0.73.7", + "metro-source-map": "0.73.7", + "nullthrows": "^1.1.1" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/metro-react-native-babel-transformer/node_modules/metro-react-native-babel-preset": { "version": "0.73.7", "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.7.tgz", "integrity": "sha512-RKcmRZREjJCzHKP+JhC9QTCohkeb3xa/DtqHU14U5KWzJHdC0mMrkTZYNXhV0cryxsaVKVEw5873KhbZyZHMVw==", - "dev": true, "dependencies": { "@babel/core": "^7.20.0", "@babel/plugin-proposal-async-generator-functions": "^7.0.0", @@ -16000,100 +16024,34 @@ "@babel/core": "*" } }, - "node_modules/metro-react-native-babel-transformer": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.72.3.tgz", - "integrity": "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==", - "dependencies": { - "@babel/core": "^7.14.0", - "babel-preset-fbjs": "^3.4.0", - "hermes-parser": "0.8.0", - "metro-babel-transformer": "0.72.3", - "metro-react-native-babel-preset": "0.72.3", - "metro-source-map": "0.72.3", - "nullthrows": "^1.1.1" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/metro-react-native-babel-transformer/node_modules/metro-react-native-babel-preset": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz", - "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", - "dependencies": { - "@babel/core": "^7.14.0", - "@babel/plugin-proposal-async-generator-functions": "^7.0.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-export-default-from": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.2.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-syntax-optional-chaining": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-async-to-generator": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.0.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.0.0", - "@babel/plugin-transform-flow-strip-types": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.0.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-modules-commonjs": "^7.0.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0", - "@babel/plugin-transform-parameters": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0", - "@babel/plugin-transform-runtime": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "@babel/plugin-transform-typescript": "^7.5.0", - "@babel/plugin-transform-unicode-regex": "^7.0.0", - "@babel/template": "^7.0.0", - "react-refresh": "^0.4.0" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, "node_modules/metro-resolver": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.72.3.tgz", - "integrity": "sha512-wu9zSMGdxpKmfECE7FtCdpfC+vrWGTdVr57lDA0piKhZV6VN6acZIvqQ1yZKtS2WfKsngncv5VbB8Y5eHRQP3w==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.73.7.tgz", + "integrity": "sha512-mGW3XPeKBCwZnkHcKo1dhFa9olcx7SyNzG1vb5kjzJYe4Qs3yx04r/qFXIJLcIgLItB69TIGvosznUhpeOOXzg==", "dependencies": { "absolute-path": "^0.0.0" } }, "node_modules/metro-runtime": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.72.3.tgz", - "integrity": "sha512-3MhvDKfxMg2u7dmTdpFOfdR71NgNNo4tzAyJumDVQKwnHYHN44f2QFZQqpPBEmqhWlojNeOxsqFsjYgeyMx6VA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.73.7.tgz", + "integrity": "sha512-2fxRGrF8FyrwwHY0TCitdUljzutfW6CWEpdvPilfrs8p0PI5X8xOWg8ficeYtw+DldHtHIAL2phT59PqzHTyVA==", "dependencies": { "@babel/runtime": "^7.0.0", "react-refresh": "^0.4.0" } }, "node_modules/metro-source-map": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.72.3.tgz", - "integrity": "sha512-eNtpjbjxSheXu/jYCIDrbNEKzMGOvYW6/ePYpRM7gDdEagUOqKOCsi3St8NJIQJzZCsxD2JZ2pYOiomUSkT1yQ==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.73.7.tgz", + "integrity": "sha512-gbC/lfUN52TtQhEsTTA+987MaFUpQlufuCI05blLGLosDcFCsARikHsxa65Gtslm/rG2MqvFLiPA5hviONNv9g==", "dependencies": { - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", "invariant": "^2.2.4", - "metro-symbolicate": "0.72.3", + "metro-symbolicate": "0.73.7", "nullthrows": "^1.1.1", - "ob1": "0.72.3", + "ob1": "0.73.7", "source-map": "^0.5.6", "vlq": "^1.0.0" } @@ -16107,12 +16065,12 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.72.3.tgz", - "integrity": "sha512-eXG0NX2PJzJ/jTG4q5yyYeN2dr1cUqUaY7worBB0SP5bRWRc3besfb+rXwfh49wTFiL5qR0oOawkU4ZiD4eHXw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.73.7.tgz", + "integrity": "sha512-571ThWmX5o8yGNzoXjlcdhmXqpByHU/bSZtWKhtgV2TyIAzYCYt4hawJAS5+/qDazUvjHdm8BbdqFUheM0EKNQ==", "dependencies": { "invariant": "^2.2.4", - "metro-source-map": "0.72.3", + "metro-source-map": "0.73.7", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -16134,34 +16092,34 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.72.3.tgz", - "integrity": "sha512-D+TcUvCKZbRua1+qujE0wV1onZvslW6cVTs7dLCyC2pv20lNHjFr1GtW01jN2fyKR2PcRyMjDCppFd9VwDKnSg==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.73.7.tgz", + "integrity": "sha512-M5isiWEau0jMudb5ezaNBZnYqXxcATMqnAYc+Cu25IahT1NHi5aWwLok9EBmBpN5641IZUZXScf+KnS7fPxPCQ==", "dependencies": { - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", "@babel/template": "^7.0.0", - "@babel/traverse": "^7.14.0", + "@babel/traverse": "^7.20.0", "nullthrows": "^1.1.1" } }, "node_modules/metro-transform-worker": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.72.3.tgz", - "integrity": "sha512-WsuWj9H7i6cHuJuy+BgbWht9DK5FOgJxHLGAyULD5FJdTG9rSMFaHDO5WfC0OwQU5h4w6cPT40iDuEGksM7+YQ==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.73.7.tgz", + "integrity": "sha512-gZYIu9JAqEI9Rxi0xGMuMW6QsHGbMSptozlTOwOd7T7yXX3WwYS/I3yLPbLhbZTjOhwMHkTt8Nhm2qBo8nh14g==", "dependencies": { - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", - "@babel/parser": "^7.14.0", - "@babel/types": "^7.0.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", "babel-preset-fbjs": "^3.4.0", - "metro": "0.72.3", - "metro-babel-transformer": "0.72.3", - "metro-cache": "0.72.3", - "metro-cache-key": "0.72.3", - "metro-hermes-compiler": "0.72.3", - "metro-source-map": "0.72.3", - "metro-transform-plugins": "0.72.3", + "metro": "0.73.7", + "metro-babel-transformer": "0.73.7", + "metro-cache": "0.73.7", + "metro-cache-key": "0.73.7", + "metro-hermes-compiler": "0.73.7", + "metro-source-map": "0.73.7", + "metro-transform-plugins": "0.73.7", "nullthrows": "^1.1.1" } }, @@ -16200,13 +16158,16 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "node_modules/metro/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/metro/node_modules/color-convert": { @@ -16233,29 +16194,11 @@ "ms": "2.0.0" } }, - "node_modules/metro/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/metro/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "node_modules/metro/node_modules/fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } - }, "node_modules/metro/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -16299,20 +16242,12 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/metro/node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/metro/node_modules/metro-react-native-babel-preset": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz", - "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.7.tgz", + "integrity": "sha512-RKcmRZREjJCzHKP+JhC9QTCohkeb3xa/DtqHU14U5KWzJHdC0mMrkTZYNXhV0cryxsaVKVEw5873KhbZyZHMVw==", "dependencies": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.20.0", "@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", @@ -16322,7 +16257,7 @@ "@babel/plugin-proposal-optional-chaining": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-export-default-from": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.2.0", + "@babel/plugin-syntax-flow": "^7.18.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", "@babel/plugin-syntax-optional-chaining": "^7.0.0", "@babel/plugin-transform-arrow-functions": "^7.0.0", @@ -16331,7 +16266,6 @@ "@babel/plugin-transform-classes": "^7.0.0", "@babel/plugin-transform-computed-properties": "^7.0.0", "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", "@babel/plugin-transform-function-name": "^7.0.0", "@babel/plugin-transform-literals": "^7.0.0", @@ -16361,17 +16295,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/metro/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/metro/node_modules/serialize-error": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", @@ -16412,55 +16335,29 @@ "node": ">=8" } }, - "node_modules/metro/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/metro/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, "node_modules/metro/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/metro/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "engines": { - "node": ">=6" + "node": ">=12" } }, "node_modules/mhchemparser": { @@ -16832,9 +16729,9 @@ } }, "node_modules/nock": { - "version": "13.2.9", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.9.tgz", - "integrity": "sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz", + "integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==", "dev": true, "dependencies": { "debug": "^4.1.0", @@ -16996,9 +16893,9 @@ } }, "node_modules/ob1": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.72.3.tgz", - "integrity": "sha512-OnVto25Sj7Ghp0vVm2THsngdze3tVq0LOg9LUHsAVXMecpqOP0Y8zaATW8M9gEgs2lNEAcCqV0P/hlmOPhVRvg==" + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.73.7.tgz", + "integrity": "sha512-DfelfvR843KADhSUATGGhuepVMRcf5VQX+6MQLy5AW0BKDLlO7Usj6YZeAAZP7P86QwsoTxB0RXCFiA7t6S1IQ==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -17912,7 +17809,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dev": true, "dependencies": { "@jest/schemas": "^29.0.0", "ansi-styles": "^5.0.0", @@ -17926,7 +17822,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -17937,8 +17832,7 @@ "node_modules/pretty-format/node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/prismjs": { "version": "1.27.0", @@ -18149,7 +18043,6 @@ "version": "4.27.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.27.1.tgz", "integrity": "sha512-qXhcxxDWiFmFAOq48jts9YQYe1+wVoUXzJTlY4jbaATzyio6dd6CUGu3dXBhREeVgpZ+y4kg6vFJzIOZh6vY2w==", - "dev": true, "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" @@ -18224,42 +18117,44 @@ "integrity": "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ==" }, "node_modules/react-native": { - "version": "0.70.6", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.70.6.tgz", - "integrity": "sha512-xtQdImPHnwgraEx3HIZFOF+D1hJ9bC5mfpIdUGoMHRws6OmvHAjmFpO6qfdnaQ29vwbmZRq7yf14sbury74R/w==", + "version": "0.71.1", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.1.tgz", + "integrity": "sha512-bLP5+IBj2IX6tgF9WnC/UL2ZPYkVUPsU4xqZV1jntTC2TH4xyLrvfKACjGlz5nQ3Mx4BmOFqsnMxithm53+6Aw==", "dependencies": { - "@jest/create-cache-key-function": "^27.0.1", - "@react-native-community/cli": "9.3.2", - "@react-native-community/cli-platform-android": "9.3.1", - "@react-native-community/cli-platform-ios": "9.3.0", + "@jest/create-cache-key-function": "^29.2.1", + "@react-native-community/cli": "10.1.3", + "@react-native-community/cli-platform-android": "10.1.3", + "@react-native-community/cli-platform-ios": "10.1.1", "@react-native/assets": "1.0.0", - "@react-native/normalize-color": "2.0.0", + "@react-native/normalize-color": "2.1.0", "@react-native/polyfills": "2.0.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "base64-js": "^1.1.2", + "deprecated-react-native-prop-types": "^3.0.1", "event-target-shim": "^5.0.1", "invariant": "^2.2.4", + "jest-environment-node": "^29.2.1", "jsc-android": "^250230.2.1", "memoize-one": "^5.0.0", - "metro-react-native-babel-transformer": "0.72.3", - "metro-runtime": "0.72.3", - "metro-source-map": "0.72.3", + "metro-react-native-babel-transformer": "0.73.7", + "metro-runtime": "0.73.7", + "metro-source-map": "0.73.7", "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", "promise": "^8.3.0", - "react-devtools-core": "4.24.0", - "react-native-codegen": "^0.70.6", - "react-native-gradle-plugin": "^0.70.3", + "react-devtools-core": "^4.26.1", + "react-native-codegen": "^0.71.3", + "react-native-gradle-plugin": "^0.71.13", "react-refresh": "^0.4.0", "react-shallow-renderer": "^16.15.0", "regenerator-runtime": "^0.13.2", - "scheduler": "^0.22.0", + "scheduler": "^0.23.0", "stacktrace-parser": "^0.1.3", "use-sync-external-store": "^1.0.0", "whatwg-fetch": "^3.0.0", - "ws": "^6.1.4" + "ws": "^6.2.2" }, "bin": { "react-native": "cli.js" @@ -18268,7 +18163,7 @@ "node": ">=14" }, "peerDependencies": { - "react": "18.1.0" + "react": "18.2.0" } }, "node_modules/react-native-android-open-settings": { @@ -18327,12 +18222,12 @@ } }, "node_modules/react-native-codegen": { - "version": "0.70.6", - "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.70.6.tgz", - "integrity": "sha512-kdwIhH2hi+cFnG5Nb8Ji2JwmcCxnaOOo9440ov7XDzSvGfmUStnCzl+MCW8jLjqHcE4icT7N9y+xx4f50vfBTw==", + "version": "0.71.3", + "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.71.3.tgz", + "integrity": "sha512-5AvdHVU1sAaXg05i0dG664ZTaCaIFaY1znV5vNsj+wUu6MGxNEUNbDKk9dxKUkkxOyk2KZOK5uhzWL0p5H5yZQ==", "dependencies": { "@babel/parser": "^7.14.0", - "flow-parser": "^0.121.0", + "flow-parser": "^0.185.0", "jscodeshift": "^0.13.1", "nullthrows": "^1.1.1" } @@ -18453,9 +18348,9 @@ "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" }, "node_modules/react-native-gesture-handler": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.8.0.tgz", - "integrity": "sha512-poOSfz/w0IyD6Qwq7aaIRRfEaVTl1ecQFoyiIbpOpfNTjm2B1niY2FLrdVQIOtIOe+K9nH55Qal04nr4jGkHdQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz", + "integrity": "sha512-a0BcH3Qb1tgVqUutc6d3VuWQkI1AM3+fJx8dkxzZs9t06qA27QgURYFoklpabuWpsUTzuKRpxleykp25E8m7tg==", "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", @@ -18469,9 +18364,9 @@ } }, "node_modules/react-native-gradle-plugin": { - "version": "0.70.3", - "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz", - "integrity": "sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==" + "version": "0.71.13", + "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.13.tgz", + "integrity": "sha512-C66LNZAXbU0YDRkWx8d/8kjesdu7fsUAc/3QPJNftSXKEvEtnFZK2aH/rIgu1s5dbTcE0fjhdVPNJMRIfKo61w==" }, "node_modules/react-native-haptic-feedback": { "version": "1.14.0", @@ -18490,9 +18385,9 @@ } }, "node_modules/react-native-image-picker": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-4.10.3.tgz", - "integrity": "sha512-gLX8J6jCBkUt6jogpSdA7YyaGVLGYywRzMEwBciXshihpFZjc/cRlKymAVlu6Q7HMw0j3vrho6pI8ZGC5O/FGg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-5.0.1.tgz", + "integrity": "sha512-+poQTHOnEGrbxJnut591XA9006svFOyfPg/i5bv+fLuwoSHh5HW0E/PVhvT8lbX0Z5C108vh3DAsnrfFFnPBGw==", "peerDependencies": { "react": "*", "react-native": "*" @@ -18589,9 +18484,9 @@ } }, "node_modules/react-native-navigation": { - "version": "7.30.6", - "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.30.6.tgz", - "integrity": "sha512-rnJ7VbMjnt8H1HkuaM65NkcFFca2QQRgsCQEF6yAe9J4Yb3I3XnywFd309D6yso4ZqRuK7EhuzP33/nReV1c/A==", + "version": "7.31.1", + "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.31.1.tgz", + "integrity": "sha512-thChSqaoi/QHGGofG/4CEyO2v6ko41RsbjQrJzAnHkp7iw1K8pjxkW3KX0qx2rlR/A69kA31VskOLj8kl+7sQw==", "dependencies": { "hoist-non-react-statics": "3.x.x", "lodash": "4.17.x", @@ -18655,13 +18550,13 @@ } }, "node_modules/react-native-reanimated": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.13.0.tgz", - "integrity": "sha512-yUHyYVIegWWIza4+nVyS3CSmI/Mc8kLFVHw2c6gnSHaYhYA4LeEjH/jBkoMzHk9Xd0Ra3cwtjYKAMG8OTp6JVg==", + "version": "2.14.4", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.14.4.tgz", + "integrity": "sha512-DquSbl7P8j4SAmc+kRdd75Ianm8G+IYQ9T4AQ6lrpLVeDkhZmjWI0wkutKWnp6L7c5XNVUrFDUf69dwETLCItQ==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", - "@types/invariant": "^2.2.35", + "convert-source-map": "^1.7.0", "invariant": "^2.2.4", "lodash.isequal": "^4.5.0", "setimmediate": "^1.0.5", @@ -18674,18 +18569,18 @@ } }, "node_modules/react-native-safe-area-context": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.4.1.tgz", - "integrity": "sha512-N9XTjiuD73ZpVlejHrUWIFZc+6Z14co1K/p1IFMkImU7+avD69F3y+lhkqA2hN/+vljdZrBSiOwXPkuo43nFQA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.5.0.tgz", + "integrity": "sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==", "peerDependencies": { "react": "*", "react-native": "*" } }, "node_modules/react-native-screens": { - "version": "3.18.2", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.18.2.tgz", - "integrity": "sha512-ANUEuvMUlsYJ1QKukEhzhfrvOUO9BVH9Nzg+6eWxpn3cfD/O83yPBOF8Mx6x5H/2+sMy+VS5x/chWOOo/U7QJw==", + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.19.0.tgz", + "integrity": "sha512-Ehsmy7jr3H3j5pmN+/FqsAaIAD+k+xkcdePfLcg4rYRbN5X7fJPgaqhcmiCcZ0YxsU8ttsstP9IvRLNQuIkRRA==", "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" @@ -18726,9 +18621,9 @@ } }, "node_modules/react-native-svg": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.6.0.tgz", - "integrity": "sha512-1wjHCMJ8siyZbDZ0MX5wM+Jr7YOkb6GADn4/Z+/u1UwJX8WfjarypxDF3UO1ugMHa+7qor39oY+URMcrgPpiww==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.7.0.tgz", + "integrity": "sha512-WR5CIURvee5cAfvMhmdoeOjh1SC8KdLq5u5eFsz4pbYzCtIFClGSkLnNgkMSDMVV5LV0qQa4jeIk75ieIBzaDA==", "dependencies": { "css-select": "^5.1.0", "css-tree": "^1.1.3" @@ -18860,9 +18755,9 @@ } }, "node_modules/react-native-walkthrough-tooltip": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/react-native-walkthrough-tooltip/-/react-native-walkthrough-tooltip-1.4.0.tgz", - "integrity": "sha512-nyBuynmCuzPKJN9NRGhSzCutGOk7/WqszGtX01gjDtlRfoJ25cSM0h+TEi/lsLbSCTEdB+e65qOTvoVhIq2gzA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-native-walkthrough-tooltip/-/react-native-walkthrough-tooltip-1.5.0.tgz", + "integrity": "sha512-xzpTs3JQkUMkmurc7WJDSAWaH2KRiRL2YoTXVCRqEEWxIvLQTn9eQv0jBzs1geR0wL+ezRpjkBEGAlfQ6eMimw==", "dependencies": { "prop-types": "^15.6.1", "react-fast-compare": "^2.0.4" @@ -18987,6 +18882,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/react-native/node_modules/deprecated-react-native-prop-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-3.0.1.tgz", + "integrity": "sha512-J0jCJcsk4hMlIb7xwOZKLfMpuJn6l8UtrPEzzQV5ewz5gvKNYakhBuq9h2rWX7YwHHJZFhU5W8ye7dB9oN8VcQ==", + "dependencies": { + "@react-native/normalize-color": "*", + "invariant": "*", + "prop-types": "*" + } + }, "node_modules/react-native/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -19009,35 +18914,6 @@ "node": ">= 10" } }, - "node_modules/react-native/node_modules/react-devtools-core": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.0.tgz", - "integrity": "sha512-Rw7FzYOOzcfyUPaAm9P3g0tFdGqGq2LLiAI+wjYcp6CsF3DeeMrRS3HZAho4s273C29G/DJhx0e8BpRE/QZNGg==", - "dependencies": { - "shell-quote": "^1.6.1", - "ws": "^7" - } - }, - "node_modules/react-native/node_modules/react-devtools-core/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/react-native/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -19117,15 +18993,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/react-test-renderer/node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/read-env": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/read-env/-/read-env-1.3.0.tgz", @@ -19388,9 +19255,9 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "node_modules/reselect": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", - "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==", "dev": true }, "node_modules/resolve": { @@ -19507,7 +19374,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -19610,9 +19476,9 @@ } }, "node_modules/scheduler": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz", - "integrity": "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "dependencies": { "loose-envify": "^1.1.0" } @@ -20292,7 +20158,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -20304,7 +20169,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, "engines": { "node": ">=8" } @@ -20768,8 +20632,6 @@ "version": "5.15.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", - "dev": true, - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", @@ -20881,9 +20743,7 @@ "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "peer": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/test-exclude": { "version": "6.0.0", @@ -21082,15 +20942,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -21151,9 +21011,9 @@ } }, "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==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -21213,7 +21073,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -22158,9 +22017,9 @@ } }, "node_modules/zod": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", - "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==", + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.2.tgz", + "integrity": "sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -22322,9 +22181,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz", - "integrity": "sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz", + "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", @@ -22332,6 +22191,7 @@ "@babel/helper-member-expression-to-functions": "^7.20.7", "@babel/helper-optimise-call-expression": "^7.18.6", "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", "@babel/helper-split-export-declaration": "^7.18.6" } }, @@ -22471,11 +22331,11 @@ } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", - "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "requires": { - "@babel/types": "^7.18.9" + "@babel/types": "^7.20.0" } }, "@babel/helper-split-export-declaration": { @@ -22586,12 +22446,12 @@ } }, "@babel/plugin-proposal-decorators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.7.tgz", - "integrity": "sha512-JB45hbUweYpwAGjkiM7uCyXMENH2lG+9r3G2E+ttc2PRXAoEkpfd/KW5jDg4j8RS6tLtTG1jZi9LbHZVSfs1/A==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.13.tgz", + "integrity": "sha512-7T6BKHa9Cpd7lCueHBBzP0nkXNina+h5giOZw+a8ZpMfPFY19VjJAjIxyFHuWkhCWgL6QMqRiY/wB1fLXzm6Mw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.20.7", + "@babel/helper-create-class-features-plugin": "^7.20.12", "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-replace-supers": "^7.20.7", "@babel/helper-split-export-declaration": "^7.18.6", @@ -23417,9 +23277,9 @@ } }, "@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", "requires": { "regenerator-runtime": "^0.13.11" } @@ -23921,83 +23781,17 @@ } }, "@jest/create-cache-key-function": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz", - "integrity": "sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ==", + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.3.1.tgz", + "integrity": "sha512-4i+E+E40gK13K78ffD/8cy4lSSqeWwyXeTZoq16tndiCP12hC8uQsPJdIu5C6Kf22fD8UbBk71so7s/6VwpUOQ==", "requires": { - "@jest/types": "^27.5.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } + "@jest/types": "^29.3.1" } }, "@jest/environment": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", - "dev": true, "requires": { "@jest/fake-timers": "^29.3.1", "@jest/types": "^29.3.1", @@ -24028,7 +23822,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", - "dev": true, "requires": { "@jest/types": "^29.3.1", "@sinonjs/fake-timers": "^9.1.2", @@ -24143,7 +23936,6 @@ "version": "29.0.0", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dev": true, "requires": { "@sinclair/typebox": "^0.24.1" } @@ -24281,7 +24073,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", - "dev": true, "requires": { "@jest/schemas": "^29.0.0", "@types/istanbul-lib-coverage": "^2.0.0", @@ -24295,7 +24086,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -24304,7 +24094,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -24314,7 +24103,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -24322,20 +24110,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -24366,8 +24151,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "peer": true, "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -24414,38 +24197,38 @@ "integrity": "sha512-qCZjvU6Vsl7cg/0urrq8ItK5CXnt3DqjFq/w9mBpWuem/YhMWLMVBoSuASAx9S2HV7Vr/iMdsMGWH/4qXkXCBg==" }, "@mattermost/react-native-emm": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-emm/-/react-native-emm-1.3.3.tgz", - "integrity": "sha512-mOPlp3C0ba1XOANTYi3i2dL9gBdQLoJZ4zvOzhqYeg5FQXBXXoJomPKAzxJH27aX3k92bu+U0BmEbnKIitKKEA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-emm/-/react-native-emm-1.3.4.tgz", + "integrity": "sha512-xdFPfAH3d9pa1og6rr+kHCWlLYMnHe7kY1IxIjhvfZ28ElNExjOhOF7JOL/s4RUvk8bZS7H72+ldRYZ6ERHlWw==", "requires": {} }, "@mattermost/react-native-network-client": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-network-client/-/react-native-network-client-1.0.2.tgz", - "integrity": "sha512-ywVxTKPT1A8eEccPpCrHXYqO9BvvEx+xdecn/VILUDeEIfpOVETLh5952SQjoc3PP0RRME0bv92+fzoxiOZ4YQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-network-client/-/react-native-network-client-1.1.0.tgz", + "integrity": "sha512-iZemjWqUaGkfSY+7Ve+m6MUJc8blUOzHoY9J5miKjez7QPiknYGMIdVFMYAiuO9jUtgQ4XSG7/nENqYR5jSwCg==", "requires": { "validator": "13.7.0", - "zod": "3.19.1" + "zod": "3.20.2" } }, "@mattermost/react-native-paste-input": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-paste-input/-/react-native-paste-input-0.5.2.tgz", - "integrity": "sha512-aQdLUidSAbWPLXWmwM1x8AhnZIO4EN5uWx813/G3+mL8kWD7mpXrQEvMpcdtKWatD705kCyKZkvnNY4yjq0TkA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-paste-input/-/react-native-paste-input-0.6.0.tgz", + "integrity": "sha512-Hy4w8RaiiXl2AKcLXT0FjJJsh4FXtLiWCxfh6zaBtCkx7jsr4d9xwJ/zqrnjv0jkG7XbRUCp40dgNBpWYZ1pyQ==", "requires": { - "deprecated-react-native-prop-types": "^2.3.0" + "semver": "7.3.8" } }, "@mattermost/react-native-turbo-log": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-log/-/react-native-turbo-log-0.2.1.tgz", - "integrity": "sha512-c5Wx82gYLEUY70lIoA3jWg2sWo+l/Ah8vAfvu2cYkGnX4NArB/NKWnC4GWaclDSuNO4Tm5DrXgFeSqqArs7IJQ==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-log/-/react-native-turbo-log-0.2.2.tgz", + "integrity": "sha512-UjatbzMyB3jp/tAI1B8lmqZtF8om103hzUAlRVnUIPvzDQl5u2OtiwkwdYlnyN1P72WiIKhNcx7W+NZO0/wjyg==", "requires": {} }, "@mattermost/react-native-turbo-mailer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-mailer/-/react-native-turbo-mailer-0.2.0.tgz", - "integrity": "sha512-KMrEkMa30zjFv8ofvQsE1c1ln+8ntGDKJWDjScK02jvN3rtD8jMz1derz1py8tbDU9uU2nQPqWu4lP4b3g27Tw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-mailer/-/react-native-turbo-mailer-0.2.3.tgz", + "integrity": "sha512-m49wYLOx6TCiv5IDZKNAzhY8hnib+CgZ31jenR5rMiEmykmnI4VIyan1nNcPTyZPRGGmBb4UYzrcPd3hdIaOSg==", "requires": {} }, "@msgpack/msgpack": { @@ -24506,28 +24289,18 @@ "integrity": "sha512-wKTFGvgf5V+bYlhXdukOWKH0XgdG0NmUQwLWG7w5Yk4EUeQS29D5uWPCeWT1Ac/NzDKuHsYP6KVOJDbJSauAAg==" }, "@nozbe/watermelondb": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@nozbe/watermelondb/-/watermelondb-0.24.0.tgz", - "integrity": "sha512-CPCsRLQY2Lyq1MwUeK6zDsjfMKpW2KWYQJlF+ijGeKWv84xND0QC6a6EBWWiflvcdAwLSuGclojoah1HZYfs0g==", + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@nozbe/watermelondb/-/watermelondb-0.25.1.tgz", + "integrity": "sha512-Yd4gXttVlfl2e8rDsduTmPWgZWidaVAMpDcJr1fmsmHJQnNWdYRR+1V07Io4muNMSSq7rdn0Yl8GHNpNzN+rfQ==", "requires": { "@babel/runtime": "^7.11.2", "@nozbe/simdjson": "1.0.0", "@nozbe/sqlite": "3.36.0", - "@nozbe/with-observables": "1.4.0", + "@nozbe/with-observables": "1.4.1", "hoist-non-react-statics": "^3.3.2", - "lokijs": "npm:@nozbe/lokijs@1.5.12-wmelon4", - "rxjs": "^7.3.0", + "lokijs": "npm:@nozbe/lokijs@1.5.12-wmelon6", + "rxjs": "^7.4.0", "sql-escape-string": "^1.1.0" - }, - "dependencies": { - "@nozbe/with-observables": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@nozbe/with-observables/-/with-observables-1.4.0.tgz", - "integrity": "sha512-vzc0QiYcXK/GmflBGBXTs02ayL25e1l4Cr9aYgSuYCZVqpyMfep9xp89RygNbiibAfVLbgEUa7thxlm3jw8hFw==", - "requires": { - "hoist-non-react-statics": "^3.3.2" - } - } } }, "@nozbe/with-observables": { @@ -24539,9 +24312,9 @@ } }, "@react-native-camera-roll/camera-roll": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.1.tgz", - "integrity": "sha512-axWwlLj/3E5PIjXcN2y2XZzK/hYTx73kDlQJpHpcurejmQR9sU22w3cs+YltaNkZGl3y7Eu/LbiPEkGIwNVQow==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.2.tgz", + "integrity": "sha512-LVzUX1KdKvOXJGiV/9tlkDyDSOEjvAzuiV8OkSUD13TXN/Tk5u2KVHTYRYJz5pmXanLN2dmEamctJcqKCeXYxg==", "requires": {} }, "@react-native-clipboard/clipboard": { @@ -24551,21 +24324,21 @@ "requires": {} }, "@react-native-community/cli": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-9.3.2.tgz", - "integrity": "sha512-IAW4X0vmX/xozNpp/JVZaX7MrC85KV0OP2DF4o7lNGOfpUhzJAEWqTfkxFYS+VsRjZHDve4wSTiGIuXwE7FG1w==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.1.3.tgz", + "integrity": "sha512-kzh6bYLGN1q1q0IiczKSP1LTrovFeVzppYRTKohPI9VdyZwp7b5JOgaQMB/Ijtwm3MxBDrZgV9AveH/eUmUcKQ==", "requires": { - "@react-native-community/cli-clean": "^9.2.1", - "@react-native-community/cli-config": "^9.2.1", - "@react-native-community/cli-debugger-ui": "^9.0.0", - "@react-native-community/cli-doctor": "^9.3.0", - "@react-native-community/cli-hermes": "^9.3.1", - "@react-native-community/cli-plugin-metro": "^9.2.1", - "@react-native-community/cli-server-api": "^9.2.1", - "@react-native-community/cli-tools": "^9.2.1", - "@react-native-community/cli-types": "^9.1.0", + "@react-native-community/cli-clean": "^10.1.1", + "@react-native-community/cli-config": "^10.1.1", + "@react-native-community/cli-debugger-ui": "^10.0.0", + "@react-native-community/cli-doctor": "^10.1.1", + "@react-native-community/cli-hermes": "^10.1.3", + "@react-native-community/cli-plugin-metro": "^10.1.1", + "@react-native-community/cli-server-api": "^10.1.1", + "@react-native-community/cli-tools": "^10.1.1", + "@react-native-community/cli-types": "^10.0.0", "chalk": "^4.1.2", - "commander": "^9.4.0", + "commander": "^9.4.1", "execa": "^1.0.0", "find-up": "^4.1.0", "fs-extra": "^8.1.0", @@ -24605,9 +24378,9 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==" + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==" }, "cross-spawn": { "version": "6.0.5", @@ -24699,11 +24472,11 @@ } }, "@react-native-community/cli-clean": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-9.2.1.tgz", - "integrity": "sha512-dyNWFrqRe31UEvNO+OFWmQ4hmqA07bR9Ief/6NnGwx67IO9q83D5PEAf/o96ML6jhSbDwCmpPKhPwwBbsyM3mQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-10.1.1.tgz", + "integrity": "sha512-iNsrjzjIRv9yb5y309SWJ8NDHdwYtnCpmxZouQDyOljUdC9MwdZ4ChbtA4rwQyAwgOVfS9F/j56ML3Cslmvrxg==", "requires": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "execa": "^1.0.0", "prompts": "^2.4.0" @@ -24812,40 +24585,84 @@ } }, "@react-native-community/cli-config": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-9.2.1.tgz", - "integrity": "sha512-gHJlBBXUgDN9vrr3aWkRqnYrPXZLztBDQoY97Mm5Yo6MidsEpYo2JIP6FH4N/N2p1TdjxJL4EFtdd/mBpiR2MQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-10.1.1.tgz", + "integrity": "sha512-p4mHrjC+s/ayiNVG6T35GdEGdP6TuyBUg5plVGRJfTl8WT6LBfLYLk+fz/iETrEZ/YkhQIsQcEUQC47MqLNHog==", "requires": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", + "chalk": "^4.1.2", "cosmiconfig": "^5.1.0", "deepmerge": "^3.2.0", "glob": "^7.1.3", "joi": "^17.2.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "deepmerge": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz", "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } } } }, "@react-native-community/cli-debugger-ui": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-9.0.0.tgz", - "integrity": "sha512-7hH05ZwU9Tp0yS6xJW0bqcZPVt0YCK7gwj7gnRu1jDNN2kughf6Lg0Ys29rAvtZ7VO1PK5c1O+zs7yFnylQDUA==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-10.0.0.tgz", + "integrity": "sha512-8UKLcvpSNxnUTRy8CkCl27GGLqZunQ9ncGYhSrWyKrU9SWBJJGeZwi2k2KaoJi5FvF2+cD0t8z8cU6lsq2ZZmA==", "requires": { "serve-static": "^1.13.1" } }, "@react-native-community/cli-doctor": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-9.3.0.tgz", - "integrity": "sha512-/fiuG2eDGC2/OrXMOWI5ifq4X1gdYTQhvW2m0TT5Lk1LuFiZsbTCp1lR+XILKekuTvmYNjEGdVpeDpdIWlXdEA==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-10.1.1.tgz", + "integrity": "sha512-9uvUhr6aJu4C7pCTsD9iRS/38tx1mzIrWuEQoh2JffTXg9MOq4jesvobkyKFRD90nOvqunEvfpnWnRdWcZO0Wg==", "requires": { - "@react-native-community/cli-config": "^9.2.1", - "@react-native-community/cli-platform-ios": "^9.3.0", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-config": "^10.1.1", + "@react-native-community/cli-platform-ios": "^10.1.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "command-exists": "^1.2.8", "envinfo": "^7.7.2", @@ -24984,12 +24801,12 @@ } }, "@react-native-community/cli-hermes": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-9.3.1.tgz", - "integrity": "sha512-Mq4PK8m5YqIdaVq5IdRfp4qK09aVO+aiCtd6vjzjNUgk1+1X5cgUqV6L65h4N+TFJYJHcp2AnB+ik1FAYXvYPQ==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-10.1.3.tgz", + "integrity": "sha512-uYl8MLBtuu6bj0tDUzVGf30nK5i9haBv7F0u+NCOq31+zVjcwiUplrCuLorb2dMLMF+Fno9wDxi66W9MxoW4nA==", "requires": { - "@react-native-community/cli-platform-android": "^9.3.1", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-platform-android": "^10.1.3", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "hermes-profile-transformer": "^0.0.6", "ip": "^1.1.5" @@ -25041,17 +24858,15 @@ } }, "@react-native-community/cli-platform-android": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-9.3.1.tgz", - "integrity": "sha512-m0bQ6Twewl7OEZoVf79I2GZmsDqh+Gh0bxfxWgwxobsKDxLx8/RNItAo1lVtTCgzuCR75cX4EEO8idIF9jYhew==", + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-10.1.3.tgz", + "integrity": "sha512-8YZEpBL6yd9l4CIoFcLOgrV8x2GDujdqrdWrNsNERDAbsiFwqAQvfjyyb57GAZVuEPEJCoqUlGlMCwOh3XQb9A==", "requires": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "execa": "^1.0.0", - "fs-extra": "^8.1.0", "glob": "^7.1.3", - "logkitty": "^0.7.1", - "slash": "^3.0.0" + "logkitty": "^0.7.1" }, "dependencies": { "ansi-styles": { @@ -25110,16 +24925,6 @@ "strip-eof": "^1.0.0" } }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -25156,11 +24961,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -25172,11 +24972,11 @@ } }, "@react-native-community/cli-platform-ios": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-9.3.0.tgz", - "integrity": "sha512-nihTX53BhF2Q8p4B67oG3RGe1XwggoGBrMb6vXdcu2aN0WeXJOXdBLgR900DAA1O8g7oy1Sudu6we+JsVTKnjw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.1.1.tgz", + "integrity": "sha512-EB9/L8j1LqrqyfJtLRixU+d8FIP6Pr83rEgUgXgya/u8wk3h/bvX70w+Ff2skwjdPLr5dLUQ/n5KFX4r3bsNmA==", "requires": { - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", "execa": "^1.0.0", "glob": "^7.1.3", @@ -25286,19 +25086,20 @@ } }, "@react-native-community/cli-plugin-metro": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-9.2.1.tgz", - "integrity": "sha512-byBGBH6jDfUvcHGFA45W/sDwMlliv7flJ8Ns9foCh3VsIeYYPoDjjK7SawE9cPqRdMAD4SY7EVwqJnOtRbwLiQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-10.1.1.tgz", + "integrity": "sha512-wEp47le4mzlelDF5sfkaaujUDYcuLep5HZqlcMx7PkL7BA3/fSHdDo1SblqaLgZ1ca6vFU+kfbHueLDct+xwFg==", "requires": { - "@react-native-community/cli-server-api": "^9.2.1", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-server-api": "^10.1.1", + "@react-native-community/cli-tools": "^10.1.1", "chalk": "^4.1.2", - "metro": "0.72.3", - "metro-config": "0.72.3", - "metro-core": "0.72.3", - "metro-react-native-babel-transformer": "0.72.3", - "metro-resolver": "0.72.3", - "metro-runtime": "0.72.3", + "execa": "^1.0.0", + "metro": "0.73.7", + "metro-config": "0.73.7", + "metro-core": "0.73.7", + "metro-react-native-babel-transformer": "0.73.7", + "metro-resolver": "0.73.7", + "metro-runtime": "0.73.7", "readline": "^1.3.0" }, "dependencies": { @@ -25332,11 +25133,68 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "requires": { + "path-key": "^2.0.0" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -25348,12 +25206,12 @@ } }, "@react-native-community/cli-server-api": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-9.2.1.tgz", - "integrity": "sha512-EI+9MUxEbWBQhWw2PkhejXfkcRqPl+58+whlXJvKHiiUd7oVbewFs0uLW0yZffUutt4FGx6Uh88JWEgwOzAdkw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-10.1.1.tgz", + "integrity": "sha512-NZDo/wh4zlm8as31UEBno2bui8+ufzsZV+KN7QjEJWEM0levzBtxaD+4je0OpfhRIIkhaRm2gl/vVf7OYAzg4g==", "requires": { - "@react-native-community/cli-debugger-ui": "^9.0.0", - "@react-native-community/cli-tools": "^9.2.1", + "@react-native-community/cli-debugger-ui": "^10.0.0", + "@react-native-community/cli-tools": "^10.1.1", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.0", @@ -25376,9 +25234,9 @@ } }, "@types/yargs": { - "version": "15.0.14", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "version": "15.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", + "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", "requires": { "@types/yargs-parser": "*" } @@ -25445,9 +25303,9 @@ } }, "@react-native-community/cli-tools": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-9.2.1.tgz", - "integrity": "sha512-bHmL/wrKmBphz25eMtoJQgwwmeCylbPxqFJnFSbkqJPXQz3ManQ6q/gVVMqFyz7D3v+riaus/VXz3sEDa97uiQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-10.1.1.tgz", + "integrity": "sha512-+FlwOnZBV+ailEzXjcD8afY2ogFEBeHOw/8+XXzMgPaquU2Zly9B+8W089tnnohO3yfiQiZqkQlElP423MY74g==", "requires": { "appdirsjs": "^1.2.4", "chalk": "^4.1.2", @@ -25562,17 +25420,17 @@ } }, "@react-native-community/cli-types": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-9.1.0.tgz", - "integrity": "sha512-KDybF9XHvafLEILsbiKwz5Iobd+gxRaPyn4zSaAerBxedug4er5VUWa8Szy+2GeYKZzMh/gsb1o9lCToUwdT/g==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-10.0.0.tgz", + "integrity": "sha512-31oUM6/rFBZQfSmDQsT1DX/5fjqfxg7sf2u8kTPJK7rXVya5SRpAMaCXsPAG0omsmJxXt+J9HxUi3Ic+5Ux5Iw==", "requires": { "joi": "^17.2.1" } }, "@react-native-community/datetimepicker": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-6.7.1.tgz", - "integrity": "sha512-NPW1YITG7N+3TsqXc4LZV3c5IEpTD5iX18r0bvFsHdIblo5qi0ykpeK3TffmMM5gbTjgKJ4DNVHOjLiWKxFUxw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/@react-native-community/datetimepicker/-/datetimepicker-6.7.3.tgz", + "integrity": "sha512-fXWbEdHMLW/e8cts3snEsbOTbnFXfUHeO2pkiDFX3fWpFoDtUrRWvn50xbY13IJUUKHDhoJ+mj24nMRVIXfX1A==", "requires": { "invariant": "^2.2.4" } @@ -25635,9 +25493,9 @@ "integrity": "sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ==" }, "@react-native/normalize-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.0.0.tgz", - "integrity": "sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-native/normalize-color/-/normalize-color-2.1.0.tgz", + "integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA==" }, "@react-native/polyfills": { "version": "2.0.0", @@ -25645,11 +25503,11 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" }, "@react-navigation/bottom-tabs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.2.tgz", - "integrity": "sha512-iN3B1cgXdo64lqXdsTsCjN7n+5ILYKRexAu0VtW6EO8E6Z/0obK5JcCEropSiimRqVRs0kyuYj3F94Oth+hMrw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.3.tgz", + "integrity": "sha512-ZA2Ko9fNwNaaSNn7738KpEk8Doi+yjRfTg8Wb/WvduIaK/28qNLAYWBCUEVjBC55y/9zJOzwc4R8Av2J2MG/4g==", "requires": { - "@react-navigation/elements": "^1.3.12", + "@react-navigation/elements": "^1.3.13", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -25679,9 +25537,9 @@ } }, "@react-navigation/core": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.5.tgz", - "integrity": "sha512-wcde35HeOM5r2P25EwLQZyJ1yhXDGKuWpnKfsSI1xrgYIvWdYi3j/yGnwgNGDelCmtUt1Fyk2pmOv8sEku9KkA==", + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.6.tgz", + "integrity": "sha512-6zaAgUT5k4vhJlddUk2l52RZyMkMelHdrRv1cL57ALi2RZzERdgmbiMKhJerxFLn9S8E3PUe8vwxHzjHOZKG4w==", "requires": { "@react-navigation/routers": "^6.1.6", "escape-string-regexp": "^4.0.0", @@ -25692,17 +25550,17 @@ } }, "@react-navigation/elements": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.12.tgz", - "integrity": "sha512-iVcLIYg/XJk1p6X1rSFhNhCjAJ3ORqNT2/bJqw7I/liujeJAoz1oZ5JDoEcZaA0wMDts1txxLuqAYJmhCgU2aA==", + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.13.tgz", + "integrity": "sha512-LqqK5s2ZfYHn2cQ376jC5V9dQztLH5ixkkJj9WR7JY2g4SghDd39WJhL3Jillw1Mu3F3b9sZwvAK+QkXhnDeAA==", "requires": {} }, "@react-navigation/native": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.1.tgz", - "integrity": "sha512-iIozx9c66EjSFyzKrZPixnk6vBuivYXp0jmbKCJXNIa7MY+8OLx9CXj/+1py/l/OGlXDhI6jiUWWetOfOtMaBQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.2.tgz", + "integrity": "sha512-qLUe0asHofr5EhxKjvUBJ9DrPPmR4535IEwmW3oU4DRb3cLbNysjajJKHL8kcYtqPvn9Bx9QZG2x0PMb2vN23A==", "requires": { - "@react-navigation/core": "^6.4.5", + "@react-navigation/core": "^6.4.6", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", "nanoid": "^3.1.23" @@ -25717,11 +25575,11 @@ } }, "@react-navigation/stack": { - "version": "6.3.10", - "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.10.tgz", - "integrity": "sha512-mghQpCbGBI9jpwYmhXDI5drGOxz6F9hLxQgLeu1IsTSA9767Edov7TDt5n/PTJqhpOru7/xoNMs4yhp9ykVhng==", + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@react-navigation/stack/-/stack-6.3.11.tgz", + "integrity": "sha512-GWOAyJfPEsjVwDWec1ERwWL5LvManJucCRUZetJqCBs4/mV7HXEt2x6l3SMitHxH1+K+9XuYXI+wBTbK1WDYOA==", "requires": { - "@react-navigation/elements": "^1.3.12", + "@react-navigation/elements": "^1.3.13", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -25751,34 +25609,20 @@ } }, "@rudderstack/rudder-sdk-react-native": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.5.1.tgz", - "integrity": "sha512-nyacl2EpJ3l2NBMm7YhijyjD1jIk0GeBpBgFMZavMdAChA+Ak7sl+quKOfewYHLuFf/g2xh07p4ULLQpLqBpZw==", - "requires": { - "@babel/runtime": "^7.7.7", - "@types/async-lock": "^1.1.3", - "@types/react-native": "^0.62.2", - "async-lock": "^1.3.0" - }, - "dependencies": { - "@types/react-native": { - "version": "0.62.18", - "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.62.18.tgz", - "integrity": "sha512-7QfU8EzIYxYqeXpPf8QNv2xi8hrePlgTbRATRo+plRSdVfJu7N6sAXqrFxKJp6bGLvp82GV1gczl93gqiAfXPA==", - "requires": { - "@types/react": "*" - } - } - } + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.5.2.tgz", + "integrity": "sha512-M6dqOHqmbDzFE3R+TfjA0AppQfS8TSuv+qLtiq57V47zlLlkusszfZvHLQ8O63iTi5XsVciO1oTyj2ZCLtJUHA==", + "requires": {} }, "@sentry/browser": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.26.0.tgz", - "integrity": "sha512-S6uW+Ni2VLGHUV9eAUtTy5QEvqKeOhcnWnv+2yTGDtQCJ0SuHfXRCM7ASAQYBiKffZqIFc9Z2XNU/2cuWcXJmw==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.29.0.tgz", + "integrity": "sha512-Af+dIcntaw405Wt7myDOMGDxiszfy4aBdshrEKYbGgcfHjgXBIdF3iKlNatvl6nrOm+IOVuKgSpCLOr2hiCwzw==", "requires": { - "@sentry/core": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/replay": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "dependencies": { @@ -25814,12 +25658,12 @@ } }, "@sentry/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.26.0.tgz", - "integrity": "sha512-ydi236ZoP/xpvLdf7B8seKjCcGc5Z+q9c14tHCFusplPZgLSXcYpiiLIDWmF7OAXO89sSbb1NaFt9YB0LkYdLQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.29.0.tgz", + "integrity": "sha512-+e9aIp2ljtT4EJq3901z6TfEVEeqZd5cWzbKEuQzPn2UO6If9+Utd7kY2Y31eQYb4QnJgZfiIEz1HonuYY6zqQ==", "requires": { - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "dependencies": { @@ -25831,13 +25675,13 @@ } }, "@sentry/hub": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.26.0.tgz", - "integrity": "sha512-djAMuA4/Jy28dOSy9z5ccXBDyYk1N9m0ljle+dKqjfJwv440tCGyoxm2arqJFHbXvqwJTt2Giv8ASR4uGD1UNg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.29.0.tgz", + "integrity": "sha512-nIV2NtTn16VukTtWFhROHJ35NyUIXgEGtesG8a1i7D4iRSvkfLkLrQ9i6D0BAE2huqKqQemO3zGEPR00szqsiA==", "requires": { - "@sentry/core": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "dependencies": { @@ -25849,12 +25693,12 @@ } }, "@sentry/integrations": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.26.0.tgz", - "integrity": "sha512-5tyBA5BnZEuosSIvBP7mJz66xJaZTb/k1EzHEc0hR2Mw8QpLgMneDZBfi4vdbhxtGpJKC/gURoUGZf9hpwW+DA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.29.0.tgz", + "integrity": "sha512-BkZe3ALij320VtC5bNkeSz3OUhT9oxZsj2lf5rCuRFqcqw4tvVNADF/Y98mf0L4VCy582M9MlNXmwfewJjxGOA==", "requires": { - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "localforage": "^1.8.1", "tslib": "^1.9.3" }, @@ -25867,13 +25711,13 @@ } }, "@sentry/react": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.26.0.tgz", - "integrity": "sha512-v5XKpG1PF4qnWvG8E0N1kcUk74lTp+TDfKx5x996NIja2oOTp/JL9V0Q+lAMlB1EKgJuxLe92IeqD5/DTtzE7A==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.29.0.tgz", + "integrity": "sha512-pJ138QTChfAiYzFrCgycBgXrAVARV6TdVvLB8z/HsqbHzPq17RhyF9M1xPE4ffeLDQAEuSudwED9CLOpJqKnAw==", "requires": { - "@sentry/browser": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/browser": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "hoist-non-react-statics": "^3.3.2", "tslib": "^1.9.3" }, @@ -25886,30 +25730,40 @@ } }, "@sentry/react-native": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-4.12.0.tgz", - "integrity": "sha512-KBRXXqqGg67oqhtGzZQ8Ls4rxxUozDyL8tMLmRLk//bkSWBC6XslyjkZkQrB1VZsv2ikEYCUgyAP7fzcj6Bbig==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@sentry/react-native/-/react-native-4.13.0.tgz", + "integrity": "sha512-CxQd5jWPKEPgR1SH5ppf555h7DMhSBZMU3eSZ/VNT+BocgzxxBnf/tcJj92+gpwrzt2m7MiZ3uDfyfQOgyMc8Q==", "requires": { - "@sentry/browser": "7.26.0", + "@sentry/browser": "7.29.0", "@sentry/cli": "1.74.4", - "@sentry/core": "7.26.0", - "@sentry/hub": "7.26.0", - "@sentry/integrations": "7.26.0", - "@sentry/react": "7.26.0", - "@sentry/tracing": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/hub": "7.29.0", + "@sentry/integrations": "7.29.0", + "@sentry/react": "7.29.0", + "@sentry/tracing": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "@sentry/wizard": "1.4.0" } }, - "@sentry/tracing": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.26.0.tgz", - "integrity": "sha512-UK8EiXxJrDTWD82Oasj2WP/QuQ+wzPlg74vYmxl1ie/LRs6C6wHkilBZwDV9HnDdqAqSjl0al8oBa075lK+U3Q==", + "@sentry/replay": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.29.0.tgz", + "integrity": "sha512-Gw7HgviJQu6pX5RFQGVY38Av4qFn9otrZdwSSl/QK5hIyg6yhlh5h7U0ydZkrYYGiW6Z6SYYRpEWCJc/Wbh+ZQ==", "requires": { - "@sentry/core": "7.26.0", - "@sentry/types": "7.26.0", - "@sentry/utils": "7.26.0", + "@sentry/core": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0" + } + }, + "@sentry/tracing": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.29.0.tgz", + "integrity": "sha512-MAN/G6XROtRhzo/KDjddb6VJn/Q1TaPLwdyj9vvfkUkBNtlt5k16oXp+u7eHWX0uujER9wnZtj2ivXaPeqq0VA==", + "requires": { + "@sentry/core": "7.29.0", + "@sentry/types": "7.29.0", + "@sentry/utils": "7.29.0", "tslib": "^1.9.3" }, "dependencies": { @@ -25921,16 +25775,16 @@ } }, "@sentry/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.26.0.tgz", - "integrity": "sha512-U2s0q3ALwWFdHJBgn8nrG9bCTJZ3hAqL/I2Si4Mf0ZWnJ/KTJKbtyrputHr8wMbHvX0NZTJGTxFVUO46J+GBRA==" + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.29.0.tgz", + "integrity": "sha512-DmoEpoqHPty3VxqubS/5gxarwebHRlcBd/yuno+PS3xy++/i9YPjOWLZhU2jYs1cW68M9R6CcCOiC9f2ckJjdw==" }, "@sentry/utils": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.26.0.tgz", - "integrity": "sha512-nIC1PRyoMBi4QB7XNCWaPDqaQbPayMwAvUm6W3MC5bHPfVZmmFt+3sLZQKUD/E0NeQnJ3vTyPewPF/LfxLOE5A==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.29.0.tgz", + "integrity": "sha512-ICcBwTiBGK8NQA8H2BJo0JcMN6yCeKLqNKNMVampRgS6wSfSk1edvcTdhRkW3bSktIGrIPZrKskBHyMwDGF2XQ==", "requires": { - "@sentry/types": "7.26.0", + "@sentry/types": "7.29.0", "tslib": "^1.9.3" }, "dependencies": { @@ -25968,9 +25822,9 @@ } }, "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" }, "@sideway/pinpoint": { "version": "2.0.0", @@ -25980,14 +25834,12 @@ "@sinclair/typebox": { "version": "0.24.44", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz", - "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==", - "dev": true + "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==" }, "@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, "requires": { "type-detect": "4.0.8" } @@ -25996,7 +25848,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", - "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } @@ -26192,11 +26043,6 @@ "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", "dev": true }, - "@types/async-lock": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/async-lock/-/async-lock-1.1.3.tgz", - "integrity": "sha512-UpeDcjGKsYEQMeqEbfESm8OWJI305I7b9KE4ji3aBjoKWyN5CTdn8izcA1FM1DVDne30R5fNEnIy89vZw5LXJQ==" - }, "@types/babel__core": { "version": "7.1.19", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", @@ -26326,11 +26172,6 @@ "hoist-non-react-statics": "^3.3.0" } }, - "@types/invariant": { - "version": "2.2.35", - "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.35.tgz", - "integrity": "sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg==" - }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -26353,9 +26194,9 @@ } }, "@types/jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", - "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.6.tgz", + "integrity": "sha512-XEUC/Tgw3uMh6Ho8GkUtQ2lPhY5Fmgyp3TdlkTJs1W9VgNxs+Ow/x3Elh8lHQKqCbZL0AubQuqWjHVT033Hhrw==", "dev": true, "requires": { "expect": "^29.0.0", @@ -26415,9 +26256,9 @@ "dev": true }, "@types/react": { - "version": "18.0.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.26.tgz", - "integrity": "sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==", + "version": "18.0.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", + "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -26531,8 +26372,7 @@ "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, "@types/tinycolor2": { "version": "1.4.3", @@ -26567,7 +26407,6 @@ "version": "17.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -26578,14 +26417,14 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz", - "integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.49.0.tgz", + "integrity": "sha512-IhxabIpcf++TBaBa1h7jtOWyon80SXPRLDq0dVz5SLFC/eW6tofkw/O7Ar3lkx5z5U6wzbKDrl2larprp5kk5Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.48.0", - "@typescript-eslint/type-utils": "5.48.0", - "@typescript-eslint/utils": "5.48.0", + "@typescript-eslint/scope-manager": "5.49.0", + "@typescript-eslint/type-utils": "5.49.0", + "@typescript-eslint/utils": "5.49.0", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -26595,31 +26434,31 @@ } }, "@typescript-eslint/parser": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz", - "integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.49.0.tgz", + "integrity": "sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.48.0", - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/typescript-estree": "5.48.0", + "@typescript-eslint/scope-manager": "5.49.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/typescript-estree": "5.49.0", "debug": "^4.3.4" }, "dependencies": { "@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", - "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz", + "integrity": "sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -26628,12 +26467,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -26646,28 +26485,28 @@ } }, "@typescript-eslint/scope-manager": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz", - "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.49.0.tgz", + "integrity": "sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0" + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0" }, "dependencies": { "@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true }, "@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -26680,31 +26519,31 @@ } }, "@typescript-eslint/type-utils": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz", - "integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.49.0.tgz", + "integrity": "sha512-eUgLTYq0tR0FGU5g1YHm4rt5H/+V2IPVkP0cBmbhRyEmyGe4XvJ2YJ6sYTmONfjmdMqyMLad7SB8GvblbeESZA==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.48.0", - "@typescript-eslint/utils": "5.48.0", + "@typescript-eslint/typescript-estree": "5.49.0", + "@typescript-eslint/utils": "5.49.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "dependencies": { "@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", - "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz", + "integrity": "sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -26713,12 +26552,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -26752,35 +26591,35 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz", - "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.49.0.tgz", + "integrity": "sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.0", - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/typescript-estree": "5.48.0", + "@typescript-eslint/scope-manager": "5.49.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/typescript-estree": "5.49.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "dependencies": { "@typescript-eslint/types": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz", - "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.49.0.tgz", + "integrity": "sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz", - "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.49.0.tgz", + "integrity": "sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", - "@typescript-eslint/visitor-keys": "5.48.0", + "@typescript-eslint/types": "5.49.0", + "@typescript-eslint/visitor-keys": "5.49.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -26789,12 +26628,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz", - "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==", + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.49.0.tgz", + "integrity": "sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.48.0", + "@typescript-eslint/types": "5.49.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -27053,8 +26892,7 @@ "acorn": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" }, "acorn-import-assertions": { "version": "1.8.0", @@ -27273,14 +27111,15 @@ "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flatmap": { @@ -27342,9 +27181,10 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "async-lock": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.0.tgz", - "integrity": "sha512-8A7SkiisnEgME2zEedtDYPxUPzdv3x//E7n5IFktPAtMYSEAV7eNJF0rMwrVyUFj6d/8rgajLantbjcNRQYXIg==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==", + "peer": true }, "asynckit": { "version": "0.4.0", @@ -27369,9 +27209,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "axios": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz", - "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", "dev": true, "requires": { "follow-redirects": "^1.15.0", @@ -27539,16 +27379,60 @@ } }, "babel-plugin-module-resolver": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.1.0.tgz", - "integrity": "sha512-MlX10UDheRr3lb3P0WcaIdtCSRlxdQsB1sBqL7W0raF070bGl1HQQq5K3T2vf2XAYie+ww+5AKC/WrkjRO2knA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz", + "integrity": "sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==", "dev": true, "requires": { - "find-babel-config": "^1.2.0", - "glob": "^7.1.6", + "find-babel-config": "^2.0.0", + "glob": "^8.0.3", "pkg-up": "^3.1.0", - "reselect": "^4.0.0", - "resolve": "^1.13.1" + "reselect": "^4.1.7", + "resolve": "^1.22.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } } }, "babel-plugin-polyfill-corejs2": { @@ -28665,9 +28549,9 @@ "dev": true }, "detox": { - "version": "20.1.1", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.1.tgz", - "integrity": "sha512-0ieeWAyo2f3YKeFwm7KCz4lBkCJIydyqzCQVN1sw/ZU9x9Qc8kz+itKAEiH4DHUlLkb4YLzfEbAXfO09wvrQ3w==", + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.1.2.tgz", + "integrity": "sha512-SGxLyuzE8TjIc4Lg49YKD0buj3JLaX+KtprSeFvn7ZTdWd4fH6o5Szd4KM21uBSpnYEEgXTgiCypPQst6dt5mQ==", "dev": true, "requires": { "ajv": "^8.6.3", @@ -28682,7 +28566,7 @@ "glob": "^8.0.3", "ini": "^1.3.4", "json-cycle": "^1.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "multi-sort-stream": "^1.0.3", "multipipe": "^4.0.0", "node-ipc": "^9.2.1", @@ -29086,9 +28970,9 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "version": "8.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz", + "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==", "dev": true, "requires": { "@eslint/eslintrc": "^1.4.1", @@ -29324,13 +29208,14 @@ "requires": {} }, "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==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "requires": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" }, "dependencies": { "debug": { @@ -29341,17 +29226,27 @@ "requires": { "ms": "^2.1.1" } + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } } } }, "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" + "debug": "^3.2.7" }, "dependencies": { "debug": { @@ -29362,49 +29257,6 @@ "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 } } }, @@ -29444,33 +29296,35 @@ "requires": {} }, "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", "dev": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "doctrine": { @@ -29482,10 +29336,21 @@ "esutils": "^2.0.2" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } @@ -29509,9 +29374,9 @@ } }, "eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.1.tgz", + "integrity": "sha512-vOjdgyd0ZHBXNsmvU+785xY8Bfe57EFbTYYk8XrROzWpr9QBvpjITvAXt9xqcE6+8cjR/g1+mfumPToxsl1www==", "dev": true, "requires": { "array-includes": "^3.1.6", @@ -29526,7 +29391,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -29541,13 +29406,14 @@ } }, "resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "semver": { @@ -30150,19 +30016,19 @@ } }, "find-babel-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.2.0.tgz", - "integrity": "sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.0.0.tgz", + "integrity": "sha512-dOKT7jvF3hGzlW60Gc3ONox/0rRZ/tz7WCil0bqA1In/3I8f1BctpXahRnEKDySZqci7u+dqq93sZST9fOJpFw==", "dev": true, "requires": { - "json5": "^0.5.1", - "path-exists": "^3.0.0" + "json5": "^2.1.1", + "path-exists": "^4.0.0" }, "dependencies": { - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true } } @@ -30260,9 +30126,9 @@ "dev": true }, "flow-parser": { - "version": "0.121.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz", - "integrity": "sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg==" + "version": "0.185.2", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.185.2.tgz", + "integrity": "sha512-2hJ5ACYeJCzNtiVULov6pljKOLygy0zddoqSI1fFetM+XRPpRshFdGEijtqlamA1XwyZ+7rhryI6FQFzvtLWUQ==" }, "follow-redirects": { "version": "1.15.2", @@ -31085,9 +30951,9 @@ } }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "requires": { "has": "^1.0.3" } @@ -31928,7 +31794,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", - "dev": true, "requires": { "@jest/environment": "^29.3.1", "@jest/fake-timers": "^29.3.1", @@ -32041,7 +31906,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", - "dev": true, "requires": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.3.1", @@ -32058,7 +31922,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -32067,7 +31930,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -32077,7 +31939,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -32085,26 +31946,22 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -32115,7 +31972,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", - "dev": true, "requires": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -32501,7 +32357,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", - "dev": true, "requires": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -32515,7 +32370,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -32524,7 +32378,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -32534,7 +32387,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -32542,20 +32394,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -33066,14 +32915,6 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", - "requires": { - "graceful-fs": "^4.1.9" - } - }, "klaw-sync": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", @@ -33347,9 +33188,9 @@ } }, "lokijs": { - "version": "npm:@nozbe/lokijs@1.5.12-wmelon4", - "resolved": "https://registry.npmjs.org/@nozbe/lokijs/-/lokijs-1.5.12-wmelon4.tgz", - "integrity": "sha512-3sYrhLI2GkdXW/VOi1w6D2tENxxL+n1LJHRIAkaSCoehTVDiysAjxa/1GQq7gb7T4CFxJ+brMGvSx0sugEwqjQ==" + "version": "npm:@nozbe/lokijs@1.5.12-wmelon6", + "resolved": "https://registry.npmjs.org/@nozbe/lokijs/-/lokijs-1.5.12-wmelon6.tgz", + "integrity": "sha512-GXsaqY8qTJ6xdCrGyno2t+ON2aj6PrUDdvhbrkxK/0Fp12C4FGvDg1wS+voLU9BANYHEnr7KRWfItDZnQkjoAg==" }, "loose-envify": { "version": "1.4.0", @@ -33459,17 +33300,17 @@ "dev": true }, "metro": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.72.3.tgz", - "integrity": "sha512-Hb3xTvPqex8kJ1hutQNZhQadUKUwmns/Du9GikmWKBFrkiG3k3xstGAyO5t5rN9JSUEzQT6y9SWzSSOGogUKIg==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.73.7.tgz", + "integrity": "sha512-pkRqFhuGUvkiu8HxKPUQelbCuyy6te6okMssTyLzQwsKilNLK4YMI2uD6PHnypg5SiMJ58lwfqkp/t5w72jEvw==", "requires": { "@babel/code-frame": "^7.0.0", - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", - "@babel/parser": "^7.14.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", "@babel/template": "^7.0.0", - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", "absolute-path": "^0.0.0", "accepts": "^1.3.7", "async": "^3.2.2", @@ -33479,40 +33320,40 @@ "debug": "^2.2.0", "denodeify": "^1.2.1", "error-stack-parser": "^2.0.6", - "fs-extra": "^1.0.0", "graceful-fs": "^4.2.4", "hermes-parser": "0.8.0", "image-size": "^0.6.0", "invariant": "^2.2.4", "jest-worker": "^27.2.0", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.72.3", - "metro-cache": "0.72.3", - "metro-cache-key": "0.72.3", - "metro-config": "0.72.3", - "metro-core": "0.72.3", - "metro-file-map": "0.72.3", - "metro-hermes-compiler": "0.72.3", - "metro-inspector-proxy": "0.72.3", - "metro-minify-uglify": "0.72.3", - "metro-react-native-babel-preset": "0.72.3", - "metro-resolver": "0.72.3", - "metro-runtime": "0.72.3", - "metro-source-map": "0.72.3", - "metro-symbolicate": "0.72.3", - "metro-transform-plugins": "0.72.3", - "metro-transform-worker": "0.72.3", + "metro-babel-transformer": "0.73.7", + "metro-cache": "0.73.7", + "metro-cache-key": "0.73.7", + "metro-config": "0.73.7", + "metro-core": "0.73.7", + "metro-file-map": "0.73.7", + "metro-hermes-compiler": "0.73.7", + "metro-inspector-proxy": "0.73.7", + "metro-minify-terser": "0.73.7", + "metro-minify-uglify": "0.73.7", + "metro-react-native-babel-preset": "0.73.7", + "metro-resolver": "0.73.7", + "metro-runtime": "0.73.7", + "metro-source-map": "0.73.7", + "metro-symbolicate": "0.73.7", + "metro-transform-plugins": "0.73.7", + "metro-transform-worker": "0.73.7", "mime-types": "^2.1.27", "node-fetch": "^2.2.0", "nullthrows": "^1.1.1", - "rimraf": "^2.5.4", + "rimraf": "^3.0.2", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "strip-ansi": "^6.0.0", "temp": "0.8.3", "throat": "^5.0.0", "ws": "^7.5.1", - "yargs": "^15.3.1" + "yargs": "^17.5.1" }, "dependencies": { "ansi-styles": { @@ -33538,13 +33379,13 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" } }, "color-convert": { @@ -33568,26 +33409,11 @@ "ms": "2.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -33618,20 +33444,12 @@ } } }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "requires": { - "graceful-fs": "^4.1.6" - } - }, "metro-react-native-babel-preset": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz", - "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.7.tgz", + "integrity": "sha512-RKcmRZREjJCzHKP+JhC9QTCohkeb3xa/DtqHU14U5KWzJHdC0mMrkTZYNXhV0cryxsaVKVEw5873KhbZyZHMVw==", "requires": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.20.0", "@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", @@ -33641,7 +33459,7 @@ "@babel/plugin-proposal-optional-chaining": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-export-default-from": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.2.0", + "@babel/plugin-syntax-flow": "^7.18.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", "@babel/plugin-syntax-optional-chaining": "^7.0.0", "@babel/plugin-transform-arrow-functions": "^7.0.0", @@ -33650,7 +33468,6 @@ "@babel/plugin-transform-classes": "^7.0.0", "@babel/plugin-transform-computed-properties": "^7.0.0", "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", "@babel/plugin-transform-function-name": "^7.0.0", "@babel/plugin-transform-literals": "^7.0.0", @@ -33677,14 +33494,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, "serialize-error": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", @@ -33713,96 +33522,63 @@ "has-flag": "^4.0.0" } }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" } } }, "metro-babel-transformer": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.72.3.tgz", - "integrity": "sha512-PTOR2zww0vJbWeeM3qN90WKENxCLzv9xrwWaNtwVlhcV8/diNdNe82sE1xIxLFI6OQuAVwNMv1Y7VsO2I7Ejrw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.73.7.tgz", + "integrity": "sha512-s7UVkwovGTEXYEQrv5hcmSBbFJ9s9lhCRNMScn4Itgj3UMdqRr9lU8DXKEFlJ7osgRxN6n5+eXqcvhE4B1H1VQ==", "requires": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.20.0", "hermes-parser": "0.8.0", - "metro-source-map": "0.72.3", + "metro-source-map": "0.73.7", "nullthrows": "^1.1.1" } }, "metro-cache": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.72.3.tgz", - "integrity": "sha512-++eyZzwkXvijWRV3CkDbueaXXGlVzH9GA52QWqTgAOgSHYp5jWaDwLQ8qpsMkQzpwSyIF4LLK9aI3eA7Xa132A==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.73.7.tgz", + "integrity": "sha512-CPPgI+i9yVzOEDCdmEEZ67JgOvZyNDs8kStmGUFgDuLSjj3//HhkqT5XyfWjGeH6KmyGiS8ip3cgLOVn3IsOSA==", "requires": { - "metro-core": "0.72.3", - "rimraf": "^2.5.4" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - } + "metro-core": "0.73.7", + "rimraf": "^3.0.2" } }, "metro-cache-key": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.72.3.tgz", - "integrity": "sha512-kQzmF5s3qMlzqkQcDwDxrOaVxJ2Bh6WRXWdzPnnhsq9LcD3B3cYqQbRBS+3tSuXmathb4gsOdhWslOuIsYS8Rg==" + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.73.7.tgz", + "integrity": "sha512-GngYzrHwZU9U0Xl81H4aq9Tn5cjQyU12v9/flB0hzpeiYO5A89TIeilb4Kg8jtfC6JcmmsdK9nxYIGEq7odHhQ==" }, "metro-config": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.72.3.tgz", - "integrity": "sha512-VEsAIVDkrIhgCByq8HKTWMBjJG6RlYwWSu1Gnv3PpHa0IyTjKJtB7wC02rbTjSaemcr82scldf2R+h6ygMEvsw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.73.7.tgz", + "integrity": "sha512-pD/F+vK3u37cbj1skYmI6cUsEEscqNRtW2KlDKu1m+n8nooDB2oGTOZatlS5WQa7Ga6jYQRydftlq4CLDexAfA==", "requires": { "cosmiconfig": "^5.0.5", "jest-validate": "^26.5.2", - "metro": "0.72.3", - "metro-cache": "0.72.3", - "metro-core": "0.72.3", - "metro-runtime": "0.72.3" + "metro": "0.73.7", + "metro-cache": "0.73.7", + "metro-core": "0.73.7", + "metro-runtime": "0.73.7" }, "dependencies": { "@jest/types": { @@ -33818,9 +33594,9 @@ } }, "@types/yargs": { - "version": "15.0.14", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz", - "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==", + "version": "15.0.15", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz", + "integrity": "sha512-IziEYMU9XoVj8hWg7k+UJrXALkGFjWJhn5QFEv9q4p+v40oZhSuC135M38st8XPjICL7Ey4TV64ferBGUoJhBg==", "requires": { "@types/yargs-parser": "*" } @@ -33910,24 +33686,24 @@ } }, "metro-core": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.72.3.tgz", - "integrity": "sha512-KuYWBMmLB4+LxSMcZ1dmWabVExNCjZe3KysgoECAIV+wyIc2r4xANq15GhS94xYvX1+RqZrxU1pa0jQ5OK+/6A==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.73.7.tgz", + "integrity": "sha512-H7j1Egj1VnNnsSYf9ZKv0SRwijgtRKIcaGNQq/T+er73vqqb4kR9H+2VIJYPXi6R8lT+QLIMfs6CWSUHAJUgtg==", "requires": { "lodash.throttle": "^4.1.1", - "metro-resolver": "0.72.3" + "metro-resolver": "0.73.7" } }, "metro-file-map": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.72.3.tgz", - "integrity": "sha512-LhuRnuZ2i2uxkpFsz1XCDIQSixxBkBG7oICAFyLyEMDGbcfeY6/NexphfLdJLTghkaoJR5ARFMiIxUg9fIY/pA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.73.7.tgz", + "integrity": "sha512-BYaCo2e/4FMN4nOajeN+Za5cPfecfikzUYuFWWMyLAmHU6dj7B+PFkaJ4OEJO3vmRoeq5vMOmhpKXgysYbNXJg==", "requires": { "abort-controller": "^3.0.0", "anymatch": "^3.0.3", "debug": "^2.2.0", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", + "fsevents": "^2.3.2", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-regex-util": "^27.0.6", @@ -33935,6 +33711,7 @@ "jest-util": "^27.2.0", "jest-worker": "^27.2.0", "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", "walker": "^1.0.7" }, "dependencies": { @@ -33951,9 +33728,9 @@ } }, "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", "requires": { "@types/yargs-parser": "*" } @@ -34055,52 +33832,31 @@ } }, "metro-hermes-compiler": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.72.3.tgz", - "integrity": "sha512-QWDQASMiXNW3j8uIQbzIzCdGYv5PpAX/ZiF4/lTWqKRWuhlkP4auhVY4eqdAKj5syPx45ggpjkVE0p8hAPDZYg==" + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-hermes-compiler/-/metro-hermes-compiler-0.73.7.tgz", + "integrity": "sha512-F8PlJ8mWEEumGNH3eMRA3gjgP70ZvH4Ex5F1KY6ofD/gpn7w5HJHSPTeVw8gtUb1pYLN4nevptpyXGg04Jfcog==" }, "metro-inspector-proxy": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.72.3.tgz", - "integrity": "sha512-UPFkaq2k93RaOi+eqqt7UUmqy2ywCkuxJLasQ55+xavTUS+TQSyeTnTczaYn+YKw+izLTLllGcvqnQcZiWYhGw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.73.7.tgz", + "integrity": "sha512-TsAtQeKr9X7NaQHlpshu+ZkGWlPi5fFKNqieLkfqvT1oXN4PQF/4q38INyiZtWLPvoUzTR6PRnm4pcUbJ7+Nzg==", "requires": { "connect": "^3.6.5", "debug": "^2.2.0", "ws": "^7.5.1", - "yargs": "^15.3.1" + "yargs": "^17.5.1" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -34109,11 +33865,6 @@ "ms": "2.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -34139,62 +33890,47 @@ "strip-ansi": "^6.0.1" } }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" } } }, + "metro-minify-terser": { + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.73.7.tgz", + "integrity": "sha512-gbv1fmMOZm6gJ6dQoD+QktlCi2wk6nlTR8j8lQCjeeXGbs6O9e5XLWNPOexHqo7S69bdbohEnfZnLJFcxgHeNw==", + "requires": { + "terser": "^5.15.0" + } + }, "metro-minify-uglify": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.72.3.tgz", - "integrity": "sha512-dPXqtMI8TQcj0g7ZrdhC8X3mx3m3rtjtMuHKGIiEXH9CMBvrET8IwrgujQw2rkPcXiSiX8vFDbGMIlfxefDsKA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.73.7.tgz", + "integrity": "sha512-DmDCzfdbaPExQuQ7NQozCNOSOAgp5Ux9kWzmKAT8seQ38/3NtUepW+PTgxXIHmwNjJV4oHsHwlBlTwJmYihKXg==", "requires": { "uglify-es": "^3.1.9" } }, "metro-react-native-babel-preset": { - "version": "0.73.7", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.7.tgz", - "integrity": "sha512-RKcmRZREjJCzHKP+JhC9QTCohkeb3xa/DtqHU14U5KWzJHdC0mMrkTZYNXhV0cryxsaVKVEw5873KhbZyZHMVw==", + "version": "0.74.1", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.74.1.tgz", + "integrity": "sha512-DjsG9nqm5C7cjB2SlgbcNJOn9y5MBUd3bRlCfnoj8CxAeGTGkS+yXd183lHR3C1bhmQNjuUE0abzzpE1CFh6JQ==", "dev": true, "requires": { "@babel/core": "^7.20.0", @@ -34202,6 +33938,7 @@ "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-proposal-numeric-separator": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", "@babel/plugin-proposal-optional-chaining": "^7.0.0", @@ -34230,7 +33967,6 @@ "@babel/plugin-transform-shorthand-properties": "^7.0.0", "@babel/plugin-transform-spread": "^7.0.0", "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", "@babel/plugin-transform-typescript": "^7.5.0", "@babel/plugin-transform-unicode-regex": "^7.0.0", "@babel/template": "^7.0.0", @@ -34238,25 +33974,25 @@ } }, "metro-react-native-babel-transformer": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.72.3.tgz", - "integrity": "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.7.tgz", + "integrity": "sha512-73HW8betjX+VPm3iqsMBe8F/F2Tt+hONO6YJwcF7FonTqQYW1oTz0dOp0dClZGfHUXxpJBz6Vuo7J6TpdzDD+w==", "requires": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.20.0", "babel-preset-fbjs": "^3.4.0", "hermes-parser": "0.8.0", - "metro-babel-transformer": "0.72.3", - "metro-react-native-babel-preset": "0.72.3", - "metro-source-map": "0.72.3", + "metro-babel-transformer": "0.73.7", + "metro-react-native-babel-preset": "0.73.7", + "metro-source-map": "0.73.7", "nullthrows": "^1.1.1" }, "dependencies": { "metro-react-native-babel-preset": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.72.3.tgz", - "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.7.tgz", + "integrity": "sha512-RKcmRZREjJCzHKP+JhC9QTCohkeb3xa/DtqHU14U5KWzJHdC0mMrkTZYNXhV0cryxsaVKVEw5873KhbZyZHMVw==", "requires": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.20.0", "@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0", @@ -34266,7 +34002,7 @@ "@babel/plugin-proposal-optional-chaining": "^7.0.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-export-default-from": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.2.0", + "@babel/plugin-syntax-flow": "^7.18.0", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", "@babel/plugin-syntax-optional-chaining": "^7.0.0", "@babel/plugin-transform-arrow-functions": "^7.0.0", @@ -34275,7 +34011,6 @@ "@babel/plugin-transform-classes": "^7.0.0", "@babel/plugin-transform-computed-properties": "^7.0.0", "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", "@babel/plugin-transform-function-name": "^7.0.0", "@babel/plugin-transform-literals": "^7.0.0", @@ -34300,33 +34035,33 @@ } }, "metro-resolver": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.72.3.tgz", - "integrity": "sha512-wu9zSMGdxpKmfECE7FtCdpfC+vrWGTdVr57lDA0piKhZV6VN6acZIvqQ1yZKtS2WfKsngncv5VbB8Y5eHRQP3w==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.73.7.tgz", + "integrity": "sha512-mGW3XPeKBCwZnkHcKo1dhFa9olcx7SyNzG1vb5kjzJYe4Qs3yx04r/qFXIJLcIgLItB69TIGvosznUhpeOOXzg==", "requires": { "absolute-path": "^0.0.0" } }, "metro-runtime": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.72.3.tgz", - "integrity": "sha512-3MhvDKfxMg2u7dmTdpFOfdR71NgNNo4tzAyJumDVQKwnHYHN44f2QFZQqpPBEmqhWlojNeOxsqFsjYgeyMx6VA==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.73.7.tgz", + "integrity": "sha512-2fxRGrF8FyrwwHY0TCitdUljzutfW6CWEpdvPilfrs8p0PI5X8xOWg8ficeYtw+DldHtHIAL2phT59PqzHTyVA==", "requires": { "@babel/runtime": "^7.0.0", "react-refresh": "^0.4.0" } }, "metro-source-map": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.72.3.tgz", - "integrity": "sha512-eNtpjbjxSheXu/jYCIDrbNEKzMGOvYW6/ePYpRM7gDdEagUOqKOCsi3St8NJIQJzZCsxD2JZ2pYOiomUSkT1yQ==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.73.7.tgz", + "integrity": "sha512-gbC/lfUN52TtQhEsTTA+987MaFUpQlufuCI05blLGLosDcFCsARikHsxa65Gtslm/rG2MqvFLiPA5hviONNv9g==", "requires": { - "@babel/traverse": "^7.14.0", - "@babel/types": "^7.0.0", + "@babel/traverse": "^7.20.0", + "@babel/types": "^7.20.0", "invariant": "^2.2.4", - "metro-symbolicate": "0.72.3", + "metro-symbolicate": "0.73.7", "nullthrows": "^1.1.1", - "ob1": "0.72.3", + "ob1": "0.73.7", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -34339,12 +34074,12 @@ } }, "metro-symbolicate": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.72.3.tgz", - "integrity": "sha512-eXG0NX2PJzJ/jTG4q5yyYeN2dr1cUqUaY7worBB0SP5bRWRc3besfb+rXwfh49wTFiL5qR0oOawkU4ZiD4eHXw==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.73.7.tgz", + "integrity": "sha512-571ThWmX5o8yGNzoXjlcdhmXqpByHU/bSZtWKhtgV2TyIAzYCYt4hawJAS5+/qDazUvjHdm8BbdqFUheM0EKNQ==", "requires": { "invariant": "^2.2.4", - "metro-source-map": "0.72.3", + "metro-source-map": "0.73.7", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "through2": "^2.0.1", @@ -34359,34 +34094,34 @@ } }, "metro-transform-plugins": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.72.3.tgz", - "integrity": "sha512-D+TcUvCKZbRua1+qujE0wV1onZvslW6cVTs7dLCyC2pv20lNHjFr1GtW01jN2fyKR2PcRyMjDCppFd9VwDKnSg==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.73.7.tgz", + "integrity": "sha512-M5isiWEau0jMudb5ezaNBZnYqXxcATMqnAYc+Cu25IahT1NHi5aWwLok9EBmBpN5641IZUZXScf+KnS7fPxPCQ==", "requires": { - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", "@babel/template": "^7.0.0", - "@babel/traverse": "^7.14.0", + "@babel/traverse": "^7.20.0", "nullthrows": "^1.1.1" } }, "metro-transform-worker": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.72.3.tgz", - "integrity": "sha512-WsuWj9H7i6cHuJuy+BgbWht9DK5FOgJxHLGAyULD5FJdTG9rSMFaHDO5WfC0OwQU5h4w6cPT40iDuEGksM7+YQ==", + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.73.7.tgz", + "integrity": "sha512-gZYIu9JAqEI9Rxi0xGMuMW6QsHGbMSptozlTOwOd7T7yXX3WwYS/I3yLPbLhbZTjOhwMHkTt8Nhm2qBo8nh14g==", "requires": { - "@babel/core": "^7.14.0", - "@babel/generator": "^7.14.0", - "@babel/parser": "^7.14.0", - "@babel/types": "^7.0.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.0", + "@babel/parser": "^7.20.0", + "@babel/types": "^7.20.0", "babel-preset-fbjs": "^3.4.0", - "metro": "0.72.3", - "metro-babel-transformer": "0.72.3", - "metro-cache": "0.72.3", - "metro-cache-key": "0.72.3", - "metro-hermes-compiler": "0.72.3", - "metro-source-map": "0.72.3", - "metro-transform-plugins": "0.72.3", + "metro": "0.73.7", + "metro-babel-transformer": "0.73.7", + "metro-cache": "0.73.7", + "metro-cache-key": "0.73.7", + "metro-hermes-compiler": "0.73.7", + "metro-source-map": "0.73.7", + "metro-transform-plugins": "0.73.7", "nullthrows": "^1.1.1" } }, @@ -34684,9 +34419,9 @@ "integrity": "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==" }, "nock": { - "version": "13.2.9", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.9.tgz", - "integrity": "sha512-1+XfJNYF1cjGB+TKMWi29eZ0b82QOvQs2YoLNzbpWGqFMtRQHTa57osqdGj4FrFPgkO4D4AZinzUJR9VvW3QUA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.0.tgz", + "integrity": "sha512-HHqYQ6mBeiMc+N038w8LkMpDCRquCHWeNmN3v6645P3NhN2+qXOBqvPqo7Rt1VyCMzKhJ733wZqw5B7cQVFNPg==", "dev": true, "requires": { "debug": "^4.1.0", @@ -34808,9 +34543,9 @@ "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==" }, "ob1": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.72.3.tgz", - "integrity": "sha512-OnVto25Sj7Ghp0vVm2THsngdze3tVq0LOg9LUHsAVXMecpqOP0Y8zaATW8M9gEgs2lNEAcCqV0P/hlmOPhVRvg==" + "version": "0.73.7", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.73.7.tgz", + "integrity": "sha512-DfelfvR843KADhSUATGGhuepVMRcf5VQX+6MQLy5AW0BKDLlO7Usj6YZeAAZP7P86QwsoTxB0RXCFiA7t6S1IQ==" }, "object-assign": { "version": "4.1.1", @@ -35465,7 +35200,6 @@ "version": "29.3.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", - "dev": true, "requires": { "@jest/schemas": "^29.0.0", "ansi-styles": "^5.0.0", @@ -35475,14 +35209,12 @@ "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" }, "react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" } } }, @@ -35650,7 +35382,6 @@ "version": "4.27.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.27.1.tgz", "integrity": "sha512-qXhcxxDWiFmFAOq48jts9YQYe1+wVoUXzJTlY4jbaATzyio6dd6CUGu3dXBhREeVgpZ+y4kg6vFJzIOZh6vY2w==", - "dev": true, "requires": { "shell-quote": "^1.6.1", "ws": "^7" @@ -35704,42 +35435,44 @@ "integrity": "sha512-txfpPCQYiazVdcbMRhatqWKcAxJweUu2wDXvts5/7Wyp6+Y9cHojqXHsLPEckzutfHlxZhG8Oiundbmp8Fd6eQ==" }, "react-native": { - "version": "0.70.6", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.70.6.tgz", - "integrity": "sha512-xtQdImPHnwgraEx3HIZFOF+D1hJ9bC5mfpIdUGoMHRws6OmvHAjmFpO6qfdnaQ29vwbmZRq7yf14sbury74R/w==", + "version": "0.71.1", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.71.1.tgz", + "integrity": "sha512-bLP5+IBj2IX6tgF9WnC/UL2ZPYkVUPsU4xqZV1jntTC2TH4xyLrvfKACjGlz5nQ3Mx4BmOFqsnMxithm53+6Aw==", "requires": { - "@jest/create-cache-key-function": "^27.0.1", - "@react-native-community/cli": "9.3.2", - "@react-native-community/cli-platform-android": "9.3.1", - "@react-native-community/cli-platform-ios": "9.3.0", + "@jest/create-cache-key-function": "^29.2.1", + "@react-native-community/cli": "10.1.3", + "@react-native-community/cli-platform-android": "10.1.3", + "@react-native-community/cli-platform-ios": "10.1.1", "@react-native/assets": "1.0.0", - "@react-native/normalize-color": "2.0.0", + "@react-native/normalize-color": "2.1.0", "@react-native/polyfills": "2.0.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "base64-js": "^1.1.2", + "deprecated-react-native-prop-types": "^3.0.1", "event-target-shim": "^5.0.1", "invariant": "^2.2.4", + "jest-environment-node": "^29.2.1", "jsc-android": "^250230.2.1", "memoize-one": "^5.0.0", - "metro-react-native-babel-transformer": "0.72.3", - "metro-runtime": "0.72.3", - "metro-source-map": "0.72.3", + "metro-react-native-babel-transformer": "0.73.7", + "metro-runtime": "0.73.7", + "metro-source-map": "0.73.7", "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "pretty-format": "^26.5.2", "promise": "^8.3.0", - "react-devtools-core": "4.24.0", - "react-native-codegen": "^0.70.6", - "react-native-gradle-plugin": "^0.70.3", + "react-devtools-core": "^4.26.1", + "react-native-codegen": "^0.71.3", + "react-native-gradle-plugin": "^0.71.13", "react-refresh": "^0.4.0", "react-shallow-renderer": "^16.15.0", "regenerator-runtime": "^0.13.2", - "scheduler": "^0.22.0", + "scheduler": "^0.23.0", "stacktrace-parser": "^0.1.3", "use-sync-external-store": "^1.0.0", "whatwg-fetch": "^3.0.0", - "ws": "^6.1.4" + "ws": "^6.2.2" }, "dependencies": { "@jest/types": { @@ -35792,6 +35525,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "deprecated-react-native-prop-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-3.0.1.tgz", + "integrity": "sha512-J0jCJcsk4hMlIb7xwOZKLfMpuJn6l8UtrPEzzQV5ewz5gvKNYakhBuq9h2rWX7YwHHJZFhU5W8ye7dB9oN8VcQ==", + "requires": { + "@react-native/normalize-color": "*", + "invariant": "*", + "prop-types": "*" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -35808,23 +35551,6 @@ "react-is": "^17.0.1" } }, - "react-devtools-core": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.0.tgz", - "integrity": "sha512-Rw7FzYOOzcfyUPaAm9P3g0tFdGqGq2LLiAI+wjYcp6CsF3DeeMrRS3HZAho4s273C29G/DJhx0e8BpRE/QZNGg==", - "requires": { - "shell-quote": "^1.6.1", - "ws": "^7" - }, - "dependencies": { - "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "requires": {} - } - } - }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -35892,12 +35618,12 @@ } }, "react-native-codegen": { - "version": "0.70.6", - "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.70.6.tgz", - "integrity": "sha512-kdwIhH2hi+cFnG5Nb8Ji2JwmcCxnaOOo9440ov7XDzSvGfmUStnCzl+MCW8jLjqHcE4icT7N9y+xx4f50vfBTw==", + "version": "0.71.3", + "resolved": "https://registry.npmjs.org/react-native-codegen/-/react-native-codegen-0.71.3.tgz", + "integrity": "sha512-5AvdHVU1sAaXg05i0dG664ZTaCaIFaY1znV5vNsj+wUu6MGxNEUNbDKk9dxKUkkxOyk2KZOK5uhzWL0p5H5yZQ==", "requires": { "@babel/parser": "^7.14.0", - "flow-parser": "^0.121.0", + "flow-parser": "^0.185.0", "jscodeshift": "^0.13.1", "nullthrows": "^1.1.1" } @@ -35980,9 +35706,9 @@ } }, "react-native-gesture-handler": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.8.0.tgz", - "integrity": "sha512-poOSfz/w0IyD6Qwq7aaIRRfEaVTl1ecQFoyiIbpOpfNTjm2B1niY2FLrdVQIOtIOe+K9nH55Qal04nr4jGkHdQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz", + "integrity": "sha512-a0BcH3Qb1tgVqUutc6d3VuWQkI1AM3+fJx8dkxzZs9t06qA27QgURYFoklpabuWpsUTzuKRpxleykp25E8m7tg==", "requires": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", @@ -35992,9 +35718,9 @@ } }, "react-native-gradle-plugin": { - "version": "0.70.3", - "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz", - "integrity": "sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==" + "version": "0.71.13", + "resolved": "https://registry.npmjs.org/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.13.tgz", + "integrity": "sha512-C66LNZAXbU0YDRkWx8d/8kjesdu7fsUAc/3QPJNftSXKEvEtnFZK2aH/rIgu1s5dbTcE0fjhdVPNJMRIfKo61w==" }, "react-native-haptic-feedback": { "version": "1.14.0", @@ -36009,9 +35735,9 @@ "requires": {} }, "react-native-image-picker": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-4.10.3.tgz", - "integrity": "sha512-gLX8J6jCBkUt6jogpSdA7YyaGVLGYywRzMEwBciXshihpFZjc/cRlKymAVlu6Q7HMw0j3vrho6pI8ZGC5O/FGg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-5.0.1.tgz", + "integrity": "sha512-+poQTHOnEGrbxJnut591XA9006svFOyfPg/i5bv+fLuwoSHh5HW0E/PVhvT8lbX0Z5C108vh3DAsnrfFFnPBGw==", "requires": {} }, "react-native-in-app-review": { @@ -36074,9 +35800,9 @@ } }, "react-native-navigation": { - "version": "7.30.6", - "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.30.6.tgz", - "integrity": "sha512-rnJ7VbMjnt8H1HkuaM65NkcFFca2QQRgsCQEF6yAe9J4Yb3I3XnywFd309D6yso4ZqRuK7EhuzP33/nReV1c/A==", + "version": "7.31.1", + "resolved": "https://registry.npmjs.org/react-native-navigation/-/react-native-navigation-7.31.1.tgz", + "integrity": "sha512-thChSqaoi/QHGGofG/4CEyO2v6ko41RsbjQrJzAnHkp7iw1K8pjxkW3KX0qx2rlR/A69kA31VskOLj8kl+7sQw==", "requires": { "hoist-non-react-statics": "3.x.x", "lodash": "4.17.x", @@ -36113,13 +35839,13 @@ } }, "react-native-reanimated": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.13.0.tgz", - "integrity": "sha512-yUHyYVIegWWIza4+nVyS3CSmI/Mc8kLFVHw2c6gnSHaYhYA4LeEjH/jBkoMzHk9Xd0Ra3cwtjYKAMG8OTp6JVg==", + "version": "2.14.4", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.14.4.tgz", + "integrity": "sha512-DquSbl7P8j4SAmc+kRdd75Ianm8G+IYQ9T4AQ6lrpLVeDkhZmjWI0wkutKWnp6L7c5XNVUrFDUf69dwETLCItQ==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", - "@types/invariant": "^2.2.35", + "convert-source-map": "^1.7.0", "invariant": "^2.2.4", "lodash.isequal": "^4.5.0", "setimmediate": "^1.0.5", @@ -36127,15 +35853,15 @@ } }, "react-native-safe-area-context": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.4.1.tgz", - "integrity": "sha512-N9XTjiuD73ZpVlejHrUWIFZc+6Z14co1K/p1IFMkImU7+avD69F3y+lhkqA2hN/+vljdZrBSiOwXPkuo43nFQA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.5.0.tgz", + "integrity": "sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==", "requires": {} }, "react-native-screens": { - "version": "3.18.2", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.18.2.tgz", - "integrity": "sha512-ANUEuvMUlsYJ1QKukEhzhfrvOUO9BVH9Nzg+6eWxpn3cfD/O83yPBOF8Mx6x5H/2+sMy+VS5x/chWOOo/U7QJw==", + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.19.0.tgz", + "integrity": "sha512-Ehsmy7jr3H3j5pmN+/FqsAaIAD+k+xkcdePfLcg4rYRbN5X7fJPgaqhcmiCcZ0YxsU8ttsstP9IvRLNQuIkRRA==", "requires": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" @@ -36166,9 +35892,9 @@ "requires": {} }, "react-native-svg": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.6.0.tgz", - "integrity": "sha512-1wjHCMJ8siyZbDZ0MX5wM+Jr7YOkb6GADn4/Z+/u1UwJX8WfjarypxDF3UO1ugMHa+7qor39oY+URMcrgPpiww==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.7.0.tgz", + "integrity": "sha512-WR5CIURvee5cAfvMhmdoeOjh1SC8KdLq5u5eFsz4pbYzCtIFClGSkLnNgkMSDMVV5LV0qQa4jeIk75ieIBzaDA==", "requires": { "css-select": "^5.1.0", "css-tree": "^1.1.3" @@ -36263,9 +35989,9 @@ } }, "react-native-walkthrough-tooltip": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/react-native-walkthrough-tooltip/-/react-native-walkthrough-tooltip-1.4.0.tgz", - "integrity": "sha512-nyBuynmCuzPKJN9NRGhSzCutGOk7/WqszGtX01gjDtlRfoJ25cSM0h+TEi/lsLbSCTEdB+e65qOTvoVhIq2gzA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-native-walkthrough-tooltip/-/react-native-walkthrough-tooltip-1.5.0.tgz", + "integrity": "sha512-xzpTs3JQkUMkmurc7WJDSAWaH2KRiRL2YoTXVCRqEEWxIvLQTn9eQv0jBzs1geR0wL+ezRpjkBEGAlfQ6eMimw==", "requires": { "prop-types": "^15.6.1", "react-fast-compare": "^2.0.4" @@ -36351,15 +36077,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, - "requires": { - "loose-envify": "^1.1.0" - } } } }, @@ -36569,9 +36286,9 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "reselect": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", - "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz", + "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A==", "dev": true }, "resolve": { @@ -36655,7 +36372,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } @@ -36734,9 +36450,9 @@ } }, "scheduler": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.22.0.tgz", - "integrity": "sha512-6QAm1BgQI88NPYymgGQLCZgvep4FyePDWFpXVK+zNSUgHwlqpJy8VEh8Et0KxTACS4VWwMousBElAZOH9nkkoQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "requires": { "loose-envify": "^1.1.0" } @@ -37292,7 +37008,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, "requires": { "escape-string-regexp": "^2.0.0" }, @@ -37300,8 +37015,7 @@ "escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" } } }, @@ -37661,8 +37375,6 @@ "version": "5.15.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", - "dev": true, - "peer": true, "requires": { "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", @@ -37673,9 +37385,7 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "peer": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" } } }, @@ -37903,15 +37613,15 @@ } }, "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "requires": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -37944,9 +37654,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -37994,8 +37704,7 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, "type-fest": { "version": "0.21.3", @@ -38687,9 +38396,9 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" }, "zod": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", - "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==" + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.2.tgz", + "integrity": "sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==" }, "zwitch": { "version": "2.0.2", diff --git a/package.json b/package.json index ec95a39221..39fb2bb305 100644 --- a/package.json +++ b/package.json @@ -15,24 +15,24 @@ "@formatjs/intl-relativetimeformat": "11.1.8", "@gorhom/bottom-sheet": "4.4.5", "@mattermost/compass-icons": "0.1.35", - "@mattermost/react-native-emm": "1.3.3", - "@mattermost/react-native-network-client": "1.0.2", - "@mattermost/react-native-paste-input": "0.5.2", - "@mattermost/react-native-turbo-log": "0.2.1", - "@mattermost/react-native-turbo-mailer": "0.2.0", + "@mattermost/react-native-emm": "1.3.4", + "@mattermost/react-native-network-client": "1.1.0", + "@mattermost/react-native-paste-input": "0.6.0", + "@mattermost/react-native-turbo-log": "0.2.2", + "@mattermost/react-native-turbo-mailer": "0.2.3", "@msgpack/msgpack": "2.8.0", - "@nozbe/watermelondb": "0.24.0", + "@nozbe/watermelondb": "0.25.1", "@nozbe/with-observables": "1.4.1", - "@react-native-camera-roll/camera-roll": "5.2.1", + "@react-native-camera-roll/camera-roll": "5.2.2", "@react-native-clipboard/clipboard": "1.11.1", - "@react-native-community/datetimepicker": "6.7.1", + "@react-native-community/datetimepicker": "6.7.3", "@react-native-community/netinfo": "9.3.7", "@react-native-cookies/cookies": "6.2.1", - "@react-navigation/bottom-tabs": "6.5.2", - "@react-navigation/native": "6.1.1", - "@react-navigation/stack": "6.3.10", - "@rudderstack/rudder-sdk-react-native": "1.5.1", - "@sentry/react-native": "4.12.0", + "@react-navigation/bottom-tabs": "6.5.3", + "@react-navigation/native": "6.1.2", + "@react-navigation/stack": "6.3.11", + "@rudderstack/rudder-sdk-react-native": "1.5.2", + "@sentry/react-native": "4.13.0", "@stream-io/flat-list-mvcp": "0.10.2", "base-64": "1.0.0", "commonmark": "npm:@mattermost/commonmark@0.30.1-0", @@ -49,7 +49,7 @@ "react": "18.2.0", "react-freeze": "1.0.3", "react-intl": "6.2.5", - "react-native": "0.70.6", + "react-native": "0.71.1", "react-native-android-open-settings": "1.3.0", "react-native-animated-numbers": "0.4.1", "react-native-background-timer": "2.4.1", @@ -64,10 +64,10 @@ "react-native-fast-image": "8.6.3", "react-native-file-viewer": "2.1.5", "react-native-fs": "2.20.0", - "react-native-gesture-handler": "2.8.0", + "react-native-gesture-handler": "2.9.0", "react-native-haptic-feedback": "1.14.0", "react-native-hw-keyboard-event": "0.0.4", - "react-native-image-picker": "4.10.3", + "react-native-image-picker": "5.0.1", "react-native-in-app-review": "4.2.1", "react-native-incall-manager": "github:cpoile/react-native-incall-manager", "react-native-keyboard-aware-scroll-view": "0.9.5", @@ -76,19 +76,19 @@ "react-native-linear-gradient": "2.6.2", "react-native-localize": "2.2.4", "react-native-math-view": "3.9.5", - "react-native-navigation": "7.30.6", + "react-native-navigation": "7.31.1", "react-native-notifications": "4.3.3", "react-native-permissions": "3.6.1", - "react-native-reanimated": "2.13.0", - "react-native-safe-area-context": "4.4.1", - "react-native-screens": "3.18.2", + "react-native-reanimated": "2.14.4", + "react-native-safe-area-context": "4.5.0", + "react-native-screens": "3.19.0", "react-native-section-list-get-item-layout": "2.2.3", "react-native-shadow-2": "7.0.6", "react-native-share": "8.1.0", - "react-native-svg": "13.6.0", + "react-native-svg": "13.7.0", "react-native-vector-icons": "9.2.0", "react-native-video": "5.2.1", - "react-native-walkthrough-tooltip": "1.4.0", + "react-native-walkthrough-tooltip": "1.5.0", "react-native-webrtc": "github:mattermost/react-native-webrtc", "react-native-webview": "11.26.0", "react-syntax-highlighter": "15.5.0", @@ -104,13 +104,13 @@ "@babel/core": "7.20.12", "@babel/eslint-parser": "7.19.1", "@babel/plugin-proposal-class-properties": "7.18.6", - "@babel/plugin-proposal-decorators": "7.20.7", + "@babel/plugin-proposal-decorators": "7.20.13", "@babel/plugin-transform-flow-strip-types": "7.19.0", "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", "@babel/preset-typescript": "7.18.6", "@babel/register": "7.18.9", - "@babel/runtime": "7.20.7", + "@babel/runtime": "7.20.13", "@react-native-community/eslint-config": "3.2.0", "@testing-library/react-hooks": "8.0.1", "@testing-library/react-native": "11.5.0", @@ -118,12 +118,11 @@ "@types/commonmark": "0.27.5", "@types/commonmark-react-renderer": "4.3.1", "@types/deep-equal": "1.0.1", - "@types/jest": "29.2.5", + "@types/jest": "29.2.6", "@types/lodash": "4.14.191", "@types/mime-db": "1.43.1", "@types/querystringify": "2.0.0", - "@types/react": "18.0.26", - "@types/react-native": "0.70.8", + "@types/react": "18.0.27", "@types/react-native-background-timer": "2.0.0", "@types/react-native-button": "3.0.1", "@types/react-native-dotenv": "0.2.0", @@ -138,36 +137,36 @@ "@types/tough-cookie": "4.0.2", "@types/url-parse": "1.4.8", "@types/uuid": "9.0.0", - "@typescript-eslint/eslint-plugin": "5.48.0", - "@typescript-eslint/parser": "5.48.0", - "axios": "1.2.2", + "@typescript-eslint/eslint-plugin": "5.49.0", + "@typescript-eslint/parser": "5.49.0", + "axios": "1.2.3", "axios-cookiejar-support": "4.0.6", "babel-jest": "29.3.1", "babel-loader": "9.1.2", - "babel-plugin-module-resolver": "4.1.0", + "babel-plugin-module-resolver": "5.0.0", "deep-freeze": "0.0.1", - "detox": "20.1.1", - "eslint": "8.31.0", + "detox": "20.1.2", + "eslint": "8.32.0", "eslint-plugin-header": "3.1.1", - "eslint-plugin-import": "2.26.0", + "eslint-plugin-import": "2.27.5", "eslint-plugin-jest": "27.2.1", - "eslint-plugin-react": "7.31.11", + "eslint-plugin-react": "7.32.1", "eslint-plugin-react-hooks": "4.6.0", "husky": "8.0.3", "isomorphic-fetch": "3.0.0", "jest": "29.3.1", "jest-cli": "29.3.1", "jetifier": "2.0.0", - "metro-react-native-babel-preset": "0.73.7", + "metro-react-native-babel-preset": "0.74.1", "mmjstool": "github:mattermost/mattermost-utilities#010f456ea8be5beebafdb8776177cba515c1969e", "mock-async-storage": "2.2.0", - "nock": "13.2.9", + "nock": "13.3.0", "patch-package": "6.5.1", "react-devtools-core": "4.27.1", "react-native-svg-transformer": "1.0.0", "react-test-renderer": "18.2.0", "tough-cookie": "4.1.2", - "ts-jest": "29.0.3", + "ts-jest": "29.0.5", "typescript": "4.9.4", "underscore": "1.13.6", "util": "0.12.5", @@ -211,7 +210,8 @@ "react": "^18.2.0" }, "@rudderstack/rudder-sdk-react-native": { - "react-native": "^0.70.0" + "react": "^18.2.0", + "react-native": "^0.71.0" }, "@testing-library/react-hooks": { "@types/react": "^18.0.15", @@ -222,7 +222,7 @@ "react": "^18.2.0" }, "react-native-elements": { - "react-native-safe-area-context": "^4.3.1" + "react-native-safe-area-context": "^4.5.0" }, "react-native-fast-image": { "react": "^18.2.0" diff --git a/patches/@nozbe+watermelondb+0.24.0.patch b/patches/@nozbe+watermelondb+0.24.0.patch deleted file mode 100644 index 284f8ede0d..0000000000 --- a/patches/@nozbe+watermelondb+0.24.0.patch +++ /dev/null @@ -1,183 +0,0 @@ -diff --git a/node_modules/@nozbe/watermelondb/Database/index.js b/node_modules/@nozbe/watermelondb/Database/index.js -index 8d71c6f..9ad75d6 100644 ---- a/node_modules/@nozbe/watermelondb/Database/index.js -+++ b/node_modules/@nozbe/watermelondb/Database/index.js -@@ -126,6 +126,10 @@ var Database = /*#__PURE__*/function () { - // subsequent changes to the record don't trip up the invariant - // TODO: What if this fails? - record._preparedState = null; -+ -+ if ('update' === preparedState) { -+ record.__original = null; -+ } - } - - if (!changeNotifications[table]) { -diff --git a/node_modules/@nozbe/watermelondb/Model/index.d.ts b/node_modules/@nozbe/watermelondb/Model/index.d.ts -index 1a7c99e..0cb7b87 100644 ---- a/node_modules/@nozbe/watermelondb/Model/index.d.ts -+++ b/node_modules/@nozbe/watermelondb/Model/index.d.ts -@@ -44,6 +44,8 @@ declare module '@nozbe/watermelondb/Model' { - - public update(recordUpdater?: (record: this) => void): Promise - -+ public cancelPrepareUpdate(): void; -+ - public prepareUpdate(recordUpdater?: (record: this) => void): this - - public markAsDeleted(): Promise -diff --git a/node_modules/@nozbe/watermelondb/Model/index.js b/node_modules/@nozbe/watermelondb/Model/index.js -index 075a047..5a1604d 100644 ---- a/node_modules/@nozbe/watermelondb/Model/index.js -+++ b/node_modules/@nozbe/watermelondb/Model/index.js -@@ -78,10 +78,22 @@ var Model = /*#__PURE__*/function () { - // database.batch() - ; - -+ _proto.cancelPrepareUpdate = function cancelPrepareUpdate() { -+ if ('test' !== process.env.NODE_ENV && 'undefined' !== typeof process && process) { -+ (0, _invariant.default)('update' !== _this._preparedState, "Cannot cancel an update on a model that has not been prepared"); -+ } -+ this.__changes = null; -+ this._preparedState = null; -+ if (this.__original) { -+ this._raw = this.__original; -+ } -+ this.__original = undefined; -+ } -+ - _proto.prepareUpdate = function prepareUpdate(recordUpdater = _noop.default) { - var _this = this; - -- (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes"); -+ (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes in table " + _this.table); - - this.__ensureNotDisposable("Model.prepareUpdate()"); - -@@ -92,6 +104,7 @@ var Model = /*#__PURE__*/function () { - } // Perform updates - - -+ this.__original = Object.assign({}, this._raw); - (0, _ensureSync.default)(recordUpdater(this)); - this._isEditing = false; - this._preparedState = 'update'; // TODO: `process.nextTick` doesn't work on React Native -diff --git a/node_modules/@nozbe/watermelondb/WatermelonDB.podspec b/node_modules/@nozbe/watermelondb/WatermelonDB.podspec -index 1f3af50..e9fea58 100644 ---- a/node_modules/@nozbe/watermelondb/WatermelonDB.podspec -+++ b/node_modules/@nozbe/watermelondb/WatermelonDB.podspec -@@ -13,7 +13,10 @@ Pod::Spec.new do |s| - s.platforms = { :ios => "9.0", :tvos => "9.0" } - s.source = { :git => "https://github.com/Nozbe/WatermelonDB.git", :tag => "v#{s.version}" } - s.source_files = "native/ios/**/*.{h,m,mm,swift,c,cpp}", "native/shared/**/*.{h,c,cpp}" -- s.public_header_files = 'native/ios/WatermelonDB/SupportingFiles/Bridging.h' -+ s.public_header_files = [ -+ 'native/ios/WatermelonDB/SupportingFiles/Bridging.h', -+ 'native/ios/WatermelonDB/JSIInstaller.h', -+ ] - s.requires_arc = true - # simdjson is annoyingly slow without compiler optimization, disable for debugging - s.compiler_flags = '-Os' -diff --git a/node_modules/@nozbe/watermelondb/native/android/build.gradle b/node_modules/@nozbe/watermelondb/native/android/build.gradle -index 90ddf7a..e5ec9ec 100644 ---- a/node_modules/@nozbe/watermelondb/native/android/build.gradle -+++ b/node_modules/@nozbe/watermelondb/native/android/build.gradle -@@ -9,7 +9,8 @@ buildscript { - } - - repositories { -- jcenter() -+ mavenCentral() -+ mavenLocal() - } - - dependencies { -@@ -40,5 +41,6 @@ dependencies { - - repositories { - mavenCentral() -+ mavenLocal() - } - -diff --git a/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt b/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt -index ca31e20..b45c753 100644 ---- a/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt -+++ b/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt -@@ -22,6 +22,21 @@ class Database( - if (name == ":memory:" || name.contains("mode=memory")) { - context.cacheDir.delete() - File(context.cacheDir, name).path -+ } else if (name.contains("/") || name.contains("file")) { -+ // Extracts the database name from the path -+ val dbName = name.substringAfterLast("/") -+ -+ // Extracts the real path where the *.db file will be created -+ val truePath = name.substringAfterLast("file://").substringBeforeLast("/") -+ -+ // Creates the directory -+ if (!truePath.contains("databases")) { -+ val fileObj = File(truePath, "databases") -+ fileObj.mkdir() -+ File("${truePath}/databases", dbName).path -+ } else { -+ File(truePath, dbName).path -+ } - } else { - // On some systems there is some kind of lock on `/databases` folder ¯\_(ツ)_/¯ - context.getDatabasePath("$name.db").path.replace("/databases", "") -diff --git a/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB/SupportingFiles/Bridging.h b/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB/SupportingFiles/Bridging.h -index 135118d..8324550 100644 ---- a/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB/SupportingFiles/Bridging.h -+++ b/node_modules/@nozbe/watermelondb/native/ios/WatermelonDB/SupportingFiles/Bridging.h -@@ -6,12 +6,6 @@ - - #import - --#if __has_include("JSIInstaller.h") --#import "JSIInstaller.h" --#else --#import "../JSIInstaller.h" --#endif -- - #if __has_include("DatabaseDeleteHelper.h") - #import "DatabaseDeleteHelper.h" - #else -diff --git a/node_modules/@nozbe/watermelondb/native/shared/Database.cpp b/node_modules/@nozbe/watermelondb/native/shared/Database.cpp -index a2bd410..44e1a58 100644 ---- a/node_modules/@nozbe/watermelondb/native/shared/Database.cpp -+++ b/node_modules/@nozbe/watermelondb/native/shared/Database.cpp -@@ -54,6 +54,7 @@ void Database::destroy() { - const std::lock_guard lock(mutex_); - - if (isDestroyed_) { -+ db_->markAsDestroyed(); - return; - } - isDestroyed_ = true; -diff --git a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp -index 4108e6c..0fa554c 100644 ---- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp -+++ b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp -@@ -69,6 +69,10 @@ void SqliteDb::destroy() { - } - } - -+void SqliteDb::markAsDestroyed() { -+ isDestroyed_ = true; -+} -+ - SqliteDb::~SqliteDb() { - destroy(); - } -diff --git a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h -index 22cffa7..4b74a7f 100644 ---- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h -+++ b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h -@@ -11,6 +11,7 @@ public: - SqliteDb(std::string path); - ~SqliteDb(); - void destroy(); -+ void markAsDestroyed(); - - sqlite3 *sqlite; - diff --git a/patches/@nozbe+watermelondb+0.25.1.patch b/patches/@nozbe+watermelondb+0.25.1.patch new file mode 100644 index 0000000000..140816529b --- /dev/null +++ b/patches/@nozbe+watermelondb+0.25.1.patch @@ -0,0 +1,292 @@ +diff --git a/node_modules/@nozbe/watermelondb/Database/index.js b/node_modules/@nozbe/watermelondb/Database/index.js +index 8d71c6f..9ad75d6 100644 +--- a/node_modules/@nozbe/watermelondb/Database/index.js ++++ b/node_modules/@nozbe/watermelondb/Database/index.js +@@ -126,6 +126,10 @@ var Database = /*#__PURE__*/function () { + // subsequent changes to the record don't trip up the invariant + // TODO: What if this fails? + record._preparedState = null; ++ ++ if ('update' === preparedState) { ++ record.__original = null; ++ } + } + + if (!changeNotifications[table]) { +diff --git a/node_modules/@nozbe/watermelondb/DatabaseProvider/index.d.ts b/node_modules/@nozbe/watermelondb/DatabaseProvider/index.d.ts +index 7c00164..10e5388 100644 +--- a/node_modules/@nozbe/watermelondb/DatabaseProvider/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/DatabaseProvider/index.d.ts +@@ -1,4 +1,4 @@ +-import { ElementType, ReactNode } from 'react' ++import React, { ReactNode } from 'react' + import Database from '../Database' + import { Provider } from './DatabaseContext' + +@@ -11,7 +11,7 @@ export type Props = { + * Database provider to create the database context + * to allow child components to consume the database without prop drilling + */ +-declare function DatabaseProvider({ children, database }: Props): ElementType ++declare function DatabaseProvider({ children, database }: Props): JSX.Element + + export { default as withDatabase } from './withDatabase' + export { default as DatabaseContext, DatabaseConsumer } from './DatabaseContext' +diff --git a/node_modules/@nozbe/watermelondb/DatabaseProvider/withDatabase.d.ts b/node_modules/@nozbe/watermelondb/DatabaseProvider/withDatabase.d.ts +index b29d8aa..b70faa9 100644 +--- a/node_modules/@nozbe/watermelondb/DatabaseProvider/withDatabase.d.ts ++++ b/node_modules/@nozbe/watermelondb/DatabaseProvider/withDatabase.d.ts +@@ -1,4 +1,5 @@ +-import { ComponentType } from 'react' ++import type { NonReactStatics } from 'hoist-non-react-statics' ++import React, { ComponentType } from 'react' + import type Database from '../Database' + import { DatabaseConsumer } from './DatabaseContext' + +@@ -8,4 +9,4 @@ type WithDatabaseProps = T & { + // HoC to inject the database into the props of consumers + export default function withDatabase( + Component: ComponentType>, +-): DatabaseConsumer ++): React.FunctionComponent> & NonReactStatics +diff --git a/node_modules/@nozbe/watermelondb/Model/index.d.ts b/node_modules/@nozbe/watermelondb/Model/index.d.ts +index 43cd902..baefb53 100644 +--- a/node_modules/@nozbe/watermelondb/Model/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/Model/index.d.ts +@@ -52,14 +52,16 @@ export default class Model { + // someTask.update(task => { + // task.name = 'New name' + // }) +- update(recordUpdater: (this) => void): Promise ++ update(recordUpdater: (record: this) => void): Promise + + // Prepares an update to the database (using passed function). + // Touches `updatedAt` if available. + // + // After preparing an update, you must execute it synchronously using + // database.batch() +- prepareUpdate(recordUpdater: (this) => void): this ++ prepareUpdate(recordUpdater: (record: this) => void): this ++ ++ cancelPrepareUpdate(): void + + prepareMarkAsDeleted(): this + +diff --git a/node_modules/@nozbe/watermelondb/Model/index.js b/node_modules/@nozbe/watermelondb/Model/index.js +index b0e3a83..47313d4 100644 +--- a/node_modules/@nozbe/watermelondb/Model/index.js ++++ b/node_modules/@nozbe/watermelondb/Model/index.js +@@ -81,7 +81,7 @@ var Model = /*#__PURE__*/function () { + _proto.prepareUpdate = function prepareUpdate(recordUpdater = _noop.default) { + var _this = this; + +- (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes"); ++ (0, _invariant.default)(!this._preparedState, "Cannot update a record with pending changes in table " + _this.table); + + this.__ensureNotDisposable("Model.prepareUpdate()"); + +@@ -92,6 +92,7 @@ var Model = /*#__PURE__*/function () { + } // Perform updates + + ++ this.__original = Object.assign({}, this._raw); + (0, _ensureSync.default)(recordUpdater(this)); + this._isEditing = false; + this._preparedState = 'update'; // TODO: `process.nextTick` doesn't work on React Native +@@ -107,6 +108,18 @@ var Model = /*#__PURE__*/function () { + return this; + }; + ++ _proto.cancelPrepareUpdate = function cancelPrepareUpdate() { ++ if ('test' !== process.env.NODE_ENV && 'undefined' !== typeof process && process) { ++ (0, _invariant.default)('update' !== _this._preparedState, "Cannot cancel an update on a model that has not been prepared in table " + this.table); ++ } ++ this.__changes = null; ++ this._preparedState = null; ++ if (this.__original) { ++ this._raw = this.__original; ++ } ++ this.__original = undefined; ++ }; ++ + _proto.prepareMarkAsDeleted = function prepareMarkAsDeleted() { + (0, _invariant.default)(!this._preparedState, "Cannot mark a record with pending changes as deleted"); + +diff --git a/node_modules/@nozbe/watermelondb/Query/index.d.ts b/node_modules/@nozbe/watermelondb/Query/index.d.ts +index eb2bd84..eb02824 100644 +--- a/node_modules/@nozbe/watermelondb/Query/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/Query/index.d.ts +@@ -73,7 +73,7 @@ export default class Query { + + // Emits the number of matching records, then emits a new count every time it changes + // Note: By default, the Observable is throttled! +- observeCount(isThrottled: boolean): Observable ++ observeCount(isThrottled?: boolean): Observable + + // Queries database and returns an array with IDs of matching records + fetchIds(): Promise +diff --git a/node_modules/@nozbe/watermelondb/QueryDescription/index.d.ts b/node_modules/@nozbe/watermelondb/QueryDescription/index.d.ts +index cf2e1e0..6910974 100644 +--- a/node_modules/@nozbe/watermelondb/QueryDescription/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/QueryDescription/index.d.ts +@@ -193,7 +193,7 @@ export function and(...clauses: Where[]): And + + export function or(...clauses: Where[]): Or + +-export function sortBy(sortColumn: ColumnName, sortOrder: SortOrder): SortBy ++export function sortBy(sortColumn: ColumnName, sortOrder?: SortOrder): SortBy + + export function take(count: number): Take + +@@ -230,7 +230,7 @@ export function experimentalJoinTables(tables: TableName[]): JoinTables + + export function experimentalNestedJoin(from: TableName, to: TableName): NestedJoinTable + +-export function unsafeSqlQuery(sql: string, values: Value[]): SqlQuery ++export function unsafeSqlQuery(sql: string, values?: Value[]): SqlQuery + + // const extractClauses: (clauses: Clause[]) => QueryDescription; + +diff --git a/node_modules/@nozbe/watermelondb/decorators/children/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/children/index.d.ts +index 53d3daf..b26a60a 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/children/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/children/index.d.ts +@@ -1,4 +1,4 @@ + import { TableName } from '../../Schema' + +-type children = (childTable: TableName) => PropertyDecorator ++const children = (childTable: TableName) => PropertyDecorator + export default children +diff --git a/node_modules/@nozbe/watermelondb/decorators/date/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/date/index.d.ts +index 10381e6..020654e 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/date/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/date/index.d.ts +@@ -1,4 +1,4 @@ + import { ColumnName } from '../../Schema' + +-type date = (columnName: ColumnName) => PropertyDecorator ++const date = (columnName: ColumnName) => PropertyDecorator + export default date +diff --git a/node_modules/@nozbe/watermelondb/decorators/field/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/field/index.d.ts +index 87625ac..520f15e 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/field/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/field/index.d.ts +@@ -1,4 +1,4 @@ + import { ColumnName } from '../../Schema' + +-type field = (columnName: ColumnName) => PropertyDecorator ++const field = (columnName: ColumnName) => PropertyDecorator + export default field +diff --git a/node_modules/@nozbe/watermelondb/decorators/immutableRelation/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/immutableRelation/index.d.ts +index 6a7e860..529bcd9 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/immutableRelation/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/immutableRelation/index.d.ts +@@ -1,6 +1,6 @@ + import { ColumnName, TableName } from '../../Schema' + +-type immutableRelation = ( ++const immutableRelation = ( + relationTable: TableName, + relationIdColumn: ColumnName, + ) => PropertyDecorator +diff --git a/node_modules/@nozbe/watermelondb/decorators/json/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/json/index.d.ts +index 55de0d8..4aae413 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/json/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/json/index.d.ts +@@ -3,6 +3,6 @@ import Model from '../../Model' + + type Sanitizer = (source: any, model?: Model) => any + +-type json = (rawFieldName: ColumnName, sanitizer: Sanitizer) => PropertyDecorator ++const json = (rawFieldName: ColumnName, sanitizer: Sanitizer) => PropertyDecorator + + export default json +diff --git a/node_modules/@nozbe/watermelondb/decorators/relation/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/relation/index.d.ts +index 9fea99e..ef7baae 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/relation/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/relation/index.d.ts +@@ -1,7 +1,7 @@ + import { ColumnName, TableName } from '../../Schema' + import { Options } from '../../Relation' + +-type relation = ( ++const relation = ( + relationTable: TableName, + relationIdColumn: ColumnName, + options?: Options, +diff --git a/node_modules/@nozbe/watermelondb/decorators/text/index.d.ts b/node_modules/@nozbe/watermelondb/decorators/text/index.d.ts +index 330f187..334adbd 100644 +--- a/node_modules/@nozbe/watermelondb/decorators/text/index.d.ts ++++ b/node_modules/@nozbe/watermelondb/decorators/text/index.d.ts +@@ -1,5 +1,5 @@ + import { ColumnName } from '../../Schema' + +-type text = (columnName: ColumnName) => PropertyDecorator ++const text = (columnName: ColumnName) => PropertyDecorator + + export default text +diff --git a/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt b/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt +index ca31e20..b45c753 100644 +--- a/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt ++++ b/node_modules/@nozbe/watermelondb/native/android/src/main/java/com/nozbe/watermelondb/Database.kt +@@ -22,6 +22,21 @@ class Database( + if (name == ":memory:" || name.contains("mode=memory")) { + context.cacheDir.delete() + File(context.cacheDir, name).path ++ } else if (name.contains("/") || name.contains("file")) { ++ // Extracts the database name from the path ++ val dbName = name.substringAfterLast("/") ++ ++ // Extracts the real path where the *.db file will be created ++ val truePath = name.substringAfterLast("file://").substringBeforeLast("/") ++ ++ // Creates the directory ++ if (!truePath.contains("databases")) { ++ val fileObj = File(truePath, "databases") ++ fileObj.mkdir() ++ File("${truePath}/databases", dbName).path ++ } else { ++ File(truePath, dbName).path ++ } + } else { + // On some systems there is some kind of lock on `/databases` folder ¯\_(ツ)_/¯ + context.getDatabasePath("$name.db").path.replace("/databases", "") +diff --git a/node_modules/@nozbe/watermelondb/native/shared/Database.cpp b/node_modules/@nozbe/watermelondb/native/shared/Database.cpp +index 1a1cabf..01bbb2b 100644 +--- a/node_modules/@nozbe/watermelondb/native/shared/Database.cpp ++++ b/node_modules/@nozbe/watermelondb/native/shared/Database.cpp +@@ -54,6 +54,7 @@ void Database::destroy() { + const std::lock_guard lock(mutex_); + + if (isDestroyed_) { ++ db_->markAsDestroyed(); + return; + } + isDestroyed_ = true; +diff --git a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp +index e740c29..6963734 100644 +--- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp ++++ b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.cpp +@@ -67,6 +67,10 @@ void SqliteDb::destroy() { + } + } + ++void SqliteDb::markAsDestroyed() { ++ isDestroyed_ = true; ++} ++ + SqliteDb::~SqliteDb() { + destroy(); + } +diff --git a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h +index 22cffa7..4b74a7f 100644 +--- a/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h ++++ b/node_modules/@nozbe/watermelondb/native/shared/Sqlite.h +@@ -11,6 +11,7 @@ public: + SqliteDb(std::string path); + ~SqliteDb(); + void destroy(); ++ void markAsDestroyed(); + + sqlite3 *sqlite; + diff --git a/patches/@rudderstack+rudder-sdk-react-native+1.5.1.patch b/patches/@rudderstack+rudder-sdk-react-native+1.5.1.patch deleted file mode 100644 index 716513169e..0000000000 --- a/patches/@rudderstack+rudder-sdk-react-native+1.5.1.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/node_modules/@rudderstack/rudder-sdk-react-native/android/build.gradle b/node_modules/@rudderstack/rudder-sdk-react-native/android/build.gradle -index 24400ea..c69c39f 100644 ---- a/node_modules/@rudderstack/rudder-sdk-react-native/android/build.gradle -+++ b/node_modules/@rudderstack/rudder-sdk-react-native/android/build.gradle -@@ -15,7 +15,7 @@ android { - compileSdkVersion 30 - - defaultConfig { -- minSdkVersion 16 -+ minSdkVersion rootProject.hasProperty('minSdkVersion') ? rootProject.minSdkVersion : 21 - targetSdkVersion 30 - versionCode 1 - versionName "1.0" -diff --git a/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h b/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h -index f9020d1..7962e7b 100644 ---- a/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h -+++ b/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h -@@ -1,9 +1,5 @@ - --#if __has_include("RCTBridgeModule.h") --#import "RCTBridgeModule.h" --#else - #import --#endif - - @interface RNRudderSdkModule : NSObject - diff --git a/patches/@rudderstack+rudder-sdk-react-native+1.5.2.patch b/patches/@rudderstack+rudder-sdk-react-native+1.5.2.patch new file mode 100644 index 0000000000..fff40d0312 --- /dev/null +++ b/patches/@rudderstack+rudder-sdk-react-native+1.5.2.patch @@ -0,0 +1,14 @@ +diff --git a/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h b/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h +index f9020d1..7962e7b 100644 +--- a/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h ++++ b/node_modules/@rudderstack/rudder-sdk-react-native/ios/RNRudderSdkModule.h +@@ -1,9 +1,5 @@ + +-#if __has_include("RCTBridgeModule.h") +-#import "RCTBridgeModule.h" +-#else + #import +-#endif + + @interface RNRudderSdkModule : NSObject + diff --git a/patches/react-native+0.70.6.patch b/patches/react-native+0.70.6.patch deleted file mode 100644 index 28b2f81302..0000000000 --- a/patches/react-native+0.70.6.patch +++ /dev/null @@ -1,205 +0,0 @@ -diff --git a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js -index 698b62a..c855146 100644 ---- a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js -+++ b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js -@@ -1780,9 +1780,15 @@ class ScrollView extends React.Component { - // Note: we should split props.style on the inner and outer props - // however, the ScrollView still needs the baseStyle to be scrollable - const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); -+ let inverted; -+ if (inner.scaleY) { -+ inverted = {scaleY: -1}; -+ delete inner['scaleY'] -+ } -+ - return React.cloneElement( - refreshControl, -- {style: StyleSheet.compose(baseStyle, outer)}, -+ {style: [baseStyle, outer, inverted]}, - { -@@ -1986,12 +1987,16 @@ class CellRenderer extends React.Component< - props: CellRendererProps, - prevState: CellRendererState, - ): ?CellRendererState { -- return { -- separatorProps: { -- ...prevState.separatorProps, -- leadingItem: props.item, -- }, -- }; -+ if (prevState.separatorProps.leadingItem !== props.item) { -+ return { -+ separatorProps: { -+ ...prevState.separatorProps, -+ leadingItem: props.item, -+ }, -+ }; -+ } else { -+ return prevState; -+ } - } - - // TODO: consider factoring separator stuff out of VirtualizedList into FlatList since it's not -@@ -2171,7 +2176,10 @@ function describeNestedLists(childList: { - - const styles = StyleSheet.create({ - verticallyInverted: { -- transform: [{scaleY: -1}], -+ ...Platform.select({ -+ android: {scaleY: -1}, -+ ios: {transform: [{scaleY: -1}]}, -+ }), - }, - horizontallyInverted: { - transform: [{scaleX: -1}], -diff --git a/node_modules/react-native/react.gradle b/node_modules/react-native/react.gradle -index 912a407..01fa3ba 100644 ---- a/node_modules/react-native/react.gradle -+++ b/node_modules/react-native/react.gradle -@@ -141,7 +141,7 @@ def enableHermesForVariant = config.enableHermesForVariant ?: { - def hermesFlagsForVariant = config.hermesFlagsForVariant ?: { - def variant -> - def hermesFlags; -- if (variant.name.toLowerCase().contains("release")) { -+ if (variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")) { - // Can't use ?: since that will also substitute valid empty lists - hermesFlags = config.hermesFlagsRelease - if (hermesFlags == null) hermesFlags = ["-O", "-output-source-map"] -@@ -157,7 +157,7 @@ def hermesFlagsForVariant = config.hermesFlagsForVariant ?: { - def disableDevForVariant = config.disableDevForVariant ?: { - def variant -> - config."devDisabledIn${variant.name.capitalize()}" || -- variant.name.toLowerCase().contains("release") -+ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned") - } - - // Set bundleForVariant to a function to configure per variant, -@@ -166,13 +166,13 @@ def bundleForVariant = config.bundleForVariant ?: { - def variant -> - config."bundleIn${variant.name.capitalize()}" || - config."bundleIn${variant.buildType.name.capitalize()}" || -- variant.name.toLowerCase().contains("release") -+ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned") - } - - // Set deleteDebugFilesForVariant to a function to configure per variant, - // defaults to True for Release variants and False for debug variants - def deleteDebugFilesForVariant = config.deleteDebugFilesForVariant ?: { -- def variant -> variant.name.toLowerCase().contains("release") -+ def variant -> variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned") - } - - android { -diff --git a/node_modules/react-native/sdks/hermes/hermes-engine.podspec b/node_modules/react-native/sdks/hermes/hermes-engine.podspec -new file mode 100644 -index 0000000..8d331e0 ---- /dev/null -+++ b/node_modules/react-native/sdks/hermes/hermes-engine.podspec -@@ -0,0 +1,84 @@ -+# Copyright (c) Meta Platforms, Inc. and affiliates. -+# -+# This source code is licensed under the MIT license found in the -+# LICENSE file in the root directory of this source tree. -+ -+require "json" -+require "open3" -+ -+# sdks/hermesc/osx-bin/ImportHermesc.cmake -+import_hermesc_file=File.join(__dir__, "..", "hermesc", "osx-bin", "ImportHermesc.cmake") -+ -+# package.json -+package_file = File.join(__dir__, "..", "..", "package.json") -+package = JSON.parse(File.read(package_file)) -+version = package['version'] -+ -+# We need to check the current git branch/remote to verify if -+# we're on a React Native release branch to actually build Hermes. -+currentbranch, err = Open3.capture3("git rev-parse --abbrev-ref HEAD") -+currentremote, err = Open3.capture3("git config --get remote.origin.url") -+ -+source = {} -+git = "https://github.com/facebook/hermes.git" -+ -+if ENV.has_key?('HERMES_ENGINE_TARBALL_PATH') -+ Pod::UI.puts '[Hermes] Using pre-built Hermes binaries from local path.' if Object.const_defined?("Pod::UI") -+ source[:http] = "file://#{ENV['HERMES_ENGINE_TARBALL_PATH']}" -+elsif version == '1000.0.0' -+ Pod::UI.puts '[Hermes] Hermes needs to be compiled, installing hermes-engine may take a while...'.yellow if Object.const_defined?("Pod::UI") -+ source[:git] = git -+ source[:commit] = `git ls-remote https://github.com/facebook/hermes main | cut -f 1`.strip -+elsif currentremote.strip.end_with?("facebook/react-native.git") and currentbranch.strip.end_with?("-stable") -+ Pod::UI.puts '[Hermes] Detected that you are on a React Native release branch, building Hermes from source...'.yellow if Object.const_defined?("Pod::UI") -+ hermestag_file = File.join(__dir__, "..", ".hermesversion") -+ hermestag = File.read(hermestag_file).strip -+ source[:git] = git -+ source[:tag] = hermestag -+else -+ source[:http] = "https://github.com/facebook/react-native/releases/download/v#{version}/hermes-runtime-darwin-v#{version}.tar.gz" -+end -+ -+module HermesHelper -+ # BUILD_TYPE = :debug -+ BUILD_TYPE = :release -+end -+ -+Pod::Spec.new do |spec| -+ spec.name = "hermes-engine" -+ spec.version = version -+ spec.summary = "Hermes is a small and lightweight JavaScript engine optimized for running React Native." -+ spec.description = "Hermes is a JavaScript engine optimized for fast start-up of React Native apps. It features ahead-of-time static optimization and compact bytecode." -+ spec.homepage = "https://hermesengine.dev" -+ spec.license = package["license"] -+ spec.author = "Facebook" -+ spec.source = source -+ spec.platforms = { :osx => "10.13", :ios => "12.4" } -+ -+ spec.preserve_paths = ["destroot/bin/*"].concat(HermesHelper::BUILD_TYPE == :debug ? ["**/*.{h,c,cpp}"] : []) -+ spec.source_files = "destroot/include/**/*.h" -+ spec.header_mappings_dir = "destroot/include" -+ -+ spec.ios.vendored_frameworks = "destroot/Library/Frameworks/universal/hermes.xcframework" -+ spec.osx.vendored_frameworks = "destroot/Library/Frameworks/macosx/hermes.framework" -+ -+ spec.xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", "CLANG_CXX_LIBRARY" => "compiler-default", "GCC_PREPROCESSOR_DEFINITIONS" => "HERMES_ENABLE_DEBUGGER=1" } -+ -+ if source[:git] then -+ spec.prepare_command = <<-EOS -+ # When true, debug build will be used. -+ # See `build-apple-framework.sh` for details -+ DEBUG=#{HermesHelper::BUILD_TYPE == :debug} -+ -+ # Set HERMES_OVERRIDE_HERMESC_PATH if pre-built HermesC is available -+ #{File.exist?(import_hermesc_file) ? "export HERMES_OVERRIDE_HERMESC_PATH=#{import_hermesc_file}" : ""} -+ #{File.exist?(import_hermesc_file) ? "echo \"Overriding HermesC path...\"" : ""} -+ -+ # Build iOS framework -+ ./utils/build-ios-framework.sh -+ -+ # Build Mac framework -+ ./utils/build-mac-framework.sh -+ EOS -+ end -+end diff --git a/patches/react-native+0.71.1.patch b/patches/react-native+0.71.1.patch new file mode 100644 index 0000000000..39656c3560 --- /dev/null +++ b/patches/react-native+0.71.1.patch @@ -0,0 +1,106 @@ +diff --git a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js +index 0c2ecf2..a04414f 100644 +--- a/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js ++++ b/node_modules/react-native/Libraries/Components/ScrollView/ScrollView.js +@@ -1819,9 +1819,14 @@ class ScrollView extends React.Component { + // Note: we should split props.style on the inner and outer props + // however, the ScrollView still needs the baseStyle to be scrollable + const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); ++ let inverted; ++ if (inner.scaleY) { ++ inverted = {scaleY: -1}; ++ delete inner['scaleY'] ++ } + return React.cloneElement( + refreshControl, +- {style: StyleSheet.compose(baseStyle, outer)}, ++ {style: StyleSheet.compose(baseStyle, outer, inverted)}, + + def hermesFlags; +- if (variant.name.toLowerCase().contains("release")) { ++ if (variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned")) { + // Can't use ?: since that will also substitute valid empty lists + hermesFlags = config.hermesFlagsRelease + if (hermesFlags == null) hermesFlags = ["-O", "-output-source-map"] +@@ -175,7 +175,7 @@ def hermesFlagsForVariant = config.hermesFlagsForVariant ?: { + def disableDevForVariant = config.disableDevForVariant ?: { + def variant -> + config."devDisabledIn${variant.name.capitalize()}" || +- variant.name.toLowerCase().contains("release") ++ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned") + } + + // Set bundleForVariant to a function to configure per variant, +@@ -184,13 +184,13 @@ def bundleForVariant = config.bundleForVariant ?: { + def variant -> + config."bundleIn${variant.name.capitalize()}" || + config."bundleIn${variant.buildType.name.capitalize()}" || +- variant.name.toLowerCase().contains("release") ++ variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned") + } + + // Set deleteDebugFilesForVariant to a function to configure per variant, + // defaults to True for Release variants and False for debug variants + def deleteDebugFilesForVariant = config.deleteDebugFilesForVariant ?: { +- def variant -> variant.name.toLowerCase().contains("release") ++ def variant -> variant.name.toLowerCase().contains("release") || variant.name.toLowerCase().contains("unsigned") + } + + android { diff --git a/patches/react-native-create-thumbnail+1.6.4.patch b/patches/react-native-create-thumbnail+1.6.4.patch index 7d1aa97d62..f5135e7e5e 100644 --- a/patches/react-native-create-thumbnail+1.6.4.patch +++ b/patches/react-native-create-thumbnail+1.6.4.patch @@ -1,3 +1,63 @@ +diff --git a/node_modules/react-native-create-thumbnail/android/src/main/java/com/createthumbnail/CreateThumbnailModule.java b/node_modules/react-native-create-thumbnail/android/src/main/java/com/createthumbnail/CreateThumbnailModule.java +index 9bd67d8..bf4175a 100644 +--- a/node_modules/react-native-create-thumbnail/android/src/main/java/com/createthumbnail/CreateThumbnailModule.java ++++ b/node_modules/react-native-create-thumbnail/android/src/main/java/com/createthumbnail/CreateThumbnailModule.java +@@ -169,31 +169,35 @@ public class CreateThumbnailModule extends ReactContextBaseJavaModule { + } + + private static Bitmap getBitmapAtTime(Context context, String filePath, int time, Map headers) { +- MediaMetadataRetriever retriever = new MediaMetadataRetriever(); +- if (URLUtil.isFileUrl(filePath)) { +- String decodedPath; +- try { +- decodedPath = URLDecoder.decode(filePath, "UTF-8"); +- } catch (UnsupportedEncodingException e) { +- decodedPath = filePath; +- } ++ try { ++ MediaMetadataRetriever retriever = new MediaMetadataRetriever(); ++ if (URLUtil.isFileUrl(filePath)) { ++ String decodedPath; ++ try { ++ decodedPath = URLDecoder.decode(filePath, "UTF-8"); ++ } catch (UnsupportedEncodingException e) { ++ decodedPath = filePath; ++ } + +- retriever.setDataSource(decodedPath.replace("file://", "")); +- } else if (filePath.contains("content://")) { +- retriever.setDataSource(context, Uri.parse(filePath)); +- } else { +- if (VERSION.SDK_INT < 14) { +- throw new IllegalStateException("Remote videos aren't supported on sdk_version < 14"); ++ retriever.setDataSource(decodedPath.replace("file://", "")); ++ } else if (filePath.contains("content://")) { ++ retriever.setDataSource(context, Uri.parse(filePath)); ++ } else { ++ if (VERSION.SDK_INT < 14) { ++ throw new IllegalStateException("Remote videos aren't supported on sdk_version < 14"); ++ } ++ retriever.setDataSource(filePath, headers); + } +- retriever.setDataSource(filePath, headers); +- } + +- Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); +- retriever.release(); +- if (image == null) { ++ Bitmap image = retriever.getFrameAtTime(time * 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC); ++ retriever.release(); ++ if (image == null) { ++ throw new IllegalStateException("File doesn't exist or not supported"); ++ } ++ return image; ++ } catch (Exception e) { + throw new IllegalStateException("File doesn't exist or not supported"); + } +- return image; + } + + private static long getDirSize(File dir) { diff --git a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h index 28b1d9b..cb63c52 100644 --- a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.h @@ -10,7 +70,7 @@ index 28b1d9b..cb63c52 100644 ++(void)create:(NSDictionary *)config findEventsWithResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject; @end diff --git a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m -index 92cc49f..23cc83c 100644 +index 92cc49f..a2bab15 100644 --- a/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m +++ b/node_modules/react-native-create-thumbnail/ios/CreateThumbnail.m @@ -6,6 +6,10 @@ RCT_EXPORT_MODULE() diff --git a/patches/react-native-navigation+7.30.6.patch b/patches/react-native-navigation+7.31.1.patch similarity index 62% rename from patches/react-native-navigation+7.30.6.patch rename to patches/react-native-navigation+7.31.1.patch index eeb56c9abb..616628d8f5 100644 --- a/patches/react-native-navigation+7.30.6.patch +++ b/patches/react-native-navigation+7.31.1.patch @@ -1,8 +1,39 @@ diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java -index 226d3bf..6213a88 100644 +index 8ddc3d5..c4acd2d 100644 --- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java +++ b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java -@@ -48,7 +48,7 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard +@@ -1,18 +1,15 @@ + package com.reactnativenavigation; + +-import android.annotation.TargetApi; + import android.content.Intent; + import android.content.res.Configuration; +-import android.graphics.Color; +-import android.os.Build; + import android.os.Bundle; + import android.view.KeyEvent; + import android.view.View; + ++import com.facebook.react.ReactActivity; + import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; + import com.facebook.react.modules.core.PermissionAwareActivity; + import com.facebook.react.modules.core.PermissionListener; +-import com.reactnativenavigation.options.Options; + import com.reactnativenavigation.viewcontrollers.overlay.OverlayManager; + import com.reactnativenavigation.viewcontrollers.viewcontroller.RootPresenter; + import com.reactnativenavigation.react.JsDevReloadHandler; +@@ -25,9 +22,8 @@ import com.reactnativenavigation.viewcontrollers.navigator.Navigator; + import androidx.activity.OnBackPressedCallback; + import androidx.annotation.NonNull; + import androidx.annotation.Nullable; +-import androidx.appcompat.app.AppCompatActivity; + +-public class NavigationActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity, JsDevReloadHandler.ReloadListener { ++public class NavigationActivity extends ReactActivity implements DefaultHardwareBackBtnHandler, PermissionAwareActivity, JsDevReloadHandler.ReloadListener { + @Nullable + private PermissionListener mPermissionListener; + +@@ -50,7 +46,7 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard ); navigator.bindViews(); getReactGateway().onActivityCreated(this); @@ -11,18 +42,40 @@ index 226d3bf..6213a88 100644 } @Override -@@ -141,6 +141,11 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard - navigator.destroyViews(); +@@ -96,15 +92,11 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard + + @Override + public void invokeDefaultOnBackPressed() { +- if (!navigator.handleBack(new CommandListenerAdapter())) { +- callback.setEnabled(false); +- NavigationActivity.super.onBackPressed(); +- callback.setEnabled(true); +- } ++ super.invokeDefaultOnBackPressed(); } -+ @Override -+ public void onBackPressed() { -+ getReactGateway().onBackPressed(); -+ } -+ - protected void addDefaultSplashLayout() { - View view = new View(this); - setContentView(view); + @Override +- protected void onActivityResult(int requestCode, int resultCode, Intent data) { ++ public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + getReactGateway().onActivityResult(this, requestCode, resultCode, data); + } +@@ -126,7 +118,6 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard + return navigator; + } + +- @TargetApi(Build.VERSION_CODES.M) + public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { + mPermissionListener = listener; + requestPermissions(permissions, requestCode); +@@ -134,6 +125,7 @@ public class NavigationActivity extends AppCompatActivity implements DefaultHard + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { ++ super.onRequestPermissionsResult(requestCode, permissions, grantResults); + NavigationApplication.instance.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { + mPermissionListener = null; diff --git a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java b/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java index a34598c..b035a76 100644 --- a/node_modules/react-native-navigation/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java @@ -109,23 +162,21 @@ index a34598c..b035a76 100644 if (navigationActivity != null) { navigationActivity.onCatalystInstanceDestroy(); } -diff --git a/node_modules/react-native-navigation/lib/android/app/src/reactNative68/java/com/reactnativenavigation/react/ReactGateway.java b/node_modules/react-native-navigation/lib/android/app/src/reactNative68/java/com/reactnativenavigation/react/ReactGateway.java -index 035ec31..38109c1 100644 ---- a/node_modules/react-native-navigation/lib/android/app/src/reactNative68/java/com/reactnativenavigation/react/ReactGateway.java -+++ b/node_modules/react-native-navigation/lib/android/app/src/reactNative68/java/com/reactnativenavigation/react/ReactGateway.java -@@ -48,6 +48,12 @@ public class ReactGateway { - } +diff --git a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java b/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java +index 035ec31..630b8d4 100644 +--- a/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java ++++ b/node_modules/react-native-navigation/lib/android/app/src/reactNative71/java/com/reactnativenavigation/react/ReactGateway.java +@@ -69,4 +69,10 @@ public class ReactGateway { + public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { + host.getReactInstanceManager().onActivityResult(activity, requestCode, resultCode, data); } - ++ + public void onWindowFocusChanged(boolean hasFocus) { + if (host.hasInstance()) { + host.getReactInstanceManager().onWindowFocusChange(hasFocus); + } + } -+ - public void onActivityPaused(NavigationActivity activity) { - initializer.onActivityPaused(activity); - jsDevReloadHandler.onActivityPaused(activity); + } diff --git a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m b/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m index 3ce9674..ae34704 100644 --- a/node_modules/react-native-navigation/lib/ios/RNNComponentViewController.m @@ -186,3 +237,14 @@ index f814815..bb39a10 100644 @interface RNNReactView : RCTFabricSurfaceHostingProxyRootView #else +diff --git a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts b/node_modules/react-native-navigation/lib/src/interfaces/Options.ts +index 4851b40..e891183 100644 +--- a/node_modules/react-native-navigation/lib/src/interfaces/Options.ts ++++ b/node_modules/react-native-navigation/lib/src/interfaces/Options.ts +@@ -1,5 +1,5 @@ + // tslint:disable jsdoc-format +-import { ImageRequireSource, ImageSourcePropType, Insets, OpaqueColorValue } from 'react-native'; ++import type { ImageRequireSource, ImageSourcePropType, Insets, OpaqueColorValue } from 'react-native'; + + // TODO: Import ColorValue instead when upgrading @types/react-native to 0.63+ + // Only assign PlatformColor or DynamicColorIOS as a Color symbol! diff --git a/patches/react-native-reanimated+2.13.0.patch b/patches/react-native-reanimated+2.14.4.patch similarity index 100% rename from patches/react-native-reanimated+2.13.0.patch rename to patches/react-native-reanimated+2.14.4.patch diff --git a/patches/react-native-svg+13.6.0.patch b/patches/react-native-svg+13.7.0.patch similarity index 100% rename from patches/react-native-svg+13.6.0.patch rename to patches/react-native-svg+13.7.0.patch diff --git a/patches/react-native-walkthrough-tooltip+1.4.0.patch b/patches/react-native-walkthrough-tooltip+1.5.0.patch similarity index 68% rename from patches/react-native-walkthrough-tooltip+1.4.0.patch rename to patches/react-native-walkthrough-tooltip+1.5.0.patch index 38e9501d4f..2a6f6e4def 100644 --- a/patches/react-native-walkthrough-tooltip+1.4.0.patch +++ b/patches/react-native-walkthrough-tooltip+1.5.0.patch @@ -1,16 +1,3 @@ -diff --git a/node_modules/react-native-walkthrough-tooltip/src/tooltip.d.ts b/node_modules/react-native-walkthrough-tooltip/src/tooltip.d.ts -index 5a7ef59..305d794 100644 ---- a/node_modules/react-native-walkthrough-tooltip/src/tooltip.d.ts -+++ b/node_modules/react-native-walkthrough-tooltip/src/tooltip.d.ts -@@ -129,6 +129,8 @@ declare module 'react-native-walkthrough-tooltip' { - - /** Will use given component instead of default react-native Modal component **/ - modalComponent?: object; -+ -+ children: React.ReactNode; - } - - /** diff --git a/node_modules/react-native-walkthrough-tooltip/src/tooltip.js b/node_modules/react-native-walkthrough-tooltip/src/tooltip.js index db612fd..0262d6d 100644 --- a/node_modules/react-native-walkthrough-tooltip/src/tooltip.js diff --git a/test/setup.ts b/test/setup.ts index eea80218bc..a2c629ad1d 100644 --- a/test/setup.ts +++ b/test/setup.ts @@ -137,6 +137,9 @@ jest.doMock('react-native', () => { const Linking = { ...RNLinking, openURL: jest.fn(), + addEventListener: jest.fn(() => { + return {remove: jest.fn()}; + }), }; return Object.setPrototypeOf({ @@ -278,7 +281,7 @@ jest.mock('react-native-navigation', () => { return {remove: jest.fn()}; }), registerNavigationButtonPressedListener: jest.fn(() => { - return {buttonId: 'buttonId'}; + return {remove: jest.fn()}; }), }), setRoot: jest.fn(), diff --git a/tsconfig.json b/tsconfig.json index 0dec6dd843..261c51508c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,13 +8,18 @@ "allowJs": false, "skipLibCheck": true, "allowSyntheticDefaultImports": true, + "allowUnreachableCode": false, + "allowUnusedLabels": false, "esModuleInterop": true, "isolatedModules": true, - "jsx": "react", + "jsx": "react-native", + "types": ["react-native", "node", "jest"], "moduleResolution": "node", "noEmit": false, "strict": true, "importHelpers": true, + "importsNotUsedAsValues": "error", + "forceConsistentCasingInFileNames": true, "declaration": true, "sourceMap": false, "rootDir": "./", @@ -29,6 +34,7 @@ "downlevelIteration": true, "noUnusedParameters": false, "noImplicitReturns": true, + "noImplicitUseStrict": false, "noFallthroughCasesInSwitch": true, "resolveJsonModule": true, "baseUrl": ".", diff --git a/types/api/teams.d.ts b/types/api/teams.d.ts index e3c0784b3e..5fe283f0a6 100644 --- a/types/api/teams.d.ts +++ b/types/api/teams.d.ts @@ -19,6 +19,11 @@ type TeamMemberWithError = { error: ApiError; } +type TeamInviteWithError = { + email: string; + error: ApiError; +} + type TeamType = 'O' | 'I'; type Team = { diff --git a/types/components/syntax_highlight.ts b/types/components/syntax_highlight.ts index d8f959e5f8..9cea988bde 100644 --- a/types/components/syntax_highlight.ts +++ b/types/components/syntax_highlight.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {TextStyle} from 'react-native'; +import type {TextStyle} from 'react-native'; export type SyntaxHiglightProps = { code: string; diff --git a/types/database/database.ts b/types/database/database.ts index 3041c2b068..2b90992f4d 100644 --- a/types/database/database.ts +++ b/types/database/database.ts @@ -9,7 +9,6 @@ import type ServerDataOperator from '@database/operator/server_data_operator'; import type {Database} from '@nozbe/watermelondb'; import type Model from '@nozbe/watermelondb/Model'; import type {Clause} from '@nozbe/watermelondb/QueryDescription'; -import type {Class} from '@nozbe/watermelondb/utils/common'; import type System from '@typings/database/models/servers/system'; export type WithDatabaseArgs = { database: Database } @@ -51,6 +50,10 @@ export type TransformerArgs = { value: RecordPair; }; +export type PrepareBaseRecordArgs = TransformerArgs & { + fieldsMapper: (model: Model) => void; +} + export type OperationArgs = { tableName: string; createRaws?: RecordPair[]; @@ -59,7 +62,7 @@ export type OperationArgs = { transformer: (args: TransformerArgs) => Promise; }; -export type Models = Array>; +export type Models = Model[]; // The elements needed to create a new database export type CreateServerDatabaseArgs = { diff --git a/types/global/data_retention.d.ts b/types/global/data_retention.d.ts new file mode 100644 index 0000000000..99e907e967 --- /dev/null +++ b/types/global/data_retention.d.ts @@ -0,0 +1,19 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +type GlobalDataRetentionPolicy = { + file_deletion_enabled: boolean; + file_retention_cutoff: number; + message_deletion_enabled: boolean; + message_retention_cutoff: number; +} + +type TeamDataRetentionPolicy = { + post_duration: number; + team_id: string; +} + +type ChannelDataRetentionPolicy = { + post_duration: number; + channel_id: string; +} diff --git a/types/global/markdown.ts b/types/global/markdown.ts index a478b1128f..df1ab69461 100644 --- a/types/global/markdown.ts +++ b/types/global/markdown.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {TextStyle, ViewStyle} from 'react-native'; +import type {TextStyle, ViewStyle} from 'react-native'; export type SearchPattern = { pattern: RegExp; diff --git a/types/global/styles.ts b/types/global/styles.ts index f3c43b0843..40d0532141 100644 --- a/types/global/styles.ts +++ b/types/global/styles.ts @@ -1,5 +1,5 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ImageStyle, TextStyle, ViewStyle} from 'react-native'; +import type {ImageStyle, TextStyle, ViewStyle} from 'react-native'; export type NamedStyles = { [P in keyof T]: ViewStyle | TextStyle | ImageStyle }; diff --git a/types/screens/edit_profile.ts b/types/screens/edit_profile.ts index 1a8d23231f..08c61f72a1 100644 --- a/types/screens/edit_profile.ts +++ b/types/screens/edit_profile.ts @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. +import type {AvailableScreens} from './navigation'; import type {FloatingTextInputRef} from '@components/floating_text_input_label'; import type {FieldProps} from '@screens/edit_profile/components/field'; import type UserModel from '@typings/database/models/servers/user'; @@ -16,7 +17,7 @@ export interface UserInfo extends Record