Merge branch 'develop' into detoxRunner

This commit is contained in:
Anant Bhasin 2021-05-19 10:58:14 +05:30
commit 6063add9ae
73 changed files with 34431 additions and 40101 deletions

View File

@ -290,6 +290,24 @@ commands:
command: bundle exec fastlane android beta official:<< parameters.official >> command: bundle exec fastlane android beta official:<< parameters.official >>
working_directory: android working_directory: android
# EXPERIMENTAL ONLY
# No plans to do it for Official
upload-to-google-play-production:
description: "Upload to Google Play production"
steps:
- checkout
- attach_workspace:
at: android
- run:
name: Store the google service account key
command: echo "$FASTLANE_GOOGLE_SERVICE_ACCOUNT" | base64 --decode > service_account.json
working_directory: android
- run: *update-fastlane-android
- run:
name: Fastlane Play Store Upload
command: bundle exec fastlane android production
working_directory: android
upload-to-testflight: upload-to-testflight:
description: "Upload to TestFlight" description: "Upload to TestFlight"
parameters: parameters:
@ -382,6 +400,13 @@ jobs:
- upload-to-google-play-beta: - upload-to-google-play-beta:
official: false official: false
android-google-play-production-experimental:
<<: *defaults
docker:
- image: circleci/android:api-28-node
steps:
- upload-to-google-play-production
android-google-play-beta-official: android-google-play-beta-official:
<<: *defaults <<: *defaults
docker: docker:
@ -466,6 +491,13 @@ workflows:
- android-google-play-beta-experimental: - android-google-play-beta-experimental:
requires: requires:
- android-hold-google-play-beta-experimental - android-hold-google-play-beta-experimental
- android-hold-google-play-production-experimental:
type: approval
requires:
- android-build-experimental
- android-google-play-production-experimental:
requires:
- android-hold-google-play-production-experimental
# Android Official # Android Official
- android-hold-build-official: - android-hold-build-official:

View File

@ -46,6 +46,7 @@ module.exports = {
"react/forbid-prop-types": 0, "react/forbid-prop-types": 0,
"jsx-quotes": [2, "prefer-single"], "jsx-quotes": [2, "prefer-single"],
"jsx-a11y/href-no-hash": 0, "jsx-a11y/href-no-hash": 0,
"jsx-a11y/aria-role": 0,
"import/prefer-default-export": 0, "import/prefer-default-export": 0,
"import/no-cycle": 0, "import/no-cycle": 0,
"camelcase": 0, "camelcase": 0,

File diff suppressed because it is too large Load Diff

View File

@ -144,7 +144,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer versionCode VERSIONCODE as Integer
versionName "4.16.0" versionName "4.16.2"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
if (!isFoss) { if (!isFoss) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String] manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]

View File

@ -32,4 +32,13 @@ platform :android do
) )
end end
end end
desc "Upload App to Play Store Production"
lane :production do |options|
upload_to_play_store(
package_name: 'chat.rocket.reactnative',
track: 'production',
aab: 'android/app/build/outputs/bundle/experimentalPlayRelease/app-experimental-play-release.aab'
)
end
end end

View File

@ -876,7 +876,7 @@ class MessageBox extends Component {
recording, showEmojiKeyboard, showSend, mentions, trackingType, commandPreview, showCommandPreview recording, showEmojiKeyboard, showSend, mentions, trackingType, commandPreview, showCommandPreview
} = this.state; } = this.state;
const { const {
editing, message, replying, replyCancel, user, getCustomEmoji, theme, Message_AudioRecorderEnabled, children, isActionsEnabled editing, message, replying, replyCancel, user, getCustomEmoji, theme, Message_AudioRecorderEnabled, children, isActionsEnabled, tmid
} = this.props; } = this.props;
const isAndroidTablet = isTablet && isAndroid ? { const isAndroidTablet = isTablet && isAndroid ? {
@ -936,7 +936,7 @@ class MessageBox extends Component {
underlineColorAndroid='transparent' underlineColorAndroid='transparent'
defaultValue='' defaultValue=''
multiline multiline
testID='messagebox-input' testID={`messagebox-input${ tmid ? '-thread' : '' }`}
theme={theme} theme={theme}
{...isAndroidTablet} {...isAndroidTablet}
/> />

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
View, Text, StyleSheet, TouchableOpacity View, Text, StyleSheet, TouchableOpacity
@ -149,11 +149,13 @@ const Header = React.memo(({
); );
} }
const handleOnPress = useCallback(() => onPress(), []);
return ( return (
<TouchableOpacity <TouchableOpacity
testID='room-header' testID='room-header'
accessibilityLabel={title} accessibilityLabel={title}
onPress={onPress} onPress={handleOnPress}
style={styles.container} style={styles.container}
disabled={tmid} disabled={tmid}
hitSlop={HIT_SLOP} hitSlop={HIT_SLOP}

View File

@ -18,6 +18,7 @@ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center' alignItems: 'center'
}, },
username: { username: {
@ -30,7 +31,7 @@ const styles = StyleSheet.create({
...sharedStyles.textMedium ...sharedStyles.textMedium
}, },
titleContainer: { titleContainer: {
flex: 1, flexShrink: 1,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center' alignItems: 'center'
}, },

5
app/definition/ITeam.js Normal file
View File

@ -0,0 +1,5 @@
// https://github.com/RocketChat/Rocket.Chat/blob/develop/definition/ITeam.ts
export const TEAM_TYPE = {
PUBLIC: 0,
PRIVATE: 1
};

View File

@ -79,19 +79,23 @@ export const setLanguage = (l) => {
return; return;
} }
// server uses lowercase pattern (pt-br), but we're forced to use standard pattern (pt-BR) // server uses lowercase pattern (pt-br), but we're forced to use standard pattern (pt-BR)
const locale = LANGUAGES.find(ll => ll.value.toLowerCase() === l.toLowerCase())?.value; let locale = LANGUAGES.find(ll => ll.value.toLowerCase() === l.toLowerCase())?.value;
if (!locale) {
locale = 'en';
}
// don't go forward if it's the same language and default language (en) was setup already // don't go forward if it's the same language and default language (en) was setup already
if (i18n.locale === locale && i18n.translations?.en) { if (i18n.locale === locale && i18n.translations?.en) {
return; return;
} }
i18n.locale = locale; i18n.locale = locale;
i18n.translations = { ...i18n.translations, [locale]: translations[locale]() }; i18n.translations = { ...i18n.translations, [locale]: translations[locale]?.() };
I18nManager.forceRTL(isRTL(locale)); I18nManager.forceRTL(isRTL(locale));
I18nManager.swapLeftAndRightInRTL(isRTL(locale)); I18nManager.swapLeftAndRightInRTL(isRTL(locale));
i18n.isRTL = I18nManager.isRTL; i18n.isRTL = I18nManager.isRTL;
moment.locale(toMomentLocale(locale)); moment.locale(toMomentLocale(locale));
}; };
i18n.translations = { en: translations.en?.() };
const defaultLanguage = { languageTag: 'en', isRTL: false }; const defaultLanguage = { languageTag: 'en', isRTL: false };
const availableLanguages = Object.keys(translations); const availableLanguages = Object.keys(translations);
const { languageTag } = RNLocalize.findBestAvailableLanguage(availableLanguages) || defaultLanguage; const { languageTag } = RNLocalize.findBestAvailableLanguage(availableLanguages) || defaultLanguage;

View File

@ -33,7 +33,7 @@
"error-invalid-date": "التاريخ غير صالح", "error-invalid-date": "التاريخ غير صالح",
"error-invalid-description": "الوصف غير صالح", "error-invalid-description": "الوصف غير صالح",
"error-invalid-domain": "عنوان الموقع غير صالح", "error-invalid-domain": "عنوان الموقع غير صالح",
"error-invalid-email": "عنوان البريد اﻹلكتروني غير صالح {{emai}}", "error-invalid-email": "عنوان البريد اﻹلكتروني غير صالح {{email}}",
"error-invalid-email-address": "عنوان البريد اﻹلكتروني غير صالح", "error-invalid-email-address": "عنوان البريد اﻹلكتروني غير صالح",
"error-invalid-file-height": "ارتفاع الملف غير صالح", "error-invalid-file-height": "ارتفاع الملف غير صالح",
"error-invalid-file-type": "نوع الملف غير صالح", "error-invalid-file-type": "نوع الملف غير صالح",
@ -100,7 +100,6 @@
"announcement": "إعلان", "announcement": "إعلان",
"Announcement": "إعلان", "Announcement": "إعلان",
"Apply_Your_Certificate": "طبق شهادتك", "Apply_Your_Certificate": "طبق شهادتك",
"Applying_a_theme_will_change_how_the_app_looks": "سيؤدي تطبيق السمة إلى تغيير شكل التطبيق",
"ARCHIVE": "أرشفة", "ARCHIVE": "أرشفة",
"archive": "أرشفة", "archive": "أرشفة",
"are_typing": "يكتب", "are_typing": "يكتب",
@ -184,8 +183,6 @@
"deleting_room": "حذف الغرفة", "deleting_room": "حذف الغرفة",
"description": "وصف", "description": "وصف",
"Description": "وصف", "Description": "وصف",
"DESKTOP_OPTIONS": "خيارات سطح المكتب",
"DESKTOP_NOTIFICATIONS": "إشعارات سطح المكتب",
"Desktop_Alert_info": "هذه الإشعارات ترسل لسطح المكتب", "Desktop_Alert_info": "هذه الإشعارات ترسل لسطح المكتب",
"Directory": "مجلد", "Directory": "مجلد",
"Direct_Messages": "رسالة مباشرة", "Direct_Messages": "رسالة مباشرة",
@ -213,7 +210,6 @@
"Email_Notification_Mode_Disabled": "معطل", "Email_Notification_Mode_Disabled": "معطل",
"Email_or_password_field_is_empty": "حقل البريد الإلكتروني أو كلمة المرور فارغ", "Email_or_password_field_is_empty": "حقل البريد الإلكتروني أو كلمة المرور فارغ",
"Email": "البريد الإلكتروني", "Email": "البريد الإلكتروني",
"EMAIL": "البريد الإلكتروني",
"email": "البريد الإلكتروني", "email": "البريد الإلكتروني",
"Empty_title": "عنوان فارغ", "Empty_title": "عنوان فارغ",
"Enable_Auto_Translate": "تمكين الترجمة التلقائية", "Enable_Auto_Translate": "تمكين الترجمة التلقائية",
@ -270,7 +266,6 @@
"I_Saved_My_E2E_Password": "قمت بحفظ كلمة المرور الطرفية", "I_Saved_My_E2E_Password": "قمت بحفظ كلمة المرور الطرفية",
"IP": " عنوان بروتوكول الإنترنت (الآيبي)", "IP": " عنوان بروتوكول الإنترنت (الآيبي)",
"In_app": "في التطبيق", "In_app": "في التطبيق",
"IN_APP_AND_DESKTOP": "داخل التطبيق وسطح المكتب",
"In_App_and_Desktop_Alert_info": "يعرض شعاراً أعلى الشاشة عندما يكون التطبيق مفتوحًا، ويعرض إشعاراً على سطح المكتب", "In_App_and_Desktop_Alert_info": "يعرض شعاراً أعلى الشاشة عندما يكون التطبيق مفتوحًا، ويعرض إشعاراً على سطح المكتب",
"Invisible": "غير مرئي", "Invisible": "غير مرئي",
"Invite": "دعوة", "Invite": "دعوة",
@ -398,7 +393,6 @@
"Profile": "الملف الشخصي", "Profile": "الملف الشخصي",
"Public_Channel": "قناة عامة", "Public_Channel": "قناة عامة",
"Public": "عام", "Public": "عام",
"PUSH_NOTIFICATIONS": "الإشعارات",
"Push_Notifications_Alert_Info": "يتم إرسال هذه الإشعارات إليك عندما لا يكون التطبيق مفتوحاً", "Push_Notifications_Alert_Info": "يتم إرسال هذه الإشعارات إليك عندما لا يكون التطبيق مفتوحاً",
"Quote": "اقتباس", "Quote": "اقتباس",
"Reactions_are_disabled": "التفاعل معطل", "Reactions_are_disabled": "التفاعل معطل",
@ -446,9 +440,9 @@
"Room_Members": "أعضاء الغرفة", "Room_Members": "أعضاء الغرفة",
"Room_name_changed": "تم تغيير اسم الغرفة إلى: {{name}} من قبل {{userBy}}", "Room_name_changed": "تم تغيير اسم الغرفة إلى: {{name}} من قبل {{userBy}}",
"SAVE": "حفظ", "SAVE": "حفظ",
"Saved": "تم الحفظ",
"Save_Changes": "حفظ التغيرات", "Save_Changes": "حفظ التغيرات",
"Save": "حفظ", "Save": "حفظ",
"Saved": "تم الحفظ",
"saving_preferences": "حفظ التفضيلات", "saving_preferences": "حفظ التفضيلات",
"saving_profile": "حفظ الملف الشخصي", "saving_profile": "حفظ الملف الشخصي",
"saving_settings": "حفظ الإعدادات", "saving_settings": "حفظ الإعدادات",

View File

@ -33,7 +33,7 @@
"error-invalid-date": "Ungültiges Datum angegeben", "error-invalid-date": "Ungültiges Datum angegeben",
"error-invalid-description": "Ungültige Beschreibung", "error-invalid-description": "Ungültige Beschreibung",
"error-invalid-domain": "Ungültige Domain", "error-invalid-domain": "Ungültige Domain",
"error-invalid-email": "Ungültige E-Mail {{emai}}", "error-invalid-email": "Ungültige E-Mail {{email}}",
"error-invalid-email-address": "Ungültige E-Mail-Adresse", "error-invalid-email-address": "Ungültige E-Mail-Adresse",
"error-invalid-file-height": "Ungültige Dateihöhe", "error-invalid-file-height": "Ungültige Dateihöhe",
"error-invalid-file-type": "Ungültiger Dateityp", "error-invalid-file-type": "Ungültiger Dateityp",
@ -69,7 +69,7 @@
"error-role-in-use": "Rolle kann nicht gelöscht werden, da sie gerade verwendet wird", "error-role-in-use": "Rolle kann nicht gelöscht werden, da sie gerade verwendet wird",
"error-role-name-required": "Der Rollenname ist erforderlich", "error-role-name-required": "Der Rollenname ist erforderlich",
"error-the-field-is-required": "Das Feld {{field}} ist erforderlich.", "error-the-field-is-required": "Das Feld {{field}} ist erforderlich.",
"error-too-many-requests": "Fehler, zu viele Anfragen. Du musst {{Sekunden}} Sekunden warten, bevor du es erneut versuchst.", "error-too-many-requests": "Fehler, zu viele Anfragen. Du musst {{seconds}} Sekunden warten, bevor du es erneut versuchst.",
"error-user-is-not-activated": "Benutzer ist nicht aktiviert", "error-user-is-not-activated": "Benutzer ist nicht aktiviert",
"error-user-has-no-roles": "Benutzer hat keine Rollen", "error-user-has-no-roles": "Benutzer hat keine Rollen",
"error-user-limit-exceeded": "Die Anzahl der Benutzer, die du zu #channel_name einladen möchtest, überschreitet die vom Administrator festgelegte Grenze", "error-user-limit-exceeded": "Die Anzahl der Benutzer, die du zu #channel_name einladen möchtest, überschreitet die vom Administrator festgelegte Grenze",
@ -185,6 +185,7 @@
"Description": "Beschreibung", "Description": "Beschreibung",
"Desktop_Options": "Desktop-Einstellungen", "Desktop_Options": "Desktop-Einstellungen",
"Desktop_Notifications": "Desktop-Benachrichtigungen", "Desktop_Notifications": "Desktop-Benachrichtigungen",
"Desktop_Alert_info": "Diese Benachrichtigungen werden auf dem Desktop angezeigt",
"Directory": "Verzeichnis", "Directory": "Verzeichnis",
"Direct_Messages": "Direkte Nachrichten", "Direct_Messages": "Direkte Nachrichten",
"Disable_notifications": "Benachrichtigungen deaktiveren", "Disable_notifications": "Benachrichtigungen deaktiveren",
@ -276,7 +277,7 @@
"is_not_a_valid_RocketChat_instance": "ist keine gültige Rocket.Chat-Instanz", "is_not_a_valid_RocketChat_instance": "ist keine gültige Rocket.Chat-Instanz",
"is_typing": "schreibt", "is_typing": "schreibt",
"Invalid_or_expired_invite_token": "Ungültiger oder abgelaufener Einladungscode", "Invalid_or_expired_invite_token": "Ungültiger oder abgelaufener Einladungscode",
"Invalid_server_version": "Der Server, zu dem du dich verbinden möchtest, verwendet eine Version, die von der App nicht mehr unterstützt wird: {{currentVersion}}.\n\nWir benötigen Version {{MinVersion}}.", "Invalid_server_version": "Der Server, zu dem du dich verbinden möchtest, verwendet eine Version, die von der App nicht mehr unterstützt wird: {{currentVersion}}.\n\nWir benötigen Version {{minVersion}}.",
"Invite_Link": "Einladungs-Link", "Invite_Link": "Einladungs-Link",
"Invite_users": "Benutzer einladen", "Invite_users": "Benutzer einladen",
"Join": "Beitreten", "Join": "Beitreten",
@ -400,7 +401,6 @@
"Public": "Öffentlich", "Public": "Öffentlich",
"Push_Notifications": "Push-Benachrichtigungen", "Push_Notifications": "Push-Benachrichtigungen",
"Push_Notifications_Alert_Info": "Diese Benachrichtigungen werden dir zugestellt, wenn die App nicht geöffnet ist.", "Push_Notifications_Alert_Info": "Diese Benachrichtigungen werden dir zugestellt, wenn die App nicht geöffnet ist.",
"Desktop_Alert_info": "Diese Benachrichtigungen werden auf dem Desktop angezeigt",
"Quote": "Zitat", "Quote": "Zitat",
"Reactions_are_disabled": "Reaktionen sind deaktiviert", "Reactions_are_disabled": "Reaktionen sind deaktiviert",
"Reactions_are_enabled": "Reaktionen sind aktiviert", "Reactions_are_enabled": "Reaktionen sind aktiviert",

View File

@ -33,7 +33,7 @@
"error-invalid-date": "Invalid date provided.", "error-invalid-date": "Invalid date provided.",
"error-invalid-description": "Invalid description", "error-invalid-description": "Invalid description",
"error-invalid-domain": "Invalid domain", "error-invalid-domain": "Invalid domain",
"error-invalid-email": "Invalid email {{emai}}", "error-invalid-email": "Invalid email {{email}}",
"error-invalid-email-address": "Invalid email address", "error-invalid-email-address": "Invalid email address",
"error-invalid-file-height": "Invalid file height", "error-invalid-file-height": "Invalid file height",
"error-invalid-file-type": "Invalid file type", "error-invalid-file-type": "Invalid file type",
@ -709,5 +709,12 @@
"This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}", "This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}",
"Teams": "Teams", "Teams": "Teams",
"No_team_channels_found": "No channels found", "No_team_channels_found": "No channels found",
"Team_not_found": "Team not found" "Team_not_found": "Team not found",
"Create_Team": "Create Team",
"Team_Name": "Team Name",
"Private_Team": "Private Team",
"Read_Only_Team": "Read Only Team",
"Broadcast_Team": "Broadcast Team",
"creating_team": "creating team",
"team-name-already-exists": "A team with that name already exists"
} }

View File

@ -30,7 +30,7 @@
"error-invalid-date": "La fecha proporcionada no es correcta.", "error-invalid-date": "La fecha proporcionada no es correcta.",
"error-invalid-description": "La descipción no es correcta", "error-invalid-description": "La descipción no es correcta",
"error-invalid-domain": "El dominio no es correcto", "error-invalid-domain": "El dominio no es correcto",
"error-invalid-email": "El email {{emai}} no es correcto", "error-invalid-email": "El email {{email}} no es correcto",
"error-invalid-email-address": "La dirección de correo no es correcta", "error-invalid-email-address": "La dirección de correo no es correcta",
"error-invalid-file-height": "La altura de la imagen no es correcta", "error-invalid-file-height": "La altura de la imagen no es correcta",
"error-invalid-file-type": "El formato del archivo no es correcto", "error-invalid-file-type": "El formato del archivo no es correcto",
@ -44,7 +44,7 @@
"error-invalid-redirectUri": "La URL de redirección no es correcta.", "error-invalid-redirectUri": "La URL de redirección no es correcta.",
"error-invalid-role": "El rol no es correcto", "error-invalid-role": "El rol no es correcto",
"error-invalid-room": "La sala no es correcta", "error-invalid-room": "La sala no es correcta",
"error-invalid-room-name": "No se puede asignar el nombre {{name}} a una sala.", "error-invalid-room-name": "No se puede asignar el nombre {{room_name}} a una sala.",
"error-invalid-room-type": "No se puede asginar el tipo {{type}} a una sala.", "error-invalid-room-type": "No se puede asginar el tipo {{type}} a una sala.",
"error-invalid-settings": "La configuración proporcionada no es correcta", "error-invalid-settings": "La configuración proporcionada no es correcta",
"error-invalid-subscription": "La subscripción no es correcta", "error-invalid-subscription": "La subscripción no es correcta",
@ -80,7 +80,6 @@
"Activity": "Actividad", "Activity": "Actividad",
"Add_Reaction": "Reaccionar", "Add_Reaction": "Reaccionar",
"Add_Server": "Añadir servidor", "Add_Server": "Añadir servidor",
"Add_user": "Añadir usuario",
"Admin_Panel": "Panel de Control", "Admin_Panel": "Panel de Control",
"Alert": "Alerta", "Alert": "Alerta",
"alert": "alerta", "alert": "alerta",

View File

@ -33,7 +33,7 @@
"error-invalid-date": "Date fournie invalide.", "error-invalid-date": "Date fournie invalide.",
"error-invalid-description": "Description invalide", "error-invalid-description": "Description invalide",
"error-invalid-domain": "Domaine invalide", "error-invalid-domain": "Domaine invalide",
"error-invalid-email": "Adresse e-mail non valide {{emai}}", "error-invalid-email": "Adresse e-mail non valide {{email}}",
"error-invalid-email-address": "Adresse e-mail invalide", "error-invalid-email-address": "Adresse e-mail invalide",
"error-invalid-file-height": "Hauteur de fichier non valide", "error-invalid-file-height": "Hauteur de fichier non valide",
"error-invalid-file-type": "Type de fichier invalide", "error-invalid-file-type": "Type de fichier invalide",

View File

@ -33,7 +33,7 @@
"error-invalid-date": "Data fornita non valida.", "error-invalid-date": "Data fornita non valida.",
"error-invalid-description": "Descrizione non valida", "error-invalid-description": "Descrizione non valida",
"error-invalid-domain": "Dominio non valido", "error-invalid-domain": "Dominio non valido",
"error-invalid-email": "E-mail {{emai}} non valida", "error-invalid-email": "E-mail {{email}} non valida",
"error-invalid-email-address": "Indirizzo e-mail non valido", "error-invalid-email-address": "Indirizzo e-mail non valido",
"error-invalid-file-height": "Altezza del file non valida", "error-invalid-file-height": "Altezza del file non valida",
"error-invalid-file-type": "Tipo di file non valido", "error-invalid-file-type": "Tipo di file non valido",
@ -157,8 +157,8 @@
"Continue_with": "Continua con", "Continue_with": "Continua con",
"Copied_to_clipboard": "Copiato negli appunti!", "Copied_to_clipboard": "Copiato negli appunti!",
"Copy": "Copia", "Copy": "Copia",
"Permalink": "Permalink",
"Conversation": "Conversazione", "Conversation": "Conversazione",
"Permalink": "Permalink",
"Certificate_password": "Password certificato", "Certificate_password": "Password certificato",
"Clear_cache": "Cancella la cache locale", "Clear_cache": "Cancella la cache locale",
"Clear_cache_loading": "Cancellando la cache.", "Clear_cache_loading": "Cancellando la cache.",

View File

@ -31,7 +31,7 @@
"error-invalid-date": "不正な日時です", "error-invalid-date": "不正な日時です",
"error-invalid-description": "不正な詳細です", "error-invalid-description": "不正な詳細です",
"error-invalid-domain": "不正なドメインです", "error-invalid-domain": "不正なドメインです",
"error-invalid-email": "不正なメールアドレスです。 {{emai}}", "error-invalid-email": "不正なメールアドレスです。 {{email}}",
"error-invalid-email-address": "不正なメールアドレスです", "error-invalid-email-address": "不正なメールアドレスです",
"error-invalid-file-height": "ファイルの高さが不正です", "error-invalid-file-height": "ファイルの高さが不正です",
"error-invalid-file-type": "ファイルの種類が不正です", "error-invalid-file-type": "ファイルの種類が不正です",
@ -179,7 +179,6 @@
"Email": "メールアドレス", "Email": "メールアドレス",
"email": "メールアドレス", "email": "メールアドレス",
"Enable_Auto_Translate": "自動翻訳を有効にする", "Enable_Auto_Translate": "自動翻訳を有効にする",
"Enable_markdown": "マークダウンを有効にする",
"Enable_notifications": "通知を有効にする", "Enable_notifications": "通知を有効にする",
"Everyone_can_access_this_channel": "全員このチャンネルにアクセスできます", "Everyone_can_access_this_channel": "全員このチャンネルにアクセスできます",
"Error_uploading": "アップロードエラー", "Error_uploading": "アップロードエラー",
@ -432,7 +431,7 @@
"Users": "ユーザー", "Users": "ユーザー",
"User_added_by": "{{userBy}} が {{userAdded}} を追加しました", "User_added_by": "{{userBy}} が {{userAdded}} を追加しました",
"User_Info": "ユーザー情報", "User_Info": "ユーザー情報",
"User_has_been_key": "ユーザーは{{ key }}", "User_has_been_key": "ユーザーは{{key}}",
"User_is_no_longer_role_by_": "{{userBy}} は {{user}} のロール {{role}} を削除しました。", "User_is_no_longer_role_by_": "{{userBy}} は {{user}} のロール {{role}} を削除しました。",
"User_muted_by": "{{userBy}} は {{userMuted}} をミュートしました。", "User_muted_by": "{{userBy}} は {{userMuted}} をミュートしました。",
"User_removed_by": "{{userBy}} は {{userRemoved}} を退出させました。", "User_removed_by": "{{userBy}} は {{userRemoved}} を退出させました。",

View File

