feat: Supported Versions (#5185)
This commit is contained in:
parent
4a6a4a3b9a
commit
18b77ab4d6
|
@ -96,16 +96,23 @@ commands:
|
|||
- ~/.pods
|
||||
- ios/Pods
|
||||
|
||||
fetch-supported-versions:
|
||||
description: "Fetch supported versions from Cloud"
|
||||
steps:
|
||||
- run:
|
||||
name: "Fetch supported versions from Cloud"
|
||||
command: sh ./scripts/fetch-supported-versions.sh
|
||||
- store_artifacts:
|
||||
path: ./app-supportedversions.json
|
||||
|
||||
android-build:
|
||||
description: "Build Android app"
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- restore_cache: *restore-npm-cache-linux
|
||||
|
||||
- run: *install-npm-modules
|
||||
|
||||
- restore_cache: *restore-gradle-cache
|
||||
- fetch-supported-versions
|
||||
|
||||
- run:
|
||||
name: Configure Gradle
|
||||
|
@ -200,6 +207,7 @@ commands:
|
|||
- run: *install-npm-modules
|
||||
- run: *update-fastlane-ios
|
||||
- manage-pods
|
||||
- fetch-supported-versions
|
||||
- run:
|
||||
name: Set Google Services
|
||||
command: |
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots Button Custom Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"purple\\",\\"padding\\":10,\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"yellow\\",\\"fontSize\\":18},[{\\"textAlign\\":\\"left\\"}]],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
exports[`Storyshots Button Custom Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"purple\\",\\"padding\\":10,\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"yellow\\",\\"fontSize\\":18},[{\\"textAlign\\":\\"left\\"}]]},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
|
||||
exports[`Storyshots Button Disabled Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
exports[`Storyshots Button Disabled Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null]},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
|
||||
exports[`Storyshots Button Disabled Loading Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":0.3}},\\"children\\":[{\\"type\\":\\"ActivityIndicator\\",\\"props\\":{\\"style\\":[{\\"padding\\":16,\\"flex\\":1},null],\\"color\\":\\"#ffffff\\"},\\"children\\":null}]}"`;
|
||||
|
||||
exports[`Storyshots Button Loading Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":true},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"ActivityIndicator\\",\\"props\\":{\\"style\\":[{\\"padding\\":16,\\"flex\\":1},null],\\"color\\":\\"#ffffff\\"},\\"children\\":null}]}"`;
|
||||
|
||||
exports[`Storyshots Button Primary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
exports[`Storyshots Button Primary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#1d74f5\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#ffffff\\",\\"fontSize\\":16},null]},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
|
||||
exports[`Storyshots Button Secondary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Press me!\\"},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
exports[`Storyshots Button Secondary Button 1`] = `"{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Press me!\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"testID\\":\\"testButton\\",\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":12,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#2f343d\\",\\"fontSize\\":16},null]},\\"children\\":[\\"Press me!\\"]}]}"`;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots Login Services Separators 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"More options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"More options\\"},\\"children\\":[\\"More options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]},{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Less options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null],\\"accessibilityLabel\\":\\"Less options\\"},\\"children\\":[\\"Less options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]}]"`;
|
||||
exports[`Storyshots Login Services Separators 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"More options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null]},\\"children\\":[\\"More options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]},{\\"type\\":\\"View\\",\\"props\\":{\\"accessible\\":true,\\"accessibilityLabel\\":\\"Less options\\",\\"accessibilityState\\":{\\"disabled\\":false},\\"focusable\\":true,\\"collapsable\\":false,\\"style\\":{\\"paddingHorizontal\\":14,\\"justifyContent\\":\\"center\\",\\"height\\":48,\\"borderRadius\\":4,\\"marginBottom\\":0,\\"backgroundColor\\":\\"#ffffff\\",\\"opacity\\":1}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"center\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#1d74f5\\",\\"fontSize\\":16},null]},\\"children\\":[\\"Less options\\"]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"marginVertical\\":24}},\\"children\\":[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"fontSize\\":14,\\"marginLeft\\":14,\\"marginRight\\":14,\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"500\\"},{\\"color\\":\\"#9ca2a8\\"}]},\\"children\\":[\\"OR\\"]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":[{\\"height\\":1,\\"flex\\":1},{\\"backgroundColor\\":\\"#e1e5e8\\"}]},\\"children\\":null}]}]"`;
|
||||
|
||||
exports[`Storyshots Login Services Service List 1`] = `"[{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},[{\\"lineHeight\\":24},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"github\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},[{\\"lineHeight\\":24},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"gitlab\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},[{\\"lineHeight\\":24},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"google\\"]}]}]},{\\"type\\":\\"View\\",\\"props\\":{\\"style\\":{\\"borderRadius\\":4,\\"width\\":\\"100%\\",\\"height\\":48,\\"flexDirection\\":\\"row\\",\\"alignItems\\":\\"center\\",\\"justifyContent\\":\\"center\\",\\"paddingHorizontal\\":15}},\\"children\\":[{\\"type\\":\\"Text\\",\\"props\\":{\\"selectable\\":false,\\"allowFontScaling\\":false,\\"style\\":[{\\"fontSize\\":24,\\"color\\":\\"#0d0e12\\"},[{\\"lineHeight\\":24},{\\"position\\":\\"absolute\\",\\"left\\":15,\\"top\\":12,\\"width\\":24,\\"height\\":24}],{\\"fontFamily\\":\\"custom\\",\\"fontWeight\\":\\"normal\\",\\"fontStyle\\":\\"normal\\"},{}]},\\"children\\":[\\"\\"]},{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":[{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"400\\",\\"fontSize\\":16},{\\"color\\":\\"#0d0e12\\"}]},\\"children\\":[\\"Continue with\\",\\" \\",{\\"type\\":\\"Text\\",\\"props\\":{\\"style\\":{\\"textAlign\\":\\"left\\",\\"backgroundColor\\":\\"transparent\\",\\"fontFamily\\":\\"Inter\\",\\"fontWeight\\":\\"600\\"}},\\"children\\":[\\"apple\\"]}]}]}]"`;
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"signed": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aW1lc3RhbXAiOiIyMDIzLTEwLTExVDE5OjI0OjEwLjc5OTkwNjgzWiIsIm1lc3NhZ2VzIjpbeyJyZW1haW5pbmdEYXlzIjozMCwidGl0bGUiOiJ2ZXJzaW9uX3Vuc3VwcG9ydGVkX3RpdGxlIiwic3VidGl0bGUiOiJ2ZXJzaW9uX3Vuc3VwcG9ydGVkX3N1YnRpdGxlIiwiZGVzY3JpcHRpb24iOiJ2ZXJzaW9uX3Vuc3VwcG9ydGVkX2JvZHkiLCJ0eXBlIjoiaW5mbyIsInBhcmFtcyI6e30sImxpbmsiOiIifV0sInZlcnNpb25zIjpbeyJ2ZXJzaW9uIjoiNi4zLjEiLCJzZWN1cml0eSI6ZmFsc2UsImluZm9VcmwiOiJodHRwczovL2dpdGh1Yi5jb20vUm9ja2V0Q2hhdC9Sb2NrZXQuQ2hhdC9yZWxlYXNlcy90YWcvNi4zLjEiLCJleHBpcmF0aW9uIjoiMjAyMy0xMi0yNlQwMDowMDowMFoifSx7InZlcnNpb24iOiI2LjMuMCIsInNlY3VyaXR5IjpmYWxzZSwiaW5mb1VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9Sb2NrZXRDaGF0L1JvY2tldC5DaGF0L3JlbGVhc2VzL3RhZy82LjMuMCIsImV4cGlyYXRpb24iOiIyMDIzLTEyLTI2VDAwOjAwOjAwWiJ9LHsidmVyc2lvbiI6IjYuMy4yIiwic2VjdXJpdHkiOmZhbHNlLCJpbmZvVXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL1JvY2tldENoYXQvUm9ja2V0LkNoYXQvcmVsZWFzZXMvdGFnLzYuMy4yIiwiZXhwaXJhdGlvbiI6IjIwMjMtMTItMjZUMDA6MDA6MDBaIn0seyJ2ZXJzaW9uIjoiNi4zLjMiLCJzZWN1cml0eSI6ZmFsc2UsImluZm9VcmwiOiJodHRwczovL2dpdGh1Yi5jb20vUm9ja2V0Q2hhdC9Sb2NrZXQuQ2hhdC9yZWxlYXNlcy90YWcvNi4zLjMiLCJleHBpcmF0aW9uIjoiMjAyMy0xMi0yNlQwMDowMDowMFoifSx7InZlcnNpb24iOiI2LjMuNCIsInNlY3VyaXR5IjpmYWxzZSwiaW5mb1VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9Sb2NrZXRDaGF0L1JvY2tldC5DaGF0L3JlbGVhc2VzL3RhZy82LjMuNCIsImV4cGlyYXRpb24iOiIyMDIzLTEyLTI2VDAwOjAwOjAwWiJ9LHsidmVyc2lvbiI6IjYuMy41Iiwic2VjdXJpdHkiOmZhbHNlLCJpbmZvVXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL1JvY2tldENoYXQvUm9ja2V0LkNoYXQvcmVsZWFzZXMvdGFnLzYuMy41IiwiZXhwaXJhdGlvbiI6IjIwMjMtMTItMjZUMDA6MDA6MDBaIn0seyJ2ZXJzaW9uIjoiNi4zLjYiLCJzZWN1cml0eSI6ZmFsc2UsImluZm9VcmwiOiJodHRwczovL2dpdGh1Yi5jb20vUm9ja2V0Q2hhdC9Sb2NrZXQuQ2hhdC9yZWxlYXNlcy90YWcvNi4zLjYiLCJleHBpcmF0aW9uIjoiMjAyMy0xMi0yNlQwMDowMDowMFoifSx7InZlcnNpb24iOiI2LjMuNyIsInNlY3VyaXR5IjpmYWxzZSwiaW5mb1VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9Sb2NrZXRDaGF0L1JvY2tldC5DaGF0L3JlbGVhc2VzL3RhZy82LjMuNyIsImV4cGlyYXRpb24iOiIyMDIzLTEyLTI2VDAwOjAwOjAwWiJ9LHsidmVyc2lvbiI6IjYuMy44Iiwic2VjdXJpdHkiOmZhbHNlLCJpbmZvVXJsIjoiaHR0cHM6Ly9naXRodWIuY29tL1JvY2tldENoYXQvUm9ja2V0LkNoYXQvcmVsZWFzZXMvdGFnLzYuMy44IiwiZXhwaXJhdGlvbiI6IjIwMjMtMTItMjZUMDA6MDA6MDBaIn0seyJ2ZXJzaW9uIjoiNi40LjAiLCJzZWN1cml0eSI6ZmFsc2UsImluZm9VcmwiOiJodHRwczovL2dpdGh1Yi5jb20vUm9ja2V0Q2hhdC9Sb2NrZXQuQ2hhdC9yZWxlYXNlcy90YWcvNi40LjAiLCJleHBpcmF0aW9uIjoiMjAyNC0wMS0xMVQwMDowMDowMFoifSx7InZlcnNpb24iOiI2LjMuOSIsInNlY3VyaXR5IjpmYWxzZSwiaW5mb1VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9Sb2NrZXRDaGF0L1JvY2tldC5DaGF0L3JlbGVhc2VzL3RhZy82LjMuOSIsImV4cGlyYXRpb24iOiIyMDIzLTEyLTI2VDAwOjAwOjAwWiJ9LHsidmVyc2lvbiI6IjYuMy4xMCIsInNlY3VyaXR5IjpmYWxzZSwiaW5mb1VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9Sb2NrZXRDaGF0L1JvY2tldC5DaGF0L3JlbGVhc2VzL3RhZy82LjMuMTAiLCJleHBpcmF0aW9uIjoiMjAyMy0xMi0yNlQwMDowMDowMFoifSx7InZlcnNpb24iOiI2LjQuMSIsInNlY3VyaXR5IjpmYWxzZSwiaW5mb1VybCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9Sb2NrZXRDaGF0L1JvY2tldC5DaGF0L3JlbGVhc2VzL3RhZy82LjQuMSIsImV4cGlyYXRpb24iOiIyMDI0LTAyLTA5VDIxOjA3OjUyLjMyOVoifSx7InZlcnNpb24iOiI2LjUuMC1kZXZlbG9wIiwic2VjdXJpdHkiOmZhbHNlLCJpbmZvVXJsIjoiIiwiZXhwaXJhdGlvbiI6IjIwMjMtMTAtMThUMTk6MjQ6MTAuODE0NzMxMTg5WiJ9XSwiaTE4biI6eyJlbiI6eyJ2ZXJzaW9uX3Vuc3VwcG9ydGVkX2JvZHkiOiJBbiBhdXRvbWF0aWMgMzAtZGF5IHdhcm5pbmcgcGVyaW9kIGhhcyBiZWVuIGFwcGxpZWQgdG8gYWxsb3cgdGltZSBmb3IgYSB3b3Jrc3BhY2UgYWRtaW4gdG8gdXBkYXRlIHdvcmtzcGFjZSB0byBhIHN1cHBvcnRlZCBzb2Z0d2FyZSB2ZXJzaW9uLiIsInZlcnNpb25fdW5zdXBwb3J0ZWRfc3VidGl0bGUiOiJNb2JpbGUgYW5kIGRlc2t0b3AgYXBwIGFjY2VzcyB0byB7e2luc3RhbmNlX3dzX25hbWV9fSB3aWxsIGJlIGN1dCBvZmYgaW4ge3tyZW1haW5pbmdfZGF5c319IGRheXMiLCJ2ZXJzaW9uX3Vuc3VwcG9ydGVkX3RpdGxlIjoie3tpbnN0YW5jZV93c19uYW1lfX0gaXMgcnVubmluZyBhbiB1bnN1cHBvcnRlZCB2ZXJzaW9uIG9mIFJvY2tldC5DaGF0In19LCJlbmZvcmNlbWVudFN0YXJ0RGF0ZSI6IjIwMjMtMTAtMzFUMDA6MDA6MDBaIn0.F83D93FJN-dQjSv4c2NjANHJ_aOou2WPioYiu7LMymvwSr9PvK87_xGA5wB_b532mRDThfbwkYU0mqvfaHylTKcteYpJn2zy1-ZGHj5Ugtt4wxBMYezW07_H7K8DEskwuGQQ5jmmy1VEwzIVcM7GoGQLDT2eafkloHBXQLRqmanhb03110NGiNu_9xkMU5cmsW2tP1-kShug89L-E4tHXzDG7TXX4yF4H_W3RdmdW6b5FNdmoYFF68I4HYGNmcgOZDBsw2gkA3xUg3vFsbnkjl_oyyBZqINFZRu0TtVu4S5OORnrM-9zJp_C6GMiueFLBy3lwjNIcAUPrZA93uu7Yg",
|
||||
"timestamp": "2023-10-11T19:24:10.79990683Z",
|
||||
"messages": [
|
||||
{
|
||||
"remainingDays": 30,
|
||||
"title": "version_unsupported_title",
|
||||
"subtitle": "version_unsupported_subtitle",
|
||||
"description": "version_unsupported_body",
|
||||
"type": "info",
|
||||
"params": {},
|
||||
"link": ""
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"version": "6.3.1",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.1",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.0",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.0",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.2",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.2",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.3",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.3",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.4",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.4",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.5",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.5",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.6",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.6",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.7",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.7",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.8",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.8",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.4.0",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.4.0",
|
||||
"expiration": "2024-01-11T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.9",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.9",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.3.10",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.3.10",
|
||||
"expiration": "2023-12-26T00:00:00Z"
|
||||
},
|
||||
{
|
||||
"version": "6.4.1",
|
||||
"security": false,
|
||||
"infoUrl": "https://github.com/RocketChat/Rocket.Chat/releases/tag/6.4.1",
|
||||
"expiration": "2024-02-09T21:07:52.329Z"
|
||||
},
|
||||
{ "version": "6.5.0-develop", "security": false, "infoUrl": "", "expiration": "2023-10-18T19:24:10.814731189Z" }
|
||||
],
|
||||
"i18n": {
|
||||
"en": {
|
||||
"version_unsupported_body": "An automatic 30-day warning period has been applied to allow time for a workspace admin to update workspace to a supported software version.",
|
||||
"version_unsupported_subtitle": "Mobile and desktop app access to {{instance_ws_name}} will be cut off in {{remaining_days}} days",
|
||||
"version_unsupported_title": "{{instance_ws_name}} is running an unsupported version of Rocket.Chat"
|
||||
}
|
||||
},
|
||||
"enforcementStartDate": "2023-10-31T00:00:00Z"
|
||||
}
|
|
@ -96,3 +96,4 @@ export const VIDEO_CONF = createRequestTypes('VIDEO_CONF', [
|
|||
'ACCEPT_CALL',
|
||||
'SET_CALLING'
|
||||
]);
|
||||
export const SUPPORTED_VERSIONS = createRequestTypes('SUPPORTED_VERSIONS', ['SET']);
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Action } from 'redux';
|
|||
|
||||
import { SERVER } from './actionsTypes';
|
||||
|
||||
interface ISelectServer extends Action {
|
||||
export interface ISelectServerAction extends Action {
|
||||
server: string;
|
||||
version?: string;
|
||||
fetchVersion: boolean;
|
||||
|
@ -12,9 +12,10 @@ interface ISelectServer extends Action {
|
|||
interface ISelectServerSuccess extends Action {
|
||||
server: string;
|
||||
version: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface IServer extends Action {
|
||||
export interface IServerRequestAction extends Action {
|
||||
server: string;
|
||||
username: string | null;
|
||||
fromServerHistory: boolean;
|
||||
|
@ -24,13 +25,14 @@ interface IServerInit extends Action {
|
|||
previousServer: string;
|
||||
}
|
||||
|
||||
interface IServerFailure extends Action {
|
||||
err: any;
|
||||
}
|
||||
export type TActionServer = ISelectServerAction & ISelectServerSuccess & IServerRequestAction & IServerInit;
|
||||
|
||||
export type TActionServer = ISelectServer & ISelectServerSuccess & IServer & IServerInit & IServerFailure;
|
||||
|
||||
export function selectServerRequest(server: string, version?: string, fetchVersion = true, changeServer = false): ISelectServer {
|
||||
export function selectServerRequest(
|
||||
server: string,
|
||||
version?: string,
|
||||
fetchVersion = true,
|
||||
changeServer = false
|
||||
): ISelectServerAction {
|
||||
return {
|
||||
type: SERVER.SELECT_REQUEST,
|
||||
server,
|
||||
|
@ -40,11 +42,20 @@ export function selectServerRequest(server: string, version?: string, fetchVersi
|
|||
};
|
||||
}
|
||||
|
||||
export function selectServerSuccess(server: string, version: string): ISelectServerSuccess {
|
||||
export function selectServerSuccess({
|
||||
server,
|
||||
version,
|
||||
name
|
||||
}: {
|
||||
server: string;
|
||||
version: string;
|
||||
name: string;
|
||||
}): ISelectServerSuccess {
|
||||
return {
|
||||
type: SERVER.SELECT_SUCCESS,
|
||||
server,
|
||||
version
|
||||
version,
|
||||
name
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -54,7 +65,7 @@ export function selectServerFailure(): Action {
|
|||
};
|
||||
}
|
||||
|
||||
export function serverRequest(server: string, username: string | null = null, fromServerHistory = false): IServer {
|
||||
export function serverRequest(server: string, username: string | null = null, fromServerHistory = false): IServerRequestAction {
|
||||
return {
|
||||
type: SERVER.REQUEST,
|
||||
server,
|
||||
|
@ -69,10 +80,9 @@ export function serverSuccess(): Action {
|
|||
};
|
||||
}
|
||||
|
||||
export function serverFailure(err: any): IServerFailure {
|
||||
export function serverFailure(): Action {
|
||||
return {
|
||||
type: SERVER.FAILURE,
|
||||
err
|
||||
type: SERVER.FAILURE
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { Action } from 'redux';
|
||||
|
||||
import { SUPPORTED_VERSIONS } from './actionsTypes';
|
||||
import { TSVDictionary, TSVMessage, TSVStatus } from '../definitions';
|
||||
|
||||
type TSetSupportedVersions = {
|
||||
status: TSVStatus;
|
||||
message?: TSVMessage;
|
||||
i18n?: TSVDictionary;
|
||||
expiration?: string;
|
||||
};
|
||||
type TSetSupportedVersionsAction = Action & TSetSupportedVersions;
|
||||
|
||||
export type TActionSupportedVersions = TSetSupportedVersionsAction;
|
||||
|
||||
export function setSupportedVersions({ status, message, i18n, expiration }: TSetSupportedVersions): TSetSupportedVersionsAction {
|
||||
return {
|
||||
type: SUPPORTED_VERSIONS.SET,
|
||||
status,
|
||||
message,
|
||||
i18n,
|
||||
expiration
|
||||
};
|
||||
}
|
|
@ -51,8 +51,8 @@ export const withActionSheet = (Component: React.ComponentType<any>): typeof Com
|
|||
const actionSheetRef: React.Ref<IActionSheetProvider> = createRef();
|
||||
|
||||
export const ActionSheetProvider = React.memo(({ children }: { children: React.ReactElement | React.ReactElement[] }) => {
|
||||
const getContext = () => ({
|
||||
showActionSheet: (options: TActionSheetOptions) => {
|
||||
const getContext = (): IActionSheetProvider => ({
|
||||
showActionSheet: options => {
|
||||
actionSheetRef.current?.showActionSheet(options);
|
||||
},
|
||||
hideActionSheet: () => {
|
||||
|
@ -69,6 +69,10 @@ export const ActionSheetProvider = React.memo(({ children }: { children: React.R
|
|||
);
|
||||
});
|
||||
|
||||
export const hideActionSheetRef = (): void => {
|
||||
export const showActionSheetRef: IActionSheetProvider['showActionSheet'] = options => {
|
||||
actionSheetRef?.current?.showActionSheet(options);
|
||||
};
|
||||
|
||||
export const hideActionSheetRef: IActionSheetProvider['hideActionSheet'] = () => {
|
||||
actionSheetRef?.current?.hideActionSheet();
|
||||
};
|
||||
|
|
|
@ -44,8 +44,8 @@ describe('ButtonTests', () => {
|
|||
});
|
||||
|
||||
test('find button using accessibilityLabel', async () => {
|
||||
const { findByA11yLabel } = render(<TestButton />);
|
||||
const Button = await findByA11yLabel(testProps.title);
|
||||
const { getByLabelText } = render(<TestButton />);
|
||||
const Button = await getByLabelText(testProps.title);
|
||||
expect(Button).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
|
@ -71,9 +71,7 @@ const Button = ({
|
|||
{loading ? (
|
||||
<ActivityIndicator color={textColor} />
|
||||
) : (
|
||||
<Text style={[styles.text, { color: textColor, fontSize }, styleText]} accessibilityLabel={title}>
|
||||
{title}
|
||||
</Text>
|
||||
<Text style={[styles.text, { color: textColor, fontSize }, styleText]}>{title}</Text>
|
||||
)}
|
||||
</Touchable>
|
||||
);
|
||||
|
|
|
@ -43,7 +43,18 @@ const styles = StyleSheet.create({
|
|||
const Item = ({ title, iconName, onPress, testID, badge, color, disabled, ...props }: IHeaderButtonItem): React.ReactElement => {
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<PlatformPressable onPress={onPress} testID={testID} hitSlop={BUTTON_HIT_SLOP} disabled={disabled} style={styles.container}>
|
||||
<PlatformPressable
|
||||
onPress={onPress}
|
||||
testID={testID}
|
||||
hitSlop={BUTTON_HIT_SLOP}
|
||||
disabled={disabled}
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
opacity: disabled ? 0.5 : 1
|
||||
}
|
||||
]}
|
||||
>
|
||||
<>
|
||||
{iconName ? (
|
||||
<CustomIcon name={iconName} size={24} color={color || colors.headerTintColor} {...props} />
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
import { STATUS_COLORS } from '../../lib/constants';
|
||||
import UnreadBadge from '../UnreadBadge';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -18,6 +17,6 @@ const styles = StyleSheet.create({
|
|||
|
||||
export const BadgeUnread = ({ ...props }): React.ReactElement => <UnreadBadge {...props} style={styles.badgeContainer} small />;
|
||||
|
||||
export const BadgeWarn = (): React.ReactElement => (
|
||||
<View style={[styles.badgeContainer, { width: 10, height: 10, backgroundColor: STATUS_COLORS.disabled }]} />
|
||||
export const BadgeWarn = ({ color }: { color: string }): React.ReactElement => (
|
||||
<View style={[styles.badgeContainer, { width: 10, height: 10, backgroundColor: color }]} />
|
||||
);
|
||||
|
|
|
@ -107,7 +107,7 @@ export const Badge = () => (
|
|||
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} />} />
|
||||
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} tunreadUser={[1]} />} />
|
||||
<HeaderButton.Item iconName='threads' badge={() => <HeaderButton.BadgeUnread tunread={[1]} tunreadGroup={[1]} />} />
|
||||
<HeaderButton.Drawer badge={() => <HeaderButton.BadgeWarn />} />
|
||||
<HeaderButton.Drawer badge={() => <HeaderButton.BadgeWarn color='red' />} />
|
||||
</HeaderButton.Container>
|
||||
)}
|
||||
/>
|
||||
|
@ -120,7 +120,7 @@ const ThemeStory = ({ theme }: { theme: TSupportedThemes }) => (
|
|||
<HeaderExample
|
||||
left={() => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Drawer badge={() => <HeaderButton.BadgeWarn />} />
|
||||
<HeaderButton.Drawer badge={() => <HeaderButton.BadgeWarn color={colors[theme].dangerColor} />} />
|
||||
<HeaderButton.Item iconName='threads' />
|
||||
</HeaderButton.Container>
|
||||
)}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import React from 'react';
|
||||
// @ts-ignore // TODO: Remove on react-native update
|
||||
import { Pressable, Text, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
import { IServerInfo } from '../../definitions';
|
||||
import Check from '../Check';
|
||||
import styles, { ROW_HEIGHT } from './styles';
|
||||
import { themes } from '../../lib/constants';
|
||||
|
@ -13,7 +11,12 @@ import { useTheme } from '../../theme';
|
|||
export { ROW_HEIGHT };
|
||||
|
||||
export interface IServerItem {
|
||||
item: IServerInfo;
|
||||
item: {
|
||||
id: string;
|
||||
iconURL: string;
|
||||
name: string;
|
||||
useRealName?: boolean;
|
||||
};
|
||||
onPress(): void;
|
||||
onLongPress?(): void;
|
||||
hasCheck?: boolean;
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import { View, Text, Linking } from 'react-native';
|
||||
|
||||
import I18n from '../../i18n';
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
import { useTheme } from '../../theme';
|
||||
import { CustomIcon } from '../CustomIcon';
|
||||
import Button from '../Button';
|
||||
import { styles } from './styles';
|
||||
import { LEARN_MORE_URL } from './constants';
|
||||
|
||||
export const SupportedVersionsExpired = () => {
|
||||
const { colors } = useTheme();
|
||||
const { name } = useAppSelector(state => state.server);
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { paddingTop: 120, backgroundColor: colors.focusedBackground }]}>
|
||||
<View style={styles.iconContainer}>
|
||||
<CustomIcon name='warning' size={36} color={colors.dangerColor} />
|
||||
</View>
|
||||
<Text style={[styles.title, { color: colors.titleText }]}>
|
||||
{I18n.t('Supported_versions_expired_title', { workspace_name: name })}
|
||||
</Text>
|
||||
<Text style={[styles.description, { color: colors.bodyText }]}>{I18n.t('Supported_versions_expired_description')}</Text>
|
||||
<Button
|
||||
title={I18n.t('Learn_more')}
|
||||
type='secondary'
|
||||
backgroundColor={colors.chatComponentBackground}
|
||||
onPress={() => Linking.openURL(LEARN_MORE_URL)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,98 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { mockedStore } from '../../reducers/mockedStore';
|
||||
import { SupportedVersionsWarning } from './SupportedVersionsWarning';
|
||||
import { setUser } from '../../actions/login';
|
||||
import { setSupportedVersions } from '../../actions/supportedVersions';
|
||||
import { selectServerSuccess } from '../../actions/server';
|
||||
|
||||
const Render = () => (
|
||||
<Provider store={mockedStore}>
|
||||
<SupportedVersionsWarning />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const TODAY = '2023-04-01T00:00:00.000Z';
|
||||
jest.useFakeTimers('modern');
|
||||
jest.setSystemTime(new Date(TODAY));
|
||||
|
||||
describe('SupportedVersionsWarning', () => {
|
||||
test('empty', () => {
|
||||
render(<Render />);
|
||||
expect(screen.queryByTestId('sv-warn-title')).toBeNull();
|
||||
expect(screen.queryByTestId('sv-warn-subtitle')).toBeNull();
|
||||
expect(screen.queryByTestId('sv-warn-description')).toBeNull();
|
||||
expect(screen.queryByTestId('sv-warn-button')).toBeNull();
|
||||
});
|
||||
|
||||
test('render properly', () => {
|
||||
mockedStore.dispatch(
|
||||
setUser({ language: 'en', username: 'rocket.cat', emails: [{ address: 'test@test.com', verified: true }] })
|
||||
);
|
||||
mockedStore.dispatch(selectServerSuccess({ server: 'https://example.com', version: '1.0', name: 'Test Server' }));
|
||||
mockedStore.dispatch(
|
||||
setSupportedVersions({
|
||||
status: 'warn',
|
||||
message: {
|
||||
link: 'Docs page',
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
remainingDays: 10,
|
||||
type: 'alert',
|
||||
params: {
|
||||
test_a: 'test A works',
|
||||
test_b: ':)'
|
||||
}
|
||||
},
|
||||
i18n: {
|
||||
en: {
|
||||
title_token: '{{instance_ws_name}} is running an unsupported version of Rocket.Chat',
|
||||
subtitle_token: 'Mobile and desktop app access to {{instance_domain}} will be cut off in {{remaining_days}} days.',
|
||||
description_token:
|
||||
'User: {{instance_username}} Email: {{instance_email}} Version: {{instance_version}} Extra params: {{test_a}} {{test_b}}'
|
||||
},
|
||||
'pt-BR': {
|
||||
title_token: 'Alô título',
|
||||
subtitle_token:
|
||||
'{{instance_ws_name}} {{instance_domain}} {{remaining_days}} {{instance_username}} {{instance_email}} {{instance_version}} {{test_a}} {{test_b}}'
|
||||
}
|
||||
},
|
||||
expiration: '2023-05-01T00:00:00.000Z'
|
||||
})
|
||||
);
|
||||
render(<Render />);
|
||||
expect(screen.getByText('Test Server is running an unsupported version of Rocket.Chat')).toBeOnTheScreen();
|
||||
expect(
|
||||
screen.getByText('Mobile and desktop app access to https://example.com will be cut off in 30 days.')
|
||||
).toBeOnTheScreen();
|
||||
expect(
|
||||
screen.getByText('User: rocket.cat Email: test@test.com Version: 1.0 Extra params: test A works :)')
|
||||
).toBeOnTheScreen();
|
||||
expect(screen.getByText('Learn more')).toBeOnTheScreen();
|
||||
});
|
||||
|
||||
test('render another language', () => {
|
||||
mockedStore.dispatch(setUser({ language: 'pt-BR' }));
|
||||
render(<Render />);
|
||||
expect(screen.getByText('Alô título')).toBeOnTheScreen();
|
||||
expect(screen.getByText('Test Server https://example.com 30 rocket.cat test@test.com 1.0 test A works :)')).toBeOnTheScreen();
|
||||
expect(screen.queryByTestId('sv-warn-description')).toBeNull();
|
||||
expect(screen.getByText('Learn more')).toBeOnTheScreen();
|
||||
});
|
||||
|
||||
test('user on unsupported language and fallback to en', () => {
|
||||
mockedStore.dispatch(setUser({ language: 'it' }));
|
||||
render(<Render />);
|
||||
expect(screen.getByText('Test Server is running an unsupported version of Rocket.Chat')).toBeOnTheScreen();
|
||||
expect(
|
||||
screen.getByText('Mobile and desktop app access to https://example.com will be cut off in 30 days.')
|
||||
).toBeOnTheScreen();
|
||||
expect(
|
||||
screen.getByText('User: rocket.cat Email: test@test.com Version: 1.0 Extra params: test A works :)')
|
||||
).toBeOnTheScreen();
|
||||
expect(screen.getByText('Learn more')).toBeOnTheScreen();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,62 @@
|
|||
import React, { ReactElement, useLayoutEffect } from 'react';
|
||||
import { View, Text, Linking } from 'react-native';
|
||||
|
||||
import { useTheme } from '../../theme';
|
||||
import { CustomIcon } from '../CustomIcon';
|
||||
import Button from '../Button';
|
||||
import { styles } from './styles';
|
||||
import { useSupportedVersionMessage } from './useSupportedVersionMessage';
|
||||
import * as HeaderButton from '../HeaderButton';
|
||||
import I18n from '../../i18n';
|
||||
import { LEARN_MORE_URL } from './constants';
|
||||
|
||||
export const SupportedVersionsWarning = ({ navigation, route }: { navigation?: any; route?: any }): ReactElement | null => {
|
||||
const { colors } = useTheme();
|
||||
const message = useSupportedVersionMessage();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
navigation?.setOptions({
|
||||
title: I18n.t('Supported_versions_warning_update_required')
|
||||
});
|
||||
|
||||
if (route?.params?.showCloseButton) {
|
||||
navigation?.setOptions({
|
||||
headerLeft: () => <HeaderButton.CloseModal />
|
||||
});
|
||||
}
|
||||
}, [navigation, route]);
|
||||
|
||||
if (!message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { backgroundColor: colors.focusedBackground }]}>
|
||||
<View style={styles.iconContainer}>
|
||||
<CustomIcon name='warning' size={36} color={colors.dangerColor} />
|
||||
</View>
|
||||
{message.title ? (
|
||||
<Text testID='sv-warn-title' style={[styles.title, { color: colors.titleText }]}>
|
||||
{message.title}
|
||||
</Text>
|
||||
) : null}
|
||||
{message.subtitle ? (
|
||||
<Text testID='sv-warn-subtitle' style={[styles.subtitle, { color: colors.bodyText }]}>
|
||||
{message.subtitle}
|
||||
</Text>
|
||||
) : null}
|
||||
{message.description ? (
|
||||
<Text testID='sv-warn-description' style={[styles.description, { color: colors.bodyText }]}>
|
||||
{message.description}
|
||||
</Text>
|
||||
) : null}
|
||||
<Button
|
||||
testID='sv-warn-button'
|
||||
title='Learn more'
|
||||
type='secondary'
|
||||
backgroundColor={colors.chatComponentBackground}
|
||||
onPress={() => Linking.openURL(message.link || LEARN_MORE_URL)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
export const LEARN_MORE_URL = 'https://go.rocket.chat/i/supported-versions';
|
|
@ -0,0 +1,2 @@
|
|||
export * from './SupportedVersionsWarning';
|
||||
export * from './SupportedVersionsExpired';
|
|
@ -0,0 +1,33 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import sharedStyles from '../../views/Styles';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 16,
|
||||
backgroundColor: '#fff'
|
||||
},
|
||||
iconContainer: {
|
||||
alignItems: 'center',
|
||||
padding: 24
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
lineHeight: 30,
|
||||
marginBottom: 24,
|
||||
...sharedStyles.textBold
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
marginBottom: 24,
|
||||
...sharedStyles.textBold
|
||||
},
|
||||
description: {
|
||||
fontSize: 16,
|
||||
lineHeight: 24,
|
||||
marginBottom: 24,
|
||||
...sharedStyles.textRegular
|
||||
}
|
||||
});
|
|
@ -0,0 +1,47 @@
|
|||
import moment from 'moment';
|
||||
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
|
||||
const applyParams = (message: string, params: Record<string, unknown>) => {
|
||||
const keys = Object.keys(params);
|
||||
const regex = new RegExp(`{{(${keys.join('|')})}}`, 'g');
|
||||
return message.replace(regex, (_, p1) => params[p1] as string);
|
||||
};
|
||||
|
||||
const useUser = () => {
|
||||
const { username, name, emails, language } = useAppSelector(state => state.login.user);
|
||||
const useRealName = useAppSelector(state => state.settings.UI_Use_Real_Name);
|
||||
const user = useRealName ? name : username;
|
||||
return { user, email: emails?.[0]?.address, language };
|
||||
};
|
||||
|
||||
export const useSupportedVersionMessage = () => {
|
||||
const { message, i18n, expiration } = useAppSelector(state => state.supportedVersions);
|
||||
const { name, server, version } = useAppSelector(state => state.server);
|
||||
const { language = 'en', user, email } = useUser();
|
||||
|
||||
const params = {
|
||||
instance_username: user,
|
||||
instance_email: email,
|
||||
instance_ws_name: name,
|
||||
instance_domain: server,
|
||||
remaining_days: moment(expiration).diff(new Date(), 'days'),
|
||||
instance_version: version,
|
||||
...message?.params
|
||||
};
|
||||
|
||||
if (!message || !i18n) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const i18nLang = i18n[language] ?? i18n.en;
|
||||
|
||||
const getTranslation = (key: string | undefined) => (key && i18nLang[key] ? applyParams(i18nLang[key], params) : undefined);
|
||||
|
||||
return {
|
||||
title: getTranslation(message.title),
|
||||
subtitle: getTranslation(message.subtitle),
|
||||
description: getTranslation(message.description),
|
||||
link: message.link
|
||||
};
|
||||
};
|
|
@ -2,6 +2,68 @@ import Model from '@nozbe/watermelondb/Model';
|
|||
|
||||
import { IEnterpriseModules } from '../reducers/enterpriseModules';
|
||||
|
||||
export type TSVStatus = 'supported' | 'expired' | 'warn';
|
||||
|
||||
export type TSVDictionary = {
|
||||
[lng: string]: Record<string, string>;
|
||||
};
|
||||
|
||||
export type TSVMessage = {
|
||||
remainingDays: number;
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
description?: string;
|
||||
type: 'info' | 'alert' | 'error';
|
||||
params?: Record<string, unknown>;
|
||||
link: string;
|
||||
};
|
||||
|
||||
export type TSVVersion = {
|
||||
version: string;
|
||||
expiration: string;
|
||||
messages?: TSVMessage[];
|
||||
};
|
||||
|
||||
export interface ISupportedVersionsData {
|
||||
timestamp: string;
|
||||
enforcementStartDate: string;
|
||||
messages?: TSVMessage[];
|
||||
versions: TSVVersion[];
|
||||
exceptions?: {
|
||||
domain: string;
|
||||
uniqueId: string;
|
||||
messages?: TSVMessage[];
|
||||
versions: TSVVersion[];
|
||||
};
|
||||
i18n?: TSVDictionary;
|
||||
}
|
||||
|
||||
export interface ISupportedVersions extends ISupportedVersionsData {
|
||||
signed: string;
|
||||
}
|
||||
|
||||
export interface IApiServerInfo {
|
||||
version: string;
|
||||
success: boolean;
|
||||
supportedVersions?: ISupportedVersions;
|
||||
minimumClientVersions?: {
|
||||
desktop: string;
|
||||
mobile: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IServerInfo {
|
||||
version: string;
|
||||
success: boolean;
|
||||
supportedVersions?: ISupportedVersionsData | null; // no signed
|
||||
minimumClientVersions?: {
|
||||
desktop: string;
|
||||
mobile: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type TCloudInfo = ISupportedVersions;
|
||||
|
||||
export interface IServer {
|
||||
name: string;
|
||||
iconURL: string;
|
||||
|
@ -17,13 +79,8 @@ export interface IServer {
|
|||
uniqueID: string;
|
||||
enterpriseModules: IEnterpriseModules;
|
||||
E2E_Enable: boolean;
|
||||
}
|
||||
|
||||
export interface IServerInfo {
|
||||
id: string;
|
||||
iconURL: string;
|
||||
name: string;
|
||||
useRealName?: boolean;
|
||||
supportedVersions?: ISupportedVersionsData;
|
||||
supportedVersionsWarningAt?: Date;
|
||||
}
|
||||
|
||||
export type TServerModel = IServer & Model;
|
||||
|
|
|
@ -17,6 +17,7 @@ import { TActionUserTyping } from '../../actions/usersTyping';
|
|||
import { TActionPermissions } from '../../actions/permissions';
|
||||
import { TActionEnterpriseModules } from '../../actions/enterpriseModules';
|
||||
import { TActionVideoConf } from '../../actions/videoConf';
|
||||
import { TActionSupportedVersions } from '../../actions/supportedVersions';
|
||||
// REDUCERS
|
||||
import { IActiveUsers } from '../../reducers/activeUsers';
|
||||
import { IApp } from '../../reducers/app';
|
||||
|
@ -38,6 +39,7 @@ import { IEnterpriseModules } from '../../reducers/enterpriseModules';
|
|||
import { IVideoConf } from '../../reducers/videoConf';
|
||||
import { TActionUsersRoles } from '../../actions/usersRoles';
|
||||
import { TUsersRoles } from '../../reducers/usersRoles';
|
||||
import { ISupportedVersionsState } from '../../reducers/supportedVersions';
|
||||
|
||||
export interface IApplicationState {
|
||||
settings: TSettingsState;
|
||||
|
@ -63,6 +65,7 @@ export interface IApplicationState {
|
|||
roles: IRoles;
|
||||
videoConf: IVideoConf;
|
||||
usersRoles: TUsersRoles;
|
||||
supportedVersions: ISupportedVersionsState;
|
||||
}
|
||||
|
||||
export type TApplicationActions = TActionActiveUsers &
|
||||
|
@ -83,4 +86,5 @@ export type TApplicationActions = TActionActiveUsers &
|
|||
TActionPermissions &
|
||||
TActionEnterpriseModules &
|
||||
TActionVideoConf &
|
||||
TActionUsersRoles;
|
||||
TActionUsersRoles &
|
||||
TActionSupportedVersions;
|
||||
|
|
|
@ -749,5 +749,8 @@
|
|||
"Jitsi_authentication_before_making_calls_ask_admin": "If you believe there are problems with Jitsi and its authentication, ask a workspace administrator for help.",
|
||||
"Continue": "Continue",
|
||||
"Message_has_been_shared": "Message has been shared",
|
||||
"No_channels_in_team": "No Channels on this team"
|
||||
"No_channels_in_team": "No Channels on this team",
|
||||
"Supported_versions_expired_title": "{{workspace_name}} is running an unsupported version of Rocket.Chat",
|
||||
"Supported_versions_expired_description": "An admin needs to update the workspace to a supported version in order to reenable access from mobile and desktop apps.",
|
||||
"Supported_versions_warning_update_required": "Update required"
|
||||
}
|
||||
|
|
|
@ -736,5 +736,8 @@
|
|||
"decline": "Recusar",
|
||||
"accept": "Aceitar",
|
||||
"Incoming_call_from": "Chamada recebida de",
|
||||
"Call_started": "Chamada iniciada"
|
||||
"Call_started": "Chamada iniciada",
|
||||
"Supported_versions_expired_title": "{{workspace_name}} está executando uma versão não suportada do Rocket.Chat",
|
||||
"Supported_versions_expired_description": "Um administrador precisa atualizar o espaço de trabalho para uma versão suportada a fim de reabilitar o acesso a partir de aplicativos móveis e de desktop.",
|
||||
"Supported_versions_warning_update_required": "Atualização necessária"
|
||||
}
|
|
@ -10,6 +10,7 @@ export * from './messagesStatus';
|
|||
export * from './messageTypeLoad';
|
||||
export * from './notifications';
|
||||
export * from './defaultSettings';
|
||||
export * from './supportedVersions';
|
||||
export * from './tablet';
|
||||
export * from './mediaAutoDownload';
|
||||
export * from './userAgent';
|
||||
|
|
|
@ -18,7 +18,6 @@ export const E2E_ROOM_TYPES: Record<string, string> = {
|
|||
export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
|
||||
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
|
||||
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
|
||||
export const MIN_ROCKETCHAT_VERSION = '0.70.0';
|
||||
export const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
||||
export const CURRENT_SERVER = 'currentServer';
|
||||
export const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY';
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
export const SIGNED_SUPPORTED_VERSIONS_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvZ/T/RHOr6+yo/iMLUlf
|
||||
agMiMLFxQR/5Qtc85ykMBvKZqbBGb9zU68VB9n54alrbZG5FdcHkSJXgJIBXF2bk
|
||||
TGTfBi58JmltZirSWzvXoXnT4ieGNZv+BqnP9zzj9HXOVhVncbRmJPEIJOZfL9AQ
|
||||
beix3rPgZx3ZepAaoMQnz11dZKDGzkMN75WkTdf324X3DeFgLVmjsYuAcLl/AJMA
|
||||
uPKSSt0XOQUsfrT7rEqXIrj8rIJcWxIHICMRrwfjw2Qh+3pfIrh7XSzxlW4zCKBN
|
||||
RpavrrCnpOFRfkC5T9eMKLgyapjufOtbjuzu25N3urBsg6oRFNzsGXWp1C7DwUO2
|
||||
kwIDAQAB
|
||||
-----END PUBLIC KEY-----`;
|
|
@ -1,5 +1,6 @@
|
|||
import { Model } from '@nozbe/watermelondb';
|
||||
import { date, field } from '@nozbe/watermelondb/decorators';
|
||||
import { date, field, json } from '@nozbe/watermelondb/decorators';
|
||||
import { sanitizer } from '../../utils';
|
||||
|
||||
export const SERVERS_TABLE = 'servers';
|
||||
|
||||
|
@ -33,4 +34,8 @@ export default class Server extends Model {
|
|||
@field('enterprise_modules') enterpriseModules;
|
||||
|
||||
@field('e2e_enable') E2E_Enable;
|
||||
|
||||
@json('supported_versions', sanitizer) supportedVersions;
|
||||
|
||||
@date('supported_versions_warning_at') supportedVersionsWarningAt;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,22 @@ export default schemaMigrations({
|
|||
]
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
toVersion: 14,
|
||||
steps: [
|
||||
addColumns({
|
||||
table: 'servers',
|
||||
columns: [
|
||||
{ name: 'supported_versions', type: 'string', isOptional: true },
|
||||
{
|
||||
name: 'supported_versions_warning_at',
|
||||
type: 'number',
|
||||
isOptional: true
|
||||
}
|
||||
]
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { appSchema, tableSchema } from '@nozbe/watermelondb';
|
||||
|
||||
export default appSchema({
|
||||
version: 13,
|
||||
version: 14,
|
||||
tables: [
|
||||
tableSchema({
|
||||
name: 'users',
|
||||
|
@ -38,7 +38,9 @@ export default appSchema({
|
|||
{ name: 'biometry', type: 'boolean', isOptional: true }, // deprecated
|
||||
{ name: 'unique_id', type: 'string', isOptional: true },
|
||||
{ name: 'enterprise_modules', type: 'string', isOptional: true },
|
||||
{ name: 'e2e_enable', type: 'boolean', isOptional: true }
|
||||
{ name: 'e2e_enable', type: 'boolean', isOptional: true },
|
||||
{ name: 'supported_versions', type: 'string', isOptional: true },
|
||||
{ name: 'supported_versions_warning_at', type: 'number', isOptional: true }
|
||||
]
|
||||
}),
|
||||
tableSchema({
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { TLoggedUserModel } from '../../../definitions';
|
||||
import database from '..';
|
||||
import { TServerDatabase } from '../interfaces';
|
||||
import { LOGGED_USERS_TABLE } from '../model';
|
||||
|
||||
const getCollection = (db: TServerDatabase) => db.get(LOGGED_USERS_TABLE);
|
||||
|
||||
export const getLoggedUserById = async (userId: string): Promise<TLoggedUserModel | null> => {
|
||||
const db = database.servers;
|
||||
const userCollection = getCollection(db);
|
||||
try {
|
||||
const result = await userCollection.find(userId);
|
||||
return result;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import { TServerModel } from '../../../definitions';
|
||||
import database from '..';
|
||||
import { TServerDatabase } from '../interfaces';
|
||||
import { SERVERS_TABLE } from '../model';
|
||||
|
||||
const getCollection = (db: TServerDatabase) => db.get(SERVERS_TABLE);
|
||||
|
||||
export const getServerById = async (server: string): Promise<TServerModel | null> => {
|
||||
const db = database.servers;
|
||||
const serverCollection = getCollection(db);
|
||||
try {
|
||||
const result = await serverCollection.find(server);
|
||||
return result;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,523 @@
|
|||
import { ISupportedVersionsData } from '../../definitions';
|
||||
import { checkSupportedVersions, getMessage } from './checkSupportedVersions';
|
||||
|
||||
const MOCK_I18N = {
|
||||
en: {
|
||||
message_token: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
};
|
||||
const TODAY = '2023-04-01T00:00:00.000Z';
|
||||
const MOCK: ISupportedVersionsData = {
|
||||
timestamp: TODAY,
|
||||
enforcementStartDate: '2023-04-02T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
i18n: MOCK_I18N,
|
||||
versions: [
|
||||
{
|
||||
version: '1.5.0',
|
||||
expiration: '2023-05-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-02-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.1.0',
|
||||
expiration: '2023-01-10T00:00:00.000Z'
|
||||
}
|
||||
],
|
||||
exceptions: {
|
||||
domain: 'https://open.rocket.chat',
|
||||
uniqueId: '123',
|
||||
versions: [
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-05-01T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const MOCK_BUILTIN_I18N = {
|
||||
en: {
|
||||
builtin_i18n: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
};
|
||||
jest.mock('../../../app-supportedversions.json', () => ({
|
||||
timestamp: '2023-04-01T00:00:00.000Z',
|
||||
enforcementStartDate: '2023-04-02T00:00:00.000Z',
|
||||
i18n: {
|
||||
en: {
|
||||
builtin_i18n: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
},
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'builtin_i18n',
|
||||
subtitle: 'builtin_i18n',
|
||||
description: 'builtin_i18n',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
versions: [
|
||||
{
|
||||
version: '1.5.0',
|
||||
expiration: '2023-05-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 10,
|
||||
message: '1.4',
|
||||
type: 'info'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
message: '1.3',
|
||||
type: 'info'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-02-10T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
jest.useFakeTimers('modern');
|
||||
jest.setSystemTime(new Date(TODAY));
|
||||
|
||||
describe('checkSupportedVersions', () => {
|
||||
describe('Built-in supported versions', () => {
|
||||
test('no supported versions', () => {
|
||||
expect(checkSupportedVersions({ supportedVersions: undefined, serverVersion: '1.5.0' })).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
expect(checkSupportedVersions({ supportedVersions: undefined, serverVersion: '1.1.0' })).toMatchObject({
|
||||
status: 'warn',
|
||||
i18n: {
|
||||
en: {
|
||||
builtin_i18n: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
},
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'builtin_i18n',
|
||||
subtitle: 'builtin_i18n',
|
||||
description: 'builtin_i18n',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('deprecated version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: { ...MOCK, timestamp: '2023-03-01T00:00:00.000Z' },
|
||||
serverVersion: '1.2.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
i18n: {
|
||||
en: {
|
||||
builtin_i18n: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
},
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'builtin_i18n',
|
||||
subtitle: 'builtin_i18n',
|
||||
description: 'builtin_i18n',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('valid version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: { ...MOCK, timestamp: '2023-03-01T00:00:00.000Z' },
|
||||
serverVersion: '1.5.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
});
|
||||
|
||||
test('valid version with message', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: { ...MOCK, timestamp: '2023-03-01T00:00:00.000Z' },
|
||||
serverVersion: '1.4.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 10,
|
||||
message: '1.4',
|
||||
type: 'info'
|
||||
},
|
||||
i18n: MOCK_BUILTIN_I18N
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Backend/Cloud and exceptions', () => {
|
||||
test('valid version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.4.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
i18n: MOCK_I18N,
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('expired version and valid exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.3.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
});
|
||||
|
||||
test('expired version and expired exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.2.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
i18n: MOCK_I18N,
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('expired version and no exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.1.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
i18n: MOCK_I18N,
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('server version is not supported', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.0.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
i18n: MOCK_I18N,
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Messages', () => {
|
||||
const MOCK_MESSAGES: ISupportedVersionsData = {
|
||||
timestamp: TODAY,
|
||||
enforcementStartDate: '2023-04-02T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 60,
|
||||
title: 'title_root',
|
||||
subtitle: 'subtitle_root',
|
||||
description: 'description_root',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
i18n: {
|
||||
en: {
|
||||
message_token: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
},
|
||||
versions: [
|
||||
{
|
||||
version: '1.5.0',
|
||||
expiration: '2023-05-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'title_version',
|
||||
subtitle: 'subtitle_version',
|
||||
description: 'description_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
{
|
||||
remainingDays: 30,
|
||||
title: 'title_version',
|
||||
subtitle: 'subtitle_version',
|
||||
description: 'description_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-02-10T00:00:00.000Z'
|
||||
}
|
||||
],
|
||||
exceptions: {
|
||||
domain: 'https://open.rocket.chat',
|
||||
uniqueId: '123',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'title_exception',
|
||||
subtitle: 'subtitle_exception',
|
||||
description: 'description_exception',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
versions: [
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-05-01T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 30,
|
||||
title: 'title_exception_version',
|
||||
subtitle: 'subtitle_exception_version',
|
||||
description: 'description_exception_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
test('from exception version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.3.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 30,
|
||||
title: 'title_exception_version',
|
||||
subtitle: 'subtitle_exception_version',
|
||||
description: 'description_exception_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('from exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.2.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'title_exception',
|
||||
subtitle: 'subtitle_exception',
|
||||
description: 'description_exception',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('from supported version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.4.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'title_version',
|
||||
subtitle: 'subtitle_version',
|
||||
description: 'description_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
i18n: MOCK_I18N
|
||||
});
|
||||
});
|
||||
|
||||
test('from root node', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.5.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 60,
|
||||
title: 'title_root',
|
||||
subtitle: 'subtitle_root',
|
||||
description: 'description_root',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
i18n: MOCK_I18N
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMessage', () => {
|
||||
test('no messages', () => {
|
||||
expect(getMessage({ messages: undefined, expiration: '2023-04-10T00:00:00.000Z' })).toBeUndefined();
|
||||
});
|
||||
|
||||
test('no expiration or already expired', () => {
|
||||
expect(getMessage({ messages: undefined, expiration: undefined })).toBeUndefined();
|
||||
expect(getMessage({ messages: undefined, expiration: '2023-01-10T00:00:00.000Z' })).toBeUndefined();
|
||||
});
|
||||
|
||||
test('receives a message that should not be triggered yet', () => {
|
||||
expect(
|
||||
getMessage({
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 1,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
})
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
test('receives two messages and returns the appropriate one', () => {
|
||||
expect(
|
||||
getMessage({
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 11,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
{
|
||||
remainingDays: 10,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
})
|
||||
).toMatchObject({
|
||||
remainingDays: 10,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,481 @@
|
|||
import { ISupportedVersionsData } from '../../definitions';
|
||||
import { checkSupportedVersions, getMessage } from './checkSupportedVersions';
|
||||
|
||||
const MOCK_I18N = {
|
||||
en: {
|
||||
message_token: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
};
|
||||
const TODAY = '2023-04-01T00:00:00.000Z';
|
||||
const MOCK: ISupportedVersionsData = {
|
||||
timestamp: TODAY,
|
||||
enforcementStartDate: TODAY,
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
i18n: MOCK_I18N,
|
||||
versions: [
|
||||
{
|
||||
version: '1.5.0',
|
||||
expiration: '2023-05-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-02-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.1.0',
|
||||
expiration: '2023-01-10T00:00:00.000Z'
|
||||
}
|
||||
],
|
||||
exceptions: {
|
||||
domain: 'https://open.rocket.chat',
|
||||
uniqueId: '123',
|
||||
versions: [
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-05-01T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
const MOCK_BUILTIN_I18N = {
|
||||
en: {
|
||||
builtin_i18n: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
};
|
||||
jest.mock('../../../app-supportedversions.json', () => ({
|
||||
timestamp: '2023-04-01T00:00:00.000Z',
|
||||
enforcementStartDate: TODAY,
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'builtin_i18n',
|
||||
subtitle: 'builtin_i18n',
|
||||
description: 'builtin_i18n',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
i18n: {
|
||||
en: {
|
||||
builtin_i18n: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
},
|
||||
versions: [
|
||||
{
|
||||
version: '1.5.0',
|
||||
expiration: '2023-05-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 10,
|
||||
message: '1.4',
|
||||
type: 'info'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
message: '1.3',
|
||||
type: 'info'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-02-10T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
jest.useFakeTimers('modern');
|
||||
jest.setSystemTime(new Date(TODAY));
|
||||
|
||||
describe('checkSupportedVersions', () => {
|
||||
describe('Built-in supported versions', () => {
|
||||
test('no supported versions', () => {
|
||||
expect(checkSupportedVersions({ supportedVersions: undefined, serverVersion: '1.5.0' })).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
expect(checkSupportedVersions({ supportedVersions: undefined, serverVersion: '1.1.0' })).toMatchObject({
|
||||
status: 'expired'
|
||||
});
|
||||
});
|
||||
|
||||
test('deprecated version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: { ...MOCK, timestamp: '2023-03-01T00:00:00.000Z' },
|
||||
serverVersion: '1.2.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'expired'
|
||||
});
|
||||
});
|
||||
|
||||
test('valid version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: { ...MOCK, timestamp: '2023-03-01T00:00:00.000Z' },
|
||||
serverVersion: '1.5.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
});
|
||||
|
||||
test('valid version with message', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: { ...MOCK, timestamp: '2023-03-01T00:00:00.000Z' },
|
||||
serverVersion: '1.4.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 10,
|
||||
message: '1.4',
|
||||
type: 'info'
|
||||
},
|
||||
i18n: MOCK_BUILTIN_I18N
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Backend/Cloud and exceptions', () => {
|
||||
test('valid version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.5.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
});
|
||||
|
||||
test('warning version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.4.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'message_token',
|
||||
subtitle: 'message_token',
|
||||
description: 'message_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
i18n: MOCK_I18N
|
||||
});
|
||||
});
|
||||
|
||||
test('expired version and valid exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.3.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'supported'
|
||||
});
|
||||
});
|
||||
|
||||
test('expired version and expired exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.2.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'expired'
|
||||
});
|
||||
});
|
||||
|
||||
test('expired version and no exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.1.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'expired'
|
||||
});
|
||||
});
|
||||
|
||||
test('server version is not supported', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK,
|
||||
serverVersion: '1.0.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'expired'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Messages', () => {
|
||||
const MOCK_MESSAGES: ISupportedVersionsData = {
|
||||
timestamp: TODAY,
|
||||
enforcementStartDate: TODAY,
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 60,
|
||||
title: 'title_root',
|
||||
subtitle: 'subtitle_root',
|
||||
description: 'description_root',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
i18n: {
|
||||
en: {
|
||||
message_token: 'Your server is about to be deprecated. Please update to the latest version.'
|
||||
}
|
||||
},
|
||||
versions: [
|
||||
{
|
||||
version: '1.5.0',
|
||||
expiration: '2023-05-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.4.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'title_version',
|
||||
subtitle: 'subtitle_version',
|
||||
description: 'description_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
{
|
||||
remainingDays: 30,
|
||||
title: 'title_version',
|
||||
subtitle: 'subtitle_version',
|
||||
description: 'description_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-03-10T00:00:00.000Z'
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-02-10T00:00:00.000Z'
|
||||
}
|
||||
],
|
||||
exceptions: {
|
||||
domain: 'https://open.rocket.chat',
|
||||
uniqueId: '123',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 15,
|
||||
title: 'title_exception',
|
||||
subtitle: 'subtitle_exception',
|
||||
description: 'description_exception',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
versions: [
|
||||
{
|
||||
version: '1.3.0',
|
||||
expiration: '2023-05-01T00:00:00.000Z',
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 30,
|
||||
title: 'title_exception_version',
|
||||
subtitle: 'subtitle_exception_version',
|
||||
description: 'description_exception_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
version: '1.2.0',
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
test('from exception version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.3.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 30,
|
||||
title: 'title_exception_version',
|
||||
subtitle: 'subtitle_exception_version',
|
||||
description: 'description_exception_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('from exception', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.2.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'title_exception',
|
||||
subtitle: 'subtitle_exception',
|
||||
description: 'description_exception',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('from supported version', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.4.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 15,
|
||||
title: 'title_version',
|
||||
subtitle: 'subtitle_version',
|
||||
description: 'description_version',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
i18n: MOCK_I18N
|
||||
});
|
||||
});
|
||||
|
||||
test('from root node', () => {
|
||||
expect(
|
||||
checkSupportedVersions({
|
||||
supportedVersions: MOCK_MESSAGES,
|
||||
serverVersion: '1.5.0'
|
||||
})
|
||||
).toMatchObject({
|
||||
status: 'warn',
|
||||
message: {
|
||||
remainingDays: 60,
|
||||
title: 'title_root',
|
||||
subtitle: 'subtitle_root',
|
||||
description: 'description_root',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
i18n: MOCK_I18N
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMessage', () => {
|
||||
test('no messages', () => {
|
||||
expect(getMessage({ messages: undefined, expiration: '2023-04-10T00:00:00.000Z' })).toBeUndefined();
|
||||
});
|
||||
|
||||
test('no expiration or already expired', () => {
|
||||
expect(getMessage({ messages: undefined, expiration: undefined })).toBeUndefined();
|
||||
expect(getMessage({ messages: undefined, expiration: '2023-01-10T00:00:00.000Z' })).toBeUndefined();
|
||||
});
|
||||
|
||||
test('receives a message that should not be triggered yet', () => {
|
||||
expect(
|
||||
getMessage({
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 1,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
})
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
test('receives two messages and returns the appropriate one', () => {
|
||||
expect(
|
||||
getMessage({
|
||||
messages: [
|
||||
{
|
||||
remainingDays: 11,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
},
|
||||
{
|
||||
remainingDays: 10,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
}
|
||||
],
|
||||
expiration: '2023-04-10T00:00:00.000Z'
|
||||
})
|
||||
).toMatchObject({
|
||||
remainingDays: 10,
|
||||
title: 'title_token',
|
||||
subtitle: 'subtitle_token',
|
||||
description: 'description_token',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,90 @@
|
|||
import moment from 'moment';
|
||||
import coerce from 'semver/functions/coerce';
|
||||
|
||||
import { ISupportedVersionsData, TSVDictionary, TSVMessage, TSVStatus } from '../../definitions';
|
||||
import builtInSupportedVersions from '../../../app-supportedversions.json';
|
||||
|
||||
export const getMessage = ({
|
||||
messages,
|
||||
expiration
|
||||
}: {
|
||||
messages?: TSVMessage[];
|
||||
expiration?: string;
|
||||
}): TSVMessage | undefined => {
|
||||
if (!messages?.length || !expiration || moment(expiration).diff(new Date(), 'days') < 0) {
|
||||
return;
|
||||
}
|
||||
const sortedMessages = messages.sort((a, b) => a.remainingDays - b.remainingDays);
|
||||
return sortedMessages.find(({ remainingDays }) => moment(expiration).diff(new Date(), 'days') <= remainingDays);
|
||||
};
|
||||
|
||||
const getStatus = ({ expiration, message }: { expiration?: string; message?: TSVMessage }): TSVStatus => {
|
||||
if (!(expiration && new Date(expiration) >= new Date())) {
|
||||
return 'expired';
|
||||
}
|
||||
if (message) {
|
||||
return 'warn';
|
||||
}
|
||||
return 'supported';
|
||||
};
|
||||
|
||||
export const checkSupportedVersions = function ({
|
||||
supportedVersions,
|
||||
serverVersion
|
||||
}: {
|
||||
supportedVersions?: ISupportedVersionsData;
|
||||
serverVersion: string;
|
||||
}): {
|
||||
status: TSVStatus;
|
||||
message?: TSVMessage;
|
||||
i18n?: TSVDictionary;
|
||||
expiration?: string;
|
||||
} {
|
||||
let sv: ISupportedVersionsData;
|
||||
if (!supportedVersions || supportedVersions.timestamp < builtInSupportedVersions.timestamp) {
|
||||
// Built-in supported versions
|
||||
sv = builtInSupportedVersions as ISupportedVersionsData;
|
||||
} else {
|
||||
// Backend/Cloud
|
||||
sv = supportedVersions;
|
||||
}
|
||||
|
||||
const versionInfo = sv.versions.find(({ version }) => coerce(version)?.version === serverVersion);
|
||||
if (versionInfo && new Date(versionInfo.expiration) >= new Date()) {
|
||||
const messages = versionInfo?.messages || sv?.messages;
|
||||
const message = getMessage({ messages, expiration: versionInfo.expiration });
|
||||
return {
|
||||
status: getStatus({ expiration: versionInfo?.expiration, message }),
|
||||
message,
|
||||
i18n: message ? sv?.i18n : undefined,
|
||||
expiration: versionInfo?.expiration
|
||||
};
|
||||
}
|
||||
|
||||
// Exceptions
|
||||
const exception = sv.exceptions?.versions.find(({ version }) => coerce(version)?.version === serverVersion);
|
||||
const messages = exception?.messages || sv.exceptions?.messages || versionInfo?.messages || sv.messages;
|
||||
const message = getMessage({ messages, expiration: exception?.expiration });
|
||||
const status = getStatus({ expiration: exception?.expiration, message });
|
||||
|
||||
// TODO: enforcement start date is temp only. Remove after a few releases.
|
||||
if (status === 'expired' && sv?.enforcementStartDate && new Date(sv.enforcementStartDate) > new Date()) {
|
||||
const enforcementMessage = getMessage({
|
||||
messages,
|
||||
expiration: sv.enforcementStartDate
|
||||
});
|
||||
return {
|
||||
status: 'warn',
|
||||
message: enforcementMessage,
|
||||
i18n: enforcementMessage ? sv?.i18n : undefined,
|
||||
expiration: sv.enforcementStartDate
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status,
|
||||
message,
|
||||
i18n: message ? sv?.i18n : undefined,
|
||||
expiration: exception?.expiration
|
||||
};
|
||||
};
|
|
@ -0,0 +1,104 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
||||
import { KJUR } from 'jsrsasign';
|
||||
|
||||
import { getSupportedVersionsCloud } from '../services/restApi';
|
||||
import { TCloudInfo, IServerInfo, ISupportedVersions, ISupportedVersionsData, IApiServerInfo } from '../../definitions';
|
||||
import { selectServerFailure } from '../../actions/server';
|
||||
import { store } from '../store/auxStore';
|
||||
import I18n from '../../i18n';
|
||||
import { SIGNED_SUPPORTED_VERSIONS_PUBLIC_KEY } from '../constants';
|
||||
|
||||
interface IServerInfoFailure {
|
||||
success: false;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface IServerInfoSuccess extends IServerInfo {
|
||||
success: true;
|
||||
}
|
||||
|
||||
export type TServerInfoResult = IServerInfoSuccess | IServerInfoFailure;
|
||||
|
||||
// Verifies if JWT is valid and returns the payload
|
||||
const verifyJWT = (jwt?: string): ISupportedVersionsData | null => {
|
||||
try {
|
||||
if (!jwt) {
|
||||
return null;
|
||||
}
|
||||
const isValid = KJUR.jws.JWS.verify(jwt, SIGNED_SUPPORTED_VERSIONS_PUBLIC_KEY, ['RS256']);
|
||||
if (!isValid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { payloadObj } = KJUR.jws.JWS.parse(jwt);
|
||||
return payloadObj as ISupportedVersions;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export async function getServerInfo(server: string): Promise<TServerInfoResult> {
|
||||
try {
|
||||
const response = await RNFetchBlob.fetch('GET', `${server}/api/info`, {
|
||||
...RocketChatSettings.customHeaders
|
||||
});
|
||||
try {
|
||||
const jsonRes: IApiServerInfo = response.json();
|
||||
if (!jsonRes?.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: I18n.t('Not_RC_Server', { contact: I18n.t('Contact_your_server_admin') })
|
||||
};
|
||||
}
|
||||
|
||||
// Makes use of signed JWT to get supported versions
|
||||
const supportedVersions = verifyJWT(jsonRes.supportedVersions?.signed);
|
||||
|
||||
// if backend doesn't have supported versions or JWT is invalid, request from cloud
|
||||
if (!supportedVersions) {
|
||||
const cloudInfo = await getCloudInfo();
|
||||
|
||||
// Makes use of signed JWT to get supported versions
|
||||
const supportedVersionsCloud = verifyJWT(cloudInfo?.signed);
|
||||
|
||||
return {
|
||||
...jsonRes,
|
||||
success: true,
|
||||
supportedVersions: supportedVersionsCloud
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...jsonRes,
|
||||
success: true,
|
||||
supportedVersions
|
||||
};
|
||||
} catch (error) {
|
||||
// Request is successful, but response isn't a json
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e?.message) {
|
||||
if (e.message === 'Aborted') {
|
||||
store.dispatch(selectServerFailure());
|
||||
throw e;
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: e.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: I18n.t('Not_RC_Server', { contact: I18n.t('Contact_your_server_admin') })
|
||||
};
|
||||
}
|
||||
|
||||
export const getCloudInfo = async (): Promise<TCloudInfo | null> => {
|
||||
const uniqueId = store.getState().settings.uniqueID as string;
|
||||
const domain = store.getState().server.server;
|
||||
const response = await getSupportedVersionsCloud(uniqueId, domain);
|
||||
return response.json() as unknown as TCloudInfo;
|
||||
};
|
|
@ -27,7 +27,7 @@ export const headers: CustomHeaders = {
|
|||
};
|
||||
|
||||
let _basicAuth;
|
||||
export const setBasicAuth = (basicAuth: string): void => {
|
||||
export const setBasicAuth = (basicAuth: string | null): void => {
|
||||
_basicAuth = basicAuth;
|
||||
if (basicAuth) {
|
||||
RocketChatSettings.customHeaders = { ...headers, Authorization: `Basic ${_basicAuth}` };
|
||||
|
|
|
@ -38,4 +38,6 @@ export * from './parseSettings';
|
|||
export * from './subscribeRooms';
|
||||
export * from './serializeAsciiUrl';
|
||||
export * from './isRoomFederated';
|
||||
export * from './checkSupportedVersions';
|
||||
export * from './getServerInfo';
|
||||
export * from './isImageBase64';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import RNFetchBlob from 'rn-fetch-blob';
|
||||
import { settings as RocketChatSettings, Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
|
||||
import { Rocketchat as RocketchatClient } from '@rocket.chat/sdk';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { InteractionManager } from 'react-native';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
@ -8,7 +7,6 @@ import log from '../methods/helpers/log';
|
|||
import { setActiveUsers } from '../../actions/activeUsers';
|
||||
import protectedFunction from '../methods/helpers/protectedFunction';
|
||||
import database from '../database';
|
||||
import { selectServerFailure } from '../../actions/server';
|
||||
import { twoFactor } from './twoFactor';
|
||||
import { store } from '../store/auxStore';
|
||||
import { loginRequest, setLoginServices, setUser } from '../../actions/login';
|
||||
|
@ -19,7 +17,7 @@ import { connectRequest, connectSuccess, disconnect as disconnectAction } from '
|
|||
import { updatePermission } from '../../actions/permissions';
|
||||
import EventEmitter from '../methods/helpers/events';
|
||||
import { updateSettings } from '../../actions/settings';
|
||||
import { defaultSettings, MIN_ROCKETCHAT_VERSION } from '../constants';
|
||||
import { defaultSettings } from '../constants';
|
||||
import {
|
||||
getSettings,
|
||||
IActiveUsers,
|
||||
|
@ -49,7 +47,7 @@ let notifyAllListener: any;
|
|||
let rolesListener: any;
|
||||
let notifyLoggedListener: any;
|
||||
|
||||
function connect({ server, logoutOnError = false }: { server: string; logoutOnError: boolean }): Promise<void> {
|
||||
function connect({ server, logoutOnError = false }: { server: string; logoutOnError?: boolean }): Promise<void> {
|
||||
return new Promise<void>(resolve => {
|
||||
if (sdk.current?.client?.host === server) {
|
||||
return resolve();
|
||||
|
@ -401,51 +399,11 @@ function disconnect() {
|
|||
return sdk.disconnect();
|
||||
}
|
||||
|
||||
async function getServerInfo(server: string) {
|
||||
try {
|
||||
const response = await RNFetchBlob.fetch('GET', `${server}/api/info`, { ...RocketChatSettings.customHeaders });
|
||||
try {
|
||||
// Try to resolve as json
|
||||
const jsonRes: { version?: string; success: boolean } = response.json();
|
||||
if (!jsonRes?.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: I18n.t('Not_RC_Server', { contact: I18n.t('Contact_your_server_admin') })
|
||||
};
|
||||
}
|
||||
if (compareServerVersion(jsonRes.version, 'lowerThan', MIN_ROCKETCHAT_VERSION)) {
|
||||
return {
|
||||
success: false,
|
||||
message: I18n.t('Invalid_server_version', {
|
||||
currentVersion: jsonRes.version,
|
||||
minVersion: MIN_ROCKETCHAT_VERSION
|
||||
})
|
||||
};
|
||||
}
|
||||
return jsonRes;
|
||||
} catch (error) {
|
||||
// Request is successful, but response isn't a json
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e?.message) {
|
||||
if (e.message === 'Aborted') {
|
||||
store.dispatch(selectServerFailure());
|
||||
throw e;
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: e.message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: I18n.t('Not_RC_Server', { contact: I18n.t('Contact_your_server_admin') })
|
||||
};
|
||||
}
|
||||
|
||||
async function getWebsocketInfo({ server }: { server: string }) {
|
||||
async function getWebsocketInfo({
|
||||
server
|
||||
}: {
|
||||
server: string;
|
||||
}): Promise<{ success: true } | { success: false; message: string }> {
|
||||
const websocketSdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: isSsl(server) });
|
||||
|
||||
try {
|
||||
|
@ -530,7 +488,6 @@ export {
|
|||
abort,
|
||||
connect,
|
||||
disconnect,
|
||||
getServerInfo,
|
||||
getWebsocketInfo,
|
||||
stopListener,
|
||||
getLoginServices,
|
||||
|
|
|
@ -999,3 +999,6 @@ export const notifyUser = (type: string, params: Record<string, any>): Promise<b
|
|||
sdk.methodCall('stream-notify-user', type, params);
|
||||
|
||||
export const getUsersRoles = (): Promise<boolean> => sdk.methodCall('getUserRoles');
|
||||
|
||||
export const getSupportedVersionsCloud = (uniqueId?: string, domain?: string) =>
|
||||
fetch(`https://releases.rocket.chat/v2/server/supportedVersions?uniqueId=${uniqueId}&domain=${domain}&source=mobile`);
|
||||
|
|
|
@ -23,6 +23,7 @@ import permissions from './permissions';
|
|||
import roles from './roles';
|
||||
import videoConf from './videoConf';
|
||||
import usersRoles from './usersRoles';
|
||||
import supportedVersions from './supportedVersions';
|
||||
|
||||
export default combineReducers({
|
||||
settings,
|
||||
|
@ -47,5 +48,6 @@ export default combineReducers({
|
|||
permissions,
|
||||
roles,
|
||||
videoConf,
|
||||
usersRoles
|
||||
usersRoles,
|
||||
supportedVersions
|
||||
});
|
||||
|
|
|
@ -41,9 +41,10 @@ describe('test server reducer', () => {
|
|||
it('should return modified store after selectServerSucess', () => {
|
||||
const server = 'https://open.rocket.chat/';
|
||||
const version = '4.1.0';
|
||||
mockedStore.dispatch(selectServerSuccess(server, version));
|
||||
const name = 'Rocket.Chat';
|
||||
mockedStore.dispatch(selectServerSuccess({ server, version, name: 'Rocket.Chat' }));
|
||||
const state = mockedStore.getState().server;
|
||||
const manipulated = { ...initialState, server, version, connected: true, loading: false };
|
||||
const manipulated = { ...initialState, server, version, connected: true, loading: false, name };
|
||||
expect(state).toEqual(manipulated);
|
||||
});
|
||||
|
||||
|
@ -61,7 +62,7 @@ describe('test server reducer', () => {
|
|||
});
|
||||
|
||||
it('should return modified store after serverRequestFailure', () => {
|
||||
mockedStore.dispatch(serverFailure('error'));
|
||||
mockedStore.dispatch(serverFailure());
|
||||
const state = mockedStore.getState().server;
|
||||
expect(state.failure).toEqual(true);
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ export interface IServer {
|
|||
failure: boolean;
|
||||
server: string;
|
||||
version: string | null;
|
||||
name: string | null;
|
||||
loading: boolean;
|
||||
previousServer: string | null;
|
||||
changingServer: boolean;
|
||||
|
@ -18,6 +19,7 @@ export const initialState: IServer = {
|
|||
failure: false,
|
||||
server: '',
|
||||
version: null,
|
||||
name: null,
|
||||
loading: true,
|
||||
previousServer: null,
|
||||
changingServer: false
|
||||
|
@ -53,6 +55,7 @@ export default function server(state = initialState, action: TActionServer): ISe
|
|||
...state,
|
||||
server: action.server,
|
||||
version: action.version,
|
||||
name: action.name,
|
||||
connecting: false,
|
||||
connected: true,
|
||||
loading: false,
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import { TSVMessage } from '../definitions';
|
||||
import { setSupportedVersions } from '../actions/supportedVersions';
|
||||
import { mockedStore } from './mockedStore';
|
||||
import { initialState } from './supportedVersions';
|
||||
|
||||
describe('test supportedVersions reducer', () => {
|
||||
test('initial state', () => {
|
||||
const state = mockedStore.getState().supportedVersions;
|
||||
expect(state).toEqual(initialState);
|
||||
});
|
||||
|
||||
test('set supported versions', () => {
|
||||
const status = 'supported';
|
||||
const message: TSVMessage = {
|
||||
remainingDays: 15,
|
||||
title: 'title',
|
||||
subtitle: 'subtitle',
|
||||
description: 'description',
|
||||
type: 'info',
|
||||
link: 'Docs page'
|
||||
};
|
||||
const i18n = {
|
||||
en: {
|
||||
title: '{{workspace-name}} is running an unsupported version of Rocket.Chat',
|
||||
subtitle: 'Mobile and desktop app access to {{workspace-name}} will be cut off in XX days.',
|
||||
description:
|
||||
'An automatic 30-day warning period has been applied to allow time for a workspace admin to update workspace to a supported software version.'
|
||||
}
|
||||
};
|
||||
mockedStore.dispatch(setSupportedVersions({ status, message, i18n }));
|
||||
const state = mockedStore.getState().supportedVersions;
|
||||
expect(state).toEqual({ status, message, i18n });
|
||||
});
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
import { TSVDictionary, TSVMessage, TSVStatus } from '../definitions';
|
||||
import { SUPPORTED_VERSIONS } from '../actions/actionsTypes';
|
||||
import { TActionSupportedVersions } from '../actions/supportedVersions';
|
||||
|
||||
export interface ISupportedVersionsState {
|
||||
status: TSVStatus;
|
||||
message?: TSVMessage;
|
||||
i18n?: TSVDictionary;
|
||||
expiration?: string;
|
||||
}
|
||||
|
||||
export const initialState: ISupportedVersionsState = { status: 'supported' };
|
||||
|
||||
export default (state = initialState, action: TActionSupportedVersions): ISupportedVersionsState => {
|
||||
switch (action.type) {
|
||||
case SUPPORTED_VERSIONS.SET:
|
||||
return {
|
||||
...state,
|
||||
status: action.status,
|
||||
message: action.message,
|
||||
i18n: action.i18n,
|
||||
expiration: action.expiration
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import { call, cancel, delay, fork, put, race, select, take, takeLatest } from 'redux-saga/effects';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import moment from 'moment';
|
||||
import * as types from '../actions/actionsTypes';
|
||||
import { appStart } from '../actions/app';
|
||||
import { selectServerRequest, serverFinishAdd } from '../actions/server';
|
||||
|
@ -37,12 +39,41 @@ import {
|
|||
} from '../lib/methods';
|
||||
import { Services } from '../lib/services';
|
||||
import { setUsersRoles } from '../actions/usersRoles';
|
||||
import { getServerById } from '../lib/database/services/Server';
|
||||
import appNavigation from '../lib/navigation/appNavigation';
|
||||
import { showActionSheetRef } from '../containers/ActionSheet';
|
||||
import { SupportedVersionsWarning } from '../containers/SupportedVersions';
|
||||
|
||||
const getServer = state => state.server.server;
|
||||
const loginWithPasswordCall = args => Services.loginWithPassword(args);
|
||||
const loginCall = (credentials, isFromWebView) => Services.login(credentials, isFromWebView);
|
||||
const logoutCall = args => logout(args);
|
||||
|
||||
const showSupportedVersionsWarning = function* showSupportedVersionsWarning(server) {
|
||||
const { status: supportedVersionsStatus } = yield select(state => state.supportedVersions);
|
||||
if (supportedVersionsStatus !== 'warn') {
|
||||
return;
|
||||
}
|
||||
const serverRecord = yield getServerById(server);
|
||||
const isMasterDetail = yield select(state => state.app.isMasterDetail);
|
||||
|
||||
if (!serverRecord || moment(serverRecord?.supportedVersionsWarningAt).diff(new Date(), 'hours') <= 12) {
|
||||
return;
|
||||
}
|
||||
|
||||
const serversDB = database.servers;
|
||||
yield serversDB.write(async () => {
|
||||
await serverRecord.update(r => {
|
||||
r.supportedVersionsWarningAt = new Date();
|
||||
});
|
||||
});
|
||||
if (isMasterDetail) {
|
||||
appNavigation.navigate('ModalStackNavigator', { screen: 'SupportedVersionsWarning', params: { showCloseButton: true } });
|
||||
} else {
|
||||
showActionSheetRef({ children: <SupportedVersionsWarning /> });
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoginRequest = function* handleLoginRequest({
|
||||
credentials,
|
||||
logoutOnError = false,
|
||||
|
@ -209,6 +240,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
|
|||
if (inviteLinkToken) {
|
||||
yield put(inviteLinksRequest(inviteLinkToken));
|
||||
}
|
||||
yield showSupportedVersionsWarning(server);
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
import { put, takeLatest, select } from 'redux-saga/effects';
|
||||
import { Alert } from 'react-native';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import valid from 'semver/functions/valid';
|
||||
import coerce from 'semver/functions/coerce';
|
||||
|
||||
import Navigation from '../lib/navigation/appNavigation';
|
||||
import { SERVER } from '../actions/actionsTypes';
|
||||
import { selectServerFailure, selectServerRequest, selectServerSuccess, serverFailure } from '../actions/server';
|
||||
import { clearSettings } from '../actions/settings';
|
||||
import { clearUser, setUser } from '../actions/login';
|
||||
import { clearActiveUsers } from '../actions/activeUsers';
|
||||
import database from '../lib/database';
|
||||
import log, { logServerVersion } from '../lib/methods/helpers/log';
|
||||
import I18n from '../i18n';
|
||||
import { BASIC_AUTH_KEY, setBasicAuth } from '../lib/methods/helpers/fetch';
|
||||
import { appStart } from '../actions/app';
|
||||
import UserPreferences from '../lib/methods/userPreferences';
|
||||
import { encryptionStop } from '../actions/encryption';
|
||||
import SSLPinning from '../lib/methods/helpers/sslPinning';
|
||||
import { inquiryReset } from '../ee/omnichannel/actions/inquiry';
|
||||
import { RootEnum } from '../definitions';
|
||||
import { CERTIFICATE_KEY, CURRENT_SERVER, TOKEN_KEY } from '../lib/constants';
|
||||
import { getLoginSettings, setCustomEmojis, setEnterpriseModules, setPermissions, setRoles, setSettings } from '../lib/methods';
|
||||
import { Services } from '../lib/services';
|
||||
import { connect } from '../lib/services/connect';
|
||||
|
||||
const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
|
||||
try {
|
||||
const serverInfo = yield Services.getServerInfo(server);
|
||||
let websocketInfo = { success: true };
|
||||
if (raiseError) {
|
||||
websocketInfo = yield Services.getWebsocketInfo({ server });
|
||||
}
|
||||
if (!serverInfo.success || !websocketInfo.success) {
|
||||
if (raiseError) {
|
||||
const info = serverInfo.success ? websocketInfo : serverInfo;
|
||||
Alert.alert(I18n.t('Oops'), info.message);
|
||||
}
|
||||
yield put(serverFailure());
|
||||
return;
|
||||
}
|
||||
|
||||
let serverVersion = valid(serverInfo.version);
|
||||
if (!serverVersion) {
|
||||
({ version: serverVersion } = coerce(serverInfo.version));
|
||||
}
|
||||
|
||||
const serversDB = database.servers;
|
||||
const serversCollection = serversDB.get('servers');
|
||||
yield serversDB.action(async () => {
|
||||
try {
|
||||
const serverRecord = await serversCollection.find(server);
|
||||
await serverRecord.update(record => {
|
||||
record.version = serverVersion;
|
||||
});
|
||||
} catch (e) {
|
||||
await serversCollection.create(record => {
|
||||
record._raw = sanitizedRaw({ id: server }, serversCollection.schema);
|
||||
record.version = serverVersion;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return serverInfo;
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }) {
|
||||
try {
|
||||
// SSL Pinning - Read certificate alias and set it to be used by network requests
|
||||
const certificate = UserPreferences.getString(`${CERTIFICATE_KEY}-${server}`);
|
||||
SSLPinning.setCertificate(certificate, server);
|
||||
yield put(inquiryReset());
|
||||
yield put(encryptionStop());
|
||||
yield put(clearActiveUsers());
|
||||
const serversDB = database.servers;
|
||||
const userId = UserPreferences.getString(`${TOKEN_KEY}-${server}`);
|
||||
const userCollections = serversDB.get('users');
|
||||
let user = null;
|
||||
if (userId) {
|
||||
try {
|
||||
// search credentials on database
|
||||
const userRecord = yield userCollections.find(userId);
|
||||
user = {
|
||||
id: userRecord.id,
|
||||
token: userRecord.token,
|
||||
username: userRecord.username,
|
||||
name: userRecord.name,
|
||||
language: userRecord.language,
|
||||
status: userRecord.status,
|
||||
statusText: userRecord.statusText,
|
||||
roles: userRecord.roles,
|
||||
avatarETag: userRecord.avatarETag,
|
||||
bio: userRecord.bio,
|
||||
nickname: userRecord.nickname
|
||||
};
|
||||
} catch {
|
||||
// search credentials on shared credentials (Experimental/Official)
|
||||
const token = UserPreferences.getString(`${TOKEN_KEY}-${userId}`);
|
||||
if (token) {
|
||||
user = { token };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const basicAuth = UserPreferences.getString(`${BASIC_AUTH_KEY}-${server}`);
|
||||
setBasicAuth(basicAuth);
|
||||
|
||||
if (user) {
|
||||
yield put(clearSettings());
|
||||
yield put(setUser(user));
|
||||
yield connect({ server, logoutOnError: true });
|
||||
yield put(appStart({ root: RootEnum.ROOT_INSIDE }));
|
||||
UserPreferences.setString(CURRENT_SERVER, server); // only set server after have a user
|
||||
} else {
|
||||
yield put(clearUser());
|
||||
yield connect({ server });
|
||||
yield put(appStart({ root: RootEnum.ROOT_OUTSIDE }));
|
||||
}
|
||||
|
||||
// We can't use yield here because fetch of Settings & Custom Emojis is slower
|
||||
// and block the selectServerSuccess raising multiples errors
|
||||
setSettings();
|
||||
setCustomEmojis();
|
||||
setPermissions();
|
||||
setRoles();
|
||||
setEnterpriseModules();
|
||||
|
||||
let serverInfo;
|
||||
if (fetchVersion) {
|
||||
serverInfo = yield getServerInfo({ server, raiseError: false });
|
||||
}
|
||||
|
||||
// Return server version even when offline
|
||||
const serverVersion = (serverInfo && serverInfo.version) || version;
|
||||
|
||||
// we'll set serverVersion as metadata for bugsnag
|
||||
logServerVersion(serverVersion);
|
||||
yield put(selectServerSuccess(server, serverVersion));
|
||||
} catch (e) {
|
||||
yield put(selectServerFailure());
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleServerRequest = function* handleServerRequest({ server, username, fromServerHistory }) {
|
||||
try {
|
||||
// SSL Pinning - Read certificate alias and set it to be used by network requests
|
||||
const certificate = UserPreferences.getString(`${CERTIFICATE_KEY}-${server}`);
|
||||
SSLPinning.setCertificate(certificate, server);
|
||||
|
||||
const serverInfo = yield getServerInfo({ server });
|
||||
const serversDB = database.servers;
|
||||
const serversHistoryCollection = serversDB.get('servers_history');
|
||||
|
||||
if (serverInfo) {
|
||||
yield Services.getLoginServices(server);
|
||||
yield getLoginSettings({ server });
|
||||
Navigation.navigate('WorkspaceView');
|
||||
|
||||
const Accounts_iframe_enabled = yield select(state => state.settings.Accounts_iframe_enabled);
|
||||
if (fromServerHistory && !Accounts_iframe_enabled) {
|
||||
Navigation.navigate('LoginView', { username });
|
||||
}
|
||||
|
||||
yield serversDB.action(async () => {
|
||||
try {
|
||||
const serversHistory = await serversHistoryCollection.query(Q.where('url', server)).fetch();
|
||||
if (!serversHistory?.length) {
|
||||
await serversHistoryCollection.create(s => {
|
||||
s.url = server;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
});
|
||||
yield put(selectServerRequest(server, serverInfo.version, false));
|
||||
}
|
||||
} catch (e) {
|
||||
yield put(serverFailure());
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const root = function* root() {
|
||||
yield takeLatest(SERVER.REQUEST, handleServerRequest);
|
||||
yield takeLatest(SERVER.SELECT_REQUEST, handleSelectServer);
|
||||
};
|
||||
export default root;
|
|
@ -0,0 +1,261 @@
|
|||
import { put, takeLatest } from 'redux-saga/effects';
|
||||
import { Alert } from 'react-native';
|
||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import valid from 'semver/functions/valid';
|
||||
import coerce from 'semver/functions/coerce';
|
||||
import { call } from 'typed-redux-saga';
|
||||
|
||||
import Navigation from '../lib/navigation/appNavigation';
|
||||
import { SERVER } from '../actions/actionsTypes';
|
||||
import {
|
||||
ISelectServerAction,
|
||||
IServerRequestAction,
|
||||
selectServerFailure,
|
||||
selectServerRequest,
|
||||
selectServerSuccess,
|
||||
serverFailure
|
||||
} from '../actions/server';
|
||||
import { clearSettings } from '../actions/settings';
|
||||
import { clearUser, setUser } from '../actions/login';
|
||||
import { clearActiveUsers } from '../actions/activeUsers';
|
||||
import database from '../lib/database';
|
||||
import log, { logServerVersion } from '../lib/methods/helpers/log';
|
||||
import I18n from '../i18n';
|
||||
import { BASIC_AUTH_KEY, setBasicAuth } from '../lib/methods/helpers/fetch';
|
||||
import { appStart } from '../actions/app';
|
||||
import { setSupportedVersions } from '../actions/supportedVersions';
|
||||
import UserPreferences from '../lib/methods/userPreferences';
|
||||
import { encryptionStop } from '../actions/encryption';
|
||||
import SSLPinning from '../lib/methods/helpers/sslPinning';
|
||||
import { inquiryReset } from '../ee/omnichannel/actions/inquiry';
|
||||
import { IServerInfo, RootEnum, TServerModel } from '../definitions';
|
||||
import { CERTIFICATE_KEY, CURRENT_SERVER, TOKEN_KEY } from '../lib/constants';
|
||||
import {
|
||||
checkSupportedVersions,
|
||||
getLoginSettings,
|
||||
getServerInfo,
|
||||
setCustomEmojis,
|
||||
setEnterpriseModules,
|
||||
setPermissions,
|
||||
setRoles,
|
||||
setSettings
|
||||
} from '../lib/methods';
|
||||
import { Services } from '../lib/services';
|
||||
import { connect } from '../lib/services/connect';
|
||||
import { appSelector } from '../lib/hooks';
|
||||
import { getServerById } from '../lib/database/services/Server';
|
||||
import { getLoggedUserById } from '../lib/database/services/LoggedUser';
|
||||
|
||||
const getServerVersion = function (version: string | null) {
|
||||
let validVersion = valid(version);
|
||||
if (validVersion) {
|
||||
return validVersion;
|
||||
}
|
||||
const coercedVersion = coerce(version);
|
||||
if (coercedVersion) {
|
||||
validVersion = valid(coercedVersion);
|
||||
}
|
||||
if (validVersion) {
|
||||
return validVersion;
|
||||
}
|
||||
throw new Error('Server version not found');
|
||||
};
|
||||
|
||||
const upsertServer = async function ({ server, serverInfo }: { server: string; serverInfo: IServerInfo }): Promise<TServerModel> {
|
||||
const serversDB = database.servers;
|
||||
const serversCollection = serversDB.get('servers');
|
||||
const serverVersion = getServerVersion(serverInfo.version);
|
||||
const record = await getServerById(server);
|
||||
if (record) {
|
||||
await serversDB.write(async () => {
|
||||
await record.update(r => {
|
||||
r.version = serverVersion;
|
||||
if (serverInfo.supportedVersions) {
|
||||
r.supportedVersions = serverInfo.supportedVersions;
|
||||
}
|
||||
});
|
||||
});
|
||||
return record;
|
||||
}
|
||||
|
||||
let newRecord;
|
||||
await serversDB.write(async () => {
|
||||
newRecord = await serversCollection.create(r => {
|
||||
r._raw = sanitizedRaw({ id: server }, serversCollection.schema);
|
||||
if (serverInfo.supportedVersions) {
|
||||
r.supportedVersions = serverInfo.supportedVersions;
|
||||
}
|
||||
r.version = serverVersion;
|
||||
});
|
||||
});
|
||||
if (newRecord) {
|
||||
return newRecord;
|
||||
}
|
||||
throw new Error('Error creating server record');
|
||||
};
|
||||
|
||||
const getServerInfoSaga = function* getServerInfoSaga({ server, raiseError = true }: { server: string; raiseError?: boolean }) {
|
||||
try {
|
||||
const serverInfoResult = yield* call(getServerInfo, server);
|
||||
if (raiseError) {
|
||||
if (!serverInfoResult.success) {
|
||||
Alert.alert(I18n.t('Oops'), serverInfoResult.message);
|
||||
yield put(serverFailure());
|
||||
return;
|
||||
}
|
||||
const websocketInfo = yield* call(Services.getWebsocketInfo, { server });
|
||||
if (!websocketInfo.success) {
|
||||
Alert.alert(I18n.t('Oops'), websocketInfo.message);
|
||||
yield put(serverFailure());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let serverRecord: TServerModel | null;
|
||||
if (serverInfoResult.success) {
|
||||
serverRecord = yield* call(upsertServer, { server, serverInfo: serverInfoResult });
|
||||
} else {
|
||||
serverRecord = yield* call(getServerById, server);
|
||||
}
|
||||
if (!serverRecord) {
|
||||
throw new Error('Server not found');
|
||||
}
|
||||
const supportedVersionsResult = yield* call(checkSupportedVersions, {
|
||||
supportedVersions: serverRecord.supportedVersions,
|
||||
serverVersion: serverRecord.version
|
||||
});
|
||||
yield put(setSupportedVersions(supportedVersionsResult));
|
||||
|
||||
return serverRecord;
|
||||
} catch (e) {
|
||||
log(e);
|
||||
yield put(serverFailure());
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }: ISelectServerAction) {
|
||||
try {
|
||||
// SSL Pinning - Read certificate alias and set it to be used by network requests
|
||||
const certificate = UserPreferences.getString(`${CERTIFICATE_KEY}-${server}`);
|
||||
if (certificate) {
|
||||
SSLPinning?.setCertificate(certificate, server);
|
||||
}
|
||||
yield put(inquiryReset());
|
||||
yield put(encryptionStop());
|
||||
yield put(clearActiveUsers());
|
||||
const userId = UserPreferences.getString(`${TOKEN_KEY}-${server}`);
|
||||
let user = null;
|
||||
if (userId) {
|
||||
// search credentials on database
|
||||
const userRecord = yield* call(getLoggedUserById, userId);
|
||||
if (userRecord) {
|
||||
user = {
|
||||
id: userRecord.id,
|
||||
token: userRecord.token,
|
||||
username: userRecord.username,
|
||||
name: userRecord.name,
|
||||
language: userRecord.language,
|
||||
status: userRecord.status,
|
||||
statusText: userRecord.statusText,
|
||||
roles: userRecord.roles,
|
||||
avatarETag: userRecord.avatarETag,
|
||||
bio: userRecord.bio,
|
||||
nickname: userRecord.nickname
|
||||
};
|
||||
} else {
|
||||
const token = UserPreferences.getString(`${TOKEN_KEY}-${userId}`);
|
||||
if (token) {
|
||||
user = { token };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const basicAuth = UserPreferences.getString(`${BASIC_AUTH_KEY}-${server}`);
|
||||
setBasicAuth(basicAuth);
|
||||
|
||||
if (user) {
|
||||
yield put(clearSettings());
|
||||
yield put(setUser(user));
|
||||
yield connect({ server, logoutOnError: true });
|
||||
yield put(appStart({ root: RootEnum.ROOT_INSIDE }));
|
||||
UserPreferences.setString(CURRENT_SERVER, server); // only set server after have a user
|
||||
} else {
|
||||
yield put(clearUser());
|
||||
yield connect({ server });
|
||||
yield put(appStart({ root: RootEnum.ROOT_OUTSIDE }));
|
||||
}
|
||||
|
||||
// We can't use yield here because fetch of Settings & Custom Emojis is slower
|
||||
// and block the selectServerSuccess raising multiples errors
|
||||
setSettings();
|
||||
setCustomEmojis();
|
||||
setPermissions();
|
||||
setRoles();
|
||||
setEnterpriseModules();
|
||||
|
||||
// We need uniqueId from settings to get cloud info, so setSettings needs to be called first
|
||||
let serverInfo;
|
||||
if (fetchVersion) {
|
||||
serverInfo = yield* getServerInfoSaga({ server, raiseError: false });
|
||||
}
|
||||
|
||||
// Return server version even when offline
|
||||
const serverVersion = (serverInfo && serverInfo.version) || (version as string);
|
||||
|
||||
// we'll set serverVersion as metadata for bugsnag
|
||||
logServerVersion(serverVersion);
|
||||
yield put(selectServerSuccess({ server, version: serverVersion, name: serverInfo?.name || 'Rocket.Chat' }));
|
||||
} catch (e) {
|
||||
yield put(selectServerFailure());
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleServerRequest = function* handleServerRequest({ server, username, fromServerHistory }: IServerRequestAction) {
|
||||
try {
|
||||
// SSL Pinning - Read certificate alias and set it to be used by network requests
|
||||
const certificate = UserPreferences.getString(`${CERTIFICATE_KEY}-${server}`);
|
||||
if (certificate) {
|
||||
SSLPinning?.setCertificate(certificate, server);
|
||||
}
|
||||
|
||||
const serverInfo = yield* getServerInfoSaga({ server });
|
||||
const serversDB = database.servers;
|
||||
const serversHistoryCollection = serversDB.get('servers_history');
|
||||
|
||||
if (serverInfo) {
|
||||
yield Services.getLoginServices(server);
|
||||
yield getLoginSettings({ server });
|
||||
Navigation.navigate('WorkspaceView');
|
||||
|
||||
const Accounts_iframe_enabled = yield* appSelector(state => state.settings.Accounts_iframe_enabled);
|
||||
if (fromServerHistory && !Accounts_iframe_enabled) {
|
||||
Navigation.navigate('LoginView', { username });
|
||||
}
|
||||
|
||||
yield serversDB.write(async () => {
|
||||
try {
|
||||
const serversHistory = await serversHistoryCollection.query(Q.where('url', server)).fetch();
|
||||
if (!serversHistory?.length) {
|
||||
await serversHistoryCollection.create(s => {
|
||||
s.url = server;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
});
|
||||
yield put(selectServerRequest(server, serverInfo.version, false));
|
||||
}
|
||||
} catch (e) {
|
||||
yield put(serverFailure());
|
||||
log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const root = function* root() {
|
||||
yield takeLatest<IServerRequestAction>(SERVER.REQUEST, handleServerRequest);
|
||||
yield takeLatest<ISelectServerAction>(SERVER.SELECT_REQUEST, handleSelectServer);
|
||||
};
|
||||
export default root;
|
|
@ -76,6 +76,7 @@ import {
|
|||
} from './types';
|
||||
import { isIOS } from '../../lib/methods/helpers';
|
||||
import { TNavigation } from '../stackType';
|
||||
import { SupportedVersionsWarning } from '../../containers/SupportedVersions';
|
||||
|
||||
// ChatsStackNavigator
|
||||
const ChatsStack = createStackNavigator<MasterDetailChatsStackParamList>();
|
||||
|
@ -184,6 +185,7 @@ const ModalStackNavigator = React.memo(({ navigation }: INavigation) => {
|
|||
<ModalStack.Screen name='SecurityPrivacyView' component={SecurityPrivacyView} />
|
||||
<ModalStack.Screen name='MediaAutoDownloadView' component={MediaAutoDownloadView} />
|
||||
<ModalStack.Screen name='E2EEncryptionSecurityView' component={E2EEncryptionSecurityView} />
|
||||
<ModalStack.Screen name='SupportedVersionsWarning' component={SupportedVersionsWarning} />
|
||||
</ModalStack.Navigator>
|
||||
</ModalContainer>
|
||||
);
|
||||
|
|
|
@ -196,6 +196,9 @@ export type ModalStackParamList = {
|
|||
SecurityPrivacyView: undefined;
|
||||
MediaAutoDownloadView: undefined;
|
||||
E2EEncryptionSecurityView: undefined;
|
||||
SupportedVersionsWarning: {
|
||||
showCloseButton?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type MasterDetailInsideStackParamList = {
|
||||
|
|
|
@ -6,6 +6,7 @@ import sharedStyles from '../../Styles';
|
|||
import { CustomIcon } from '../../../containers/CustomIcon';
|
||||
import { useTheme } from '../../../theme';
|
||||
import SearchHeader from '../../../containers/SearchHeader';
|
||||
import { useAppSelector } from '../../../lib/hooks';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
|
@ -54,13 +55,16 @@ const Header = React.memo(
|
|||
onSearchChangeText,
|
||||
onPress
|
||||
}: IRoomHeader) => {
|
||||
const { status: supportedVersionsStatus } = useAppSelector(state => state.supportedVersions);
|
||||
const { colors } = useTheme();
|
||||
|
||||
if (showSearchHeader) {
|
||||
return <SearchHeader onSearchChangeText={onSearchChangeText} testID='rooms-list-view-search-input' />;
|
||||
}
|
||||
let subtitle;
|
||||
if (connecting) {
|
||||
if (supportedVersionsStatus === 'expired') {
|
||||
subtitle = 'Cannot connect';
|
||||
} else if (connecting) {
|
||||
subtitle = I18n.t('Connecting');
|
||||
} else if (isFetching) {
|
||||
subtitle = I18n.t('Updating');
|
||||
|
|
|
@ -26,7 +26,7 @@ import { goRoom } from '../../lib/methods/helpers/goRoom';
|
|||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import { withDimensions } from '../../dimensions';
|
||||
import { getInquiryQueueSelector } from '../../ee/omnichannel/selectors/inquiry';
|
||||
import { IApplicationState, ISubscription, IUser, SubscriptionType, TSubscriptionModel } from '../../definitions';
|
||||
import { IApplicationState, ISubscription, IUser, TSVStatus, SubscriptionType, TSubscriptionModel } from '../../definitions';
|
||||
import styles from './styles';
|
||||
import ServerDropdown from './ServerDropdown';
|
||||
import ListHeader, { TEncryptionBanner } from './ListHeader';
|
||||
|
@ -44,8 +44,9 @@ import {
|
|||
isTablet,
|
||||
compareServerVersion
|
||||
} from '../../lib/methods/helpers';
|
||||
import { E2E_BANNER_TYPE, DisplayMode, SortBy, MAX_SIDEBAR_WIDTH, themes } from '../../lib/constants';
|
||||
import { E2E_BANNER_TYPE, DisplayMode, SortBy, MAX_SIDEBAR_WIDTH, themes, STATUS_COLORS, colors } from '../../lib/constants';
|
||||
import { Services } from '../../lib/services';
|
||||
import { SupportedVersionsExpired } from '../../containers/SupportedVersions';
|
||||
|
||||
type TNavigation = CompositeNavigationProp<
|
||||
StackNavigationProp<ChatsStackParamList, 'RoomsListView'>,
|
||||
|
@ -73,6 +74,7 @@ interface IRoomsListViewProps {
|
|||
useRealName: boolean;
|
||||
isMasterDetail: boolean;
|
||||
notificationPresenceCap: boolean;
|
||||
supportedVersionsStatus: TSVStatus;
|
||||
subscribedRoom: string;
|
||||
width: number;
|
||||
insets: {
|
||||
|
@ -143,7 +145,8 @@ const shouldUpdateProps = [
|
|||
'createDirectMessagePermission',
|
||||
'createPublicChannelPermission',
|
||||
'createPrivateChannelPermission',
|
||||
'createDiscussionPermission'
|
||||
'createDiscussionPermission',
|
||||
'supportedVersionsStatus'
|
||||
];
|
||||
|
||||
const sortPreferencesShouldUpdate = ['sortBy', 'groupByType', 'showFavorites', 'showUnread'];
|
||||
|
@ -330,7 +333,8 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
createDirectMessagePermission,
|
||||
createDiscussionPermission,
|
||||
showAvatar,
|
||||
displayMode
|
||||
displayMode,
|
||||
supportedVersionsStatus
|
||||
} = this.props;
|
||||
const { item } = this.state;
|
||||
|
||||
|
@ -353,7 +357,8 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
if (
|
||||
insets.left !== prevProps.insets.left ||
|
||||
insets.right !== prevProps.insets.right ||
|
||||
notificationPresenceCap !== prevProps.notificationPresenceCap
|
||||
notificationPresenceCap !== prevProps.notificationPresenceCap ||
|
||||
supportedVersionsStatus !== prevProps.supportedVersionsStatus
|
||||
) {
|
||||
this.setHeader();
|
||||
}
|
||||
|
@ -406,7 +411,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
|
||||
getHeader = (): StackNavigationOptions => {
|
||||
const { searching, canCreateRoom } = this.state;
|
||||
const { navigation, isMasterDetail, notificationPresenceCap } = this.props;
|
||||
const { navigation, isMasterDetail, notificationPresenceCap, supportedVersionsStatus, theme } = this.props;
|
||||
if (searching) {
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
|
@ -422,6 +427,16 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
};
|
||||
}
|
||||
|
||||
const getBadge = () => {
|
||||
if (supportedVersionsStatus === 'warn') {
|
||||
return <HeaderButton.BadgeWarn color={colors[theme].dangerColor} />;
|
||||
}
|
||||
if (notificationPresenceCap) {
|
||||
return <HeaderButton.BadgeWarn color={STATUS_COLORS.disabled} />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: { flex: 1, marginHorizontal: 4, maxWidth: undefined },
|
||||
|
@ -436,17 +451,33 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
: // @ts-ignore
|
||||
() => navigation.toggleDrawer()
|
||||
}
|
||||
badge={() => (notificationPresenceCap ? <HeaderButton.BadgeWarn /> : null)}
|
||||
badge={() => getBadge()}
|
||||
disabled={supportedVersionsStatus === 'expired'}
|
||||
/>
|
||||
),
|
||||
headerTitle: () => <RoomsListHeaderView />,
|
||||
headerRight: () => (
|
||||
<HeaderButton.Container>
|
||||
{canCreateRoom ? (
|
||||
<HeaderButton.Item iconName='create' onPress={this.goToNewMessage} testID='rooms-list-view-create-channel' />
|
||||
<HeaderButton.Item
|
||||
iconName='create'
|
||||
onPress={this.goToNewMessage}
|
||||
testID='rooms-list-view-create-channel'
|
||||
disabled={supportedVersionsStatus === 'expired'}
|
||||
/>
|
||||
) : null}
|
||||
<HeaderButton.Item iconName='search' onPress={this.initSearching} testID='rooms-list-view-search' />
|
||||
<HeaderButton.Item iconName='directory' onPress={this.goDirectory} testID='rooms-list-view-directory' />
|
||||
<HeaderButton.Item
|
||||
iconName='search'
|
||||
onPress={this.initSearching}
|
||||
testID='rooms-list-view-search'
|
||||
disabled={supportedVersionsStatus === 'expired'}
|
||||
/>
|
||||
<HeaderButton.Item
|
||||
iconName='directory'
|
||||
onPress={this.goDirectory}
|
||||
testID='rooms-list-view-directory'
|
||||
disabled={supportedVersionsStatus === 'expired'}
|
||||
/>
|
||||
</HeaderButton.Container>
|
||||
)
|
||||
};
|
||||
|
@ -896,7 +927,7 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
|
||||
renderScroll = () => {
|
||||
const { loading, chats, search, searching } = this.state;
|
||||
const { theme, refreshing, displayMode } = this.props;
|
||||
const { theme, refreshing, displayMode, supportedVersionsStatus } = this.props;
|
||||
|
||||
const height = displayMode === DisplayMode.Condensed ? ROW_HEIGHT_CONDENSED : ROW_HEIGHT;
|
||||
|
||||
|
@ -904,6 +935,10 @@ class RoomsListView extends React.Component<IRoomsListViewProps, IRoomsListViewS
|
|||
return <ActivityIndicator />;
|
||||
}
|
||||
|
||||
if (supportedVersionsStatus === 'expired') {
|
||||
return <SupportedVersionsExpired />;
|
||||
}
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
ref={this.getScrollRef}
|
||||
|
@ -949,6 +984,7 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
user: getUserSelector(state),
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
notificationPresenceCap: state.app.notificationPresenceCap,
|
||||
supportedVersionsStatus: state.supportedVersions.status,
|
||||
server: state.server.server,
|
||||
changingServer: state.server.changingServer,
|
||||
searchText: state.rooms.searchText,
|
||||
|
|
|
@ -10,13 +10,14 @@ interface SidebarItemProps {
|
|||
left: JSX.Element;
|
||||
right?: JSX.Element;
|
||||
text: string;
|
||||
textColor?: string;
|
||||
current?: boolean;
|
||||
onPress(): void;
|
||||
testID: string;
|
||||
theme: TSupportedThemes;
|
||||
}
|
||||
|
||||
const Item = React.memo(({ left, right, text, onPress, testID, current, theme }: SidebarItemProps) => (
|
||||
const Item = React.memo(({ left, right, text, onPress, testID, current, theme, textColor }: SidebarItemProps) => (
|
||||
<Touch
|
||||
key={testID}
|
||||
testID={testID}
|
||||
|
@ -25,7 +26,11 @@ const Item = React.memo(({ left, right, text, onPress, testID, current, theme }:
|
|||
>
|
||||
<View style={styles.itemHorizontal}>{left}</View>
|
||||
<View style={styles.itemCenter}>
|
||||
<Text style={[styles.itemText, { color: themes[theme].titleText }]} numberOfLines={1} accessibilityLabel={text}>
|
||||
<Text
|
||||
style={[styles.itemText, { color: textColor || themes[theme].titleText }]}
|
||||
numberOfLines={1}
|
||||
accessibilityLabel={text}
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
|
|
|
@ -21,9 +21,11 @@ import Navigation from '../../lib/navigation/appNavigation';
|
|||
import SidebarItem from './SidebarItem';
|
||||
import styles from './styles';
|
||||
import { DrawerParamList } from '../../stacks/types';
|
||||
import { IApplicationState, IUser } from '../../definitions';
|
||||
import { IApplicationState, IUser, TSVStatus } from '../../definitions';
|
||||
import * as List from '../../containers/List';
|
||||
import { IActionSheetProvider, showActionSheetRef, withActionSheet } from '../../containers/ActionSheet';
|
||||
import { setNotificationPresenceCap } from '../../actions/app';
|
||||
import { SupportedVersionsWarning } from '../../containers/SupportedVersions';
|
||||
|
||||
interface ISidebarState {
|
||||
showStatus: boolean;
|
||||
|
@ -42,11 +44,13 @@ interface ISidebarProps {
|
|||
allowStatusMessage: boolean;
|
||||
notificationPresenceCap: boolean;
|
||||
Presence_broadcast_disabled: boolean;
|
||||
supportedVersionsStatus: TSVStatus;
|
||||
isMasterDetail: boolean;
|
||||
viewStatisticsPermission: string[];
|
||||
viewRoomAdministrationPermission: string[];
|
||||
viewUserAdministrationPermission: string[];
|
||||
viewPrivilegedSettingPermission: string[];
|
||||
showActionSheet: IActionSheetProvider['showActionSheet'];
|
||||
}
|
||||
|
||||
class Sidebar extends Component<ISidebarProps, ISidebarState> {
|
||||
|
@ -197,6 +201,15 @@ class Sidebar extends Component<ISidebarProps, ISidebarState> {
|
|||
);
|
||||
};
|
||||
|
||||
onPressSupportedVersionsWarning = () => {
|
||||
const { isMasterDetail } = this.props;
|
||||
if (isMasterDetail) {
|
||||
Navigation.navigate('ModalStackNavigator', { screen: 'SupportedVersionsWarning' });
|
||||
} else {
|
||||
showActionSheetRef({ children: <SupportedVersionsWarning /> });
|
||||
}
|
||||
};
|
||||
|
||||
renderAdmin = () => {
|
||||
const { theme, isMasterDetail } = this.props;
|
||||
if (!this.getIsAdmin()) {
|
||||
|
@ -286,6 +299,23 @@ class Sidebar extends Component<ISidebarProps, ISidebarState> {
|
|||
);
|
||||
};
|
||||
|
||||
renderSupportedVersionsWarn = () => {
|
||||
const { theme, supportedVersionsStatus } = this.props;
|
||||
if (supportedVersionsStatus === 'warn') {
|
||||
return (
|
||||
<SidebarItem
|
||||
text={I18n.t('Supported_versions_warning_update_required')}
|
||||
textColor={themes[theme!].dangerColor}
|
||||
left={<CustomIcon name='warning' size={20} color={themes[theme!].dangerColor} />}
|
||||
theme={theme!}
|
||||
onPress={() => this.onPressSupportedVersionsWarning()}
|
||||
testID={`sidebar-supported-versions-warn`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { user, Site_Name, baseUrl, useRealName, allowStatusMessage, isMasterDetail, theme } = this.props;
|
||||
|
||||
|
@ -323,6 +353,9 @@ class Sidebar extends Component<ISidebarProps, ISidebarState> {
|
|||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
|
||||
<List.Separator />
|
||||
{this.renderSupportedVersionsWarn()}
|
||||
|
||||
<List.Separator />
|
||||
|
||||
{allowStatusMessage ? this.renderCustomStatus() : null}
|
||||
|
@ -350,6 +383,7 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
allowStatusMessage: state.settings.Accounts_AllowUserStatusMessageChange as boolean,
|
||||
Presence_broadcast_disabled: state.settings.Presence_broadcast_disabled as boolean,
|
||||
notificationPresenceCap: state.app.notificationPresenceCap,
|
||||
supportedVersionsStatus: state.supportedVersions.status,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
viewStatisticsPermission: state.permissions['view-statistics'] as string[],
|
||||
viewRoomAdministrationPermission: state.permissions['view-room-administration'] as string[],
|
||||
|
@ -357,4 +391,4 @@ const mapStateToProps = (state: IApplicationState) => ({
|
|||
viewPrivilegedSettingPermission: state.permissions['view-privileged-setting'] as string[]
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(Sidebar));
|
||||
export default connect(mapStateToProps)(withActionSheet(withTheme(Sidebar)));
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
import '@testing-library/jest-native/extend-expect';
|
||||
// @ts-ignore
|
||||
import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock.js';
|
||||
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';
|
||||
|
||||
jest.mock('@react-native-async-storage/async-storage', () => mockAsyncStorage);
|
||||
|
||||
jest.mock('react-native-safe-area-context', () => {
|
||||
const inset = { top: 0, right: 0, bottom: 0, left: 0 };
|
||||
return {
|
||||
...jest.requireActual('react-native-safe-area-context'),
|
||||
SafeAreaProvider: jest.fn(({ children }) => children),
|
||||
SafeAreaConsumer: jest.fn(({ children }) => children(inset)),
|
||||
useSafeAreaInsets: jest.fn(() => inset),
|
||||
useSafeAreaFrame: jest.fn(() => ({ x: 0, y: 0, width: 390, height: 844 }))
|
||||
};
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
global.__reanimatedWorkletInit = () => {};
|
||||
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));
|
||||
|
|
@ -84,6 +84,7 @@
|
|||
"i18n-js": "3.9.2",
|
||||
"js-base64": "3.6.1",
|
||||
"js-sha256": "^0.9.0",
|
||||
"jsrsasign": "^10.8.6",
|
||||
"lint-staged": "^11.1.0",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "2.29.4",
|
||||
|
@ -172,13 +173,14 @@
|
|||
"@storybook/addon-storyshots": "6.3",
|
||||
"@storybook/react": "6.3",
|
||||
"@storybook/react-native": "^6.0.1-beta.7",
|
||||
"@testing-library/jest-native": "^4.0.4",
|
||||
"@testing-library/jest-native": "^5.4.2",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@testing-library/react-native": "^9.0.0",
|
||||
"@testing-library/react-native": "^12.1.2",
|
||||
"@types/bytebuffer": "^5.0.44",
|
||||
"@types/ejson": "^2.1.3",
|
||||
"@types/i18n-js": "^3.8.3",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/jsrsasign": "^10.5.8",
|
||||
"@types/lodash": "^4.14.188",
|
||||
"@types/react": "^17.0.14",
|
||||
"@types/react-native": "0.68.1",
|
||||
|
@ -241,8 +243,7 @@
|
|||
".+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js"
|
||||
},
|
||||
"setupFilesAfterEnv": [
|
||||
"@testing-library/jest-native/extend-expect",
|
||||
"./jest.setup.js"
|
||||
"./jest.setup.ts"
|
||||
]
|
||||
},
|
||||
"jest-junit": {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
# URL to fetch data from
|
||||
URL="https://releases.rocket.chat/v2/server/supportedVersions?source=mobile"
|
||||
|
||||
# Output file name
|
||||
OUTPUT_FILE="app-supportedversions.json"
|
||||
|
||||
# Use curl to fetch data and save it to a temporary file
|
||||
TEMP_FILE=$(mktemp)
|
||||
curl -s "$URL" > "$TEMP_FILE"
|
||||
|
||||
# Check if the curl command was successful (HTTP status code 200)
|
||||
if [ $? -eq 0 ]; then
|
||||
# Use jq to pretty-print the JSON and save it to the output file
|
||||
jq '.' "$TEMP_FILE" > "$OUTPUT_FILE"
|
||||
echo "Data fetched and saved to $OUTPUT_FILE"
|
||||
else
|
||||
echo "Failed to fetch data from $URL"
|
||||
fi
|
||||
|
||||
# Clean up the temporary file
|
||||
rm "$TEMP_FILE"
|
188
yarn.lock
188
yarn.lock
|
@ -4564,6 +4564,13 @@
|
|||
dependencies:
|
||||
"@sinclair/typebox" "^0.24.1"
|
||||
|
||||
"@jest/schemas@^29.6.3":
|
||||
version "29.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
|
||||
integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
|
||||
dependencies:
|
||||
"@sinclair/typebox" "^0.27.8"
|
||||
|
||||
"@jest/source-map@^28.1.2":
|
||||
version "28.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24"
|
||||
|
@ -4645,15 +4652,6 @@
|
|||
slash "^3.0.0"
|
||||
write-file-atomic "^4.0.1"
|
||||
|
||||
"@jest/types@^24.9.0":
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59"
|
||||
integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==
|
||||
dependencies:
|
||||
"@types/istanbul-lib-coverage" "^2.0.0"
|
||||
"@types/istanbul-reports" "^1.1.1"
|
||||
"@types/yargs" "^13.0.0"
|
||||
|
||||
"@jest/types@^25.5.0":
|
||||
version "25.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d"
|
||||
|
@ -5677,6 +5675,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.28.tgz#15aa0b416f82c268b1573ab653e4413c965fe794"
|
||||
integrity sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow==
|
||||
|
||||
"@sinclair/typebox@^0.27.8":
|
||||
version "0.27.8"
|
||||
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
|
||||
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
|
||||
|
||||
"@sinonjs/commons@^1.7.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
|
||||
|
@ -6282,17 +6285,16 @@
|
|||
resolve-from "^5.0.0"
|
||||
store2 "^2.12.0"
|
||||
|
||||
"@testing-library/jest-native@^4.0.4":
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/jest-native/-/jest-native-4.0.4.tgz#25e2046896118f887683202a6e5fd8a4056131cd"
|
||||
integrity sha512-4q5FeTFyFgPCmQH18uMJsZkVnYvBtK24yhSfbd9hQi0SZzCpbjSeQQcsGXIaX+WjWcMeeip8B7NUvZmLhGHiZw==
|
||||
"@testing-library/jest-native@^5.4.2":
|
||||
version "5.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/jest-native/-/jest-native-5.4.3.tgz#9334c68eaf45db9eb20d0876728cc5d7fc2c3ea2"
|
||||
integrity sha512-/sSDGaOuE+PJ1Z9Kp4u7PQScSVVXGud59I/qsBFFJvIbcn4P6yYw6cBnBmbPF+X9aRIsTJRDl6gzw5ZkJNm66w==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
jest-diff "^24.0.0"
|
||||
jest-matcher-utils "^24.0.0"
|
||||
pretty-format "^27.3.1"
|
||||
ramda "^0.26.1"
|
||||
redent "^2.0.0"
|
||||
chalk "^4.1.2"
|
||||
jest-diff "^29.0.1"
|
||||
jest-matcher-utils "^29.0.1"
|
||||
pretty-format "^29.0.3"
|
||||
redent "^3.0.0"
|
||||
|
||||
"@testing-library/react-hooks@^8.0.1":
|
||||
version "8.0.1"
|
||||
|
@ -6302,12 +6304,12 @@
|
|||
"@babel/runtime" "^7.12.5"
|
||||
react-error-boundary "^3.1.0"
|
||||
|
||||
"@testing-library/react-native@^9.0.0":
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-9.0.0.tgz#e9c63411e93d2e8e70d744b12aeb78c58025c5fc"
|
||||
integrity sha512-UE3FWOsDUr+2l3Pg6JTpn2rV5uzYsxIus6ZyN1uMOTmn30bIuBBDDlWQtdWGJx92YcY4xgJA4vViCEKv7wVzJA==
|
||||
"@testing-library/react-native@^12.1.2":
|
||||
version "12.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react-native/-/react-native-12.2.2.tgz#4b2275d5d1feb689c9b1e5cd9cb03ffe32a43228"
|
||||
integrity sha512-aLr7YQ6pyn8PbLmdbtADG2aKcmarTLI7VhgWNVzJLxQHOtsDxLpJGKMSw10j406BE/GyGHbB0Gln3Of8/2TjnA==
|
||||
dependencies:
|
||||
pretty-format "^27.0.0"
|
||||
pretty-format "^29.0.0"
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
|
@ -6576,6 +6578,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||
|
||||
"@types/jsrsasign@^10.5.8":
|
||||
version "10.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/jsrsasign/-/jsrsasign-10.5.8.tgz#0d6c638505454b5e95c684d6f604d57641417336"
|
||||
integrity sha512-1oZ3TbarAhKtKUpyrCIqXpbx3ZAfoSulleJs6/UzzyYty0ut+kjRX7zHLAaHwVIuw8CBjIymwW4J2LK944HoHQ==
|
||||
|
||||
"@types/lodash@^4.14.175":
|
||||
version "4.14.182"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
|
||||
|
@ -6880,13 +6887,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
|
||||
integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==
|
||||
|
||||
"@types/yargs@^13.0.0":
|
||||
version "13.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.9.tgz#44028e974343c7afcf3960f1a2b1099c39a7b5e1"
|
||||
integrity sha512-xrvhZ4DZewMDhoH1utLtOAwYQy60eYFoXeje30TzM3VOvQlBwQaEpKFq5m34k1wOw2AKIi2pwtiAjdmhvlBUzg==
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@types/yargs@^15.0.0":
|
||||
version "15.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79"
|
||||
|
@ -7430,7 +7430,7 @@ ansi-regex@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
ansi-regex@^4.0.0, ansi-regex@^4.1.0:
|
||||
ansi-regex@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
|
||||
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
|
||||
|
@ -10165,11 +10165,6 @@ detox@^20.1.2:
|
|||
yargs-parser "^20.2.9"
|
||||
yargs-unparser "^2.0.0"
|
||||
|
||||
diff-sequences@^24.9.0:
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
|
||||
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
|
||||
|
||||
diff-sequences@^25.2.6:
|
||||
version "25.2.6"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd"
|
||||
|
@ -10185,6 +10180,11 @@ diff-sequences@^28.1.1:
|
|||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6"
|
||||
integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==
|
||||
|
||||
diff-sequences@^29.6.3:
|
||||
version "29.6.3"
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
|
||||
integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
|
@ -12908,11 +12908,6 @@ imurmurhash@^0.1.4:
|
|||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||
|
||||
indent-string@^3.0.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
|
||||
integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=
|
||||
|
||||
indent-string@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||
|
@ -13700,16 +13695,6 @@ jest-config@^28.1.3:
|
|||
slash "^3.0.0"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
jest-diff@^24.0.0, jest-diff@^24.9.0:
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da"
|
||||
integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==
|
||||
dependencies:
|
||||
chalk "^2.0.1"
|
||||
diff-sequences "^24.9.0"
|
||||
jest-get-type "^24.9.0"
|
||||
pretty-format "^24.9.0"
|
||||
|
||||
jest-diff@^25.2.1:
|
||||
version "25.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9"
|
||||
|
@ -13740,6 +13725,16 @@ jest-diff@^28.1.3:
|
|||
jest-get-type "^28.0.2"
|
||||
pretty-format "^28.1.3"
|
||||
|
||||
jest-diff@^29.0.1, jest-diff@^29.6.4:
|
||||
version "29.6.4"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.4.tgz#85aaa6c92a79ae8cd9a54ebae8d5b6d9a513314a"
|
||||
integrity sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
diff-sequences "^29.6.3"
|
||||
jest-get-type "^29.6.3"
|
||||
pretty-format "^29.6.3"
|
||||
|
||||
jest-docblock@^28.1.1:
|
||||
version "28.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8"
|
||||
|
@ -13785,11 +13780,6 @@ jest-expo@^46.0.1:
|
|||
lodash "^4.17.19"
|
||||
react-test-renderer "~18.0.0"
|
||||
|
||||
jest-get-type@^24.9.0:
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e"
|
||||
integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==
|
||||
|
||||
jest-get-type@^25.2.6:
|
||||
version "25.2.6"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877"
|
||||
|
@ -13805,6 +13795,11 @@ jest-get-type@^28.0.2:
|
|||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203"
|
||||
integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==
|
||||
|
||||
jest-get-type@^29.6.3:
|
||||
version "29.6.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
|
||||
integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
|
||||
|
||||
jest-haste-map@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa"
|
||||
|
@ -13883,16 +13878,6 @@ jest-leak-detector@^28.1.3:
|
|||
jest-get-type "^28.0.2"
|
||||
pretty-format "^28.1.3"
|
||||
|
||||
jest-matcher-utils@^24.0.0:
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073"
|
||||
integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==
|
||||
dependencies:
|
||||
chalk "^2.0.1"
|
||||
jest-diff "^24.9.0"
|
||||
jest-get-type "^24.9.0"
|
||||
pretty-format "^24.9.0"
|
||||
|
||||
jest-matcher-utils@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a"
|
||||
|
@ -13913,6 +13898,16 @@ jest-matcher-utils@^28.1.3:
|
|||
jest-get-type "^28.0.2"
|
||||
pretty-format "^28.1.3"
|
||||
|
||||
jest-matcher-utils@^29.0.1:
|
||||
version "29.6.4"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz#327db7ababea49455df3b23e5d6109fe0c709d24"
|
||||
integrity sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
jest-diff "^29.6.4"
|
||||
jest-get-type "^29.6.3"
|
||||
pretty-format "^29.6.3"
|
||||
|
||||
jest-message-util@^26.6.2:
|
||||
version "26.6.2"
|
||||
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07"
|
||||
|
@ -14539,6 +14534,11 @@ jsonfile@^6.0.1:
|
|||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsrsasign@^10.8.6:
|
||||
version "10.8.6"
|
||||
resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-10.8.6.tgz#ebf7f3c812c6517af84f0d8a10115e0dbfabe145"
|
||||
integrity sha512-bQmbVtsfbgaKBTWCKiDCPlUPbdlRIK/FzSwT3BzIgZl/cU6TqXu6pZJsCI/dJVrZ9Gir5GC4woqw9shH/v7MBw==
|
||||
|
||||
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz#e624f259143b9062c92b6413ff92a164c80d3ccb"
|
||||
|
@ -17051,16 +17051,6 @@ pretty-error@^2.1.1:
|
|||
renderkid "^2.0.1"
|
||||
utila "~0.4"
|
||||
|
||||
pretty-format@^24.9.0:
|
||||
version "24.9.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9"
|
||||
integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==
|
||||
dependencies:
|
||||
"@jest/types" "^24.9.0"
|
||||
ansi-regex "^4.0.0"
|
||||
ansi-styles "^3.2.0"
|
||||
react-is "^16.8.4"
|
||||
|
||||
pretty-format@^25.2.1, pretty-format@^25.5.0:
|
||||
version "25.5.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a"
|
||||
|
@ -17081,16 +17071,7 @@ pretty-format@^26.0.0, pretty-format@^26.5.2, pretty-format@^26.6.2:
|
|||
ansi-styles "^4.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^27.0.0:
|
||||
version "27.4.6"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7"
|
||||
integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^27.3.1, pretty-format@^27.5.1:
|
||||
pretty-format@^27.5.1:
|
||||
version "27.5.1"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
|
||||
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
|
||||
|
@ -17109,6 +17090,15 @@ pretty-format@^28.1.3:
|
|||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
pretty-format@^29.0.0, pretty-format@^29.0.3, pretty-format@^29.6.3:
|
||||
version "29.6.3"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.3.tgz#d432bb4f1ca6f9463410c3fb25a0ba88e594ace7"
|
||||
integrity sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==
|
||||
dependencies:
|
||||
"@jest/schemas" "^29.6.3"
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
pretty-format@^3.8.0:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385"
|
||||
|
@ -17430,11 +17420,6 @@ ramda@^0.21.0:
|
|||
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35"
|
||||
integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=
|
||||
|
||||
ramda@^0.26.1:
|
||||
version "0.26.1"
|
||||
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
|
||||
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
|
||||
|
||||
random-bytes@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
|
||||
|
@ -17617,7 +17602,7 @@ react-hook-form@^7.34.2:
|
|||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.34.2.tgz#9ac6d1a309a7c4aaa369d1269357a70e9e9bf4de"
|
||||
integrity sha512-1lYWbEqr0GW7HHUjMScXMidGvV0BE2RJV3ap2BL7G0EJirkqpccTaawbsvBO8GZaB3JjCeFBEbnEWI1P8ZoLRQ==
|
||||
|
||||
react-is@^16.12.0, react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4:
|
||||
react-is@^16.12.0, react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
@ -18269,13 +18254,13 @@ recursive-readdir@2.2.2:
|
|||
dependencies:
|
||||
minimatch "3.0.4"
|
||||
|
||||
redent@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
|
||||
integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=
|
||||
redent@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
|
||||
integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
|
||||
dependencies:
|
||||
indent-string "^3.0.0"
|
||||
strip-indent "^2.0.0"
|
||||
indent-string "^4.0.0"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
reduce-flatten@^2.0.0:
|
||||
version "2.0.0"
|
||||
|
@ -19788,11 +19773,6 @@ strip-final-newline@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
|
||||
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
|
||||
|
||||
strip-indent@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
|
||||
integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
|
||||
|
||||
strip-indent@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
|
||||
|
|
Loading…
Reference in New Issue