@ -1,7 +1,7 @@
{ {
"1_person_reacted": "1 persoon heeft gereageerd", "1_person_reacted": "1 persoon heeft gereageerd",
"1_user": "1 gebruiker", "1_user": "1 gebruiker",
"error-action-not-allowed": "{{actie}} is niet toegestaan", "error-action-not-allowed": "{{action}} is niet toegestaan",
"error-application-not-found": "Applicatie niet gevonden", "error-application-not-found": "Applicatie niet gevonden",
"error-archived-duplicate-name": "Er is een gearchiveerd kanaal met de naam {{room_name}}", "error-archived-duplicate-name": "Er is een gearchiveerd kanaal met de naam {{room_name}}",
"error-avatar-invalid-url": "Foutieve avatar URL: {{url}}", "error-avatar-invalid-url": "Foutieve avatar URL: {{url}}",
@ -31,7 +31,7 @@
"error-invalid-date": "Ongeldige datum opgegeven.", "error-invalid-date": "Ongeldige datum opgegeven.",
"error-invalid-description": "Ongeldige beschrijving", "error-invalid-description": "Ongeldige beschrijving",
"error-invalid-domain": "Ongeldig domein", "error-invalid-domain": "Ongeldig domein",
"error-invalid-email": "Ongeldige email {{emai}}", "error-invalid-email": "Ongeldige email {{email}}",
"error-invalid-email-address": "Ongeldig emailadres", "error-invalid-email-address": "Ongeldig emailadres",
"error-invalid-file-height": "Ongeldige file height", "error-invalid-file-height": "Ongeldige file height",
"error-invalid-file-type": "Ongeldig bestandstype", "error-invalid-file-type": "Ongeldig bestandstype",
@ -123,7 +123,6 @@
"creating_invite": "uitnodiging maken", "creating_invite": "uitnodiging maken",
"Channel_Name": "Kanaal Name", "Channel_Name": "Kanaal Name",
"Channels": "Kanalen", "Channels": "Kanalen",
"Chats": "Chats",
"Call_already_ended": "Gesprek al beeïndigd!", "Call_already_ended": "Gesprek al beeïndigd!",
"Click_to_join": "Klik om lid te worden!", "Click_to_join": "Klik om lid te worden!",
"Close": "Sluiten", "Close": "Sluiten",

View File

@ -62,22 +62,14 @@
"error-no-tokens-for-this-user": "Não existem tokens para este usuário", "error-no-tokens-for-this-user": "Não existem tokens para este usuário",
"error-not-allowed": "Não permitido", "error-not-allowed": "Não permitido",
"error-not-authorized": "Não autorizado", "error-not-authorized": "Não autorizado",
"error-password-policy-not-met": "A senha não atende a política do servidor",
"error-password-policy-not-met-maxLength": "A senha não está de acordo com a política de comprimento máximo do servidor (senha muito longa)",
"error-password-policy-not-met-minLength": "A senha não está de acordo com a política de comprimento mínimo do servidor (senha muito curta)",
"error-password-policy-not-met-oneLowercase": "A senha não está de acordo com a política do servidor de pelo menos um caractere minúsculo.",
"error-password-policy-not-met-oneNumber": "A senha não está de acordo com a política do servidor, de pelo menos um caractere numérico.",
"error-password-policy-not-met-oneSpecial": "A senha não está de acordo com a política do servidor, de pelo menos um caractere especial.",
"error-password-policy-not-met-oneUppercase": "A senha não está de acordo com a política do servidor, de pelo menos um caractere maiúsculo.",
"error-password-policy-not-met-repeatingCharacters": "A senha não está de acordo com a política do servidor, relativamente aos caracteres proibidos repetidos (existem vários caracteres proibidos próximos uns dos outros)",
"error-push-disabled": "Notificações push desativadas", "error-push-disabled": "Notificações push desativadas",
"error-remove-last-owner": "Este é o último proprietário. Por favor, defina um novo proprietário antes de remover este.", "error-remove-last-owner": "Este é o último proprietário. Por favor, defina um novo proprietário antes de remover este.",
"error-role-in-use": "Não é possível remover o papel pois ele está em uso", "error-role-in-use": "Não é possível remover o papel pois ele está em uso",
"error-role-name-required": "Nome do papel é obrigatório", "error-role-name-required": "Nome do papel é obrigatório",
"error-the-field-is-required": "O campo {{field}} é obrigatório.", "error-the-field-is-required": "O campo {{field}} é obrigatório.",
"error-too-many-requests": "Erro, muitas solicitações. Por favor, diminua a velocidade. Você deve esperar {{seconds}} segundos antes de tentar novamente.", "error-too-many-requests": "Erro, muitas solicitações. Por favor, diminua a velocidade. Você deve esperar {{seconds}} segundos antes de tentar novamente.",
"error-user-has-no-roles": "O usuário não possui permissões",
"error-user-is-not-activated": "O usuário não está ativo", "error-user-is-not-activated": "O usuário não está ativo",
"error-user-has-no-roles": "O usuário não possui permissões",
"error-user-limit-exceeded": "O número de usuários que você está tentando convidar para #channel_name excede o limite determindado pelo administrador", "error-user-limit-exceeded": "O número de usuários que você está tentando convidar para #channel_name excede o limite determindado pelo administrador",
"error-user-not-in-room": "O usuário não está nesta sala", "error-user-not-in-room": "O usuário não está nesta sala",
"error-user-registration-disabled": "O registro do usuário está desativado", "error-user-registration-disabled": "O registro do usuário está desativado",
@ -102,6 +94,7 @@
"and": "e", "and": "e",
"announcement": "anúncio", "announcement": "anúncio",
"Announcement": "Anúncio", "Announcement": "Anúncio",
"Apply_Your_Certificate": "Aplicar certificado",
"ARCHIVE": "ARQUIVAR", "ARCHIVE": "ARQUIVAR",
"archive": "arquivar", "archive": "arquivar",
"are_typing": "estão digitando", "are_typing": "estão digitando",
@ -131,10 +124,7 @@
"Channel_Name": "Nome do Canal", "Channel_Name": "Nome do Canal",
"Channels": "Canais", "Channels": "Canais",
"Chats": "Conversas", "Chats": "Conversas",
"Change_Language": "Alterar idioma",
"Change_language_loading": "Alterando idioma.",
"Call_already_ended": "A chamada já terminou!", "Call_already_ended": "A chamada já terminou!",
"Clear_cache_loading": "Limpando cache.",
"Clear_cookies_alert": "Você quer limpar seus cookies?", "Clear_cookies_alert": "Você quer limpar seus cookies?",
"Clear_cookies_desc": "Esta ação limpará todos os cookies de login permitindo que você faça login em outras contas.", "Clear_cookies_desc": "Esta ação limpará todos os cookies de login permitindo que você faça login em outras contas.",
"Clear_cookies_yes": "Sim, limpar cookies", "Clear_cookies_yes": "Sim, limpar cookies",
@ -143,8 +133,9 @@
"Close": "Fechar", "Close": "Fechar",
"Close_emoji_selector": "Fechar seletor de emojis", "Close_emoji_selector": "Fechar seletor de emojis",
"Closing_chat": "Fechando conversa", "Closing_chat": "Fechando conversa",
"Choose": "Escolher", "Change_language_loading": "Alterando idioma.",
"Chat_closed_by_agent": "Conversa fechada por agente", "Chat_closed_by_agent": "Conversa fechada por agente",
"Choose": "Escolher",
"Choose_from_library": "Escolha da biblioteca", "Choose_from_library": "Escolha da biblioteca",
"Choose_file": "Enviar arquivo", "Choose_file": "Enviar arquivo",
"Choose_where_you_want_links_be_opened": "Escolha onde deseja que os links sejam abertos", "Choose_where_you_want_links_be_opened": "Escolha onde deseja que os links sejam abertos",
@ -154,15 +145,16 @@
"Confirm": "Confirmar", "Confirm": "Confirmar",
"Connect": "Conectar", "Connect": "Conectar",
"Connected": "Conectado", "Connected": "Conectado",
"Conversation": "Conversação",
"connecting_server": "conectando no servidor", "connecting_server": "conectando no servidor",
"Connecting": "Conectando...", "Connecting": "Conectando...",
"Contact_us": "Entre em contato", "Contact_us": "Entre em contato",
"Continue_with": "Entrar com",
"Contact_your_server_admin": "Contate o administrador do servidor.", "Contact_your_server_admin": "Contate o administrador do servidor.",
"Continue_with": "Entrar com",
"Copied_to_clipboard": "Copiado para a área de transferência!", "Copied_to_clipboard": "Copiado para a área de transferência!",
"Copy": "Copiar", "Copy": "Copiar",
"Conversation": "Conversação",
"Permalink": "Link-Permanente", "Permalink": "Link-Permanente",
"Clear_cache_loading": "Limpando cache.",
"Create_account": "Criar conta", "Create_account": "Criar conta",
"Create_Channel": "Criar Canal", "Create_Channel": "Criar Canal",
"Create_Direct_Messages": "Criar Mensagens Diretas", "Create_Direct_Messages": "Criar Mensagens Diretas",
@ -172,19 +164,21 @@
"Create": "Criar", "Create": "Criar",
"Dark": "Escuro", "Dark": "Escuro",
"Dark_level": "Nível escuro", "Dark_level": "Nível escuro",
"Default": "Padrão",
"Default_browser": "Navegador padrão", "Default_browser": "Navegador padrão",
"Delete_Room_Warning": "A exclusão de uma sala irá apagar todas as mensagens postadas na sala. Isso não pode ser desfeito.", "Delete_Room_Warning": "A exclusão de uma sala irá apagar todas as mensagens postadas na sala. Isso não pode ser desfeito.",
"Department": "Departamento",
"delete": "excluir", "delete": "excluir",
"Delete": "Excluir", "Delete": "Excluir",
"DELETE": "EXCLUIR", "DELETE": "EXCLUIR",
"deleting_room": "excluindo sala", "deleting_room": "excluindo sala",
"Direct_Messages": "Mensagens Diretas", "description": "descrição",
"Description": "Descrição",
"Desktop_Options": "Opções De Área De Trabalho", "Desktop_Options": "Opções De Área De Trabalho",
"Desktop_Notifications": "Notificações da Área de Trabalho", "Desktop_Notifications": "Notificações da Área de Trabalho",
"Desktop_Alert_info": "Essas notificações são entregues a você na área de trabalho", "Desktop_Alert_info": "Essas notificações são entregues a você na área de trabalho",
"Directory": "Diretório", "Directory": "Diretório",
"description": "descrição", "Direct_Messages": "Mensagens Diretas",
"Description": "Descrição",
"Disable_notifications": "Desabilitar notificações", "Disable_notifications": "Desabilitar notificações",
"Discussions": "Discussões", "Discussions": "Discussões",
"Discussion_Desc": "Ajude a manter uma visão geral sobre o que está acontecendo! Ao criar uma discussão, um sub-canal do que você selecionou é criado e os dois são vinculados.", "Discussion_Desc": "Ajude a manter uma visão geral sobre o que está acontecendo! Ao criar uma discussão, um sub-canal do que você selecionou é criado e os dois são vinculados.",
@ -192,6 +186,7 @@
"Done": "Pronto", "Done": "Pronto",
"Dont_Have_An_Account": "Não tem uma conta?", "Dont_Have_An_Account": "Não tem uma conta?",
"Do_you_have_an_account": "Você tem uma conta?", "Do_you_have_an_account": "Você tem uma conta?",
"Do_you_have_a_certificate": "Você tem um certificado?",
"Do_you_really_want_to_key_this_room_question_mark": "Você quer realmente {{key}} esta sala?", "Do_you_really_want_to_key_this_room_question_mark": "Você quer realmente {{key}} esta sala?",
"E2E_Encryption": "Encriptação ponta a ponta", "E2E_Encryption": "Encriptação ponta a ponta",
"E2E_How_It_Works_info1": "Agora você pode criar grupos privados criptografados e mensagens diretas. Você também pode alterar grupos privados existentes ou DMs para criptografados.", "E2E_How_It_Works_info1": "Agora você pode criar grupos privados criptografados e mensagens diretas. Você também pode alterar grupos privados existentes ou DMs para criptografados.",
@ -201,16 +196,16 @@
"edit": "editar", "edit": "editar",
"edited": "editado", "edited": "editado",
"Edit": "Editar", "Edit": "Editar",
"Edit_Invite": "Editar convite",
"Edit_Status": "Editar Status", "Edit_Status": "Editar Status",
"Edit_Invite": "Editar convite",
"End_to_end_encrypted_room": "Sala criptografada de ponta a ponta", "End_to_end_encrypted_room": "Sala criptografada de ponta a ponta",
"end_to_end_encryption": "criptografia de ponta a ponta", "end_to_end_encryption": "criptografia de ponta a ponta",
"Email_Notification_Mode_All": "Cada Menção / Mensagem Direta",
"Email_Notification_Mode_Disabled": "Desativado",
"Email_or_password_field_is_empty": "Email ou senha estão vazios", "Email_or_password_field_is_empty": "Email ou senha estão vazios",
"Email": "E-mail", "Email": "E-mail",
"email": "e-mail", "email": "e-mail",
"Empty_title": "Título vazio", "Empty_title": "Título vazio",
"Email_Notification_Mode_All": "Cada Menção / Mensagem Direta",
"Email_Notification_Mode_Disabled": "Desativado",
"Enable_Auto_Translate": "Ativar a tradução automática", "Enable_Auto_Translate": "Ativar a tradução automática",
"Enable_notifications": "Habilitar notificações", "Enable_notifications": "Habilitar notificações",
"Encrypted": "Criptografado", "Encrypted": "Criptografado",
@ -223,6 +218,7 @@
"Everyone_can_access_this_channel": "Todos podem acessar este canal", "Everyone_can_access_this_channel": "Todos podem acessar este canal",
"Error_uploading": "Erro subindo", "Error_uploading": "Erro subindo",
"Expiration_Days": "Expira em (dias)", "Expiration_Days": "Expira em (dias)",
"Favorite": "Adicionar aos Favoritos",
"Favorites": "Favoritos", "Favorites": "Favoritos",
"Files": "Arquivos", "Files": "Arquivos",
"File_description": "Descrição do arquivo", "File_description": "Descrição do arquivo",
@ -241,6 +237,7 @@
"Generate_New_Link": "Gerar novo convite", "Generate_New_Link": "Gerar novo convite",
"Group_by_favorites": "Agrupar favoritos", "Group_by_favorites": "Agrupar favoritos",
"Group_by_type": "Agrupar por tipo", "Group_by_type": "Agrupar por tipo",
"Hide": "Ocultar",
"Has_joined_the_channel": "entrou no canal", "Has_joined_the_channel": "entrou no canal",
"Has_joined_the_conversation": "entrou na conversa", "Has_joined_the_conversation": "entrou na conversa",
"Has_left_the_channel": "saiu da conversa", "Has_left_the_channel": "saiu da conversa",
@ -286,8 +283,8 @@
"Login": "Entrar", "Login": "Entrar",
"Login_error": "Suas credenciais foram rejeitadas. Tente novamente por favor!", "Login_error": "Suas credenciais foram rejeitadas. Tente novamente por favor!",
"Login_with": "Login with", "Login_with": "Login with",
"Logout": "Sair",
"Logging_out": "Saindo.", "Logging_out": "Saindo.",
"Logout": "Sair",
"Max_number_of_uses": "Número máximo de usos", "Max_number_of_uses": "Número máximo de usos",
"Max_number_of_users_allowed_is_number": "Número máximo de usuários é {{maxUsers}}", "Max_number_of_users_allowed_is_number": "Número máximo de usuários é {{maxUsers}}",
"Members": "Membros", "Members": "Membros",
@ -300,6 +297,7 @@
"Message_removed": "Mensagem removida", "Message_removed": "Mensagem removida",
"message": "mensagem", "message": "mensagem",
"messages": "mensagens", "messages": "mensagens",
"Message": "Mensagem",
"Messages": "Mensagens", "Messages": "Mensagens",
"Microphone_Permission_Message": "Rocket.Chat precisa de acesso ao seu microfone para enviar mensagens de áudio.", "Microphone_Permission_Message": "Rocket.Chat precisa de acesso ao seu microfone para enviar mensagens de áudio.",
"Microphone_Permission": "Acesso ao Microfone", "Microphone_Permission": "Acesso ao Microfone",
@ -311,7 +309,6 @@
"Name": "Nome", "Name": "Nome",
"Navigation_history": "Histórico de navegação", "Navigation_history": "Histórico de navegação",
"Never": "Nunca", "Never": "Nunca",
"New_in_RocketChat_question_mark": "Novo no Rocket.Chat?",
"New_Message": "Nova Mensagem", "New_Message": "Nova Mensagem",
"New_Password": "Nova Senha", "New_Password": "Nova Senha",
"Next": "Próximo", "Next": "Próximo",
@ -326,19 +323,20 @@
"No_Message": "Não há mensagens", "No_Message": "Não há mensagens",
"No_messages_yet": "Não há mensagens ainda", "No_messages_yet": "Não há mensagens ainda",
"No_Reactions": "Sem reações", "No_Reactions": "Sem reações",
"Not_RC_Server": "Este não é um servidor Rocket.Chat.\n{{contact}}",
"Nothing": "Nada",
"Nothing_to_save": "Nada para salvar!", "Nothing_to_save": "Nada para salvar!",
"Notify_active_in_this_room": "Notificar usuários ativos nesta sala", "Notify_active_in_this_room": "Notificar usuários ativos nesta sala",
"Notify_all_in_this_room": "Notificar todos nesta sala", "Notify_all_in_this_room": "Notificar todos nesta sala",
"Notifications": "Notificações", "Notifications": "Notificações",
"Notification_Duration": "Duração da notificação", "Notification_Duration": "Duração da notificação",
"Notification_Preferences": "Preferências de notificação", "Notification_Preferences": "Preferências de notificação",
"Not_RC_Server": "Este não é um servidor Rocket.Chat.\n{{contact}}",
"No_available_agents_to_transfer": "Nenhum agente disponível para transferência", "No_available_agents_to_transfer": "Nenhum agente disponível para transferência",
"Offline": "Offline", "Offline": "Offline",
"Oops": "Ops!",
"Omnichannel": "Omnichannel", "Omnichannel": "Omnichannel",
"Open_Livechats": "Bate-papos em Andamento", "Open_Livechats": "Bate-papos em Andamento",
"Omnichannel_enable_alert": "Você não está disponível no Omnichannel. Você quer ficar disponível?", "Omnichannel_enable_alert": "Você não está disponível no Omnichannel. Você quer ficar disponível?",
"Oops": "Ops!",
"Onboarding_description": "Workspace é o espaço de colaboração do seu time ou organização. Peça um convite ou o endereço ao seu administrador ou crie uma workspace para o seu time.", "Onboarding_description": "Workspace é o espaço de colaboração do seu time ou organização. Peça um convite ou o endereço ao seu administrador ou crie uma workspace para o seu time.",
"Onboarding_join_workspace": "Entre numa workspace", "Onboarding_join_workspace": "Entre numa workspace",
"Onboarding_subtitle": "Além da colaboração em equipe", "Onboarding_subtitle": "Além da colaboração em equipe",
@ -358,13 +356,14 @@
"Password": "Senha", "Password": "Senha",
"Parent_channel_or_group": "Canal ou grupo pai", "Parent_channel_or_group": "Canal ou grupo pai",
"Permalink_copied_to_clipboard": "Link-permanente copiado para a área de transferência!", "Permalink_copied_to_clipboard": "Link-permanente copiado para a área de transferência!",
"Phone": "Telefone",
"Pin": "Fixar", "Pin": "Fixar",
"Pinned_Messages": "Mensagens Fixadas", "Pinned_Messages": "Mensagens Fixadas",
"pinned": "fixada", "pinned": "fixada",
"Pinned": "Mensagens Fixadas", "Pinned": "Mensagens Fixadas",
"Please_wait": "Por favor, aguarde.",
"Please_enter_your_password": "Por favor, digite sua senha",
"Please_add_a_comment": "Por favor, adicione um comentário", "Please_add_a_comment": "Por favor, adicione um comentário",
"Please_enter_your_password": "Por favor, digite sua senha",
"Please_wait": "Por favor, aguarde.",
"Preferences": "Preferências", "Preferences": "Preferências",
"Preferences_saved": "Preferências salvas!", "Preferences_saved": "Preferências salvas!",
"Privacy_Policy": " Política de Privacidade", "Privacy_Policy": " Política de Privacidade",
@ -386,15 +385,16 @@
"Read_External_Permission": "Permissão de acesso à arquivos", "Read_External_Permission": "Permissão de acesso à arquivos",
"Read_Only_Channel": "Canal Somente Leitura", "Read_Only_Channel": "Canal Somente Leitura",
"Read_Only": "Somente Leitura", "Read_Only": "Somente Leitura",
"Read_Receipt": "Lida por",
"Receive_Group_Mentions": "Receber menções de grupo", "Receive_Group_Mentions": "Receber menções de grupo",
"Receive_Group_Mentions_Info": "Receber menções @all e @here", "Receive_Group_Mentions_Info": "Receber menções @all e @here",
"Register": "Registrar", "Register": "Registrar",
"Read_Receipt": "Lida por",
"Repeat_Password": "Repetir Senha", "Repeat_Password": "Repetir Senha",
"Replied_on": "Respondido em:", "Replied_on": "Respondido em:",
"replies": "respostas", "replies": "respostas",
"reply": "resposta", "reply": "resposta",
"Reply": "Responder", "Reply": "Responder",
"Report": "Reportar",
"Receive_Notification": "Receber Notificação", "Receive_Notification": "Receber Notificação",
"Receive_notifications_from": "Receber notificação de {{name}}", "Receive_notifications_from": "Receber notificação de {{name}}",
"Resend": "Reenviar", "Resend": "Reenviar",
@ -424,6 +424,7 @@
"SAVE": "SALVAR", "SAVE": "SALVAR",
"Save_Changes": "Salvar Alterações", "Save_Changes": "Salvar Alterações",
"Save": "Salvar", "Save": "Salvar",
"Saved": "Salvo",
"saving_preferences": "salvando preferências", "saving_preferences": "salvando preferências",
"saving_profile": "salvando perfil", "saving_profile": "salvando perfil",
"saving_settings": "salvando configurações", "saving_settings": "salvando configurações",
@ -472,12 +473,14 @@
"starred": "favoritou", "starred": "favoritou",
"Starred": "Mensagens Favoritas", "Starred": "Mensagens Favoritas",
"Start_of_conversation": "Início da conversa", "Start_of_conversation": "Início da conversa",
"Started_call": "Chamada iniciada por {{userBy}}", "Start_a_Discussion": "Iniciar uma Discussão",
"Started_discussion": "Iniciou uma discussão:", "Started_discussion": "Iniciou uma discussão:",
"Started_call": "Chamada iniciada por {{userBy}}",
"Submit": "Enviar", "Submit": "Enviar",
"Table": "Tabela", "Table": "Tabela",
"Take_a_photo": "Tirar uma foto", "Take_a_photo": "Tirar uma foto",
"Take_a_video": "Gravar um vídeo", "Take_a_video": "Gravar um vídeo",
"Take_it": "Pegue!",
"Terms_of_Service": " Termos de Serviço ", "Terms_of_Service": " Termos de Serviço ",
"Theme": "Tema", "Theme": "Tema",
"The_user_wont_be_able_to_type_in_roomName": "O usuário não poderá digitar em {{roomName}}", "The_user_wont_be_able_to_type_in_roomName": "O usuário não poderá digitar em {{roomName}}",
@ -491,12 +494,14 @@
"To": "Para", "To": "Para",
"topic": "tópico", "topic": "tópico",
"Topic": "Tópico", "Topic": "Tópico",
"Translate": "Traduzir",
"Try_again": "Tentar novamente", "Try_again": "Tentar novamente",
"Two_Factor_Authentication": "Autenticação de dois fatores", "Two_Factor_Authentication": "Autenticação de dois fatores",
"Type_the_channel_name_here": "Digite o nome do canal", "Type_the_channel_name_here": "Digite o nome do canal",
"unarchive": "desarquivar", "unarchive": "desarquivar",
"UNARCHIVE": "DESARQUIVAR", "UNARCHIVE": "DESARQUIVAR",
"Unblock_user": "Desbloquear usuário", "Unblock_user": "Desbloquear usuário",
"Unfavorite": "Remover dos Favoritos",
"Unfollowed_thread": "Parou de seguir tópico", "Unfollowed_thread": "Parou de seguir tópico",
"Unmute": "Permitir que o usuário fale", "Unmute": "Permitir que o usuário fale",
"unmuted": "permitiu que o usuário fale", "unmuted": "permitiu que o usuário fale",
@ -511,6 +516,7 @@
"User": "Usuário", "User": "Usuário",
"Users": "Usuários", "Users": "Usuários",
"User_added_by": "Usuário {{userAdded}} adicionado por {{userBy}}", "User_added_by": "Usuário {{userAdded}} adicionado por {{userBy}}",
"User_Info": "Informações do usuário",
"User_has_been_key": "Usuário foi {{key}}", "User_has_been_key": "Usuário foi {{key}}",
"User_is_no_longer_role_by_": "{{user}} não pertence mais à {{role}} por {{userBy}}", "User_is_no_longer_role_by_": "{{user}} não pertence mais à {{role}} por {{userBy}}",
"User_muted_by": "User {{userMuted}} muted por {{userBy}}", "User_muted_by": "User {{userMuted}} muted por {{userBy}}",
@ -527,25 +533,31 @@
"Verify_email_desc": "Nós lhe enviamos um e-mail para confirmar o seu registro. Se você não receber um e-mail em breve, por favor retorne e tente novamente.", "Verify_email_desc": "Nós lhe enviamos um e-mail para confirmar o seu registro. Se você não receber um e-mail em breve, por favor retorne e tente novamente.",
"Verify_your_email_for_the_code_we_sent": "Verifique em seu e-mail o código que enviamos", "Verify_your_email_for_the_code_we_sent": "Verifique em seu e-mail o código que enviamos",
"Video_call": "Chamada de vídeo", "Video_call": "Chamada de vídeo",
"View_Original": "Visualizar original",
"Voice_call": "Chamada de voz", "Voice_call": "Chamada de voz",
"Waiting_for_network": "Aguardando rede...", "Waiting_for_network": "Aguardando rede...",
"Websocket_disabled": "Websocket está desativado para esse servidor.\n{{contact}}", "Websocket_disabled": "Websocket está desativado para esse servidor.\n{{contact}}",
"Welcome": "Bem vindo", "Welcome": "Bem vindo",
"Whats_your_2fa": "Qual seu código de autenticação?",
"What_are_you_doing_right_now": "O que você está fazendo agora?", "What_are_you_doing_right_now": "O que você está fazendo agora?",
"Whats_your_2fa": "Qual seu código de autenticação?",
"Without_Servers": "Sem Servidores", "Without_Servers": "Sem Servidores",
"Workspaces": "Workspaces", "Workspaces": "Workspaces",
"Would_you_like_to_return_the_inquiry": "Deseja retornar a consulta?",
"Write_External_Permission_Message": "Rocket.Chat precisa de acesso à sua galeria para salvar imagens",
"Write_External_Permission": "Acesso à Galeria",
"Yes": "Sim",
"Yes_action_it": "Sim, {{action}}!", "Yes_action_it": "Sim, {{action}}!",
"Yesterday": "Ontem", "Yesterday": "Ontem",
"You_are_in_preview_mode": "Está é uma prévia do canal", "You_are_in_preview_mode": "Está é uma prévia do canal",
"You_are_offline": "Você está offline", "You_are_offline": "Você está offline",
"You_can_search_using_RegExp_eg": "Você pode usar expressões regulares, por exemplo `/^text$/i`", "You_can_search_using_RegExp_eg": "Você pode usar expressões regulares, por exemplo `/^text$/i`",
"You_need_to_verifiy_your_email_address_to_get_notications": "Você precisa confirmar seu endereço de e-mail para obter notificações",
"You_colon": "Você: ", "You_colon": "Você: ",
"you_were_mentioned": "você foi mencionado", "you_were_mentioned": "você foi mencionado",
"You_were_removed_from_channel": "Você foi removido de {{channel}}", "You_were_removed_from_channel": "Você foi removido de {{channel}}",
"you": "você", "you": "você",
"You": "Você", "You": "Você",
"You_need_to_verifiy_your_email_address_to_get_notications": "Você precisa confirmar seu endereço de e-mail para obter notificações",
"Your_certificate": "Seu certificado",
"Your_invite_link_will_expire_after__usesLeft__uses": "Seu link de convite irá vencer depois de {{usesLeft}} usos.", "Your_invite_link_will_expire_after__usesLeft__uses": "Seu link de convite irá vencer depois de {{usesLeft}} usos.",
"Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Seu link de convite irá vencer em {{date}} ou depois de {{usesLeft}} usos.", "Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Seu link de convite irá vencer em {{date}} ou depois de {{usesLeft}} usos.",
"Your_invite_link_will_expire_on__date__": "Seu link de convite irá vencer em {{date}}.", "Your_invite_link_will_expire_on__date__": "Seu link de convite irá vencer em {{date}}.",
@ -553,10 +565,7 @@
"Your_workspace": "Sua workspace", "Your_workspace": "Sua workspace",
"You_will_not_be_able_to_recover_this_message": "Você não será capaz de recuperar essa mensagem!", "You_will_not_be_able_to_recover_this_message": "Você não será capaz de recuperar essa mensagem!",
"You_will_unset_a_certificate_for_this_server": "Você cancelará a configuração de um certificado para este servidor", "You_will_unset_a_certificate_for_this_server": "Você cancelará a configuração de um certificado para este servidor",
"Would_you_like_to_return_the_inquiry": "Deseja retornar a consulta?", "Change_Language": "Alterar idioma",
"Write_External_Permission_Message": "Rocket.Chat precisa de acesso à sua galeria para salvar imagens",
"Write_External_Permission": "Acesso à Galeria",
"Yes": "Sim",
"Crash_report_disclaimer": "Nós não rastreamos o conteúdo das suas conversas. O relatório de erros e os eventos do analytics apenas contém informações relevantes para identificarmos problemas e corrigí-los.", "Crash_report_disclaimer": "Nós não rastreamos o conteúdo das suas conversas. O relatório de erros e os eventos do analytics apenas contém informações relevantes para identificarmos problemas e corrigí-los.",
"Type_message": "Digitar mensagem", "Type_message": "Digitar mensagem",
"Room_search": "Busca de sala", "Room_search": "Busca de sala",
@ -568,6 +577,7 @@
"Search_messages": "Buscar mensagens", "Search_messages": "Buscar mensagens",
"Scroll_messages": "Rolar mensagens", "Scroll_messages": "Rolar mensagens",
"Reply_latest": "Responder para última mensagem", "Reply_latest": "Responder para última mensagem",
"Reply_in_Thread": "Responder por Tópico",
"Server_selection": "Seleção de servidor", "Server_selection": "Seleção de servidor",
"Server_selection_numbers": "Selecionar servidor 1...9", "Server_selection_numbers": "Selecionar servidor 1...9",
"Add_server": "Adicionar servidor", "Add_server": "Adicionar servidor",
@ -654,10 +664,8 @@
"Workspace_URL_Example": "Ex. sua-empresa.rocket.chat", "Workspace_URL_Example": "Ex. sua-empresa.rocket.chat",
"This_room_encryption_has_been_enabled_by__username_": "A criptografia para essa sala foi habilitada por {{username}}", "This_room_encryption_has_been_enabled_by__username_": "A criptografia para essa sala foi habilitada por {{username}}",
"This_room_encryption_has_been_disabled_by__username_": "A criptografia para essa sala foi desabilitada por {{username}}", "This_room_encryption_has_been_disabled_by__username_": "A criptografia para essa sala foi desabilitada por {{username}}",
"Apply_Your_Certificate": "Aplicar certificado",
"Do_you_have_a_certificate": "Você tem um certificado?",
"Your_certificate": "Seu certificado",
"Teams": "Times", "Teams": "Times",
"No_team_channels_found": "Nenhum canal encontrado", "No_team_channels_found": "Nenhum canal encontrado",
"Team_not_found": "Time não encontrado" "Team_not_found": "Time não encontrado",
"Private_Team": "Equipe Privada"
} }

View File

@ -30,7 +30,7 @@
"error-invalid-date": "Data inválida fornecida.", "error-invalid-date": "Data inválida fornecida.",
"error-invalid-description": "Descrição inválida", "error-invalid-description": "Descrição inválida",
"error-invalid-domain": "Domínio inválido", "error-invalid-domain": "Domínio inválido",
"error-invalid-email": "E-mail inválido {{emai}}", "error-invalid-email": "E-mail inválido {{email}}",
"error-invalid-email-address": "Endereço de e-mail invalido", "error-invalid-email-address": "Endereço de e-mail invalido",
"error-invalid-file-height": "Altura de ficheiro inválida", "error-invalid-file-height": "Altura de ficheiro inválida",
"error-invalid-file-type": "Tipo de ficheiro inválido", "error-invalid-file-type": "Tipo de ficheiro inválido",
@ -137,14 +137,14 @@
"delete": "apagar", "delete": "apagar",
"Delete": "Apagar", "Delete": "Apagar",
"DELETE": "APAGAR", "DELETE": "APAGAR",
"deleting_room": "apagando sala",
"description": "descrição", "description": "descrição",
"Description": "Descrição", "Description": "Descrição",
"Disable_notifications": "Desactivar notificações",
"Direct_Messages": "Mensagens Directas", "Direct_Messages": "Mensagens Directas",
"Disable_notifications": "Desactivar notificações",
"Dont_Have_An_Account": "Não tem uma conta?", "Dont_Have_An_Account": "Não tem uma conta?",
"Do_you_really_want_to_key_this_room_question_mark": "Você quer mesmo {{key}} esta sala?", "Do_you_really_want_to_key_this_room_question_mark": "Você quer mesmo {{key}} esta sala?",
"edit": "editar", "edit": "editar",
"deleting_room": "apagando sala",
"Edit": "Editar", "Edit": "Editar",
"Email_or_password_field_is_empty": "O campo de e-mail ou palavra-passe está vazio", "Email_or_password_field_is_empty": "O campo de e-mail ou palavra-passe está vazio",
"Email": "E-mail", "Email": "E-mail",

View File

@ -29,7 +29,7 @@
"error-invalid-channel": "Недействительный канал.", "error-invalid-channel": "Недействительный канал.",
"error-invalid-channel-start-with-chars": "Недействительный канал. Начните с @ или #", "error-invalid-channel-start-with-chars": "Недействительный канал. Начните с @ или #",
"error-invalid-custom-field": "Неверное настраиваемое поле", "error-invalid-custom-field": "Неверное настраиваемое поле",
"error-invalid-custom-field-name": "Неверное имя настраиваемого поля. Используйте только буквы, цифры, дефисы и символы подчеркивания.", "error-invalid-custom-field-name": "Неверное имя настраиваемого поля. Используйте только буквы, цифры, дефис и символ подчеркивания.",
"error-invalid-date": "Указана недопустимая дата.", "error-invalid-date": "Указана недопустимая дата.",
"error-invalid-description": "Недопустимое описание", "error-invalid-description": "Недопустимое описание",
"error-invalid-domain": "Недопустимый домен", "error-invalid-domain": "Недопустимый домен",
@ -46,9 +46,9 @@
"error-invalid-password": "Неверный пароль", "error-invalid-password": "Неверный пароль",
"error-invalid-redirectUri": "Недопустимый redirectUri", "error-invalid-redirectUri": "Недопустимый redirectUri",
"error-invalid-role": "Недопустимая роль", "error-invalid-role": "Недопустимая роль",
"error-invalid-room": "Недопустимый канал", "error-invalid-room": "Недопустимый чат",
"error-invalid-room-name": "{{room_name}} не является допустимым именем канала", "error-invalid-room-name": "{{room_name}} не является допустимым именем чата",
"error-invalid-room-type": "{{type}} не является допустимым типом канала.", "error-invalid-room-type": "{{type}} не является допустимым типом чата.",
"error-invalid-settings": "Недопустимые параметры", "error-invalid-settings": "Недопустимые параметры",
"error-invalid-subscription": "Недействительная подписка", "error-invalid-subscription": "Недействительная подписка",
"error-invalid-token": "Недопустимый токен", "error-invalid-token": "Недопустимый токен",
@ -77,7 +77,7 @@
"error-user-registration-custom-field": "error-user-registration-custom-field", "error-user-registration-custom-field": "error-user-registration-custom-field",
"error-user-registration-disabled": "Регистрация пользователей отключена", "error-user-registration-disabled": "Регистрация пользователей отключена",
"error-user-registration-secret": "Регистрация пользователей разрешена только через секретный URL", "error-user-registration-secret": "Регистрация пользователей разрешена только через секретный URL",
"error-you-are-last-owner": "Вы последний владелец. Пожалуйста, установите нового владельца, прежде чем покинуть комнату.", "error-you-are-last-owner": "Вы последний владелец. Пожалуйста, назначьте нового владельца, прежде чем покинуть чат.",
"Actions": "Действия", "Actions": "Действия",
"activity": "активности", "activity": "активности",
"Activity": "По активности", "Activity": "По активности",
@ -281,6 +281,8 @@
"Invite_Link": "Ссылка Приглашения", "Invite_Link": "Ссылка Приглашения",
"Invite_users": "Приглашение пользователей", "Invite_users": "Приглашение пользователей",
"Join": "Присоединиться", "Join": "Присоединиться",
"Join_Code": "Код присоединения",
"Insert_Join_Code": "Вставить код присоединения",
"Join_our_open_workspace": "Присоединиться к нашему открытому серверу", "Join_our_open_workspace": "Присоединиться к нашему открытому серверу",
"Join_your_workspace": "Присоединиться к вашему серверу", "Join_your_workspace": "Присоединиться к вашему серверу",
"Just_invited_people_can_access_this_channel": "Только приглашенные люди могут получить доступ к этому каналу", "Just_invited_people_can_access_this_channel": "Только приглашенные люди могут получить доступ к этому каналу",
@ -322,7 +324,7 @@
"Mute": "Заглушить", "Mute": "Заглушить",
"muted": "Заглушен", "muted": "Заглушен",
"My_servers": "Мои серверы", "My_servers": "Мои серверы",
"N_person_reacted": "{{n}} людей отреагировало", "N_people_reacted": "отреагировало {{n}} человек",
"N_users": "{{n}} пользователи", "N_users": "{{n}} пользователи",
"name": "имя", "name": "имя",
"Name": "Имя", "Name": "Имя",
@ -704,5 +706,15 @@
"Enter_workspace_URL": "Введите URL вашего рабочего пространства", "Enter_workspace_URL": "Введите URL вашего рабочего пространства",
"Workspace_URL_Example": "Например, your-company.rocket.chat", "Workspace_URL_Example": "Например, your-company.rocket.chat",
"This_room_encryption_has_been_enabled_by__username_": "Шифрование для этого чата включено {{username}}", "This_room_encryption_has_been_enabled_by__username_": "Шифрование для этого чата включено {{username}}",
"This_room_encryption_has_been_disabled_by__username_": "Шифрование для этого чата выключено {{username}}" "This_room_encryption_has_been_disabled_by__username_": "Шифрование для этого чата выключено {{username}}",
"Teams": "Команды",
"No_team_channels_found": "Каналы не найдены",
"Team_not_found": "Команда не найдена",
"Create_Team": "Создать Команду",
"Team_Name": "Имя Команды",
"Private_Team": "Приватная Команда",
"Read_Only_Team": "Команда только для чтения",
"Broadcast_Team": "Широковещательная Команда",
"creating_team": "создание Команды",
"team-name-already-exists": "Команда с таким названием уже существует"
} }

View File

@ -440,7 +440,6 @@
"Room_changed_announcement": "Oda duyurusu, {{userBy}} tarafından {{announcement}} olarak değiştirildi", "Room_changed_announcement": "Oda duyurusu, {{userBy}} tarafından {{announcement}} olarak değiştirildi",
"Room_changed_avatar": "Oda profil fotoğrafı {{userBy}} tarafından değiştirildi", "Room_changed_avatar": "Oda profil fotoğrafı {{userBy}} tarafından değiştirildi",
"Room_changed_description": "Oda açıklaması, {{userBy}} tarafından {{description}} olarak değiştirildi", "Room_changed_description": "Oda açıklaması, {{userBy}} tarafından {{description}} olarak değiştirildi",
"Room_changed_privacy": "Oda açıklaması, {{userBy}} tarafından {{description}} olarak değiştirildi",
"Room_changed_topic": "Oda konusu, {{userBy}} tarafından {{topic}} olarak değiştirildi", "Room_changed_topic": "Oda konusu, {{userBy}} tarafından {{topic}} olarak değiştirildi",
"Room_Files": "Oda Dosyaları", "Room_Files": "Oda Dosyaları",
"Room_Info_Edit": "Oda Bilgilerini Düzenle", "Room_Info_Edit": "Oda Bilgilerini Düzenle",
@ -565,7 +564,6 @@
"Username": "Kullanıcı adı", "Username": "Kullanıcı adı",
"Username_or_email": "Kullanıcı adı ya da e-posta", "Username_or_email": "Kullanıcı adı ya da e-posta",
"Uses_server_configuration": "Sunucu yapılandırmasını kullanır", "Uses_server_configuration": "Sunucu yapılandırmasını kullanır",
"Usually_a_discussion_starts_with_a_question_like_How_do_I_upload_a_picture": "Genellikle tartışma, \"Nasıl resim yüklerim?\" gibi bir soruyla başlar.",
"Validating": "Doğrulanıyor", "Validating": "Doğrulanıyor",
"Registration_Succeeded": "Kayıt Başarılı!", "Registration_Succeeded": "Kayıt Başarılı!",
"Verify": "Onayla", "Verify": "Onayla",
@ -600,7 +598,6 @@
"You_need_to_access_at_least_one_RocketChat_server_to_share_something": "Bir şeyler paylaşmak için Rocket.Chat sunucusuna erişmeniz gerekir.", "You_need_to_access_at_least_one_RocketChat_server_to_share_something": "Bir şeyler paylaşmak için Rocket.Chat sunucusuna erişmeniz gerekir.",
"You_need_to_verifiy_your_email_address_to_get_notications": "Bildirim almak için e-posta adresinizi doğrulamanız gerekiyor", "You_need_to_verifiy_your_email_address_to_get_notications": "Bildirim almak için e-posta adresinizi doğrulamanız gerekiyor",
"Your_certificate": "Sertifikanız", "Your_certificate": "Sertifikanız",
"Your_message": "İletiınız",
"Your_invite_link_will_expire_after__usesLeft__uses": "Davet bağlantınızın geçerliliği {{usesLeft}} kullanımdan sonra sona erecek.", "Your_invite_link_will_expire_after__usesLeft__uses": "Davet bağlantınızın geçerliliği {{usesLeft}} kullanımdan sonra sona erecek.",
"Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Davet bağlantınızın geçerliliği {{date}} tarihinde veya {{usesLeft}} kullanımdan sonra sona erecek.", "Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Davet bağlantınızın geçerliliği {{date}} tarihinde veya {{usesLeft}} kullanımdan sonra sona erecek.",
"Your_invite_link_will_expire_on__date__": "Davet bağlantınızın geçerlilik süresi {{date}} tarihinde sona erecek.", "Your_invite_link_will_expire_on__date__": "Davet bağlantınızın geçerlilik süresi {{date}} tarihinde sona erecek.",
@ -695,12 +692,12 @@
"User_has_been_ignored": "Kullanıcı yok sayıldı.", "User_has_been_ignored": "Kullanıcı yok sayıldı.",
"User_has_been_unignored": "Kullanıcı artık yok sayılmıyor.", "User_has_been_unignored": "Kullanıcı artık yok sayılmıyor.",
"User_has_been_removed_from_s": "Kullanıcı {{s}} alanından kaldırıldı.", "User_has_been_removed_from_s": "Kullanıcı {{s}} alanından kaldırıldı.",
"User__username__is_now_a_leader_of__room_name_": "{{Username}} kullanıcısı artık {{room_name}} lideridir.", "User__username__is_now_a_leader_of__room_name_": "{{username}} kullanıcısı artık {{room_name}} lideridir.",
"User__username__is_now_a_moderator_of__room_name_": "{{Username}} kullanıcısı artık bir {{room_name}} moderatörüdür.", "User__username__is_now_a_moderator_of__room_name_": "{{username}} kullanıcısı artık bir {{room_name}} moderatörüdür.",
"User__username__is_now_a_owner_of__room_name_": "{{Username}} kullanıcısı artık {{room_name}} adlı odanın sahibidir.", "User__username__is_now_a_owner_of__room_name_": "{{username}} kullanıcısı artık {{room_name}} adlı odanın sahibidir.",
"User__username__removed_from__room_name__leaders": "{{Username}} adlı kullanıcı, {{room_name}} liderlerinden kaldırıldı.", "User__username__removed_from__room_name__leaders": "{{username}} adlı kullanıcı, {{room_name}} liderlerinden kaldırıldı.",
"User__username__removed_from__room_name__moderators": "{{Username}} adlı kullanıcı, {{room_name}} moderatörlerinden kaldırıldı.", "User__username__removed_from__room_name__moderators": "{{username}} adlı kullanıcı, {{room_name}} moderatörlerinden kaldırıldı.",
"User__username__removed_from__room_name__owners": "{{Username}} adlı kullanıcı, {{room_name}} sahiplerinden kaldırıldı.", "User__username__removed_from__room_name__owners": "{{username}} adlı kullanıcı, {{room_name}} sahiplerinden kaldırıldı.",
"The_user_will_be_removed_from_s": "Kullanıcı, {{s}} alanından kaldırılacak!", "The_user_will_be_removed_from_s": "Kullanıcı, {{s}} alanından kaldırılacak!",
"Yes_remove_user": "Evet, kullanıcıyı kaldır!", "Yes_remove_user": "Evet, kullanıcıyı kaldır!",
"Direct_message": "Özel ileti", "Direct_message": "Özel ileti",

View File

@ -33,7 +33,7 @@
"error-invalid-date": "无效的日期", "error-invalid-date": "无效的日期",
"error-invalid-description": "无效的描述", "error-invalid-description": "无效的描述",
"error-invalid-domain": "无效的域名", "error-invalid-domain": "无效的域名",
"error-invalid-email": "无效的电子邮件{{emai}}", "error-invalid-email": "无效的电子邮件{{email}}",
"error-invalid-email-address": "无效的邮件地址", "error-invalid-email-address": "无效的邮件地址",
"error-invalid-file-height": "无效的文件长度", "error-invalid-file-height": "无效的文件长度",
"error-invalid-file-type": "无效的文件类型", "error-invalid-file-type": "无效的文件类型",
@ -278,11 +278,11 @@
"is_typing": "正在输入", "is_typing": "正在输入",
"Invalid_or_expired_invite_token": "无效或到期的邀请 token", "Invalid_or_expired_invite_token": "无效或到期的邀请 token",
"Invalid_server_version": "此 App 版本已不支援您正在连线之服务器版本。当前版本: {{currentVersion}}.\\n\\n最低版本要求: {{minVersion}}", "Invalid_server_version": "此 App 版本已不支援您正在连线之服务器版本。当前版本: {{currentVersion}}.\\n\\n最低版本要求: {{minVersion}}",
"Join_your_workspace": "加入您的工作区",
"Invite_Link": "邀请链接", "Invite_Link": "邀请链接",
"Invite_users": "邀请用戶", "Invite_users": "邀请用戶",
"Join": "加入", "Join": "加入",
"Join_our_open_workspace": "加入开放工作区", "Join_our_open_workspace": "加入开放工作区",
"Join_your_workspace": "加入您的工作区",
"Just_invited_people_can_access_this_channel": "仅有被邀请人能进入这个频道", "Just_invited_people_can_access_this_channel": "仅有被邀请人能进入这个频道",
"Language": "语言", "Language": "语言",
"last_message": "最后一条信息", "last_message": "最后一条信息",
@ -300,7 +300,7 @@
"Logging_out": "正在登出", "Logging_out": "正在登出",
"Logout": "注销", "Logout": "注销",
"Max_number_of_uses": "最大使用次数", "Max_number_of_uses": "最大使用次数",
"Max_number_of_users_allowed_is_number": "允许使用者上限数量", "Max_number_of_users_allowed_is_number": "允许使用者上限数量{{maxUsers}}",
"members": "成员", "members": "成员",
"Members": "成员", "Members": "成员",
"Mentioned_Messages": "被提及的信息", "Mentioned_Messages": "被提及的信息",
@ -444,7 +444,7 @@
"Room_Info_Edit": "聊天室信息编辑", "Room_Info_Edit": "聊天室信息编辑",
"Room_Info": "聊天室信息", "Room_Info": "聊天室信息",
"Room_Members": "聊天室成员", "Room_Members": "聊天室成员",
"Room_name_changed": "{{userBy}} 将聊天室名称改为:{{{name}}", "Room_name_changed": "{{userBy}} 将聊天室名称改为:{{name}}",
"SAVE": "保存", "SAVE": "保存",
"Save_Changes": "保存更改", "Save_Changes": "保存更改",
"Save": "保存", "Save": "保存",

View File

@ -278,11 +278,11 @@
"is_typing": "正在輸入", "is_typing": "正在輸入",
"Invalid_or_expired_invite_token": "無效或到期的邀請 token", "Invalid_or_expired_invite_token": "無效或到期的邀請 token",
"Invalid_server_version": "此 App 版本已不支援您正在連線之伺服器版本。當前版本: {{currentVersion}}.\\n\\n最低版本要求: {{minVersion}}", "Invalid_server_version": "此 App 版本已不支援您正在連線之伺服器版本。當前版本: {{currentVersion}}.\\n\\n最低版本要求: {{minVersion}}",
"Join_your_workspace": "加入您的工作區",
"Invite_Link": "邀請連結", "Invite_Link": "邀請連結",
"Invite_users": "邀請使用者", "Invite_users": "邀請使用者",
"Join": "加入", "Join": "加入",
"Join_our_open_workspace": "加入開放工作區", "Join_our_open_workspace": "加入開放工作區",
"Join_your_workspace": "加入您的工作區",
"Just_invited_people_can_access_this_channel": "僅有受邀者能存取此頻道", "Just_invited_people_can_access_this_channel": "僅有受邀者能存取此頻道",
"Language": "語言", "Language": "語言",
"last_message": "最後一則訊息", "last_message": "最後一則訊息",
@ -300,7 +300,7 @@
"Logging_out": "正在登出", "Logging_out": "正在登出",
"Logout": "登出", "Logout": "登出",
"Max_number_of_uses": "最大使用次數", "Max_number_of_uses": "最大使用次數",
"Max_number_of_users_allowed_is_number": "允許使用者上限數量", "Max_number_of_users_allowed_is_number": "允許使用者上限數量 {{maxUsers}}",
"members": "成員", "members": "成員",
"Members": "成員", "Members": "成員",
"Mentioned_Messages": "被提及的訊息", "Mentioned_Messages": "被提及的訊息",
@ -444,7 +444,7 @@
"Room_Info_Edit": "修改聊天室資訊", "Room_Info_Edit": "修改聊天室資訊",
"Room_Info": "聊天室資訊", "Room_Info": "聊天室資訊",
"Room_Members": "聊天室成員", "Room_Members": "聊天室成員",
"Room_name_changed": "{{userBy}} 將聊天室名稱改為:{{{name}}", "Room_name_changed": "{{userBy}} 將聊天室名稱改為:{{name}}",
"SAVE": "儲存", "SAVE": "儲存",
"Save_Changes": "儲存更改", "Save_Changes": "儲存更改",
"Save": "儲存", "Save": "儲存",

View File

@ -60,6 +60,7 @@ import UserPreferences from './userPreferences';
import { Encryption } from './encryption'; import { Encryption } from './encryption';
import EventEmitter from '../utils/events'; import EventEmitter from '../utils/events';
import { sanitizeLikeString } from './database/utils'; import { sanitizeLikeString } from './database/utils';
import { TEAM_TYPE } from '../definition/ITeam';
const TOKEN_KEY = 'reactnativemeteor_usertoken'; const TOKEN_KEY = 'reactnativemeteor_usertoken';
const CURRENT_SERVER = 'currentServer'; const CURRENT_SERVER = 'currentServer';
@ -196,6 +197,10 @@ const RocketChat = {
clearTimeout(this.connectTimeout); clearTimeout(this.connectTimeout);
} }
if (this.connectingListener) {
this.connectingListener.then(this.stopListener);
}
if (this.connectedListener) { if (this.connectedListener) {
this.connectedListener.then(this.stopListener); this.connectedListener.then(this.stopListener);
} }
@ -243,7 +248,7 @@ const RocketChat = {
sdkConnect(); sdkConnect();
this.connectedListener = this.sdk.onStreamData('connecting', () => { this.connectingListener = this.sdk.onStreamData('connecting', () => {
reduxStore.dispatch(connectRequest()); reduxStore.dispatch(connectRequest());
}); });
@ -728,7 +733,24 @@ const RocketChat = {
prid, pmid, t_name, reply, users, encrypted prid, pmid, t_name, reply, users, encrypted
}); });
}, },
createTeam({
name, users, type, readOnly, broadcast, encrypted
}) {
const params = {
name,
users,
type: type ? TEAM_TYPE.PRIVATE : TEAM_TYPE.PUBLIC,
room: {
readOnly,
extraData: {
broadcast,
encrypted
}
}
};
// RC 3.13.0
return this.post('teams.create', params);
},
joinRoom(roomId, joinCode, type) { joinRoom(roomId, joinCode, type) {
// TODO: join code // TODO: join code
// RC 0.48.0 // RC 0.48.0
@ -1136,7 +1158,7 @@ const RocketChat = {
methodCall(...args) { methodCall(...args) {
return new Promise(async(resolve, reject) => { return new Promise(async(resolve, reject) => {
try { try {
const result = await this.sdk.methodCall(...args, this.code || ''); const result = await this.sdk?.methodCall(...args, this.code || '');
return resolve(result); return resolve(result);
} catch (e) { } catch (e) {
if (e.error && (e.error === 'totp-required' || e.error === 'totp-invalid')) { if (e.error && (e.error === 'totp-required' || e.error === 'totp-invalid')) {

View File

@ -21,6 +21,10 @@ const createGroupChat = function createGroupChat() {
return RocketChat.createGroupChat(); return RocketChat.createGroupChat();
}; };
const createTeam = function createTeam(data) {
return RocketChat.createTeam(data);
};
const handleRequest = function* handleRequest({ data }) { const handleRequest = function* handleRequest({ data }) {
try { try {
const auth = yield select(state => state.login.isAuthenticated); const auth = yield select(state => state.login.isAuthenticated);
@ -29,7 +33,21 @@ const handleRequest = function* handleRequest({ data }) {
} }
let sub; let sub;
if (data.group) { if (data.isTeam) {
const {
type,
readOnly,
broadcast,
encrypted
} = data;
logEvent(events.CR_CREATE, {
type,
readOnly,
broadcast,
encrypted
});
sub = yield call(createTeam, data);
} else if (data.group) {
logEvent(events.SELECTED_USERS_CREATE_GROUP); logEvent(events.SELECTED_USERS_CREATE_GROUP);
const result = yield call(createGroupChat); const result = yield call(createGroupChat);
if (result.success) { if (result.success) {
@ -56,7 +74,7 @@ const handleRequest = function* handleRequest({ data }) {
const subCollection = db.get('subscriptions'); const subCollection = db.get('subscriptions');
yield db.action(async() => { yield db.action(async() => {
await subCollection.create((s) => { await subCollection.create((s) => {
s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema); s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid }, subCollection.schema);
Object.assign(s, sub); Object.assign(s, sub);
}); });
}); });
@ -64,7 +82,17 @@ const handleRequest = function* handleRequest({ data }) {
// do nothing // do nothing
} }
yield put(createChannelSuccess(sub)); let successParams = {};
if (data.isTeam) {
successParams = {
...sub.team,
rid: sub.team.roomId,
t: sub.team.type ? 'p' : 'c'
};
} else {
successParams = data;
}
yield put(createChannelSuccess(successParams));
} catch (err) { } catch (err) {
logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']); logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']);
yield put(createChannelFailure(err)); yield put(createChannelFailure(err));
@ -81,7 +109,7 @@ const handleSuccess = function* handleSuccess({ data }) {
const handleFailure = function handleFailure({ err }) { const handleFailure = function handleFailure({ err }) {
setTimeout(() => { setTimeout(() => {
const msg = err.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') }); const msg = err.data ? I18n.t(err.data.error) : err.reason || I18n.t('There_was_an_error_while_action', { action: I18n.t('creating_channel') });
showErrorAlert(msg); showErrorAlert(msg);
}, 300); }, 300);
}; };

View File

@ -51,6 +51,7 @@ export default {
STATUS_F: 'status_f', STATUS_F: 'status_f',
STATUS_CUSTOM: 'status_custom', STATUS_CUSTOM: 'status_custom',
STATUS_CUSTOM_F: 'status_custom_f', STATUS_CUSTOM_F: 'status_custom_f',
SET_STATUS_FAIL: 'set_status_fail',
// ROOMS LIST VIEW // ROOMS LIST VIEW
RL_TOGGLE_SERVER_DROPDOWN: 'rl_toggle_server_dropdown', RL_TOGGLE_SERVER_DROPDOWN: 'rl_toggle_server_dropdown',
@ -87,6 +88,7 @@ export default {
// NEW MESSAGE VIEW // NEW MESSAGE VIEW
NEW_MSG_CREATE_CHANNEL: 'new_msg_create_channel', NEW_MSG_CREATE_CHANNEL: 'new_msg_create_channel',
NEW_MSG_CREATE_TEAM: 'new_msg_create_team',
NEW_MSG_CREATE_GROUP_CHAT: 'new_msg_create_group_chat', NEW_MSG_CREATE_GROUP_CHAT: 'new_msg_create_group_chat',
NEW_MSG_CREATE_DISCUSSION: 'new_msg_create_discussion', NEW_MSG_CREATE_DISCUSSION: 'new_msg_create_discussion',
NEW_MSG_CHAT_WITH_USER: 'new_msg_chat_with_user', NEW_MSG_CHAT_WITH_USER: 'new_msg_chat_with_user',

View File

@ -45,3 +45,5 @@ export const getBadgeColor = ({ subscription, messageId, theme }) => {
}; };
export const makeThreadName = messageRecord => messageRecord.msg || messageRecord?.attachments[0]?.title; export const makeThreadName = messageRecord => messageRecord.msg || messageRecord?.attachments[0]?.title;
export const isTeamRoom = ({ teamId, joined }) => teamId && joined;

View File

@ -88,8 +88,8 @@ class AuthenticationWebView extends React.PureComponent {
this.dismiss(); this.dismiss();
} }
// eslint-disable-next-line react/sort-comp // Force 3s delay so the server has time to evaluate the token
debouncedLogin = debounce(params => this.login(params), 3000, true); debouncedLogin = debounce(params => this.login(params), 3000);
tryLogin = debounce(async() => { tryLogin = debounce(async() => {
const { Accounts_Iframe_api_url, Accounts_Iframe_api_method } = this.props; const { Accounts_Iframe_api_url, Accounts_Iframe_api_method } = this.props;

View File

@ -68,12 +68,9 @@ const styles = StyleSheet.create({
}); });
class CreateChannelView extends React.Component { class CreateChannelView extends React.Component {
static navigationOptions = () => ({
title: I18n.t('Create_Channel')
});
static propTypes = { static propTypes = {
navigation: PropTypes.object, navigation: PropTypes.object,
route: PropTypes.object,
baseUrl: PropTypes.string, baseUrl: PropTypes.string,
create: PropTypes.func.isRequired, create: PropTypes.func.isRequired,
removeUser: PropTypes.func.isRequired, removeUser: PropTypes.func.isRequired,
@ -89,12 +86,19 @@ class CreateChannelView extends React.Component {
theme: PropTypes.string theme: PropTypes.string
}; };
state = { constructor(props) {
super(props);
const { route } = this.props;
const isTeam = route?.params?.isTeam || false;
this.state = {
channelName: '', channelName: '',
type: true, type: true,
readOnly: false, readOnly: false,
encrypted: false, encrypted: false,
broadcast: false broadcast: false,
isTeam
};
this.setHeader();
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
@ -134,6 +138,15 @@ class CreateChannelView extends React.Component {
return false; return false;
} }
setHeader = () => {
const { navigation } = this.props;
const { isTeam } = this.state;
navigation.setOptions({
title: isTeam ? I18n.t('Create_Team') : I18n.t('Create_Channel')
});
}
toggleRightButton = (channelName) => { toggleRightButton = (channelName) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.setOptions({ navigation.setOptions({
@ -152,9 +165,11 @@ class CreateChannelView extends React.Component {
submit = () => { submit = () => {
const { const {
channelName, type, readOnly, broadcast, encrypted channelName, type, readOnly, broadcast, encrypted, isTeam
} = this.state; } = this.state;
const { users: usersProps, isFetching, create } = this.props; const {
users: usersProps, isFetching, create
} = this.props;
if (!channelName.trim() || isFetching) { if (!channelName.trim() || isFetching) {
return; return;
@ -163,9 +178,9 @@ class CreateChannelView extends React.Component {
// transform users object into array of usernames // transform users object into array of usernames
const users = usersProps.map(user => user.name); const users = usersProps.map(user => user.name);
// create channel // create channel or team
create({ create({
name: channelName, users, type, readOnly, broadcast, encrypted name: channelName, users, type, readOnly, broadcast, encrypted, isTeam
}); });
Review.pushPositiveEvent(); Review.pushPositiveEvent();
@ -196,11 +211,12 @@ class CreateChannelView extends React.Component {
} }
renderType() { renderType() {
const { type } = this.state; const { type, isTeam } = this.state;
return this.renderSwitch({ return this.renderSwitch({
id: 'type', id: 'type',
value: type, value: type,
label: 'Private_Channel', label: isTeam ? 'Private_Team' : 'Private_Channel',
onValueChange: (value) => { onValueChange: (value) => {
logEvent(events.CR_TOGGLE_TYPE); logEvent(events.CR_TOGGLE_TYPE);
// If we set the channel as public, encrypted status should be false // If we set the channel as public, encrypted status should be false
@ -210,11 +226,12 @@ class CreateChannelView extends React.Component {
} }
renderReadOnly() { renderReadOnly() {
const { readOnly, broadcast } = this.state; const { readOnly, broadcast, isTeam } = this.state;
return this.renderSwitch({ return this.renderSwitch({
id: 'readonly', id: 'readonly',
value: readOnly, value: readOnly,
label: 'Read_Only_Channel', label: isTeam ? 'Read_Only_Team' : 'Read_Only_Channel',
onValueChange: (value) => { onValueChange: (value) => {
logEvent(events.CR_TOGGLE_READ_ONLY); logEvent(events.CR_TOGGLE_READ_ONLY);
this.setState({ readOnly: value }); this.setState({ readOnly: value });
@ -244,11 +261,12 @@ class CreateChannelView extends React.Component {
} }
renderBroadcast() { renderBroadcast() {
const { broadcast, readOnly } = this.state; const { broadcast, readOnly, isTeam } = this.state;
return this.renderSwitch({ return this.renderSwitch({
id: 'broadcast', id: 'broadcast',
value: broadcast, value: broadcast,
label: 'Broadcast_Channel', label: isTeam ? 'Broadcast_Team' : 'Broadcast_Channel',
onValueChange: (value) => { onValueChange: (value) => {
logEvent(events.CR_TOGGLE_BROADCAST); logEvent(events.CR_TOGGLE_BROADCAST);
this.setState({ this.setState({
@ -301,8 +319,10 @@ class CreateChannelView extends React.Component {
} }
render() { render() {
const { channelName } = this.state; const { channelName, isTeam } = this.state;
const { users, isFetching, theme } = this.props; const {
users, isFetching, theme
} = this.props;
const userCount = users.length; const userCount = users.length;
return ( return (
@ -312,18 +332,18 @@ class CreateChannelView extends React.Component {
keyboardVerticalOffset={128} keyboardVerticalOffset={128}
> >
<StatusBar /> <StatusBar />
<SafeAreaView testID='create-channel-view'> <SafeAreaView testID={isTeam ? 'create-team-view' : 'create-channel-view'}>
<ScrollView {...scrollPersistTaps}> <ScrollView {...scrollPersistTaps}>
<View style={[sharedStyles.separatorVertical, { borderColor: themes[theme].separatorColor }]}> <View style={[sharedStyles.separatorVertical, { borderColor: themes[theme].separatorColor }]}>
<TextInput <TextInput
autoFocus autoFocus
style={[styles.input, { backgroundColor: themes[theme].backgroundColor }]} style={[styles.input, { backgroundColor: themes[theme].backgroundColor }]}
label={I18n.t('Channel_Name')} label={isTeam ? I18n.t('Team_Name') : I18n.t('Channel_Name')}
value={channelName} value={channelName}
onChangeText={this.onChangeText} onChangeText={this.onChangeText}
placeholder={I18n.t('Channel_Name')} placeholder={isTeam ? I18n.t('Team_Name') : I18n.t('Channel_Name')}
returnKeyType='done' returnKeyType='done'
testID='create-channel-name' testID={isTeam ? 'create-team-name' : 'create-channel-name'}
autoCorrect={false} autoCorrect={false}
autoCapitalize='none' autoCapitalize='none'
theme={theme} theme={theme}

View File

@ -116,6 +116,12 @@ class NewMessageView extends React.Component {
navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView') }); navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView') });
} }
createTeam = () => {
logEvent(events.NEW_MSG_CREATE_TEAM);
const { navigation } = this.props;
navigation.navigate('SelectedUsersViewCreateChannel', { nextAction: () => navigation.navigate('CreateChannelView', { isTeam: true }) });
}
createGroupChat = () => { createGroupChat = () => {
logEvent(events.NEW_MSG_CREATE_GROUP_CHAT); logEvent(events.NEW_MSG_CREATE_GROUP_CHAT);
const { createChannel, maxUsers, navigation } = this.props; const { createChannel, maxUsers, navigation } = this.props;
@ -172,6 +178,12 @@ class NewMessageView extends React.Component {
testID: 'new-message-view-create-channel', testID: 'new-message-view-create-channel',
first: true first: true
})} })}
{this.renderButton({
onPress: this.createTeam,
title: I18n.t('Create_Team'),
icon: 'teams',
testID: 'new-message-view-create-team'
})}
{maxUsers > 2 ? this.renderButton({ {maxUsers > 2 ? this.renderButton({
onPress: this.createGroupChat, onPress: this.createGroupChat,
title: I18n.t('Create_Direct_Messages'), title: I18n.t('Create_Direct_Messages'),
@ -253,7 +265,7 @@ const mapStateToProps = state => ({
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
createChannel: params => dispatch(createChannelRequest(params)) create: params => dispatch(createChannelRequest(params))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewMessageView)); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(NewMessageView));

View File

@ -595,7 +595,7 @@ class RoomActionsView extends React.Component {
return ( return (
<SafeAreaView testID='room-actions-view'> <SafeAreaView testID='room-actions-view'>
<StatusBar /> <StatusBar />
<List.Container> <List.Container testID='room-actions-scrollview'>
{this.renderRoomInfo()} {this.renderRoomInfo()}
{this.renderJitsi()} {this.renderJitsi()}
{this.renderE2EEncryption()} {this.renderE2EEncryption()}

View File

@ -7,6 +7,7 @@ import * as HeaderButton from '../../containers/HeaderButton';
import database from '../../lib/database'; import database from '../../lib/database';
import { getUserSelector } from '../../selectors/login'; import { getUserSelector } from '../../selectors/login';
import { logEvent, events } from '../../utils/log'; import { logEvent, events } from '../../utils/log';
import { isTeamRoom } from '../../utils/room';
class RightButtonsContainer extends Component { class RightButtonsContainer extends Component {
static propTypes = { static propTypes = {
@ -15,10 +16,11 @@ class RightButtonsContainer extends Component {
rid: PropTypes.string, rid: PropTypes.string,
t: PropTypes.string, t: PropTypes.string,
tmid: PropTypes.string, tmid: PropTypes.string,
teamId: PropTypes.bool, teamId: PropTypes.string,
navigation: PropTypes.object, navigation: PropTypes.object,
isMasterDetail: PropTypes.bool, isMasterDetail: PropTypes.bool,
toggleFollowThread: PropTypes.func toggleFollowThread: PropTypes.func,
joined: PropTypes.bool
}; };
constructor(props) { constructor(props) {
@ -163,7 +165,7 @@ class RightButtonsContainer extends Component {
isFollowingThread, tunread, tunreadUser, tunreadGroup isFollowingThread, tunread, tunreadUser, tunreadGroup
} = this.state; } = this.state;
const { const {
t, tmid, threadsEnabled, teamId t, tmid, threadsEnabled, teamId, joined
} = this.props; } = this.props;
if (t === 'l') { if (t === 'l') {
return null; return null;
@ -181,7 +183,7 @@ class RightButtonsContainer extends Component {
} }
return ( return (
<HeaderButton.Container> <HeaderButton.Container>
{teamId ? ( {isTeamRoom({ teamId, joined }) ? (
<HeaderButton.Item <HeaderButton.Item
iconName='channel-public' iconName='channel-public'
onPress={this.goTeamChannels} onPress={this.goTeamChannels}

View File

@ -38,7 +38,9 @@ import { themes } from '../../constants/colors';
import debounce from '../../utils/debounce'; import debounce from '../../utils/debounce';
import ReactionsModal from '../../containers/ReactionsModal'; import ReactionsModal from '../../containers/ReactionsModal';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import { getBadgeColor, isBlocked, makeThreadName } from '../../utils/room'; import {
getBadgeColor, isBlocked, makeThreadName, isTeamRoom
} from '../../utils/room';
import { isReadOnly } from '../../utils/isReadOnly'; import { isReadOnly } from '../../utils/isReadOnly';
import { isIOS, isTablet } from '../../utils/deviceInfo'; import { isIOS, isTablet } from '../../utils/deviceInfo';
import { showErrorAlert } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
@ -301,7 +303,7 @@ class RoomView extends React.Component {
setHeader = () => { setHeader = () => {
const { const {
room, unreadsCount, roomUserId room, unreadsCount, roomUserId, joined
} = this.state; } = this.state;
const { const {
navigation, isMasterDetail, theme, baseUrl, user, insets, route navigation, isMasterDetail, theme, baseUrl, user, insets, route
@ -331,7 +333,7 @@ class RoomView extends React.Component {
let numIconsRight = 2; let numIconsRight = 2;
if (tmid) { if (tmid) {
numIconsRight = 1; numIconsRight = 1;
} else if (teamId) { } else if (isTeamRoom({ teamId, joined })) {
numIconsRight = 3; numIconsRight = 3;
} }
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight }); const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight });
@ -380,6 +382,8 @@ class RoomView extends React.Component {
rid={rid} rid={rid}
tmid={tmid} tmid={tmid}
teamId={teamId} teamId={teamId}
teamMain={teamMain}
joined={joined}
t={t} t={t}
navigation={navigation} navigation={navigation}
toggleFollowThread={this.toggleFollowThread} toggleFollowThread={this.toggleFollowThread}

View File

@ -17,7 +17,6 @@ import sharedStyles from './Styles';
import * as HeaderButton from '../containers/HeaderButton'; import * as HeaderButton from '../containers/HeaderButton';
import StatusBar from '../containers/StatusBar'; import StatusBar from '../containers/StatusBar';
import { themes } from '../constants/colors'; import { themes } from '../constants/colors';
import { animateNextTransition } from '../utils/layoutAnimation';
import { withTheme } from '../theme'; import { withTheme } from '../theme';
import { getUserSelector } from '../selectors/login'; import { getUserSelector } from '../selectors/login';
import { import {
@ -28,6 +27,9 @@ import {
import { showErrorAlert } from '../utils/info'; import { showErrorAlert } from '../utils/info';
import SafeAreaView from '../containers/SafeAreaView'; import SafeAreaView from '../containers/SafeAreaView';
const ITEM_WIDTH = 250;
const getItemLayout = (_, index) => ({ length: ITEM_WIDTH, offset: ITEM_WIDTH * index, index });
class SelectedUsersView extends React.Component { class SelectedUsersView extends React.Component {
static propTypes = { static propTypes = {
baseUrl: PropTypes.string, baseUrl: PropTypes.string,
@ -50,7 +52,7 @@ class SelectedUsersView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.init(); this.init();
this.flatlist = React.createRef();
const maxUsers = props.route.params?.maxUsers; const maxUsers = props.route.params?.maxUsers;
this.state = { this.state = {
maxUsers, maxUsers,
@ -151,7 +153,6 @@ class SelectedUsersView extends React.Component {
return; return;
} }
animateNextTransition();
if (!this.isChecked(user.name)) { if (!this.isChecked(user.name)) {
if (this.isGroupChat() && users.length === maxUsers) { if (this.isGroupChat() && users.length === maxUsers) {
return showErrorAlert(I18n.t('Max_number_of_users_allowed_is_number', { maxUsers }), I18n.t('Oops')); return showErrorAlert(I18n.t('Max_number_of_users_allowed_is_number', { maxUsers }), I18n.t('Oops'));
@ -184,15 +185,23 @@ class SelectedUsersView extends React.Component {
); );
} }
setFlatListRef = ref => this.flatlist = ref;
onContentSizeChange = () => this.flatlist.scrollToEnd({ animated: true });
renderSelected = () => { renderSelected = () => {
const { users, theme } = this.props; const { users, theme } = this.props;
if (users.length === 0) { if (users.length === 0) {
return null; return null;
} }
return ( return (
<FlatList <FlatList
data={users} data={users}
ref={this.setFlatListRef}
onContentSizeChange={this.onContentSizeChange}
getItemLayout={getItemLayout}
keyExtractor={item => item._id} keyExtractor={item => item._id}
style={[sharedStyles.separatorTop, { borderColor: themes[theme].separatorColor }]} style={[sharedStyles.separatorTop, { borderColor: themes[theme].separatorColor }]}
contentContainerStyle={{ marginVertical: 5 }} contentContainerStyle={{ marginVertical: 5 }}

View File

@ -91,7 +91,7 @@ class StatusView extends React.Component {
const { statusText } = this.state; const { statusText } = this.state;
const { user } = this.props; const { user } = this.props;
if (statusText !== user.statusText) { if (statusText !== user.statusText) {
await this.setCustomStatus(); await this.setCustomStatus(statusText);
} }
this.close(); this.close();
} }
@ -101,8 +101,7 @@ class StatusView extends React.Component {
navigation.goBack(); navigation.goBack();
} }
setCustomStatus = async() => { setCustomStatus = async(statusText) => {
const { statusText } = this.state;
const { user, setUser } = this.props; const { user, setUser } = this.props;
this.setState({ loading: true }); this.setState({ loading: true });

View File

@ -1,9 +1,9 @@
const random = require('./helpers/random'); const random = require('./helpers/random');
const value = random(20); const value = random(20);
const data = { const data = {
server: 'http://localhost:3000', server: 'https://mobile.rocket.chat',
adminUser: 'admin', adminUser: 'e2e_admin',
adminPassword: 'password', adminPassword: 'p7mFh4yLwCRXSnMvG',
alternateServer: 'https://stable.rocket.chat', alternateServer: 'https://stable.rocket.chat',
users: { users: {
regular: { regular: {
@ -42,6 +42,11 @@ const data = {
name: `detox-private-${ value }` name: `detox-private-${ value }`
} }
}, },
teams: {
private: {
name: `detox-team-${ value }`
}
},
registeringUser: { registeringUser: {
username: `newuser${ value }`, username: `newuser${ value }`,
password: `password${ value }`, password: `password${ value }`,
@ -57,6 +62,11 @@ const data = {
password: `passwordthree${ value }`, password: `passwordthree${ value }`,
email: `mobile+registeringthree${ value }@rocket.chat` email: `mobile+registeringthree${ value }@rocket.chat`
}, },
registeringUser4: {
username: `newuserfour${ value }`,
password: `passwordfour${ value }`,
email: `mobile+registeringfour${ value }@rocket.chat`
},
random: value random: value
} }
module.exports = data; module.exports = data;

View File

@ -7,8 +7,7 @@ async function navigateToWorkspace(server = data.server) {
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(10000);
await element(by.id('join-workspace')).tap(); await element(by.id('join-workspace')).tap();
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
await element(by.id('new-server-view-input')).replaceText(server); await element(by.id('new-server-view-input')).typeText(`${server}\n`);
await element(by.id('new-server-view-button')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('workspace-view'))).toBeVisible(); await expect(element(by.id('workspace-view'))).toBeVisible();
} }
@ -33,7 +32,7 @@ async function login(username, password) {
await element(by.id('login-view-email')).replaceText(username); await element(by.id('login-view-email')).replaceText(username);
await element(by.id('login-view-password')).replaceText(password); await element(by.id('login-view-password')).replaceText(password);
await element(by.id('login-view-submit')).tap(); await element(by.id('login-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(30000);
} }
async function logout() { async function logout() {
@ -52,24 +51,24 @@ async function logout() {
await expect(element(by.id('onboarding-view'))).toBeVisible(); await expect(element(by.id('onboarding-view'))).toBeVisible();
} }
async function mockMessage(message) { async function mockMessage(message, isThread = false) {
await element(by.id('messagebox-input')).atIndex(0).tap(); let input = isThread ? 'messagebox-input-thread' : 'messagebox-input';
await element(by.id('messagebox-input')).atIndex(0).typeText(`${ data.random }${ message }`); await element(by.id(input)).tap();
await element(by.id('messagebox-send-message')).atIndex(0).tap(); await element(by.id(input)).typeText(`${ data.random }${ message }`);
await waitFor(element(by.label(`${ data.random }${ message }`)).atIndex(0)).toExist().withTimeout(60000); await element(by.id('messagebox-send-message')).tap();
await expect(element(by.label(`${ data.random }${ message }`)).atIndex(0)).toExist(); await waitFor(element(by.label(`${ data.random }${ message }`))).toExist().withTimeout(60000);
await expect(element(by.label(`${ data.random }${ message }`))).toExist();
await element(by.label(`${ data.random }${ message }`)).atIndex(0).tap(); await element(by.label(`${ data.random }${ message }`)).atIndex(0).tap();
}; };
async function starMessage(message){ async function starMessage(message){
const messageLabel = `${ data.random }${ message }` const messageLabel = `${ data.random }${ message }`
await waitFor(element(by.label(messageLabel))).toBeVisible().withTimeout(5000);
await element(by.label(messageLabel)).atIndex(0).longPress(); await element(by.label(messageLabel)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Star')).tap(); await element(by.label('Star')).tap();
await waitFor(element(by.id('action-sheet'))).toNotExist().withTimeout(5000); await waitFor(element(by.id('action-sheet'))).not.toExist().withTimeout(5000);
}; };
async function pinMessage(message){ async function pinMessage(message){
@ -80,7 +79,7 @@ async function pinMessage(message){
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Pin')).tap(); await element(by.label('Pin')).tap();
await waitFor(element(by.id('action-sheet'))).toNotExist().withTimeout(5000); await waitFor(element(by.id('action-sheet'))).not.toExist().withTimeout(5000);
} }
async function dismissReviewNag(){ async function dismissReviewNag(){

View File

@ -1,5 +1,6 @@
const axios = require('axios').default; const axios = require('axios').default;
const data = require('../data'); const data = require('../data');
const { TEAM_TYPE } = require('../../app/definition/ITeam');
let server = data.server let server = data.server
@ -20,6 +21,7 @@ const login = async (username, password) => {
const authToken = response.data.data.authToken const authToken = response.data.data.authToken
rocketchat.defaults.headers.common['X-User-Id'] = userId rocketchat.defaults.headers.common['X-User-Id'] = userId
rocketchat.defaults.headers.common['X-Auth-Token'] = authToken rocketchat.defaults.headers.common['X-Auth-Token'] = authToken
return { authToken, userId };
} }
const createUser = async (username, password, name, email) => { const createUser = async (username, password, name, email) => {
@ -56,6 +58,24 @@ const createChannelIfNotExists = async (channelname) => {
} }
} }
const createTeamIfNotExists = async (teamname) => {
console.log(`Creating private team ${teamname}`)
try {
await rocketchat.post('teams.create', {
"name": teamname,
"type": TEAM_TYPE.PRIVATE
})
} catch (createError) {
try { //Maybe it exists already?
await rocketchat.get(`teams.info?teamName=${teamname}`)
} catch (infoError) {
console.log(JSON.stringify(createError))
console.log(JSON.stringify(infoError))
throw "Failed to find or create private team"
}
}
}
const createGroupIfNotExists = async (groupname) => { const createGroupIfNotExists = async (groupname) => {
console.log(`Creating private group ${groupname}`) console.log(`Creating private group ${groupname}`)
try { try {
@ -91,11 +111,11 @@ const changeChannelJoinCode = async (roomId, joinCode) => {
} }
} }
const sendMessage = async (user, groupname, msg) => { const sendMessage = async (user, channel, msg) => {
console.log(`Sending message to ${groupname}`) console.log(`Sending message to ${channel}`)
try { try {
await login(user.username, user.password); await login(user.username, user.password);
await rocketchat.post('chat.postMessage', { channel: `#${groupname}`, msg }); await rocketchat.post('chat.postMessage', { channel, msg });
} catch (infoError) { } catch (infoError) {
console.log(JSON.stringify(infoError)) console.log(JSON.stringify(infoError))
throw "Failed to find or create private group" throw "Failed to find or create private group"
@ -132,6 +152,13 @@ const setup = async () => {
} }
} }
for (var teamKey in data.teams) {
if (data.teams.hasOwnProperty(teamKey)) {
const team = data.teams[teamKey]
await createTeamIfNotExists(team.name)
}
}
return return
} }
@ -146,5 +173,5 @@ const post = (endpoint, body) => {
} }
module.exports = { module.exports = {
setup, sendMessage, get, post setup, sendMessage, get, post, login
} }

View File

@ -166,7 +166,7 @@ describe('E2E Encryption', () => {
await navigateToLogin(); await navigateToLogin();
await login(testuser.username, testuser.password); await login(testuser.username, testuser.password);
await navigateToRoom(room); await navigateToRoom(room);
await waitFor(element(by.label(`${ data.random }message`)).atIndex(0)).toNotExist().withTimeout(2000); await waitFor(element(by.label(`${ data.random }message`)).atIndex(0)).not.toExist().withTimeout(2000);
await expect(element(by.label('Encrypted message')).atIndex(0)).toExist(); await expect(element(by.label('Encrypted message')).atIndex(0)).toExist();
}); });
@ -178,7 +178,7 @@ describe('E2E Encryption', () => {
await waitFor(element(by.id('e2e-enter-your-password-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('e2e-enter-your-password-view'))).toBeVisible().withTimeout(2000);
await element(by.id('e2e-enter-your-password-view-password')).typeText(newPassword); await element(by.id('e2e-enter-your-password-view-password')).typeText(newPassword);
await element(by.id('e2e-enter-your-password-view-confirm')).tap(); await element(by.id('e2e-enter-your-password-view-confirm')).tap();
await waitFor(element(by.id('listheader-encryption'))).toNotExist().withTimeout(10000); await waitFor(element(by.id('listheader-encryption'))).not.toExist().withTimeout(10000);
await navigateToRoom(room); await navigateToRoom(room);
await waitFor(element(by.label(`${ data.random }message`)).atIndex(0)).toExist().withTimeout(2000); await waitFor(element(by.label(`${ data.random }message`)).atIndex(0)).toExist().withTimeout(2000);
}); });
@ -221,8 +221,7 @@ describe('E2E Encryption', () => {
// TODO: refactor // TODO: refactor
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
await element(by.id('new-server-view-input')).replaceText(data.alternateServer); await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
await element(by.id('new-server-view-button')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000);
await element(by.id('workspace-view-register')).tap(); await element(by.id('workspace-view-register')).tap();
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
@ -231,7 +230,7 @@ describe('E2E Encryption', () => {
await element(by.id('register-view-name')).replaceText(data.registeringUser.username); await element(by.id('register-view-name')).replaceText(data.registeringUser.username);
await element(by.id('register-view-username')).replaceText(data.registeringUser.username); await element(by.id('register-view-username')).replaceText(data.registeringUser.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser.email); await element(by.id('register-view-email')).replaceText(data.registeringUser.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password); await element(by.id('register-view-password')).typeText(data.registeringUser.password);
await element(by.id('register-view-submit')).tap(); await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);

View File

@ -75,7 +75,7 @@ describe('Broadcast room', () => {
}); });
it('should have the message created earlier', async() => { it('should have the message created earlier', async() => {
await waitFor(element(by.label(`${ data.random }message`)).atIndex(0)).toBeVisible().withTimeout(60000); await waitFor(element(by.label(`${ data.random }message`))).toExist().withTimeout(60000);
}); });
it('should have reply button', async() => { it('should have reply button', async() => {

View File

@ -9,10 +9,10 @@ const profileChangeUser = data.users.profileChanges
const scrollDown = 200; const scrollDown = 200;
async function waitForToast() { async function waitForToast() {
// await waitFor(element(by.id('toast'))).toBeVisible().withTimeout(10000); // await waitFor(element(by.id('toast'))).toBeVisible().withTimeout(1000);
// await expect(element(by.id('toast'))).toBeVisible(); // await expect(element(by.id('toast'))).toBeVisible();
// await waitFor(element(by.id('toast'))).toBeNotVisible().withTimeout(10000); // await waitFor(element(by.id('toast'))).not.toBeNotVisible().withTimeout(1000);
// await expect(element(by.id('toast'))).toBeNotVisible(); // await expect(element(by.id('toast'))).not.toBeVisible();
await sleep(300); await sleep(300);
} }
@ -76,9 +76,8 @@ describe('Profile screen', () => {
describe('Usage', async() => { describe('Usage', async() => {
it('should change name and username', async() => { it('should change name and username', async() => {
await element(by.type('UIScrollView')).atIndex(1).swipe('down');
await element(by.id('profile-view-name')).replaceText(`${ profileChangeUser.username }new`); await element(by.id('profile-view-name')).replaceText(`${ profileChangeUser.username }new`);
await element(by.id('profile-view-username')).replaceText(`${ profileChangeUser.username }new`); await element(by.id('profile-view-username')).typeText(`${ profileChangeUser.username }new`);
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.type('UIScrollView')).atIndex(1).swipe('up');
await element(by.id('profile-view-submit')).tap(); await element(by.id('profile-view-submit')).tap();
await waitForToast(); await waitForToast();
@ -88,9 +87,7 @@ describe('Profile screen', () => {
await element(by.id('profile-view-email')).replaceText(`mobile+profileChangesNew${ data.random }@rocket.chat`); await element(by.id('profile-view-email')).replaceText(`mobile+profileChangesNew${ data.random }@rocket.chat`);
await element(by.id('profile-view-new-password')).replaceText(`${ profileChangeUser.password }new`); await element(by.id('profile-view-new-password')).replaceText(`${ profileChangeUser.password }new`);
await element(by.id('profile-view-submit')).tap(); await element(by.id('profile-view-submit')).tap();
await element(by.type('_UIAlertControllerTextField')).replaceText(`${ profileChangeUser.password }`) await element(by.type('_UIAlertControllerTextField')).typeText(`${ profileChangeUser.password }\n`)
// For some reason, replaceText does some type of submit, which submits the alert for us
// await element(by.label('Save').and(by.type('_UIAlertControllerActionView'))).tap();
await waitForToast(); await waitForToast();
}); });

View File

@ -63,31 +63,12 @@ describe('Settings screen', () => {
}); });
describe('Usage', async() => { describe('Usage', async() => {
it('should navigate to language view', async() => {
await element(by.id('settings-view-language')).tap();
await waitFor(element(by.id('language-view'))).toBeVisible().withTimeout(60000);
await expect(element(by.id('language-view-zh-CN'))).toExist();
await expect(element(by.id('language-view-de'))).toExist();
await expect(element(by.id('language-view-en'))).toExist();
await expect(element(by.id('language-view-fr'))).toExist();
await expect(element(by.id('language-view-pt-BR'))).toExist();
await expect(element(by.id('language-view-pt-PT'))).toExist();
await expect(element(by.id('language-view-ru'))).toExist();
await tapBack();
});
it('should tap clear cache and navigate to roomslistview', async() => { it('should tap clear cache and navigate to roomslistview', async() => {
await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000);
await element(by.id('settings-view-clear-cache')).tap(); await element(by.id('settings-view-clear-cache')).tap();
await waitFor(element(by.text('This will clear all your offline data.'))).toExist().withTimeout(2000); await waitFor(element(by.text('This will clear all your offline data.'))).toExist().withTimeout(2000);
await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap(); await element(by.label('Clear').and(by.type('_UIAlertControllerActionView'))).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(5000);
// Database was cleared, so the room shouldn't be there anymore while it's fetched again from the server
/**
* FIXME: rooms are fetched to quickly on docker and the test below fails
* We need to think on another way to test database being resetted
*/
// await waitFor(element(by.id(`rooms-list-view-item-${ data.groups.private.name }`))).toNotExist().withTimeout(10000);
await waitFor(element(by.id(`rooms-list-view-item-${ data.groups.private.name }`))).toExist().withTimeout(10000); await waitFor(element(by.id(`rooms-list-view-item-${ data.groups.private.name }`))).toExist().withTimeout(10000);
}) })
}); });

View File

@ -63,7 +63,7 @@ describe('Join public room', () => {
describe('Room Actions', async() => { describe('Room Actions', async() => {
before(async() => { before(async() => {
await navigateToRoomActions('c'); await navigateToRoomActions();
}); });
it('should have room actions screen', async() => { it('should have room actions screen', async() => {
@ -103,7 +103,6 @@ describe('Join public room', () => {
}); });
it('should have share', async() => { it('should have share', async() => {
await element(by.type('UIScrollView')).atIndex(1).swipe('down');
await expect(element(by.id('room-actions-share'))).toBeVisible(); await expect(element(by.id('room-actions-share'))).toBeVisible();
}); });
@ -142,7 +141,7 @@ describe('Join public room', () => {
}); });
it('should have disable notifications and leave channel', async() => { it('should have disable notifications and leave channel', async() => {
await navigateToRoomActions('c'); await navigateToRoomActions();
await expect(element(by.id('room-actions-view'))).toBeVisible(); await expect(element(by.id('room-actions-view'))).toBeVisible();
await expect(element(by.id('room-actions-info'))).toBeVisible(); await expect(element(by.id('room-actions-info'))).toBeVisible();
// await expect(element(by.id('room-actions-voice'))).toBeVisible(); // await expect(element(by.id('room-actions-voice'))).toBeVisible();
@ -165,7 +164,6 @@ describe('Join public room', () => {
await expect(element(by.text('Yes, leave it!'))).toBeVisible(); await expect(element(by.text('Yes, leave it!'))).toBeVisible();
await element(by.text('Yes, leave it!')).tap(); await element(by.text('Yes, leave it!')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
// await element(by.id('rooms-list-view-search')).typeText('');
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000); await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toBeNotVisible().withTimeout(60000);
}); });
}); });

View File

@ -41,10 +41,10 @@ describe('Status screen', () => {
}); });
it('should change status text', async () => { it('should change status text', async () => {
await element(by.id('status-view-input')).replaceText('status-text-new'); await element(by.id('status-view-input')).typeText('status-text-new');
await element(by.id('status-view-submit')).tap(); await element(by.id('status-view-submit')).tap();
await waitForToast(); await waitForToast();
await waitFor(element(by.label('status-text-new').withAncestor(by.id('sidebar-custom-status')))).toBeVisible().withTimeout(2000); await waitFor(element(by.label('status-text-new').withAncestor(by.id('sidebar-custom-status')))).toExist().withTimeout(2000);
}); });
}); });
}); });

View File

@ -24,9 +24,8 @@ describe('Change server', () => {
await element(by.id('rooms-list-header-server-add')).tap(); await element(by.id('rooms-list-header-server-add')).tap();
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(6000); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(6000);
await element(by.id('new-server-view-input')).replaceText(data.alternateServer); await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
await element(by.id('new-server-view-button')).tap(); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(10000);
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(6000);
await reopenAndCheckServer(data.server); await reopenAndCheckServer(data.server);
}); });

View File

@ -14,17 +14,12 @@ async function navigateToRoom() {
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
} }
async function navigateToRoomActions() {
await element(by.id('room-header')).tap();
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
}
async function openJoinCode() { async function openJoinCode() {
await element(by.id('room-view-join-button')).tap(); await element(by.id('room-view-join-button')).tap();
await waitFor(element(by.id('join-code'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id('join-code'))).toBeVisible().withTimeout(5000);
} }
describe('Join public room', () => { describe('Join protected room', () => {
before(async() => { before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin(); await navigateToLogin();

View File

@ -22,8 +22,7 @@ describe('Delete server', () => {
await element(by.id('rooms-list-header-server-add')).tap(); await element(by.id('rooms-list-header-server-add')).tap();
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(10000);
await element(by.id('new-server-view-input')).replaceText(data.alternateServer); await element(by.id('new-server-view-input')).typeText(`${data.alternateServer}\n`);
await element(by.id('new-server-view-button')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(10000);
await element(by.id('workspace-view-register')).tap(); await element(by.id('workspace-view-register')).tap();
await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('register-view'))).toBeVisible().withTimeout(2000);
@ -32,7 +31,7 @@ describe('Delete server', () => {
await element(by.id('register-view-name')).replaceText(data.registeringUser3.username); await element(by.id('register-view-name')).replaceText(data.registeringUser3.username);
await element(by.id('register-view-username')).replaceText(data.registeringUser3.username); await element(by.id('register-view-username')).replaceText(data.registeringUser3.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser3.email); await element(by.id('register-view-email')).replaceText(data.registeringUser3.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser3.password); await element(by.id('register-view-password')).typeText(data.registeringUser3.password);
await element(by.id('register-view-submit')).tap(); await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(60000);

View File

@ -2,8 +2,8 @@ const {
device, element, by, waitFor device, element, by, waitFor
} = require('detox'); } = require('detox');
const data = require('../../data'); const data = require('../../data');
const { tapBack, checkServer, navigateToRegister, login } = require('../../helpers/app'); const { tapBack, checkServer, navigateToRegister } = require('../../helpers/app');
const { post, get } = require('../../helpers/data_setup'); const { post, get, login } = require('../../helpers/data_setup');
const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' }; const DEEPLINK_METHODS = { AUTH: 'auth', ROOM: 'room' };
const getDeepLink = (method, server, params) => { const getDeepLink = (method, server, params) => {
@ -14,35 +14,31 @@ const getDeepLink = (method, server, params) => {
describe('Deep linking', () => { describe('Deep linking', () => {
let userId; let userId;
let token; let authToken;
before(async() => { before(async() => {
const loginResult = await post('login', { const loginResult = await login(data.users.regular.username, data.users.regular.password);
user: data.users.regular.username, ({ userId, authToken } = loginResult);
password: data.users.regular.password
})
userId = loginResult.data.data.userId
token = loginResult.data.data.authToken
}); });
describe('Authentication', () => { describe('Authentication', () => {
it('should run a deep link to an invalid account and raise error', async() => { it('should run a deep link to an invalid account and raise error', async() => {
await device.launchApp({ await device.launchApp({
permissions: { notifications: 'YES' }, permissions: { notifications: 'YES' },
newInstance: true, delete: true,
url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, 'userId=123&token=abc'), url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, 'userId=123&token=abc'),
sourceApp: 'com.apple.mobilesafari' sourceApp: 'com.apple.mobilesafari'
}); });
await waitFor(element(by.text('You\'ve been logged out by the server. Please log in again.'))).toExist().withTimeout(5000); // TODO: we need to improve this message await waitFor(element(by.text('You\'ve been logged out by the server. Please log in again.'))).toExist().withTimeout(10000); // TODO: we need to improve this message
}); });
const authAndNavigate = async() => { const authAndNavigate = async() => {
await device.launchApp({ await device.launchApp({
permissions: { notifications: 'YES' }, permissions: { notifications: 'YES' },
newInstance: true, newInstance: true,
url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, `userId=${ userId }&token=${ token }&path=group/${ data.groups.private.name }`), url: getDeepLink(DEEPLINK_METHODS.AUTH, data.server, `userId=${ userId }&token=${ authToken }&path=group/${ data.groups.private.name }`),
sourceApp: 'com.apple.mobilesafari' sourceApp: 'com.apple.mobilesafari'
}); });
await waitFor(element(by.id(`room-view-title-${ data.groups.private.name }`))).toExist().withTimeout(10000); await waitFor(element(by.id(`room-view-title-${ data.groups.private.name }`))).toExist().withTimeout(30000);
await tapBack(); await tapBack();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await checkServer(data.server); await checkServer(data.server);
@ -56,10 +52,10 @@ describe('Deep linking', () => {
it('should authenticate while logged in another server', async() => { it('should authenticate while logged in another server', async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true }); await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToRegister(data.alternateServer); await navigateToRegister(data.alternateServer);
await element(by.id('register-view-name')).replaceText(data.registeringUser.username); await element(by.id('register-view-name')).replaceText(data.registeringUser4.username);
await element(by.id('register-view-username')).replaceText(data.registeringUser.username); await element(by.id('register-view-username')).replaceText(data.registeringUser4.username);
await element(by.id('register-view-email')).replaceText(data.registeringUser.email); await element(by.id('register-view-email')).replaceText(data.registeringUser4.email);
await element(by.id('register-view-password')).replaceText(data.registeringUser.password); await element(by.id('register-view-password')).typeText(data.registeringUser4.password);
await element(by.id('register-view-submit')).tap(); await element(by.id('register-view-submit')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000); await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await authAndNavigate(); await authAndNavigate();
@ -86,7 +82,7 @@ describe('Deep linking', () => {
url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `rid=${ roomResult.data.group._id }`), url: getDeepLink(DEEPLINK_METHODS.ROOM, data.server, `rid=${ roomResult.data.group._id }`),
sourceApp: 'com.apple.mobilesafari' sourceApp: 'com.apple.mobilesafari'
}); });
await waitFor(element(by.id(`room-view-title-${ data.groups.private.name }`))).toExist().withTimeout(10000); await waitFor(element(by.id(`room-view-title-${ data.groups.private.name }`))).toExist().withTimeout(15000);
await tapBack(); await tapBack();
}); });
}); });

View File

@ -0,0 +1,114 @@
const {
device, element, by, waitFor
} = require('detox');
const { navigateToLogin, login, sleep } = require('../../helpers/app');
const { post } = require('../../helpers/data_setup');
const data = require('../../data');
const testuser = data.users.regular
const defaultLaunchArgs = { permissions: { notifications: 'YES' } };
const navToLanguage = async() => {
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('sidebar-settings'))).toBeVisible().withTimeout(2000);
await element(by.id('sidebar-settings')).tap();
await waitFor(element(by.id('settings-view'))).toBeVisible().withTimeout(2000);
await element(by.id('settings-view-language')).tap();
await waitFor(element(by.id('language-view'))).toBeVisible().withTimeout(10000);
};
describe('i18n', () => {
describe('OS language', () => {
it('OS set to \'en\' and proper translate to \'en\'', async() => {
await device.launchApp({
...defaultLaunchArgs,
languageAndLocale: {
language: "en",
locale: "en"
},
delete: true
});
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000);
await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible();
await expect(element(by.id('create-workspace-button').and(by.label('Create a new workspace')))).toBeVisible();
});
it('OS set to unavailable language and fallback to \'en\'', async() => {
await device.launchApp({
...defaultLaunchArgs,
languageAndLocale: {
language: "es-MX",
locale: "es-MX"
}
});
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000);
await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible();
await expect(element(by.id('create-workspace-button').and(by.label('Create a new workspace')))).toBeVisible();
});
/**
* This test might become outdated as soon as we support the language
* Although this seems to be a bad approach, that's the intention for having fallback enabled
*/
it('OS set to available language and fallback to \'en\' on strings missing translation', async() => {
await device.launchApp({
...defaultLaunchArgs,
languageAndLocale: {
language: "nl",
locale: "nl"
}
});
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(20000);
await expect(element(by.id('join-workspace').and(by.label('Join a workspace')))).toBeVisible(); // Missing nl translation
await expect(element(by.id('create-workspace-button').and(by.label('Een nieuwe workspace maken')))).toBeVisible();
});
});
describe('Rocket.Chat language', () => {
before(async() => {
await device.launchApp(defaultLaunchArgs);
await navigateToLogin();
await login(testuser.username, testuser.password);
});
it('should select \'en\'', async() => {
await navToLanguage();
await element(by.id('language-view-en')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('sidebar-chats').withDescendant(by.label('Chats')))).toBeVisible();
await expect(element(by.id('sidebar-profile').withDescendant(by.label('Profile')))).toBeVisible();
await expect(element(by.id('sidebar-settings').withDescendant(by.label('Settings')))).toBeVisible();
await element(by.id('sidebar-close-drawer')).tap();
});
it('should select \'nl\' and fallback to \'en\'', async() => {
await navToLanguage();
await element(by.id('language-view-nl')).tap();
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('sidebar-chats').withDescendant(by.label('Chats')))).toBeVisible(); // fallback to en
await expect(element(by.id('sidebar-profile').withDescendant(by.label('Profiel')))).toBeVisible();
await expect(element(by.id('sidebar-settings').withDescendant(by.label('Instellingen')))).toBeVisible();
await element(by.id('sidebar-close-drawer')).tap();
});
it('should set unsupported language and fallback to \'en\'', async() => {
await post('users.setPreferences', { data: { language: 'eo' } }); // Set language to Esperanto
await device.launchApp(defaultLaunchArgs);
await waitFor(element(by.id('rooms-list-view'))).toBeVisible().withTimeout(10000);
await element(by.id('rooms-list-view-sidebar')).tap();
await waitFor(element(by.id('sidebar-view'))).toBeVisible().withTimeout(2000);
// give the app some time to apply new language
await sleep(3000);
await expect(element(by.id('sidebar-chats').withDescendant(by.label('Chats')))).toBeVisible();
await expect(element(by.id('sidebar-profile').withDescendant(by.label('Profile')))).toBeVisible();
await expect(element(by.id('sidebar-settings').withDescendant(by.label('Settings')))).toBeVisible();
await post('users.setPreferences', { data: { language: 'en' } }); // Set back to english
});
})
});

View File

@ -34,8 +34,7 @@ describe('Onboarding', () => {
}); });
it('should enter an invalid server and get error', async() => { it('should enter an invalid server and get error', async() => {
await element(by.id('new-server-view-input')).replaceText('invalidtest'); await element(by.id('new-server-view-input')).typeText('invalidtest\n');
await element(by.id('new-server-view-button')).tap();
const errorText = 'Oops!'; const errorText = 'Oops!';
await waitFor(element(by.text(errorText))).toBeVisible().withTimeout(60000); await waitFor(element(by.text(errorText))).toBeVisible().withTimeout(60000);
await element(by.text('OK')).tap(); await element(by.text('OK')).tap();
@ -51,8 +50,7 @@ describe('Onboarding', () => {
await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('onboarding-view'))).toBeVisible().withTimeout(2000);
await element(by.id('join-workspace')).tap(); await element(by.id('join-workspace')).tap();
await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('new-server-view'))).toBeVisible().withTimeout(60000);
await element(by.id('new-server-view-input')).replaceText(data.server); await element(by.id('new-server-view-input')).typeText(`${data.server}\n`);
await element(by.id('new-server-view-button')).tap();
await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('workspace-view'))).toBeVisible().withTimeout(60000);
}); });
}); });

View File

@ -30,6 +30,7 @@ describe('Forgot password screen', () => {
it('should reset password and navigate to login', async() => { it('should reset password and navigate to login', async() => {
await element(by.id('forgot-password-view-email')).replaceText(data.users.existing.email); await element(by.id('forgot-password-view-email')).replaceText(data.users.existing.email);
await element(by.id('forgot-password-view-submit')).tap(); await element(by.id('forgot-password-view-submit')).tap();
await waitFor(element(by.text('OK'))).toExist().withTimeout(10000);
await element(by.text('OK')).tap(); await element(by.text('OK')).tap();
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(60000); await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(60000);
}); });

View File

@ -25,7 +25,7 @@ describe('Server history', () => {
it('should tap on a server history and navigate to login', async() => { it('should tap on a server history and navigate to login', async() => {
await element(by.id(`server-history-${ data.server }`)).tap(); await element(by.id(`server-history-${ data.server }`)).tap();
await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('login-view'))).toBeVisible().withTimeout(5000);
await expect(element(by.id('login-view-email'))).toHaveText(data.users.regular.username); await expect(element(by.id('login-view-email'))).toHaveText(data.users.regular.username);
}); });

View File

@ -94,7 +94,7 @@ describe('Create room screen', () => {
describe('Usage', async() => { describe('Usage', async() => {
it('should get invalid room', async() => { it('should get invalid room', async() => {
await element(by.id('create-channel-name')).replaceText('general'); await element(by.id('create-channel-name')).typeText('general');
await element(by.id('create-channel-submit')).tap(); await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.text(`A channel with name 'general' exists`))).toExist().withTimeout(60000); await waitFor(element(by.text(`A channel with name 'general' exists`))).toExist().withTimeout(60000);
await expect(element(by.text(`A channel with name 'general' exists`))).toExist(); await expect(element(by.text(`A channel with name 'general' exists`))).toExist();
@ -103,16 +103,17 @@ describe('Create room screen', () => {
it('should create public room', async() => { it('should create public room', async() => {
const room = `public${ data.random }`; const room = `public${ data.random }`;
await element(by.id('create-channel-name')).replaceText(room); await element(by.id('create-channel-name')).replaceText('');
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-type')).tap(); await element(by.id('create-channel-type')).tap();
await element(by.id('create-channel-submit')).tap(); await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000); await waitFor(element(by.id('room-view'))).toExist().withTimeout(6000);
await expect(element(by.id('room-view'))).toExist(); await expect(element(by.id('room-view'))).toExist();
await waitFor(element(by.id(`room-view-title-${ room }`))).toExist().withTimeout(60000); await waitFor(element(by.id(`room-view-title-${ room }`))).toExist().withTimeout(6000);
await expect(element(by.id(`room-view-title-${ room }`))).toExist(); await expect(element(by.id(`room-view-title-${ room }`))).toExist();
await tapBack(); await tapBack();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000); await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000); await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(6000);
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toExist(); await expect(element(by.id(`rooms-list-view-item-${ room }`))).toExist();
}); });
@ -127,7 +128,7 @@ describe('Create room screen', () => {
await waitFor(element(by.id('selected-user-rocket.cat'))).toExist().withTimeout(5000); await waitFor(element(by.id('selected-user-rocket.cat'))).toExist().withTimeout(5000);
await element(by.id('selected-users-view-submit')).tap(); await element(by.id('selected-users-view-submit')).tap();
await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000); await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(5000);
await element(by.id('create-channel-name')).replaceText(room); await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-submit')).tap(); await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000); await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view'))).toExist(); await expect(element(by.id('room-view'))).toExist();
@ -149,7 +150,7 @@ describe('Create room screen', () => {
await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(5000); await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(5000);
await element(by.id('selected-users-view-submit')).tap(); await element(by.id('selected-users-view-submit')).tap();
await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(10000); await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(10000);
await element(by.id('create-channel-name')).replaceText(room); await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-submit')).tap(); await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000); await waitFor(element(by.id('room-view'))).toExist().withTimeout(60000);
await expect(element(by.id('room-view'))).toExist(); await expect(element(by.id('room-view'))).toExist();

View File

@ -125,7 +125,6 @@ describe('Room screen', () => {
}); });
it('should not show user autocomplete on @ in the middle of a string', async() => { it('should not show user autocomplete on @ in the middle of a string', async() => {
const username = data.users.regular.username
await element(by.id('messagebox-input')).tap(); await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).typeText(`email@gmail`); await element(by.id('messagebox-input')).typeText(`email@gmail`);
await waitFor(element(by.id('messagebox-container'))).toNotExist().withTimeout(4000); await waitFor(element(by.id('messagebox-container'))).toNotExist().withTimeout(4000);
@ -149,8 +148,8 @@ describe('Room screen', () => {
await element(by.id('messagebox-input')).clearText(); await element(by.id('messagebox-input')).clearText();
}); });
it('should draft message', async () => { it('should draft message', async () => {
await element(by.id('messagebox-input')).atIndex(0).tap(); await element(by.id('messagebox-input')).tap();
await element(by.id('messagebox-input')).atIndex(0).typeText(`${ data.random }draft`); await element(by.id('messagebox-input')).typeText(`${ data.random }draft`);
await tapBack(); await tapBack();
await navigateToRoom(mainRoom); await navigateToRoom(mainRoom);
@ -191,9 +190,9 @@ describe('Room screen', () => {
await element(by.label(`${ data.random }message`)).atIndex(0).longPress(); await element(by.label(`${ data.random }message`)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.id('action-sheet-handle')).swipe('up', 'slow', 0.5);
await waitFor(element(by.label('Unstar'))).toBeVisible().withTimeout(2000); await waitFor(element(by.label('Unstar'))).toBeVisible().withTimeout(6000);
await element(by.id('action-sheet-backdrop')).tap(); await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.8);
}); });
it('should react to message', async() => { it('should react to message', async() => {
@ -267,14 +266,14 @@ describe('Room screen', () => {
await mockMessage('pin') await mockMessage('pin')
await pinMessage('pin') await pinMessage('pin')
await waitFor(element(by.label(`${ data.random }pin`)).atIndex(0)).toBeVisible().withTimeout(2000); await waitFor(element(by.label(`${ data.random }pin`)).atIndex(0)).toExist().withTimeout(5000);
await waitFor(element(by.label(`${ data.users.regular.username } Message pinned`)).atIndex(0)).toBeVisible().withTimeout(2000); await waitFor(element(by.label(`${ data.users.regular.username } Message pinned`)).atIndex(0)).toExist().withTimeout(5000);
await element(by.label(`${ data.random }pin`)).atIndex(0).longPress(); await element(by.label(`${ data.random }pin`)).atIndex(0).longPress();
await waitFor(element(by.id('action-sheet'))).toExist().withTimeout(1000); await waitFor(element(by.id('action-sheet'))).toExist().withTimeout(1000);
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await waitFor(element(by.label('Unpin'))).toBeVisible().withTimeout(2000); await waitFor(element(by.label('Unpin'))).toBeVisible().withTimeout(2000);
await element(by.id('action-sheet-backdrop')).tap(); await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.8);
}); });
it('should delete message', async() => { it('should delete message', async() => {
@ -285,6 +284,7 @@ describe('Room screen', () => {
await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await waitFor(element(by.label('Delete'))).toExist().withTimeout(1000);
await element(by.label('Delete')).tap(); await element(by.label('Delete')).tap();
const deleteAlertMessage = 'You will not be able to recover this message!'; const deleteAlertMessage = 'You will not be able to recover this message!';
@ -294,12 +294,5 @@ describe('Room screen', () => {
await waitFor(element(by.label(`${ data.random }delete`)).atIndex(0)).toNotExist().withTimeout(2000); await waitFor(element(by.label(`${ data.random }delete`)).atIndex(0)).toNotExist().withTimeout(2000);
}); });
}); });
// after(async() => {
// await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
// await tapBack();
// await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
// await expect(element(by.id('rooms-list-view'))).toExist();
// });
}); });
}); });

View File

@ -223,10 +223,10 @@ describe('Room actions screen', () => {
//Go to starred messages //Go to starred messages
await element(by.id('room-actions-starred')).tap(); await element(by.id('room-actions-starred')).tap();
await waitFor(element(by.id('starred-messages-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('starred-messages-view'))).toExist().withTimeout(2000);
await waitFor(element(by.label(`${ data.random }messageToStar`).withAncestor(by.id('starred-messages-view')))).toBeVisible().withTimeout(60000); await waitFor(element(by.label(`${ data.random }messageToStar`).withAncestor(by.id('starred-messages-view')))).toExist().withTimeout(60000);
//Unstar message //Unstar message
await element(by.label(`${ data.random }messageToStar`).withAncestor(by.id('starred-messages-view'))).longPress(); await element(by.label(`${ data.random }messageToStar`)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.label('Unstar')).tap(); await element(by.label('Unstar')).tap();
@ -247,18 +247,18 @@ describe('Room actions screen', () => {
//Back into Room Actions //Back into Room Actions
await element(by.id('room-header')).tap(); await element(by.id('room-header')).tap();
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000); await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom'); await element(by.id('room-actions-scrollview')).scrollTo('bottom');
await waitFor(element(by.id('room-actions-pinned'))).toExist(); await waitFor(element(by.id('room-actions-pinned'))).toExist();
await element(by.id('room-actions-pinned')).tap(); await element(by.id('room-actions-pinned')).tap();
await waitFor(element(by.id('pinned-messages-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('pinned-messages-view'))).toExist().withTimeout(2000);
await waitFor(element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view')))).toBeVisible().withTimeout(60000); await waitFor(element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view')))).toExist().withTimeout(6000);
await element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view'))).longPress(); await element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view'))).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.label('Unpin')).tap(); await element(by.label('Unpin')).tap();
await waitFor(element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view')))).toBeNotVisible().withTimeout(60000); await waitFor(element(by.label(`${ data.random }messageToPin`).withAncestor(by.id('pinned-messages-view')))).not.toExist().withTimeout(6000);
await backToActions(); await backToActions();
}); });
@ -283,7 +283,7 @@ describe('Room actions screen', () => {
describe('Notification', async() => { describe('Notification', async() => {
it('should navigate to notification preference view', async() => { it('should navigate to notification preference view', async() => {
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom'); await element(by.id('room-actions-scrollview')).scrollTo('bottom');
await waitFor(element(by.id('room-actions-notifications'))).toExist().withTimeout(2000); await waitFor(element(by.id('room-actions-notifications'))).toExist().withTimeout(2000);
await element(by.id('room-actions-notifications')).tap(); await element(by.id('room-actions-notifications')).tap();
await waitFor(element(by.id('notification-preference-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('notification-preference-view'))).toExist().withTimeout(2000);
@ -311,7 +311,7 @@ describe('Room actions screen', () => {
it('should have notification sound option', async() => { it('should have notification sound option', async() => {
// Ugly hack to scroll on detox // Ugly hack to scroll on detox
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom'); await element(by.id('room-actions-scrollview')).scrollTo('bottom');
await waitFor(element(by.id('notification-preference-view-sound'))).toExist().withTimeout(4000); await waitFor(element(by.id('notification-preference-view-sound'))).toExist().withTimeout(4000);
}); });
@ -335,7 +335,7 @@ describe('Room actions screen', () => {
const user = data.users.alternate const user = data.users.alternate
it('should tap on leave channel and raise alert', async() => { it('should tap on leave channel and raise alert', async() => {
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom'); await element(by.id('room-actions-scrollview')).scrollTo('bottom');
await waitFor(element(by.id('room-actions-leave-channel'))).toExist().withTimeout(2000); await waitFor(element(by.id('room-actions-leave-channel'))).toExist().withTimeout(2000);
await element(by.id('room-actions-leave-channel')).tap(); await element(by.id('room-actions-leave-channel')).tap();
await waitFor(element(by.text('Yes, leave it!'))).toExist().withTimeout(2000); await waitFor(element(by.text('Yes, leave it!'))).toExist().withTimeout(2000);
@ -368,7 +368,7 @@ describe('Room actions screen', () => {
await element(by.id('room-actions-members')).tap(); await element(by.id('room-actions-members')).tap();
await element(by.id('room-members-view-toggle-status')).tap(); await element(by.id('room-members-view-toggle-status')).tap();
await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000); await waitFor(element(by.id(`room-members-view-item-${ user.username }`))).toExist().withTimeout(60000);
await backToActions(1); await backToActions();
}); });
describe('Room Members', async() => { describe('Room Members', async() => {
@ -414,7 +414,7 @@ describe('Room actions screen', () => {
} }
const closeActionSheet = async() => { const closeActionSheet = async() => {
await element(by.id('action-sheet-backdrop')).tap(); await element(by.id('action-sheet-handle')).swipe('down', 'fast', 0.6);
} }
it('should set/remove as owner', async() => { it('should set/remove as owner', async() => {
@ -483,7 +483,7 @@ describe('Room actions screen', () => {
it('should ignore user', async() => { it('should ignore user', async() => {
const message = `${ data.random }ignoredmessagecontent`; const message = `${ data.random }ignoredmessagecontent`;
const channelName = data.groups.private.name; const channelName = `#${ data.groups.private.name }`;
await sendMessage(user, channelName, message); await sendMessage(user, channelName, message);
await openActionSheet(user.username); await openActionSheet(user.username);
await element(by.label('Ignore')).tap(); await element(by.label('Ignore')).tap();

View File

@ -81,7 +81,7 @@ describe('Threads', () => {
it('should navigate to thread from button', async() => { it('should navigate to thread from button', async() => {
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id('room-view'))).toExist().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ thread }`))).toExist(); await expect(element(by.id(`room-view-title-${ thread }`))).toExist();
await tapBack(); await tapBack();
@ -89,7 +89,7 @@ describe('Threads', () => {
it('should toggle follow thread', async() => { it('should toggle follow thread', async() => {
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000); await waitFor(element(by.id('room-view'))).toExist().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ thread }`))).toExist(); await expect(element(by.id(`room-view-title-${ thread }`))).toExist();
await element(by.id('room-view-header-unfollow')).tap(); await element(by.id('room-view-header-unfollow')).tap();
@ -102,7 +102,7 @@ describe('Threads', () => {
it('should send message in thread only', async() => { it('should send message in thread only', async() => {
const messageText = 'threadonly'; const messageText = 'threadonly';
await mockMessage(messageText); await mockMessage(messageText, true);
await tapBack(); await tapBack();
await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000); await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
@ -113,7 +113,7 @@ describe('Threads', () => {
it('should mark send to channel and show on main channel', async() => { it('should mark send to channel and show on main channel', async() => {
const messageText = 'sendToChannel'; const messageText = 'sendToChannel';
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await element(by.id('messagebox-input')).atIndex(0).typeText(messageText); await element(by.id('messagebox-input-thread')).typeText(messageText);
await element(by.id('messagebox-send-to-channel')).tap(); await element(by.id('messagebox-send-to-channel')).tap();
await element(by.id('messagebox-send-message')).tap(); await element(by.id('messagebox-send-message')).tap();
await tapBack(); await tapBack();
@ -128,16 +128,14 @@ describe('Threads', () => {
await mockMessage('dummymessagebetweenthethread'); await mockMessage('dummymessagebetweenthethread');
await dismissReviewNag() //TODO: Create a proper test for this elsewhere. await dismissReviewNag() //TODO: Create a proper test for this elsewhere.
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await element(by.id('messagebox-input')).atIndex(0).typeText(messageText); await element(by.id('messagebox-input-thread')).typeText(messageText);
await element(by.id('messagebox-send-to-channel')).tap(); await element(by.id('messagebox-send-to-channel')).tap();
await element(by.id('messagebox-send-message')).tap(); await element(by.id('messagebox-send-message')).tap();
await tapBack(); await tapBack();
await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000); await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
await sleep(500) //TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :( await waitFor(element(by.id(`message-thread-replied-on-${ thread }`))).toBeVisible().withTimeout(2000);
await element(by.id(`message-thread-replied-on-${ thread }`)).tap(); await element(by.id(`message-thread-replied-on-${ thread }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ thread }`))).toExist(); await expect(element(by.id(`room-view-title-${ thread }`))).toExist();
await tapBack(); await tapBack();
@ -149,7 +147,6 @@ describe('Threads', () => {
await waitFor(element(by.id('thread-messages-view'))).toExist().withTimeout(5000); await waitFor(element(by.id('thread-messages-view'))).toExist().withTimeout(5000);
await expect(element(by.id('thread-messages-view'))).toExist(); await expect(element(by.id('thread-messages-view'))).toExist();
await element(by.id(`thread-messages-view-${ thread }`)).atIndex(0).tap(); await element(by.id(`thread-messages-view-${ thread }`)).atIndex(0).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id(`room-view-title-${ thread }`))).toExist(); await expect(element(by.id(`room-view-title-${ thread }`))).toExist();
await tapBack(); await tapBack();
@ -160,31 +157,20 @@ describe('Threads', () => {
it('should draft thread message', async () => { it('should draft thread message', async () => {
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await element(by.id('messagebox-input')).atIndex(0).tap(); await element(by.id('messagebox-input-thread')).typeText(`${ thread }draft`);
await element(by.id('messagebox-input')).atIndex(0).typeText(`${ thread }draft`);
await tapBack(); await tapBack();
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id('messagebox-input')).atIndex(0)).toHaveText(`${ thread }draft`); await expect(element(by.id('messagebox-input-thread'))).toHaveText(`${ thread }draft`);
await element(by.id('messagebox-input')).atIndex(0).clearText(); await element(by.id('messagebox-input-thread')).clearText();
await tapBack(); await tapBack();
await element(by.id(`message-thread-button-${ thread }`)).tap(); await element(by.id(`message-thread-button-${ thread }`)).tap();
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000); await waitFor(element(by.id(`room-view-title-${ thread }`))).toExist().withTimeout(5000);
await expect(element(by.id('messagebox-input')).atIndex(0)).toHaveText(''); await expect(element(by.id('messagebox-input-thread'))).toHaveText('');
}); });
}); });
// after(async() => {
// await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(5000);
// await tapBack();
// await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(2000);
// await expect(element(by.id('rooms-list-view'))).toExist();
// });
}); });
}); });

View File

@ -2,7 +2,8 @@ const {
device, expect, element, by, waitFor device, expect, element, by, waitFor
} = require('detox'); } = require('detox');
const data = require('../../data'); const data = require('../../data');
const { navigateToLogin, login, mockMessage, tapBack, searchRoom, logout } = require('../../helpers/app'); const { navigateToLogin, login, searchRoom } = require('../../helpers/app');
const { sendMessage } = require('../../helpers/data_setup')
async function navigateToRoom(user) { async function navigateToRoom(user) {
await searchRoom(`${ user }`); await searchRoom(`${ user }`);
@ -20,23 +21,21 @@ describe('Mark as unread', () => {
await navigateToRoom(user); await navigateToRoom(user);
}); });
// TODO: Fix flakiness. If it fails, run it solo.
describe('Usage', async() => { describe('Usage', async() => {
describe('Mark message as unread', async() => { describe('Mark message as unread', async() => {
it('should mark message as unread', async() => { it('should mark message as unread', async() => {
await mockMessage('message') const message = `${ data.random }message`;
await expect(element(by.label(`${ data.random }message`)).atIndex(0)).toExist(); const channelName = `@${ data.users.regular.username }`;
await tapBack(); await sendMessage(data.users.alternate, channelName, message);
await logout(); await waitFor(element(by.label(message)).atIndex(0)).toExist().withTimeout(30000);
await navigateToLogin(); await element(by.label(message)).atIndex(0).longPress();
await login(data.users.alternate.username, data.users.alternate.password);
await navigateToRoom(data.users.regular.username);
await element(by.label(`${ data.random }message`)).atIndex(0).longPress();
await expect(element(by.id('action-sheet'))).toExist(); await expect(element(by.id('action-sheet'))).toExist();
await expect(element(by.id('action-sheet-handle'))).toBeVisible(); await expect(element(by.id('action-sheet-handle'))).toBeVisible();
await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5); await element(by.id('action-sheet-handle')).swipe('up', 'fast', 0.5);
await element(by.label('Mark Unread')).tap(); await element(by.label('Mark Unread')).tap();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(5000); await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(5000);
await expect(element(by.id(`rooms-list-view-item-${data.users.regular.username}`))).toExist(); await expect(element(by.id(`rooms-list-view-item-${data.users.alternate.username}`))).toExist();
}); });
}); });
}); });

View File

@ -119,7 +119,7 @@ describe('Room info screen', () => {
it('should have type switch', async() => { it('should have type switch', async() => {
// Ugly hack to scroll on detox // Ugly hack to scroll on detox
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.8);
await expect(element(by.id('room-info-edit-view-t'))).toExist(); await expect(element(by.id('room-info-edit-view-t'))).toExist();
}); });
@ -145,7 +145,7 @@ describe('Room info screen', () => {
after(async() => { after(async() => {
// Ugly hack to scroll on detox // Ugly hack to scroll on detox
await element(by.type('UIScrollView')).atIndex(1).swipe('down'); await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
}); });
}); });
@ -164,7 +164,7 @@ describe('Room info screen', () => {
it('should change room name', async() => { it('should change room name', async() => {
await element(by.id('room-info-edit-view-name')).replaceText(`${ privateRoomName }new`); await element(by.id('room-info-edit-view-name')).replaceText(`${ privateRoomName }new`);
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
await tapBack(); await tapBack();
@ -174,10 +174,10 @@ describe('Room info screen', () => {
await element(by.id('room-info-view-edit-button')).tap(); await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await element(by.id('room-info-edit-view-name')).replaceText(`${ privateRoomName }`); await element(by.id('room-info-edit-view-name')).replaceText(`${ privateRoomName }`);
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
await element(by.type('UIScrollView')).atIndex(1).swipe('down'); await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
}); });
it('should reset form', async() => { it('should reset form', async() => {
@ -186,7 +186,7 @@ describe('Room info screen', () => {
await element(by.id('room-info-edit-view-topic')).replaceText('abc'); await element(by.id('room-info-edit-view-topic')).replaceText('abc');
await element(by.id('room-info-edit-view-announcement')).replaceText('abc'); await element(by.id('room-info-edit-view-announcement')).replaceText('abc');
await element(by.id('room-info-edit-view-password')).replaceText('abc'); await element(by.id('room-info-edit-view-password')).replaceText('abc');
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-t')).tap(); await element(by.id('room-info-edit-view-t')).tap();
await element(by.id('room-info-edit-view-ro')).longPress(); //https://github.com/facebook/react-native/issues/28032 await element(by.id('room-info-edit-view-ro')).longPress(); //https://github.com/facebook/react-native/issues/28032
await element(by.id('room-info-edit-view-react-when-ro')).tap(); await element(by.id('room-info-edit-view-react-when-ro')).tap();
@ -200,12 +200,12 @@ describe('Room info screen', () => {
await expect(element(by.id('room-info-edit-view-t'))).toHaveValue('1'); await expect(element(by.id('room-info-edit-view-t'))).toHaveValue('1');
await expect(element(by.id('room-info-edit-view-ro'))).toHaveValue('0'); await expect(element(by.id('room-info-edit-view-ro'))).toHaveValue('0');
await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeNotVisible(); await expect(element(by.id('room-info-edit-view-react-when-ro'))).toBeNotVisible();
await element(by.type('UIScrollView')).atIndex(1).swipe('down'); await element(by.id('room-info-edit-view-list')).swipe('down', 'fast', 0.8);
}); });
it('should change room description', async() => { it('should change room description', async() => {
await element(by.id('room-info-edit-view-description')).replaceText('new description'); await element(by.id('room-info-edit-view-description')).replaceText('new description');
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
await tapBack(); await tapBack();
@ -218,7 +218,7 @@ describe('Room info screen', () => {
await element(by.id('room-info-view-edit-button')).tap(); await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await element(by.id('room-info-edit-view-topic')).replaceText('new topic'); await element(by.id('room-info-edit-view-topic')).replaceText('new topic');
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
await tapBack(); await tapBack();
@ -231,7 +231,7 @@ describe('Room info screen', () => {
await element(by.id('room-info-view-edit-button')).tap(); await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement'); await element(by.id('room-info-edit-view-announcement')).replaceText('new announcement');
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
await tapBack(); await tapBack();
@ -243,14 +243,14 @@ describe('Room info screen', () => {
await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000); await waitFor(element(by.id('room-info-view-edit-button'))).toExist().withTimeout(10000);
await element(by.id('room-info-view-edit-button')).tap(); await element(by.id('room-info-view-edit-button')).tap();
await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000); await waitFor(element(by.id('room-info-edit-view'))).toExist().withTimeout(2000);
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-password')).replaceText('password'); await element(by.id('room-info-edit-view-password')).replaceText('password');
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
}); });
it('should change room type', async() => { it('should change room type', async() => {
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-t')).tap(); await element(by.id('room-info-edit-view-t')).tap();
await element(by.id('room-info-edit-view-submit')).tap(); await element(by.id('room-info-edit-view-submit')).tap();
await waitForToast(); await waitForToast();
@ -272,7 +272,7 @@ describe('Room info screen', () => {
// }); // });
it('should archive room', async() => { it('should archive room', async() => {
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-archive')).tap(); await element(by.id('room-info-edit-view-archive')).tap();
await waitFor(element(by.text('Yes, archive it!'))).toExist().withTimeout(5000); await waitFor(element(by.text('Yes, archive it!'))).toExist().withTimeout(5000);
await element(by.text('Yes, archive it!')).tap(); await element(by.text('Yes, archive it!')).tap();
@ -288,7 +288,7 @@ describe('Room info screen', () => {
}); });
it('should delete room', async() => { it('should delete room', async() => {
await element(by.type('UIScrollView')).atIndex(1).swipe('up'); await element(by.id('room-info-edit-view-list')).swipe('up', 'fast', 0.5);
await element(by.id('room-info-edit-view-delete')).tap(); await element(by.id('room-info-edit-view-delete')).tap();
await waitFor(element(by.text('Yes, delete it!'))).toExist().withTimeout(5000); await waitFor(element(by.text('Yes, delete it!'))).toExist().withTimeout(5000);
await element(by.text('Yes, delete it!')).tap(); await element(by.text('Yes, delete it!')).tap();

View File

@ -0,0 +1,82 @@
const {
device, expect, element, by, waitFor
} = require('detox');
const data = require('../../data');
const { tapBack, sleep, navigateToLogin, login, tryTapping } = require('../../helpers/app');
describe('Create team screen', () => {
before(async() => {
await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
await navigateToLogin();
await login(data.users.regular.username, data.users.regular.password);
});
describe('New Message', async() => {
before(async() => {
await element(by.id('rooms-list-view-create-channel')).tap();
});
describe('Render', async() => {
it('should have team button', async() => {
await waitFor(element(by.id('new-message-view-create-channel'))).toBeVisible().withTimeout(2000);
});
})
describe('Usage', async() => {
it('should navigate to select users', async() => {
await element(by.id('new-message-view-create-channel')).tap();
await waitFor(element(by.id('select-users-view'))).toExist().withTimeout(5000);
});
})
});
describe('Select Users', async() => {
it('should search users', async() => {
await element(by.id('select-users-view-search')).replaceText('rocket.cat');
await waitFor(element(by.id(`select-users-view-item-rocket.cat`))).toBeVisible().withTimeout(10000);
});
it('should select/unselect user', async() => {
// Spotlight issues
await element(by.id('select-users-view-item-rocket.cat')).tap();
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(10000);
await element(by.id('selected-user-rocket.cat')).tap();
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeNotVisible().withTimeout(10000);
// Spotlight issues
await element(by.id('select-users-view-item-rocket.cat')).tap();
await waitFor(element(by.id('selected-user-rocket.cat'))).toBeVisible().withTimeout(10000);
});
it('should create team', async() => {
await element(by.id('selected-users-view-submit')).tap();
await waitFor(element(by.id('create-channel-view'))).toExist().withTimeout(10000);
});
})
describe('Create Team', async() => {
describe('Usage', async() => {
it('should get invalid team name', async() => {
await element(by.id('create-channel-name')).typeText(`${data.teams.private.name}`);
await element(by.id('create-channel-submit')).tap();
await element(by.text('OK')).tap();
});
it('should create private team', async() => {
const room = `private${ data.random }`;
await element(by.id('create-channel-name')).replaceText('');
await element(by.id('create-channel-name')).typeText(room);
await element(by.id('create-channel-submit')).tap();
await waitFor(element(by.id('room-view'))).toExist().withTimeout(20000);
await expect(element(by.id('room-view'))).toExist();
await waitFor(element(by.id(`room-view-title-${ room }`))).toExist().withTimeout(6000);
await expect(element(by.id(`room-view-title-${ room }`))).toExist();
await tapBack();
await waitFor(element(by.id('rooms-list-view'))).toExist().withTimeout(10000);
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(6000);
await expect(element(by.id(`rooms-list-view-item-${ room }`))).toExist();
});
})
});
});

View File

@ -1450,6 +1450,7 @@
DEAD_CODE_STRIPPING = NO; DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = S6UPZG7ZR3; DEVELOPMENT_TEAM = S6UPZG7ZR3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)", "$(PROJECT_DIR)",
@ -1569,6 +1570,7 @@
DEVELOPMENT_TEAM = S6UPZG7ZR3; DEVELOPMENT_TEAM = S6UPZG7ZR3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"\"${PODS_ROOT}/Crashlytics/iOS\"", "\"${PODS_ROOT}/Crashlytics/iOS\"",
@ -1687,11 +1689,12 @@
DEBUG_INFORMATION_FORMAT = dwarf; DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = S6UPZG7ZR3; DEVELOPMENT_TEAM = S6UPZG7ZR3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = NotificationService/Info.plist; INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 4.16.0; MARKETING_VERSION = 4.16.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
@ -1728,7 +1731,7 @@
INFOPLIST_FILE = NotificationService/Info.plist; INFOPLIST_FILE = NotificationService/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 4.16.0; MARKETING_VERSION = 4.16.2;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -1756,6 +1759,7 @@
DEAD_CODE_STRIPPING = NO; DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = S6UPZG7ZR3; DEVELOPMENT_TEAM = S6UPZG7ZR3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)", "$(PROJECT_DIR)",

View File

@ -23,7 +23,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.16.0</string> <string>4.16.2</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>

View File

@ -21,7 +21,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>XPC!</string> <string>XPC!</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>4.16.0</string> <string>4.16.2</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>1</string>
<key>KeychainGroup</key> <key>KeychainGroup</key>

View File

@ -1,6 +1,6 @@
{ {
"name": "rocket-chat-reactnative", "name": "rocket-chat-reactnative",
"version": "4.16.0", "version": "4.16.2",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-native start", "start": "react-native start",
@ -67,6 +67,7 @@
"js-base64": "2.5.2", "js-base64": "2.5.2",
"js-sha256": "^0.9.0", "js-sha256": "^0.9.0",
"lodash": "4.17.20", "lodash": "4.17.20",
"mocha": "7.1.2",
"moment": "2.27.0", "moment": "2.27.0",
"pretty-bytes": "^5.3.0", "pretty-bytes": "^5.3.0",
"prop-types": "15.7.2", "prop-types": "15.7.2",
@ -144,7 +145,7 @@
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"bugsnag-sourcemaps": "1.3.0", "bugsnag-sourcemaps": "1.3.0",
"codecov": "3.7.1", "codecov": "3.7.1",
"detox": "^18.8.1", "detox": "^18.10.0",
"emotion-theming": "10.0.27", "emotion-theming": "10.0.27",
"eslint": "6.8.0", "eslint": "6.8.0",
"eslint-plugin-import": "2.22.0", "eslint-plugin-import": "2.22.0",
@ -156,7 +157,6 @@
"jest": "^25.1.0", "jest": "^25.1.0",
"jest-cli": "^23.6.0", "jest-cli": "^23.6.0",
"metro-react-native-babel-preset": "^0.59.0", "metro-react-native-babel-preset": "^0.59.0",
"mocha": "7.1.2",
"otp.js": "1.2.0", "otp.js": "1.2.0",
"patch-package": "6.2.2", "patch-package": "6.2.2",
"react-dom": "16.13.1", "react-dom": "16.13.1",
@ -209,8 +209,7 @@
"build": "xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build", "build": "xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator", "type": "ios.simulator",
"device": { "device": {
"type": "iPhone 11 Pro", "type": "iPhone 11 Pro"
"os": "13.7"
} }
}, },
"ios.sim.release": { "ios.sim.release": {
@ -218,8 +217,7 @@
"build": "xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Release -sdk iphonesimulator -derivedDataPath ios/build", "build": "xcodebuild -workspace ios/RocketChatRN.xcworkspace -scheme RocketChatRN -configuration Release -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator", "type": "ios.simulator",
"device": { "device": {
"type": "iPhone 11 Pro", "type": "iPhone 11 Pro"
"os": "13.7"
}, },
"artifacts": { "artifacts": {
"plugins": { "plugins": {

View File

@ -1,11 +1,10 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react'; import React from 'react';
import { ScrollView, StyleSheet, View } from 'react-native'; import { StyleSheet } from 'react-native';
import PropTypes from 'prop-types'; import { storiesOf } from '@storybook/react-native';
import { themes } from '../../app/constants/colors';
import Avatar from '../../app/containers/Avatar/Avatar'; import Avatar from '../../app/containers/Avatar/Avatar';
import Status from '../../app/containers/Status/Status'; import Status from '../../app/containers/Status/Status';
import StoriesSeparator from './StoriesSeparator';
import sharedStyles from '../../app/views/Styles'; import sharedStyles from '../../app/views/Styles';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -16,40 +15,44 @@ const styles = StyleSheet.create({
const server = 'https://open.rocket.chat'; const server = 'https://open.rocket.chat';
const Separator = ({ title, theme }) => <StoriesSeparator title={title} theme={theme} />; const _theme = 'light';
Separator.propTypes = {
title: PropTypes.string,
theme: PropTypes.string
};
const AvatarStories = ({ theme }) => ( const stories = storiesOf('Avatar', module);
<ScrollView style={{ backgroundColor: themes[theme].backgroundColor }}>
<Separator title='Avatar by text' theme={theme} /> stories.add('Avatar by text', () => (
<Avatar <Avatar
text='Avatar' text='Avatar'
server={server} server={server}
size={56} size={56}
/> />
<Separator title='Avatar by roomId' theme={theme} /> ));
stories.add('Avatar by roomId', () => (
<Avatar <Avatar
type='p' type='p'
rid='devWBbYr7inwupPqK' rid='devWBbYr7inwupPqK'
server={server} server={server}
size={56} size={56}
/> />
<Separator title='Avatar by url' theme={theme} /> ));
stories.add('Avatar by url', () => (
<Avatar <Avatar
avatar='https://user-images.githubusercontent.com/29778115/89444446-14738480-d728-11ea-9412-75fd978d95fb.jpg' avatar='https://user-images.githubusercontent.com/29778115/89444446-14738480-d728-11ea-9412-75fd978d95fb.jpg'
server={server} server={server}
size={56} size={56}
/> />
<Separator title='Avatar by path' theme={theme} /> ));
stories.add('Avatar by path', () => (
<Avatar <Avatar
avatar='/avatar/diego.mello' avatar='/avatar/diego.mello'
server={server} server={server}
size={56} size={56}
/> />
<Separator title='With ETag' theme={theme} /> ));
stories.add('With ETag', () => (
<Avatar <Avatar
type='d' type='d'
text='djorkaeff.alexandre' text='djorkaeff.alexandre'
@ -57,84 +60,107 @@ const AvatarStories = ({ theme }) => (
server={server} server={server}
size={56} size={56}
/> />
<Separator title='Without ETag' theme={theme} /> ));
stories.add('Without ETag', () => (
<Avatar <Avatar
type='d' type='d'
text='djorkaeff.alexandre' text='djorkaeff.alexandre'
server={server} server={server}
size={56} size={56}
/> />
<Separator title='Emoji' theme={theme} /> ));
stories.add('Emoji', () => (
<Avatar <Avatar
emoji='troll' emoji='troll'
getCustomEmoji={() => ({ name: 'troll', extension: 'jpg' })} getCustomEmoji={() => ({ name: 'troll', extension: 'jpg' })}
server={server} server={server}
size={56} size={56}
/> />
<Separator title='Direct' theme={theme} /> ));
stories.add('Direct', () => (
<Avatar <Avatar
text='diego.mello' text='diego.mello'
server={server} server={server}
type='d' type='d'
size={56} size={56}
/> />
<Separator title='Channel' theme={theme} /> ));
stories.add('Channel', () => (
<Avatar <Avatar
text='general' text='general'
server={server} server={server}
type='c' type='c'
size={56} size={56}
/> />
<Separator title='Touchable' theme={theme} /> ));
stories.add('Touchable', () => (
<Avatar <Avatar
text='Avatar' text='Avatar'
server={server} server={server}
onPress={() => console.log('Pressed!')} onPress={() => console.log('Pressed!')}
size={56} size={56}
/> />
<Separator title='Static' theme={theme} /> ));
stories.add('Static', () => (
<Avatar <Avatar
avatar='https://user-images.githubusercontent.com/29778115/89444446-14738480-d728-11ea-9412-75fd978d95fb.jpg' avatar='https://user-images.githubusercontent.com/29778115/89444446-14738480-d728-11ea-9412-75fd978d95fb.jpg'
server={server} server={server}
isStatic isStatic
size={56} size={56}
/> />
<Separator title='Custom borderRadius' theme={theme} /> ));
stories.add('Avatar by roomId', () => (
<Avatar
type='p'
rid='devWBbYr7inwupPqK'
server={server}
size={56}
/>
));
stories.add('Custom borderRadius', () => (
<Avatar <Avatar
text='Avatar' text='Avatar'
server={server} server={server}
borderRadius={28} borderRadius={28}
size={56} size={56}
/> />
<Separator title='Children' theme={theme} /> ));
stories.add('Children', () => (
<Avatar <Avatar
text='Avatar' text='Avatar'
server={server} server={server}
size={56} size={56}
> >
<View style={[sharedStyles.status, { backgroundColor: themes[theme].backgroundColor }]}>
<Status <Status
size={20} size={24}
status='online' style={[sharedStyles.status, styles.status]}
theme={_theme}
/> />
</View>
</Avatar> </Avatar>
<Separator title='Wrong server' theme={theme} /> ));
stories.add('Wrong server', () => (
<Avatar <Avatar
text='Avatar' text='Avatar'
server='https://google.com' server='https://google.com'
size={56} size={56}
/> />
<Separator title='Custom style' theme={theme} /> ));
stories.add('Custom style', () => (
<Avatar <Avatar
text='Avatar' text='Avatar'
server={server} server={server}
size={56} size={56}
style={styles.custom} style={styles.custom}
/> />
</ScrollView> ));
);
AvatarStories.propTypes = {
theme: PropTypes.string
};
export default AvatarStories;

View File

@ -1,14 +1,19 @@
/* eslint-disable react/prop-types */ /* eslint-disable import/no-extraneous-dependencies */
import React from 'react'; import React from 'react';
import { ScrollView, StyleSheet, View } from 'react-native'; import { ScrollView, StyleSheet, View } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import Markdown from '../../app/containers/markdown'; import Markdown from '../../app/containers/markdown';
import StoriesSeparator from './StoriesSeparator';
import { themes } from '../../app/constants/colors'; import { themes } from '../../app/constants/colors';
const theme = 'light';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
marginHorizontal: 15 marginHorizontal: 15,
backgroundColor: themes[theme].backgroundColor,
marginVertical: 50
}, },
separator: { separator: {
marginHorizontal: 10, marginHorizontal: 10,
@ -37,48 +42,31 @@ const getCustomEmoji = (content) => {
return customEmoji; return customEmoji;
}; };
// eslint-disable-next-line arrow-body-style const stories = storiesOf('Markdown', module);
export default ({ theme }) => {
return ( stories.add('Text', () => (
<ScrollView
style={{
backgroundColor: themes[theme].backgroundColor,
marginVertical: 50
}}
contentContainerStyle={{
paddingBottom: 50
}}
>
<StoriesSeparator style={styles.separator} title='Short Text' theme={theme} />
<View style={styles.container}> <View style={styles.container}>
<Markdown msg='This is Rocket.Chat' theme={theme} /> <Markdown msg='This is Rocket.Chat' theme={theme} />
</View>
<StoriesSeparator style={styles.separator} title='Long Text' theme={theme} />
<View style={styles.container}>
<Markdown <Markdown
msg={longText} msg={longText}
theme={theme} theme={theme}
/> />
</View>
<StoriesSeparator style={styles.separator} title='Line Break Text' theme={theme} />
<View style={styles.container}>
<Markdown <Markdown
msg={lineBreakText} msg={lineBreakText}
theme={theme} theme={theme}
/> />
</View>
<StoriesSeparator style={styles.separator} title='Sequential empty spaces' theme={theme} />
<View style={styles.container}>
<Markdown <Markdown
msg={sequentialEmptySpacesText} msg={sequentialEmptySpacesText}
theme={theme} theme={theme}
/> />
<Markdown
msg='Strong emphasis, aka bold, with **asterisks** or __underscores__'
theme={theme}
/>
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Edited' theme={theme} /> stories.add('Edited', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg='This is edited' msg='This is edited'
@ -86,8 +74,9 @@ export default ({ theme }) => {
isEdited isEdited
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Preview' theme={theme} /> stories.add('Preview', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg={longText} msg={longText}
@ -129,9 +118,10 @@ export default ({ theme }) => {
preview preview
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Mentions' theme={theme} /> stories.add('Mentions', () => (
<View style={styles.container}> <ScrollView style={styles.container}>
<Markdown <Markdown
msg='@rocket.cat @name1 @all @here @unknown' msg='@rocket.cat @name1 @all @here @unknown'
theme={theme} theme={theme}
@ -143,10 +133,6 @@ export default ({ theme }) => {
]} ]}
username='rocket.cat' username='rocket.cat'
/> />
</View>
<StoriesSeparator style={styles.separator} title='Mentions with Real Name' theme={theme} />
<View style={styles.container}>
<Markdown <Markdown
msg='@rocket.cat @name1 @all @here @unknown' msg='@rocket.cat @name1 @all @here @unknown'
theme={theme} theme={theme}
@ -159,9 +145,10 @@ export default ({ theme }) => {
username='rocket.cat' username='rocket.cat'
useRealName useRealName
/> />
</View> </ScrollView>
));
<StoriesSeparator style={styles.separator} title='Hashtag' theme={theme} /> stories.add('Hashtag', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg='#test-channel #unknown' msg='#test-channel #unknown'
@ -169,8 +156,9 @@ export default ({ theme }) => {
channels={[{ _id: '123', name: 'test-channel' }]} channels={[{ _id: '123', name: 'test-channel' }]}
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Emoji' theme={theme} /> stories.add('Emoji', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown msg='Unicode: 😃😇👍' theme={theme} /> <Markdown msg='Unicode: 😃😇👍' theme={theme} />
<Markdown msg='Shortnames: :joy::+1:' theme={theme} /> <Markdown msg='Shortnames: :joy::+1:' theme={theme} />
@ -187,8 +175,9 @@ export default ({ theme }) => {
baseUrl={baseUrl} baseUrl={baseUrl}
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Block Quote' theme={theme} /> stories.add('Block quote', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg={`> This is block quote msg={`> This is block quote
@ -196,19 +185,23 @@ this is a normal line`}
theme={theme} theme={theme}
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Links' theme={theme} /> stories.add('Links', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown msg='[Markdown link](https://rocket.chat): `[description](url)`' theme={theme} /> <Markdown msg='[Markdown link](https://rocket.chat): `[description](url)`' theme={theme} />
<Markdown msg='<https://rocket.chat|Formatted Link>: `<url|description>`' theme={theme} /> <Markdown msg='<https://rocket.chat|Formatted Link>: `<url|description>`' theme={theme} />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Image' theme={theme} />
stories.add('Image', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown msg='![alt text](https://play.google.com/intl/en_us/badges/images/badge_new.png)' theme={theme} /> <Markdown msg='![alt text](https://play.google.com/intl/en_us/badges/images/badge_new.png)' theme={theme} />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Headers' theme={theme} /> stories.add('Headers', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg='# Header 1' msg='# Header 1'
@ -235,17 +228,14 @@ this is a normal line`}
theme={theme} theme={theme}
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Inline Code' theme={theme} /> stories.add('Code', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg='This is `inline code`' msg='This is `inline code`'
theme={theme} theme={theme}
/> />
</View>
<StoriesSeparator style={styles.separator} title='Code Block' theme={theme} />
<View style={styles.container}>
<Markdown <Markdown
msg='Inline `code` has `back-ticks around` it. msg='Inline `code` has `back-ticks around` it.
``` ```
@ -254,32 +244,22 @@ Code block
theme={theme} theme={theme}
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Lists' theme={theme} /> stories.add('Lists', () => (
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg={'* Open Source\n* Rocket.Chat\n - nodejs\n - ReactNative'} msg={'* Open Source\n* Rocket.Chat\n - nodejs\n - ReactNative'}
theme={theme} theme={theme}
/> />
</View>
<StoriesSeparator style={styles.separator} title='Numbered Lists' theme={theme} />
<View style={styles.container}>
<Markdown <Markdown
msg={'1. Open Source\n2. Rocket.Chat'} msg={'1. Open Source\n2. Rocket.Chat'}
theme={theme} theme={theme}
/> />
</View> </View>
));
<StoriesSeparator style={styles.separator} title='Emphasis' theme={theme} /> stories.add('Table', () => (
<View style={styles.container}>
<Markdown
msg='Strong emphasis, aka bold, with **asterisks** or __underscores__'
theme={theme}
/>
</View>
<StoriesSeparator style={styles.separator} title='Table' theme={theme} />
<View style={styles.container}> <View style={styles.container}>
<Markdown <Markdown
msg='First Header | Second Header msg='First Header | Second Header
@ -289,6 +269,4 @@ Content in the first column | Content in the second column'
theme={theme} theme={theme}
/> />
</View> </View>
</ScrollView> ));
);
};

View File

@ -1,21 +1,21 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react'; import React from 'react';
import { ScrollView, StyleSheet } from 'react-native'; import { StyleSheet, ScrollView } from 'react-native';
import { Provider } from 'react-redux';
import { storiesOf } from '@storybook/react-native';
// import moment from 'moment'; // import moment from 'moment';
import MessageComponent from '../../app/containers/message/Message'; import MessageComponent from '../../app/containers/message/Message';
import StoriesSeparator from './StoriesSeparator';
import messagesStatus from '../../app/constants/messagesStatus'; import messagesStatus from '../../app/constants/messagesStatus';
import MessageSeparator from '../../app/views/RoomView/Separator'; import MessageSeparator from '../../app/views/RoomView/Separator';
import MessageContext from '../../app/containers/message/Context';
import { themes } from '../../app/constants/colors'; import { themes } from '../../app/constants/colors';
import { store } from './index';
let _theme = 'light'; const _theme = 'light';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
separator: {
marginTop: 30,
marginBottom: 0
}
}); });
const user = { const user = {
@ -40,6 +40,26 @@ const getCustomEmoji = (content) => {
return customEmoji; return customEmoji;
}; };
const messageDecorator = story => (
<MessageContext.Provider
value={{
user,
baseUrl,
onPress: () => {},
onLongPress: () => {},
reactionInit: () => {},
onErrorPress: () => {},
replyBroadcast: () => {},
onReactionPress: () => {},
onDiscussionPress: () => {},
onReactionLongPress: () => {},
threadBadgeColor: themes.light.tunreadColor
}}
>
{story()}
</MessageContext.Provider>
);
const Message = props => ( const Message = props => (
<MessageComponent <MessageComponent
baseUrl={baseUrl} baseUrl={baseUrl}
@ -54,22 +74,22 @@ const Message = props => (
/> />
); );
// eslint-disable-next-line react/prop-types
const Separator = ({ title, theme }) => <StoriesSeparator title={title} theme={theme} style={styles.separator} />;
// eslint-disable-next-line react/prop-types
export default ({ theme }) => {
_theme = theme;
return (
<ScrollView style={{ backgroundColor: themes[theme].backgroundColor }}>
<Separator title='Simple' theme={theme} /> const stories = storiesOf('Message', module)
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
.addDecorator(story => <ScrollView style={{ backgroundColor: themes[_theme].backgroundColor }}>{story()}</ScrollView>)
.addDecorator(messageDecorator);
stories.add('Basic', () => (
<>
<Message msg='Message' /> <Message msg='Message' />
<Separator title='Long message' theme={theme} />
<Message msg={longText} /> <Message msg={longText} />
</>
));
<Separator title='Grouped messages' theme={theme} /> stories.add('Grouped messages', () => (
<>
<Message msg='...' /> <Message msg='...' />
<Message <Message
msg='Different user' msg='Different user'
@ -81,11 +101,15 @@ export default ({ theme }) => {
<Message msg='This is the third message' isHeader={false} /> <Message msg='This is the third message' isHeader={false} />
<Message msg='This is the second message' isHeader={false} /> <Message msg='This is the second message' isHeader={false} />
<Message msg='This is the first message' /> <Message msg='This is the first message' />
</>
));
<Separator title='Without header' theme={theme} /> stories.add('Without header', () => (
<Message msg='Message' isHeader={false} /> <Message msg='Message' isHeader={false} />
));
<Separator title='With alias' theme={theme} /> stories.add('With alias', () => (
<>
<Message msg='Message' alias='Diego Mello' /> <Message msg='Message' alias='Diego Mello' />
<Message <Message
msg='Message' msg='Message'
@ -95,11 +119,15 @@ export default ({ theme }) => {
}} }}
alias='Diego Mello' alias='Diego Mello'
/> />
</>
));
<Separator title='Edited' theme={theme} /> stories.add('Edited', () => (
<Message msg='Message' edited /> <Message msg='Message' edited />
));
<Separator title='Encrypted' theme={theme} /> stories.add('Encrypted', () => (
<>
<Message <Message
msg='Message' msg='Message'
type='e2e' type='e2e'
@ -113,13 +141,13 @@ export default ({ theme }) => {
msg='Message Encrypted with Reactions' msg='Message Encrypted with Reactions'
reactions={[{ reactions={[{
emoji: ':joy:', emoji: ':joy:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':marioparty:', emoji: ':marioparty:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':thinking:', emoji: ':thinking:',
usernames: [{ value: 'username' }] usernames: [user.username]
}]} }]}
onReactionPress={() => {}} onReactionPress={() => {}}
type='e2e' type='e2e'
@ -162,28 +190,33 @@ export default ({ theme }) => {
isHeader={false} isHeader={false}
type='e2e' type='e2e'
/> />
</>
));
<Separator title='Block Quote' theme={theme} /> stories.add('Block Quote', () => (
<>
<Message msg='> Testing block quote' /> <Message msg='> Testing block quote' />
<Message msg={'> Testing block quote\nTesting block quote'} /> <Message msg={'> Testing block quote\nTesting block quote'} />
</>
));
<Separator title='Lists' theme={theme} /> stories.add('Lists', () => (
<>
<Message msg={'* Dogs\n * cats\n - cats'} /> <Message msg={'* Dogs\n * cats\n - cats'} />
<Separator title='Numerated lists' theme={theme} />
<Message msg={'1. Dogs \n 2. Cats'} /> <Message msg={'1. Dogs \n 2. Cats'} />
<Separator title='Numerated lists in separated messages' theme={theme} />
<Message msg='1. Dogs' /> <Message msg='1. Dogs' />
<Message msg='2. Cats' isHeader={false} /> <Message msg='2. Cats' isHeader={false} />
</>
));
<Separator title='Static avatar' theme={theme} /> stories.add('Static avatar', () => (
<Message <Message
msg='Message' msg='Message'
avatar='https://pbs.twimg.com/profile_images/1016397063649660929/14EIApTi_400x400.jpg' avatar='https://pbs.twimg.com/profile_images/1016397063649660929/14EIApTi_400x400.jpg'
/> />
));
<Separator title='Full name' theme={theme} /> stories.add('Full name', () => (
<Message <Message
msg='Message' msg='Message'
author={{ author={{
@ -193,8 +226,10 @@ export default ({ theme }) => {
}} }}
useRealName useRealName
/> />
));
<Separator title='Mentions' theme={theme} /> stories.add('Mentions', () => (
<>
<Message <Message
msg='@rocket.cat @diego.mello @all @here #general' msg='@rocket.cat @diego.mello @all @here #general'
mentions={[{ mentions={[{
@ -225,76 +260,77 @@ export default ({ theme }) => {
name: 'general' name: 'general'
}]} }]}
/> />
</>
));
<Separator title='Emojis' theme={theme} /> stories.add('Emojis', () => (
<>
<Message msg='👊🤙👏' /> <Message msg='👊🤙👏' />
<Separator title='Single Emoji' theme={theme} />
<Message msg='👏' /> <Message msg='👏' />
<Separator title='Custom Emojis' theme={theme} />
<Message msg=':react_rocket: :nyan_rocket: :marioparty:' /> <Message msg=':react_rocket: :nyan_rocket: :marioparty:' />
<Separator title='Single Custom Emojis' theme={theme} />
<Message msg=':react_rocket:' /> <Message msg=':react_rocket:' />
<Separator title='Normal Emoji + Custom Emojis' theme={theme} />
<Message msg='🤙:react_rocket:' /> <Message msg='🤙:react_rocket:' />
<Separator title='Four emoji' theme={theme} />
<Message msg='🤙:react_rocket:🤙🤙' /> <Message msg='🤙:react_rocket:🤙🤙' />
</>
));
<Separator title='Time format' theme={theme} /> stories.add('Time format', () => (
<Message msg='Testing' timeFormat='DD MMMM YYYY' /> <Message msg='Testing' timeFormat='DD MMMM YYYY' />
));
<Separator title='Reactions' theme={theme} /> stories.add('Reactions', () => (
<>
<Message <Message
msg='Reactions' msg='Reactions'
reactions={[{ reactions={[{
emoji: ':joy:', emoji: ':joy:',
usernames: [{ value: 'username' }, { value: 'rocket.cat' }, { value: 'diego.mello' }] usernames: [user.username]
}, { }, {
emoji: ':marioparty:', emoji: ':marioparty:',
usernames: [{ value: 'username' }, { value: 'rocket.cat' }, { value: 'diego.mello' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }, { value: 'user1' }] usernames: new Array(99)
}, { }, {
emoji: ':thinking:', emoji: ':thinking:',
usernames: [{ value: 'username' }] usernames: new Array(999)
}, {
emoji: ':thinking:',
usernames: new Array(9999)
}]} }]}
onReactionPress={() => {}} onReactionPress={() => {}}
/> />
<Separator title='Multiple reactions' theme={theme} />
<Message <Message
msg='Multiple Reactions' msg='Multiple Reactions'
reactions={[{ reactions={[{
emoji: ':marioparty:', emoji: ':marioparty:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':react_rocket:', emoji: ':react_rocket:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':nyan_rocket:', emoji: ':nyan_rocket:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':heart:', emoji: ':heart:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':dog:', emoji: ':dog:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':grinning:', emoji: ':grinning:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':grimacing:', emoji: ':grimacing:',
usernames: [{ value: 'username' }] usernames: [user.username]
}, { }, {
emoji: ':grin:', emoji: ':grin:',
usernames: [{ value: 'username' }] usernames: [user.username]
}]} }]}
onReactionPress={() => {}} onReactionPress={() => {}}
/> />
</>
));
<Separator title='Intercalated users' theme={theme} /> stories.add('Date and Unread separators', () => (
<>
<Message <Message
msg='Fourth message' msg='Fourth message'
author={{ author={{
@ -302,27 +338,9 @@ export default ({ theme }) => {
username: 'rocket.cat' username: 'rocket.cat'
}} }}
/> />
<MessageSeparator ts={date} unread theme={_theme} />
<Message msg='Third message' /> <Message msg='Third message' />
<Message <MessageSeparator unread theme={_theme} />
msg='Second message'
author={{
...author,
username: 'rocket.cat'
}}
/>
<Message msg='First message' />
<Separator title='Date and Unread separators' theme={theme} />
<Message
msg='Fourth message'
author={{
...author,
username: 'rocket.cat'
}}
/>
<MessageSeparator ts={date} unread theme={theme} />
<Message msg='Third message' />
<MessageSeparator unread theme={theme} />
<Message <Message
msg='Second message' msg='Second message'
author={{ author={{
@ -338,10 +356,13 @@ export default ({ theme }) => {
username: 'rocket.cat' username: 'rocket.cat'
}} }}
/> />
<MessageSeparator ts={date} theme={theme} /> <MessageSeparator ts={date} theme={_theme} />
<Message msg='First message' /> <Message msg='First message' />
</>
));
<Separator title='With image' theme={theme} /> stories.add('With image', () => (
<>
<Message <Message
attachments={[{ attachments={[{
title: 'This is a title', title: 'This is a title',
@ -356,8 +377,11 @@ export default ({ theme }) => {
image_url: '/dummypath' image_url: '/dummypath'
}]} }]}
/> />
</>
));
<Separator title='With video' theme={theme} /> stories.add('With video', () => (
<>
<Message <Message
attachments={[{ attachments={[{
title: 'This is a title', title: 'This is a title',
@ -371,8 +395,11 @@ export default ({ theme }) => {
video_url: '/dummypath' video_url: '/dummypath'
}]} }]}
/> />
</>
));
<Separator title='With audio' theme={theme} /> stories.add('With audio', () => (
<>
<Message <Message
attachments={[{ attachments={[{
title: 'This is a title', title: 'This is a title',
@ -403,8 +430,11 @@ export default ({ theme }) => {
}]} }]}
isHeader={false} isHeader={false}
/> />
</>
));
<Separator title='With file' theme={theme} /> stories.add('With file', () => (
<>
<Message <Message
attachments={[{ attachments={[{
text: 'File.pdf', text: 'File.pdf',
@ -418,16 +448,18 @@ export default ({ theme }) => {
}]} }]}
isHeader={false} isHeader={false}
/> />
</>
));
<Separator title='Message with reply' theme={theme} /> stories.add('Message with reply', () => (
<>
<Message <Message
msg="I'm fine!" msg="I'm fine!"
attachments={[{ attachments={[{
author_name: 'I\'m a very long long title and I\'ll break', author_name: 'I\'m a very long long title and I\'ll break',
ts: date, ts: date,
timeFormat: 'LT', timeFormat: 'LT',
text: 'How are you?', text: 'How are you?'
message_link: 'http:///example.com'
}]} }]}
/> />
<Message <Message
@ -436,12 +468,14 @@ export default ({ theme }) => {
author_name: 'rocket.cat', author_name: 'rocket.cat',
ts: date, ts: date,
timeFormat: 'LT', timeFormat: 'LT',
text: 'How are you? :nyan_rocket:', text: 'How are you? :nyan_rocket:'
message_link: 'http:///example.com'
}]} }]}
/> />
</>
));
<Separator title='Message with read receipt' theme={theme} /> stories.add('Message with read receipt', () => (
<>
<Message <Message
msg="I'm fine!" msg="I'm fine!"
isReadReceiptEnabled isReadReceiptEnabled
@ -464,8 +498,11 @@ export default ({ theme }) => {
read read
isHeader={false} isHeader={false}
/> />
</>
));
<Separator title='Message with thread' theme={theme} /> stories.add('Message with thread', () => (
<>
<Message <Message
msg='How are you?' msg='How are you?'
tcount={1} tcount={1}
@ -483,12 +520,6 @@ export default ({ theme }) => {
tmsg='Thread with emoji :) :joy:' tmsg='Thread with emoji :) :joy:'
isThreadReply isThreadReply
/> />
<Message
msg="I'm fine!"
tmid='1'
tmsg='Markdown: [link](http://www.google.com/) ```block code```'
isThreadReply
/>
<Message <Message
msg="I'm fine!" msg="I'm fine!"
tmid='1' tmid='1'
@ -517,8 +548,11 @@ export default ({ theme }) => {
}]} }]}
isThreadReply isThreadReply
/> />
</>
));
<Separator title='Sequential thread messages following thread button' theme={theme} /> stories.add('Sequential thread messages following thread button', () => (
<>
<Message <Message
msg='How are you?' msg='How are you?'
tcount={1} tcount={1}
@ -543,8 +577,11 @@ export default ({ theme }) => {
tmid='1' tmid='1'
isThreadSequential isThreadSequential
/> />
</>
));
<Separator title='Sequential thread messages following thread reply' theme={theme} /> stories.add('Sequential thread messages following thread reply', () => (
<>
<Message <Message
msg="I'm fine!" msg="I'm fine!"
tmid='1' tmid='1'
@ -570,29 +607,11 @@ export default ({ theme }) => {
tmid='1' tmid='1'
isThreadSequential isThreadSequential
/> />
</>
));
{/* <Message stories.add('Discussion', () => (
msg='How are you?' <>
tcount={9999}
tlm={moment().subtract(1, 'hour')}
/>
<Message
msg='How are you?'
tcount={9999}
tlm={moment().subtract(1, 'day')}
/>
<Message
msg='How are you?'
tcount={9999}
tlm={moment().subtract(5, 'day')}
/>
<Message
msg='How are you?'
tcount={9999}
tlm={moment().subtract(30, 'day')}
/> */}
<Separator title='Discussion' theme={theme} />
<Message <Message
type='discussion-created' type='discussion-created'
drid='aisduhasidhs' drid='aisduhasidhs'
@ -621,37 +640,11 @@ export default ({ theme }) => {
dlm={date} dlm={date}
msg='This is a discussion' msg='This is a discussion'
/> />
{/* <Message </>
type='discussion-created' ));
drid='aisduhasidhs'
dcount={1000}
dlm={moment().subtract(1, 'hour')}
msg='This is a discussion'
/>
<Message
type='discussion-created'
drid='aisduhasidhs'
dcount={1000}
dlm={moment().subtract(1, 'day')}
msg='This is a discussion'
/>
<Message
type='discussion-created'
drid='aisduhasidhs'
dcount={1000}
dlm={moment().subtract(5, 'day')}
msg='This is a discussion'
/>
<Message
type='discussion-created'
drid='aisduhasidhs'
dcount={1000}
dlm={moment().subtract(30, 'day')}
msg='This is a discussion'
/> */}
stories.add('URL', () => (
<Separator title='URL' theme={theme} /> <>
<Message <Message
urls={[{ urls={[{
url: 'https://rocket.chat', url: 'https://rocket.chat',
@ -680,8 +673,11 @@ export default ({ theme }) => {
}]} }]}
isHeader={false} isHeader={false}
/> />
</>
));
<Separator title='Custom fields' theme={theme} /> stories.add('Custom fields', () => (
<>
<Message <Message
msg='Message' msg='Message'
attachments={[{ attachments={[{
@ -689,7 +685,6 @@ export default ({ theme }) => {
ts: date, ts: date,
timeFormat: 'LT', timeFormat: 'LT',
text: 'Custom fields', text: 'Custom fields',
message_link: 'http:///example.com',
fields: [{ fields: [{
title: 'Field 1', title: 'Field 1',
value: 'Value 1' value: 'Value 1'
@ -708,8 +703,10 @@ export default ({ theme }) => {
}] }]
}]} }]}
/> />
</>
));
<Separator title='Two short custom fields with markdown' theme={theme} /> stories.add('Two short custom fields with markdown', () => (
<Message <Message
msg='Message' msg='Message'
attachments={[{ attachments={[{
@ -717,7 +714,6 @@ export default ({ theme }) => {
ts: date, ts: date,
timeFormat: 'LT', timeFormat: 'LT',
text: 'Custom fields', text: 'Custom fields',
message_link: 'http:///example.com',
fields: [{ fields: [{
title: 'Field 1', title: 'Field 1',
value: 'Value 1', value: 'Value 1',
@ -732,7 +728,6 @@ export default ({ theme }) => {
ts: date, ts: date,
timeFormat: 'LT', timeFormat: 'LT',
text: 'Custom fields 2', text: 'Custom fields 2',
message_link: 'http:///example.com',
fields: [{ fields: [{
title: 'Field 1', title: 'Field 1',
value: 'Value 1', value: 'Value 1',
@ -744,8 +739,9 @@ export default ({ theme }) => {
}] }]
}]} }]}
/> />
));
<Separator title='Colored attachments' theme={theme} /> stories.add('Colored attachments', () => (
<Message <Message
attachments={[{ attachments={[{
color: 'red', color: 'red',
@ -780,41 +776,37 @@ export default ({ theme }) => {
value: 'Value 2', value: 'Value 2',
short: true short: true
}] }]
}, {
color: 'ASDASD',
fields: [{
title: 'Invalid color',
short: true
}]
}]} }]}
/> />
));
<Separator title='Broadcast' theme={theme} /> stories.add('Broadcast', () => (
<Message msg='Broadcasted message' broadcast replyBroadcast={() => alert('broadcast!')} /> <Message msg='Broadcasted message' broadcast replyBroadcast={() => alert('broadcast!')} />
));
<Separator title='Archived' theme={theme} /> stories.add('Archived', () => (
<Message msg='This message is inside an archived room' archived /> <Message msg='This message is inside an archived room' archived />
));
<Separator title='Error' theme={theme} /> stories.add('Error', () => (
<>
<Message hasError msg='This message has error' status={messagesStatus.ERROR} onErrorPress={() => alert('Error pressed')} /> <Message hasError msg='This message has error' status={messagesStatus.ERROR} onErrorPress={() => alert('Error pressed')} />
<Message hasError msg='This message has error too' status={messagesStatus.ERROR} onErrorPress={() => alert('Error pressed')} isHeader={false} /> <Message hasError msg='This message has error too' status={messagesStatus.ERROR} onErrorPress={() => alert('Error pressed')} isHeader={false} />
</>
));
<Separator title='Temp' theme={theme} /> stories.add('Temp', () => (
<Message msg='Temp message' status={messagesStatus.TEMP} isTemp /> <Message msg='Temp message' status={messagesStatus.TEMP} isTemp />
));
<Separator title='Editing' theme={theme} /> stories.add('Editing', () => (
<Message msg='Message being edited' editing /> <Message msg='Message being edited' editing />
));
<Separator title='Removed' theme={theme} /> stories.add('System messages', () => (
<>
<Message type='rm' isInfo /> <Message type='rm' isInfo />
<Separator title='Joined' theme={theme} />
<Message type='uj' isInfo /> <Message type='uj' isInfo />
<Separator title='Room name changed' theme={theme} />
<Message msg='New name' type='r' isInfo />
<Separator title='Message pinned' theme={theme} />
<Message <Message
msg='New name' msg='New name'
type='message_pinned' type='message_pinned'
@ -823,104 +815,40 @@ export default ({ theme }) => {
author_name: 'rocket.cat', author_name: 'rocket.cat',
ts: date, ts: date,
timeFormat: 'LT', timeFormat: 'LT',
message_link: 'http:///example.com',
text: 'First message' text: 'First message'
}]} }]}
/> />
<Separator title='Has left the channel' theme={theme} />
<Message type='ul' isInfo /> <Message type='ul' isInfo />
<Separator title='User removed' theme={theme} />
<Message msg='rocket.cat' type='ru' isInfo /> <Message msg='rocket.cat' type='ru' isInfo />
<Separator title='User added' theme={theme} />
<Message msg='rocket.cat' type='au' isInfo /> <Message msg='rocket.cat' type='au' isInfo />
<Separator title='User muted' theme={theme} />
<Message msg='rocket.cat' type='user-muted' isInfo /> <Message msg='rocket.cat' type='user-muted' isInfo />
<Separator title='User unmuted' theme={theme} />
<Message msg='rocket.cat' type='user-unmuted' isInfo /> <Message msg='rocket.cat' type='user-unmuted' isInfo />
<Separator title='Role added' theme={theme} />
<Message <Message
msg='rocket.cat' msg='rocket.cat'
role='admin' // eslint-disable-line role='admin'
type='subscription-role-added' type='subscription-role-added'
isInfo isInfo
/> />
<Separator title='Role removed' theme={theme} />
<Message <Message
msg='rocket.cat' msg='rocket.cat'
role='admin' // eslint-disable-line role='admin'
type='subscription-role-removed' type='subscription-role-removed'
isInfo isInfo
/> />
<Message msg='New name' type='r' isInfo />
<Separator title='Changed description' theme={theme} />
<Message msg='new description' type='room_changed_description' isInfo /> <Message msg='new description' type='room_changed_description' isInfo />
<Separator title='Changed announcement' theme={theme} />
<Message msg='new announcement' type='room_changed_announcement' isInfo /> <Message msg='new announcement' type='room_changed_announcement' isInfo />
<Separator title='Changed topic' theme={theme} />
<Message msg='new topic' type='room_changed_topic' isInfo /> <Message msg='new topic' type='room_changed_topic' isInfo />
<Separator title='Changed type' theme={theme} />
<Message msg='public' type='room_changed_privacy' isInfo /> <Message msg='public' type='room_changed_privacy' isInfo />
<Separator title='Toggle e2e encryption' theme={theme} />
<Message type='room_e2e_disabled' isInfo /> <Message type='room_e2e_disabled' isInfo />
<Message type='room_e2e_enabled' isInfo /> <Message type='room_e2e_enabled' isInfo />
</>
));
<Separator title='Ignored' theme={theme} /> stories.add('Ignored', () => (
<Message isIgnored /> <Message isIgnored />
));
<Separator title='Custom style' theme={theme} /> stories.add('Custom style', () => (
<Message msg='Message' style={[styles.normalize, { backgroundColor: '#ddd' }]} /> <Message msg='Message' style={[styles.normalize, { backgroundColor: '#ddd' }]} />
));
<Separator title='Markdown emphasis' theme={theme} />
<Message msg='Italic with single _underscore_ or double __underscores__. Bold with single *asterisk* or double **asterisks**. Strikethrough with single ~Strikethrough~ or double ~~Strikethrough~~' />
<Separator title='Markdown headers' theme={theme} />
<Message
msg='# H1
## H2
### H3
#### H4
##### H5
###### H6'
/>
<Separator title='Markdown links' theme={theme} />
<Message msg='Support <http://google.com|Google> [I`m an inline-style link](https://www.google.com) https://google.com' />
<Separator title='Starting with empty link' theme={theme} />
<Message msg='[ ](https://www.google.com) <- No link should render' />
<Separator title='Markdown image' theme={theme} />
<Message msg='![alt text](https://play.google.com/intl/en_us/badges/images/badge_new.png)' />
<Separator title='Markdown code' theme={theme} />
<Message
msg='Inline `code` has `back-ticks around` it.
```
Code block
```'
/>
<Separator title='Markdown quote' theme={theme} />
<Message msg='> Quote' />
<Separator title='Markdown table' theme={theme} />
<Message
msg='First Header | Second Header
------------ | -------------
Content from cell 1 | Content from cell 2
Content in the first column | Content in the second column'
/>
</ScrollView>
);
};

View File

@ -1,15 +1,18 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react'; import React from 'react';
import { ScrollView, Dimensions } from 'react-native'; import { ScrollView, Dimensions } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import { Provider } from 'react-redux';
// import moment from 'moment'; // import moment from 'moment';
import { themes } from '../../app/constants/colors'; import { themes } from '../../app/constants/colors';
import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem'; import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem';
import { longText } from '../utils'; import { longText } from '../utils';
import StoriesSeparator from './StoriesSeparator'; import { store } from './index';
const baseUrl = 'https://open.rocket.chat'; const baseUrl = 'https://open.rocket.chat';
const { width } = Dimensions.get('window'); const { width } = Dimensions.get('window');
let _theme = 'light'; const _theme = 'light';
const lastMessage = { const lastMessage = {
u: { u: {
username: 'diego.mello' username: 'diego.mello'
@ -22,7 +25,6 @@ const updatedAt = {
const RoomItem = props => ( const RoomItem = props => (
<RoomItemComponent <RoomItemComponent
rid='abc'
type='d' type='d'
name='rocket.cat' name='rocket.cat'
avatar='rocket.cat' avatar='rocket.cat'
@ -34,24 +36,27 @@ const RoomItem = props => (
/> />
); );
// eslint-disable-next-line react/prop-types const stories = storiesOf('Room Item', module)
const Separator = ({ title }) => <StoriesSeparator title={title} theme={_theme} />; .addDecorator(story => <Provider store={store}>{story()}</Provider>)
.addDecorator(story => <ScrollView style={{ backgroundColor: themes[_theme].backgroundColor }}>{story()}</ScrollView>);
// eslint-disable-next-line react/prop-types
export default ({ theme }) => { stories.add('Basic', () => (
_theme = theme;
return (
<ScrollView style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
<Separator title='Basic' />
<RoomItem /> <RoomItem />
));
<Separator title='User' />
stories.add('User', () => (
<>
<RoomItem name='diego.mello' avatar='diego.mello' /> <RoomItem name='diego.mello' avatar='diego.mello' />
<RoomItem <RoomItem
name={longText} name={longText}
/> />
</>
));
<Separator title='Type' /> stories.add('Type', () => (
<>
<RoomItem type='d' /> <RoomItem type='d' />
<RoomItem type='c' /> <RoomItem type='c' />
<RoomItem type='p' /> <RoomItem type='p' />
@ -59,16 +64,22 @@ export default ({ theme }) => {
<RoomItem type='discussion' /> <RoomItem type='discussion' />
<RoomItem type='d' isGroupChat /> <RoomItem type='d' isGroupChat />
<RoomItem type='&' /> <RoomItem type='&' />
</>
));
<Separator title='User status' /> stories.add('User status', () => (
<>
<RoomItem status='online' /> <RoomItem status='online' />
<RoomItem status='away' /> <RoomItem status='away' />
<RoomItem status='busy' /> <RoomItem status='busy' />
<RoomItem status='offline' /> <RoomItem status='offline' />
<RoomItem status='loading' /> <RoomItem status='loading' />
<RoomItem status='wrong' /> <RoomItem status='wrong' />
</>
));
<Separator title='Alerts' /> stories.add('Alerts', () => (
<>
<RoomItem alert /> <RoomItem alert />
<RoomItem alert name='unread' unread={1} /> <RoomItem alert name='unread' unread={1} />
<RoomItem alert name='unread' unread={1000} /> <RoomItem alert name='unread' unread={1000} />
@ -80,8 +91,11 @@ export default ({ theme }) => {
<RoomItem name='user mentions priority 1' alert unread={1} userMentions={1} groupMentions={1} tunread={[1]} /> <RoomItem name='user mentions priority 1' alert unread={1} userMentions={1} groupMentions={1} tunread={[1]} />
<RoomItem name='group mentions priority 2' alert unread={1} groupMentions={1} tunread={[1]} /> <RoomItem name='group mentions priority 2' alert unread={1} groupMentions={1} tunread={[1]} />
<RoomItem name='thread unread priority 3' alert unread={1} tunread={[1]} /> <RoomItem name='thread unread priority 3' alert unread={1} tunread={[1]} />
</>
));
<Separator title='Last Message' /> stories.add('Last Message', () => (
<>
<RoomItem <RoomItem
showLastMessage showLastMessage
/> />
@ -126,6 +140,5 @@ export default ({ theme }) => {
tunread={[1]} tunread={[1]}
lastMessage={lastMessage} lastMessage={lastMessage}
/> />
</ScrollView> </>
); ));
};

View File

@ -1,36 +0,0 @@
import React from 'react';
import { Text, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { themes } from '../../app/constants/colors';
const styles = StyleSheet.create({
separator: {
marginVertical: 30,
marginLeft: 10,
fontSize: 20,
fontWeight: '300'
}
});
const Separator = ({ title, style, theme }) => (
<Text
style={[
styles.separator,
{
color: themes[theme].titleText
},
style
]}
>
{title}
</Text>
);
Separator.propTypes = {
title: PropTypes.string.isRequired,
theme: PropTypes.string,
style: PropTypes.object
};
export default Separator;

View File

@ -1,11 +1,11 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react'; import React from 'react';
import { ScrollView, StyleSheet, SafeAreaView } from 'react-native'; import { ScrollView, StyleSheet, SafeAreaView } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import MessageContext from '../../app/containers/message/Context';
import { UiKitMessage } from '../../app/containers/UIKit'; import { UiKitMessage } from '../../app/containers/UIKit';
import StoriesSeparator from './StoriesSeparator'; import { themes } from '../../app/constants/colors';
// eslint-disable-next-line react/prop-types
const Separator = ({ title }) => <StoriesSeparator title={title} theme='light' />;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -17,34 +17,58 @@ const styles = StyleSheet.create({
} }
}); });
export default () => ( const user = {
<SafeAreaView style={styles.container}> id: 'y8bd77ptZswPj3EW8',
<ScrollView style={[styles.container, styles.padding]} keyboardShouldPersistTaps='always'> username: 'diego.mello',
<Separator title='Section' /> token: '79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz'
{ };
UiKitMessage([{
const baseUrl = 'https://open.rocket.chat';
const messageDecorator = story => (
<MessageContext.Provider
value={{
user,
baseUrl,
onPress: () => {},
onLongPress: () => {},
reactionInit: () => {},
onErrorPress: () => {},
replyBroadcast: () => {},
onReactionPress: () => {},
onDiscussionPress: () => {},
onReactionLongPress: () => {},
threadBadgeColor: themes.light.tunreadColor
}}
>
{story()}
</MessageContext.Provider>
);
const stories = storiesOf('UiKitMessage', module)
.addDecorator(story => <SafeAreaView style={styles.container}>{story()}</SafeAreaView>)
.addDecorator(story => <ScrollView style={[styles.container, styles.padding]} keyboardShouldPersistTaps='always'>{story()}</ScrollView>)
.addDecorator(messageDecorator);
const Section = () => UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
text: 'Section' text: 'Section'
} }
}]) }]);
} stories.add('Section', () => <Section />);
<Separator title='Section + Markdown List' /> const SectionMarkdownList = () => UiKitMessage([{
{
UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
text: '*List*:\n1. Item' text: '*List*:\n1. Item'
} }
}]) }]);
} stories.add('Section + Markdown List', () => <SectionMarkdownList />);
<Separator title='Section + Overflow' /> const SectionOverflow = () => UiKitMessage([
{
UiKitMessage([
{ {
type: 'section', type: 'section',
text: { text: {
@ -89,12 +113,10 @@ export default () => (
] ]
} }
} }
]) ]);
} stories.add('Section + Overflow', () => <SectionOverflow />);
<Separator title='Section + image' /> const SectionImage = () => UiKitMessage([{
{
UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
@ -105,12 +127,10 @@ export default () => (
imageUrl: 'https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png', imageUrl: 'https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png',
altText: 'plants' altText: 'plants'
} }
}]) }]);
} stories.add('Section + image', () => <SectionImage />);
<Separator title='Section + button' /> const SectionButton = () => UiKitMessage([{
{
UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
@ -123,12 +143,10 @@ export default () => (
text: 'button' text: 'button'
} }
} }
}]) }]);
} stories.add('Section + button', () => <SectionButton />);
<Separator title='Section + Select' /> const SectionSelect = () => UiKitMessage([{
{
UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
@ -151,12 +169,10 @@ export default () => (
} }
}] }]
} }
}]) }]);
} stories.add('Section + Select', () => <SectionSelect />);
<Separator title='Section + DatePicker' /> const SectionDatePicker = () => UiKitMessage([{
{
UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
@ -171,12 +187,10 @@ export default () => (
emoji: true emoji: true
} }
} }
}]) }]);
} stories.add('Section + DatePicker', () => <SectionDatePicker />);
<Separator title='Section + Multi Select' /> const SectionMultiSelect = () => UiKitMessage([{
{
UiKitMessage([{
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
@ -210,12 +224,10 @@ export default () => (
value: 4 value: 4
}] }]
} }
}]) }]);
} stories.add('Section + Multi Select', () => <SectionMultiSelect />);
<Separator title='Image' /> const Image = () => UiKitMessage([{
{
UiKitMessage([{
type: 'image', type: 'image',
title: { title: {
type: 'plain_text', type: 'plain_text',
@ -224,12 +236,10 @@ export default () => (
}, },
imageUrl: 'https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png', imageUrl: 'https://raw.githubusercontent.com/RocketChat/Rocket.Chat.Artwork/master/Logos/icon-circle-256.png',
altText: 'Example Image' altText: 'Example Image'
}]) }]);
} stories.add('Image', () => <Image />);
<Separator title='Context' /> const Context = () => UiKitMessage([{
{
UiKitMessage([{
type: 'context', type: 'context',
elements: [{ elements: [{
type: 'image', type: 'image',
@ -246,12 +256,10 @@ export default () => (
text: 'context' text: 'context'
} }
] ]
}]) }]);
} stories.add('Context', () => <Context />);
<Separator title='Action - Buttons' /> const ActionButton = () => UiKitMessage([{
{
UiKitMessage([{
type: 'actions', type: 'actions',
elements: [ elements: [
{ {
@ -325,12 +333,10 @@ export default () => (
value: 'click_me_123' value: 'click_me_123'
} }
] ]
}]) }]);
} stories.add('Action - Buttons', () => <ActionButton />);
<Separator title='Fields' /> const Fields = () => UiKitMessage([
{
UiKitMessage([
{ {
type: 'section', type: 'section',
fields: [ fields: [
@ -360,12 +366,10 @@ export default () => (
emoji: true emoji: true
} }
] ]
}]) }]);
} stories.add('Fields', () => <Fields />);
<Separator title='Action - Select' /> const ActionSelect = () => UiKitMessage([{
{
UiKitMessage([{
type: 'actions', type: 'actions',
elements: [ elements: [
{ {
@ -435,8 +439,13 @@ export default () => (
] ]
} }
] ]
}]) }]);
} stories.add('Action - Select', () => <ActionSelect />);
</ScrollView>
</SafeAreaView> // stories.add('Section', () => UiKitMessage([{
); // type: 'section',
// text: {
// type: 'mrkdwn',
// text: 'Section'
// }
// }]));

View File

@ -1,12 +1,12 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react'; import React from 'react';
import { ScrollView, StyleSheet, SafeAreaView } from 'react-native'; import { ScrollView, StyleSheet, SafeAreaView } from 'react-native';
import { storiesOf } from '@storybook/react-native';
import { UiKitModal, UiKitComponent } from '../../app/containers/UIKit'; import { UiKitModal, UiKitComponent } from '../../app/containers/UIKit';
import { KitContext, defaultContext } from '../../app/containers/UIKit/utils'; import { KitContext, defaultContext } from '../../app/containers/UIKit/utils';
import StoriesSeparator from './StoriesSeparator'; import MessageContext from '../../app/containers/message/Context';
import { themes } from '../../app/constants/colors';
// eslint-disable-next-line react/prop-types
const Separator = ({ title }) => <StoriesSeparator title={title} theme='light' />;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -18,12 +18,40 @@ const styles = StyleSheet.create({
} }
}); });
export default () => ( const user = {
<SafeAreaView style={styles.container}> id: 'y8bd77ptZswPj3EW8',
<ScrollView style={[styles.container, styles.padding]} keyboardShouldPersistTaps='always'> username: 'diego.mello',
<Separator title='Modal - Section and Selects' /> token: '79q6lH40W4ZRGLOshDiDiVlQaCc4f_lU9HNdHLAzuHz'
{ };
UiKitModal([
const baseUrl = 'https://open.rocket.chat';
const messageDecorator = story => (
<MessageContext.Provider
value={{
user,
baseUrl,
onPress: () => {},
onLongPress: () => {},
reactionInit: () => {},
onErrorPress: () => {},
replyBroadcast: () => {},
onReactionPress: () => {},
onDiscussionPress: () => {},
onReactionLongPress: () => {},
threadBadgeColor: themes.light.tunreadColor
}}
>
{story()}
</MessageContext.Provider>
);
const stories = storiesOf('UiKitModal', module)
.addDecorator(story => <SafeAreaView style={styles.container}>{story()}</SafeAreaView>)
.addDecorator(story => <ScrollView style={[styles.container, styles.padding]} keyboardShouldPersistTaps='always'>{story()}</ScrollView>)
.addDecorator(messageDecorator);
const ModalSectionSelects = () => UiKitModal([
{ {
type: 'section', type: 'section',
text: { text: {
@ -60,12 +88,10 @@ export default () => (
} }
] ]
} }
]) ]);
} stories.add('Modal - Section and Selects', () => <ModalSectionSelects />);
<Separator title='Modal - Section Accessories' /> const ModalSectionAccessories = () => UiKitModal([
{
UiKitModal([
{ {
type: 'section', type: 'section',
text: { text: {
@ -108,12 +134,10 @@ export default () => (
text: '*Notes:*\nWebSummit Conference' text: '*Notes:*\nWebSummit Conference'
} }
} }
]) ]);
} stories.add('Modal - Section Accessories', () => <ModalSectionAccessories />);
<Separator title='Modal - Form Input' /> const ModalFormInput = () => UiKitModal([
{
UiKitModal([
{ {
type: 'input', type: 'input',
element: { element: {
@ -171,12 +195,10 @@ export default () => (
emoji: true emoji: true
} }
} }
]) ]);
} stories.add('Modal - Form Input', () => <ModalFormInput />);
<Separator title='Modal - Form TextArea' /> const ModalFormTextArea = () => UiKitModal([
{
UiKitModal([
{ {
type: 'context', type: 'context',
elements: [{ elements: [{
@ -228,12 +250,10 @@ export default () => (
emoji: true emoji: true
} }
} }
]) ]);
} stories.add('Modal - Form TextArea', () => <ModalFormTextArea />);
<Separator title='Modal - Images' /> const ModalImages = () => UiKitModal([
{
UiKitModal([
{ {
type: 'image', type: 'image',
title: { title: {
@ -271,12 +291,10 @@ export default () => (
text: '*Next stop, Mars!*\nMussum Ipsum, cacilds vidis litro abertis. Admodum accumsan disputationi eu sit. Vide electram sadipscing et per. Diuretics paradis num copo é motivis de denguis. Mais vale um bebadis conhecidiss, que um alcoolatra anonimis. Aenean aliquam molestie leo, vitae iaculis nisl.' text: '*Next stop, Mars!*\nMussum Ipsum, cacilds vidis litro abertis. Admodum accumsan disputationi eu sit. Vide electram sadipscing et per. Diuretics paradis num copo é motivis de denguis. Mais vale um bebadis conhecidiss, que um alcoolatra anonimis. Aenean aliquam molestie leo, vitae iaculis nisl.'
} }
} }
]) ]);
} stories.add('Modal - Images', () => <ModalImages />);
<Separator title='Modal - Actions' /> const ModalActions = () => UiKitModal([{
{
UiKitModal([{
type: 'input', type: 'input',
element: { element: {
type: 'plain_text_input' type: 'plain_text_input'
@ -286,15 +304,15 @@ export default () => (
text: 'Title', text: 'Title',
emoji: true emoji: true
} }
}, },
{ {
type: 'section', type: 'section',
text: { text: {
type: 'mrkdwn', type: 'mrkdwn',
text: 'Details' text: 'Details'
} }
}, },
{ {
type: 'section', type: 'section',
accessory: { accessory: {
type: 'static_select', type: 'static_select',
@ -313,8 +331,8 @@ export default () => (
} }
}] }]
} }
}, },
{ {
type: 'section', type: 'section',
accessory: { accessory: {
type: 'static_select', type: 'static_select',
@ -333,8 +351,8 @@ export default () => (
} }
}] }]
} }
}, },
{ {
type: 'section', type: 'section',
accessory: { accessory: {
type: 'static_select', type: 'static_select',
@ -353,8 +371,8 @@ export default () => (
} }
}] }]
} }
}, },
{ {
type: 'section', type: 'section',
accessory: { accessory: {
type: 'static_select', type: 'static_select',
@ -373,8 +391,8 @@ export default () => (
} }
}] }]
} }
}, },
{ {
type: 'input', type: 'input',
element: { element: {
type: 'plain_text_input', type: 'plain_text_input',
@ -390,12 +408,10 @@ export default () => (
text: 'Description', text: 'Description',
emoji: true emoji: true
} }
}]) }]);
} stories.add('Modal - Actions', () => <ModalActions />);
<Separator title='Modal - Contexts and Dividers' /> const ModalContextsDividers = () => UiKitModal([
{
UiKitModal([
{ {
type: 'context', type: 'context',
elements: [{ elements: [{
@ -493,10 +509,10 @@ export default () => (
] ]
} }
} }
]) ]);
} stories.add('Modal - Contexts and Dividers', () => <ModalContextsDividers />);
<Separator title='Modal - Input with error' /> const ModalInputWithError = () => (
<KitContext.Provider value={{ ...defaultContext, errors: { 'input-test': 'error test' } }}> <KitContext.Provider value={{ ...defaultContext, errors: { 'input-test': 'error test' } }}>
<UiKitComponent <UiKitComponent
render={UiKitModal} render={UiKitModal}
@ -514,8 +530,10 @@ export default () => (
}]} }]}
/> />
</KitContext.Provider> </KitContext.Provider>
);
stories.add('Modal - Input with error', () => <ModalInputWithError />);
<Separator title='Modal - Multilne with error' /> const ModalMultilneWithError = () => (
<KitContext.Provider value={{ ...defaultContext, errors: { 'input-test': 'error test' } }}> <KitContext.Provider value={{ ...defaultContext, errors: { 'input-test': 'error test' } }}>
<UiKitComponent <UiKitComponent
render={UiKitModal} render={UiKitModal}
@ -534,8 +552,10 @@ export default () => (
}]} }]}
/> />
</KitContext.Provider> </KitContext.Provider>
);
stories.add('Modal - Multilne with error', () => <ModalMultilneWithError />);
<Separator title='Modal - DatePicker with error' /> const ModalDatePickerWithError = () => (
<KitContext.Provider value={{ ...defaultContext, errors: { 'input-test': 'error test' } }}> <KitContext.Provider value={{ ...defaultContext, errors: { 'input-test': 'error test' } }}>
<UiKitComponent <UiKitComponent
render={UiKitModal} render={UiKitModal}
@ -559,6 +579,5 @@ export default () => (
}]} }]}
/> />
</KitContext.Provider> </KitContext.Provider>
</ScrollView>
</SafeAreaView>
); );
stories.add('Modal - DatePicker with error', () => <ModalDatePickerWithError />);

View File

@ -1,37 +1,22 @@
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */ /* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import React from 'react';
import { Provider } from 'react-redux';
import { createStore, combineReducers } from 'redux'; import { createStore, combineReducers } from 'redux';
import { storiesOf } from '@storybook/react-native';
import RoomItem from './RoomItem'; import './RoomItem';
import './List'; import './List';
import './ServerItem'; import './ServerItem';
import Message from './Message'; import './Message';
import UiKitMessage from './UiKitMessage'; import './UiKitMessage';
import UiKitModal from './UiKitModal'; import './UiKitModal';
import Markdown from './Markdown'; import './Markdown';
import './HeaderButtons'; import './HeaderButtons';
import './UnreadBadge'; import './UnreadBadge';
import '../../app/views/ThreadMessagesView/Item.stories.js'; import '../../app/views/ThreadMessagesView/Item.stories.js';
import './Avatar';
import '../../app/containers/BackgroundContainer/index.stories.js'; import '../../app/containers/BackgroundContainer/index.stories.js';
import '../../app/containers/RoomHeader/RoomHeader.stories.js'; import '../../app/containers/RoomHeader/RoomHeader.stories.js';
import Avatar from './Avatar';
// import RoomViewHeader from './RoomViewHeader';
import MessageContext from '../../app/containers/message/Context';
import { themes } from '../../app/constants/colors';
// MessageProvider
const baseUrl = 'https://open.rocket.chat';
const user = {
id: '',
username: 'diego.mello',
token: ''
};
// Change here to see themed storybook // Change here to see themed storybook
const theme = 'light'; export const theme = 'light';
const reducers = combineReducers({ const reducers = combineReducers({
settings: () => ({}), settings: () => ({}),
@ -52,47 +37,4 @@ const reducers = combineReducers({
meteor: () => ({ connected: true }), meteor: () => ({ connected: true }),
activeUsers: () => ({ abc: { status: 'online', statusText: 'dog' } }) activeUsers: () => ({ abc: { status: 'online', statusText: 'dog' } })
}); });
const store = createStore(reducers); export const store = createStore(reducers);
const messageDecorator = story => (
<MessageContext.Provider
value={{
user,
baseUrl,
onPress: () => {},
onLongPress: () => {},
reactionInit: () => {},
onErrorPress: () => {},
replyBroadcast: () => {},
onReactionPress: () => {},
onDiscussionPress: () => {},
onReactionLongPress: () => {},
threadBadgeColor: themes.light.tunreadColor
}}
>
{story()}
</MessageContext.Provider>
);
storiesOf('RoomItem', module)
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
.add('list roomitem', () => <RoomItem theme={theme} />);
storiesOf('Message', module)
.addDecorator(story => <Provider store={store}>{story()}</Provider>)
.addDecorator(messageDecorator)
.add('list message', () => <Message theme={theme} />);
storiesOf('UiKitMessage', module)
.addDecorator(messageDecorator)
.add('list uikitmessage', () => <UiKitMessage theme={theme} />);
storiesOf('UiKitModal', module)
.addDecorator(messageDecorator)
.add('list UiKitModal', () => <UiKitModal theme={theme} />);
storiesOf('Markdown', module)
.add('list Markdown', () => <Markdown theme={theme} />);
storiesOf('Avatar', module)
.add('list Avatar', () => <Avatar theme={theme} />);
// FIXME: I couldn't make these pass on jest :(
// storiesOf('RoomViewHeader', module)
// .add('list', () => <RoomViewHeader theme='black' />);

View File

@ -4610,12 +4610,12 @@ bunyan-debug-stream@^1.1.0:
exception-formatter "^1.0.4" exception-formatter "^1.0.4"
bunyan@^1.8.12: bunyan@^1.8.12:
version "1.8.12" version "1.8.15"
resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797" resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.15.tgz#8ce34ca908a17d0776576ca1b2f6cbd916e93b46"
integrity sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c= integrity sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==
optionalDependencies: optionalDependencies:
dtrace-provider "~0.8" dtrace-provider "~0.8"
moment "^2.10.6" moment "^2.19.3"
mv "~2" mv "~2"
safe-json-stringify "~1" safe-json-stringify "~1"
@ -5923,10 +5923,10 @@ detect-port@^1.3.0:
address "^1.0.1" address "^1.0.1"
debug "^2.6.0" debug "^2.6.0"
detox@^18.8.1: detox@^18.10.0:
version "18.8.1" version "18.10.0"
resolved "https://registry.yarnpkg.com/detox/-/detox-18.8.1.tgz#49893bd8fd139826f78fc5c6773624c467bbda66" resolved "https://registry.yarnpkg.com/detox/-/detox-18.10.0.tgz#8b8d6b6f2bf9775f09d92b63f98dc1b5f4c9334e"
integrity sha512-dxtyM5f/IyzkL5wVsmWyg2an3Ls0rNRSOOJ82pk26alBY7TKGm+PqtK9vnFuS84vN1uxdsBez+4W15ojmAEZZw== integrity sha512-okqMongBq0hKuJN8hxVHoBjM3Ms0XbaaWq5PyZGWuog3SXTX18ux8YjSmCU2J8ESA8muXyuOpl9KGgT8bWJTHA==
dependencies: dependencies:
bunyan "^1.8.12" bunyan "^1.8.12"
bunyan-debug-stream "^1.1.0" bunyan-debug-stream "^1.1.0"
@ -5942,13 +5942,14 @@ detox@^18.8.1:
proper-lockfile "^3.0.2" proper-lockfile "^3.0.2"
resolve-from "^5.0.0" resolve-from "^5.0.0"
sanitize-filename "^1.6.1" sanitize-filename "^1.6.1"
serialize-error "^8.0.1"
shell-quote "^1.7.2" shell-quote "^1.7.2"
signal-exit "^3.0.3" signal-exit "^3.0.3"
tail "^2.0.0" tail "^2.0.0"
telnet-client "1.2.8" telnet-client "1.2.8"
tempfile "^2.0.0" tempfile "^2.0.0"
which "^1.3.1" which "^1.3.1"
ws "^3.3.1" ws "^7.4.3"
yargs "^16.0.3" yargs "^16.0.3"
yargs-unparser "^2.0.0" yargs-unparser "^2.0.0"
@ -7306,9 +7307,9 @@ flat-cache@^2.0.1:
write "1.0.3" write "1.0.3"
flat@^4.1.0: flat@^4.1.0:
version "4.1.0" version "4.1.1"
resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b"
integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==
dependencies: dependencies:
is-buffer "~2.0.3" is-buffer "~2.0.3"
@ -8324,7 +8325,12 @@ inherits@2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: ini@^1.3.4:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
ini@^1.3.5, ini@~1.3.0:
version "1.3.5" version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
@ -8495,9 +8501,9 @@ is-buffer@^1.1.5:
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-buffer@~2.0.3: is-buffer@~2.0.3:
version "2.0.4" version "2.0.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
is-callable@^1.1.4, is-callable@^1.1.5: is-callable@^1.1.4, is-callable@^1.1.5:
version "1.1.5" version "1.1.5"
@ -10325,11 +10331,16 @@ lodash@4.17.20, lodash@^4.0.0:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0:
version "4.17.15" version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
lodash@^4.17.5:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@3.0.0: log-symbols@3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4"
@ -11156,12 +11167,12 @@ moment@2.27.0:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d" resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ== integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
moment@2.x.x, moment@^2.10.6: moment@2.x.x:
version "2.26.0" version "2.26.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
moment@^2.24.0: moment@^2.19.3, moment@^2.24.0:
version "2.29.1" version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
@ -11212,11 +11223,16 @@ mv@~2:
ncp "~2.0.0" ncp "~2.0.0"
rimraf "~2.4.0" rimraf "~2.4.0"
nan@^2.12.1, nan@^2.14.0: nan@^2.12.1:
version "2.14.1" version "2.14.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
nan@^2.14.0:
version "2.14.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
nanoid@^3.1.9: nanoid@^3.1.9:
version "3.1.10" version "3.1.10"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.10.tgz#69a8a52b77892de0d11cede96bc9762852145bc4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.10.tgz#69a8a52b77892de0d11cede96bc9762852145bc4"
@ -14057,6 +14073,13 @@ serialize-error@^2.1.0:
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a"
integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go= integrity sha1-ULZ51WNc34Rme9yOWa9OW4HV9go=
serialize-error@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-8.0.1.tgz#7a67f8ecbbf28973b5a954a2852ff9f4eef52d99"
integrity sha512-r5o60rWFS+8/b49DNAbB+GXZA0SpDpuWE758JxDKgRTga05r3U5lwyksE91dYKDhXSmnu36RALj615E6Aj5pSg==
dependencies:
type-fest "^0.20.2"
serialize-javascript@^2.1.2: serialize-javascript@^2.1.2:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
@ -14918,9 +14941,9 @@ table@^5.2.3:
string-width "^3.0.0" string-width "^3.0.0"
tail@^2.0.0: tail@^2.0.0:
version "2.0.3" version "2.2.1"
resolved "https://registry.yarnpkg.com/tail/-/tail-2.0.3.tgz#37567adc4624a70b35f1d146c3376fa3d6ef7c04" resolved "https://registry.yarnpkg.com/tail/-/tail-2.2.1.tgz#3369a786dde3d7b1a5baa3a0accea09348bc5a83"
integrity sha512-s9NOGkLqqiDEtBttQZI7acLS8ycYK5sTlDwNjGnpXG9c8AWj0cfAtwEIzo/hVRMMiC5EYz+bXaJWC1u1u0GPpQ== integrity sha512-pqtI8HB6pbltcaDxkTq12meYxMeLNtZg7+h+c2WlXofaOh4bUeLFQ3eU8S23niqb8We4/UFc+QNlky9nCRnrSQ==
tapable@^1.0.0, tapable@^1.1.3: tapable@^1.0.0, tapable@^1.1.3:
version "1.1.3" version "1.1.3"
@ -15316,6 +15339,11 @@ type-fest@^0.11.0:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==
type-fest@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type-fest@^0.6.0: type-fest@^0.6.0:
version "0.6.0" version "0.6.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
@ -16128,7 +16156,7 @@ ws@^1.1.0, ws@^1.1.5:
options ">=0.0.5" options ">=0.0.5"
ultron "1.0.x" ultron "1.0.x"
ws@^3.3.1, ws@^3.3.3: ws@^3.3.3:
version "3.3.3" version "3.3.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==
@ -16154,6 +16182,11 @@ ws@^7.0.0:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"
integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==
ws@^7.4.3:
version "7.4.4"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==
xcode@^2.0.0: xcode@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe" resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe"
@ -16262,9 +16295,9 @@ y18n@^4.0.0:
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
y18n@^5.0.5: y18n@^5.0.5:
version "5.0.5" version "5.0.7"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.7.tgz#0c514aba53fc40e2db911aeb8b51566a3374efe7"
integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== integrity sha512-oOhslryvNcA1lB9WYr+M6TMyLkLg81Dgmyb48ZDU0lvR+5bmNDTMz7iobM1QXooaLhbbrcHrlNaABhI6Vo6StQ==
yallist@^2.1.2: yallist@^2.1.2:
version "2.1.2" version "2.1.2"