Merge branch 'main' into display_mfa_codes

This commit is contained in:
Neeraj Gupta 2023-04-03 11:17:29 +05:30
commit 9a686335aa
No known key found for this signature in database
GPG key ID: 3C5A1684DC1729E1
63 changed files with 4703 additions and 1433 deletions

View file

@ -28,12 +28,6 @@ module.exports = (phase) =>
'@mui/system',
'@mui/icons-material',
],
compiler: {
styledComponents: {
ssr: true,
displayName: true,
},
},
env: {
SENTRY_RELEASE: GIT_SHA,
NEXT_PUBLIC_IS_TEST_APP: process.env.IS_TEST_RELEASE,

View file

@ -14,10 +14,12 @@
},
"dependencies": {
"@date-io/date-fns": "^2.14.0",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.6",
"@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.6",
"@mui/icons-material": "^5.6.2",
"@mui/material": "^5.6.2",
"@mui/styled-engine": "npm:@mui/styled-engine-sc@latest",
"@mui/styled-engine-sc": "^5.6.1",
"@mui/x-date-pickers": "^5.0.0-alpha.6",
"@sentry/nextjs": "^6.7.1",
"@stripe/stripe-js": "^1.13.2",
@ -99,7 +101,6 @@
"@types/react-select": "^4.0.15",
"@types/react-window": "^1.8.2",
"@types/react-window-infinite-loader": "^1.0.3",
"@types/styled-components": "^5.1.25",
"@types/wicg-file-system-access": "^2020.9.5",
"@types/yup": "^0.29.7",
"@types/zxcvbn": "^4.4.1",
@ -114,8 +115,5 @@
},
"standard": {
"parser": "babel-eslint"
},
"resolutions": {
"@mui/styled-engine": "npm:@mui/styled-engine-sc@latest"
}
}
}

View file

@ -0,0 +1,592 @@
{
"HERO_SLIDE_1_TITLE": "",
"HERO_SLIDE_1": "",
"HERO_SLIDE_2_TITLE": "",
"HERO_SLIDE_2": "",
"HERO_SLIDE_3_TITLE": "",
"HERO_SLIDE_3": "",
"LOGIN": "",
"SIGN_UP": "",
"NEW_USER": "",
"EXISTING_USER": "",
"NAME": "",
"ENTER_NAME": "",
"PUBLIC_UPLOADER_NAME_MESSAGE": "",
"EMAIL": "",
"ENTER_EMAIL": "",
"DATA_DISCLAIMER": "",
"SUBMIT": "",
"EMAIL_ERROR": "",
"REQUIRED": "",
"VERIFY_EMAIL": "",
"EMAIL_SENT": "",
"CHECK_INBOX": "",
"ENTER_OTT": "",
"RESEND_MAIL": "",
"VERIFY": "",
"UNKNOWN_ERROR": "",
"INVALID_CODE": "",
"EXPIRED_CODE": "",
"SENDING": "",
"SENT": "",
"PASSWORD": "",
"LINK_PASSWORD": "",
"ENTER_PASSPHRASE": "",
"RETURN_PASSPHRASE_HINT": "",
"SET_PASSPHRASE": "",
"VERIFY_PASSPHRASE": "",
"INCORRECT_PASSPHRASE": "",
"ENTER_ENC_PASSPHRASE": "",
"PASSPHRASE_DISCLAIMER": "",
"WELCOME_TO_ENTE_HEADING": "",
"WELCOME_TO_ENTE_SUBHEADING": "",
"WHERE_YOUR_BEST_PHOTOS_LIVE": "",
"KEY_GENERATION_IN_PROGRESS_MESSAGE": "",
"PASSPHRASE_HINT": "",
"CONFIRM_PASSPHRASE": "",
"PASSPHRASE_MATCH_ERROR": "",
"CONSOLE_WARNING_STOP": "",
"CONSOLE_WARNING_DESC": "",
"SELECT_COLLECTION": "",
"CREATE_COLLECTION": "",
"ENTER_ALBUM_NAME": "",
"CLOSE_OPTION": "",
"ENTER_FILE_NAME": "",
"CLOSE": "",
"NO": "",
"NOTHING_HERE": "",
"UPLOAD": "",
"IMPORT": "",
"ADD_PHOTOS": "",
"ADD_MORE_PHOTOS": "",
"add_photos_one": "",
"add_photos_other": "",
"SELECT_PHOTOS": "",
"FILE_UPLOAD": "",
"UPLOAD_STAGE_MESSAGE": {
"0": "",
"1": "",
"2": "",
"3": "",
"4": "",
"5": ""
},
"UPLOADING_FILES": "",
"FILE_NOT_UPLOADED_LIST": "",
"SUBSCRIPTION_EXPIRED": "",
"SUBSCRIPTION_EXPIRED_MESSAGE": "",
"STORAGE_QUOTA_EXCEEDED": "",
"INITIAL_LOAD_DELAY_WARNING": "",
"USER_DOES_NOT_EXIST": "",
"UPLOAD_BUTTON_TEXT": "",
"NO_ACCOUNT": "",
"ACCOUNT_EXISTS": "",
"ALBUM_NAME": "",
"CREATE": "",
"DOWNLOAD": "",
"DOWNLOAD_OPTION": "",
"DOWNLOAD_FAVORITES": "",
"DOWNLOAD_UNCATEGORIZED": "",
"COPY_OPTION": "",
"TOGGLE_FULLSCREEN": "",
"ZOOM_IN_OUT": "",
"PREVIOUS": "",
"NEXT": "",
"NO_INTERNET_CONNECTION": "",
"TITLE": "",
"UPLOAD_FIRST_PHOTO": "",
"IMPORT_YOUR_FOLDERS": "",
"UPLOAD_DROPZONE_MESSAGE": "",
"WATCH_FOLDER_DROPZONE_MESSAGE": "",
"TRASH_FILES_TITLE": "",
"TRASH_FILE_TITLE": "",
"DELETE_FILES_TITLE": "",
"DELETE_FILES_MESSAGE": "",
"DELETE_FILE": "",
"DELETE": "",
"DELETE_OPTION": "",
"FAVORITE": "",
"FAVORITE_OPTION": "",
"UNFAVORITE_OPTION": "",
"UNFAVORITE": "",
"MULTI_FOLDER_UPLOAD": "",
"UPLOAD_STRATEGY_CHOICE": "",
"UPLOAD_STRATEGY_SINGLE_COLLECTION": "",
"OR": "",
"UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "",
"SESSION_EXPIRED_MESSAGE": "",
"SESSION_EXPIRED": "",
"SYNC_FAILED": "",
"PASSWORD_GENERATION_FAILED": "",
"CHANGE_PASSWORD": "",
"GO_BACK": "",
"RECOVERY_KEY": "",
"SAVE_LATER": "",
"SAVE": "",
"RECOVERY_KEY_DESCRIPTION": "",
"RECOVER_KEY_GENERATION_FAILED": "",
"KEY_NOT_STORED_DISCLAIMER": "",
"FORGOT_PASSWORD": "",
"RECOVER_ACCOUNT": "",
"RECOVERY_KEY_HINT": "",
"RECOVER": "",
"NO_RECOVERY_KEY": "",
"INCORRECT_RECOVERY_KEY": "",
"SORRY": "",
"NO_RECOVERY_KEY_MESSAGE": "",
"NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "",
"CONTACT_SUPPORT": "",
"REQUEST_FEATURE": "",
"SUPPORT": "",
"CONFIRM": "",
"SKIP_SUBSCRIPTION_PURCHASE": "",
"CANCEL": "",
"LOGOUT": "",
"DELETE_ACCOUNT": "",
"DELETE_ACCOUNT_MESSAGE": "",
"LOGOUT_MESSAGE": "",
"CHANGE": "",
"CHANGE_EMAIL": "",
"OK": "",
"SUCCESS": "",
"ERROR": "",
"MESSAGE": "",
"INSTALL_MOBILE_APP": "",
"DOWNLOAD_APP_MESSAGE": "",
"DOWNLOAD_APP": "",
"EXPORT": "",
"SUBSCRIPTION": "",
"SUBSCRIBE": "",
"SUBSCRIPTION_PLAN": "",
"USAGE_DETAILS": "",
"MANAGE": "",
"MANAGEMENT_PORTAL": "",
"MANAGE_FAMILY_PORTAL": "",
"LEAVE_FAMILY_PLAN": "",
"LEAVE": "",
"LEAVE_FAMILY_CONFIRM": "",
"CHOOSE_PLAN": "",
"MANAGE_PLAN": "",
"ACTIVE": "",
"OFFLINE_MSG": "",
"FREE_SUBSCRIPTION_INFO": "",
"FAMILY_SUBSCRIPTION_INFO": "",
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
"SUBSCRIPTION_VERIFICATION_FAILED": "",
"SUBSCRIPTION_PURCHASE_FAILED": "",
"SUBSCRIPTION_UPDATE_FAILED": "",
"UPDATE_PAYMENT_METHOD_MESSAGE": "",
"STRIPE_AUTHENTICATION_FAILED": "",
"UPDATE_PAYMENT_METHOD": "",
"MONTHLY": "",
"YEARLY": "",
"UPDATE_SUBSCRIPTION_MESSAGE": "",
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",
"REACTIVATE_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_ACTIVATE_SUCCESS": "",
"SUBSCRIPTION_ACTIVATE_FAILED": "",
"SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE": "",
"MAIL_TO_MANAGE_SUBSCRIPTION": "",
"RENAME": "",
"RENAME_FILE": "",
"RENAME_COLLECTION": "",
"DELETE_COLLECTION_TITLE": "",
"DELETE_COLLECTION": "",
"DELETE_COLLECTION_FAILED": "",
"DELETE_COLLECTION_MESSAGE": "",
"DELETE_PHOTOS": "",
"KEEP_PHOTOS": "",
"SHARE": "",
"SHARE_COLLECTION": "",
"SHARE_WITH_PEOPLE": "",
"SHAREES": "",
"PUBLIC_URL": "",
"SHARE_WITH_SELF": "",
"ALREADY_SHARED": "",
"SHARING_BAD_REQUEST_ERROR": "",
"SHARING_DISABLED_FOR_FREE_ACCOUNTS": "",
"DOWNLOAD_COLLECTION": "",
"DOWNLOAD_COLLECTION_MESSAGE": "",
"DOWNLOAD_COLLECTION_FAILED": "",
"CREATE_ALBUM_FAILED": "",
"SEARCH_RESULTS": "",
"SEARCH_HINT": "",
"SEARCH_TYPE": {
"COLLECTION": "",
"LOCATION": "",
"DATE": "",
"FILE_NAME": "",
"THING": "",
"FILE_CAPTION": ""
},
"photos_count_zero": "",
"photos_count_one": "",
"photos_count_other": "",
"TERMS_AND_CONDITIONS": "",
"CONFIRM_PASSWORD_NOT_SAVED": "",
"ADD_TO_COLLECTION": "",
"SELECTED": "",
"VIDEO_PLAYBACK_FAILED": "",
"VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD": "",
"PEOPLE": "",
"INDEXING_SCHEDULED": "",
"ANALYZING_PHOTOS": "",
"INDEXING_PEOPLE": "",
"INDEXING_DONE": "",
"UNIDENTIFIED_FACES": "",
"OBJECTS": "",
"TEXT": "",
"METADATA": "",
"INFO": "",
"INFO_OPTION": "",
"FILE_ID": "",
"FILE_NAME": "",
"CAPTION": "",
"CAPTION_PLACEHOLDER": "",
"CREATION_TIME": "",
"UPDATED_ON": "",
"LOCATION": "",
"SHOW_ON_MAP": "",
"DETAILS": "",
"VIEW_EXIF": "",
"NO_EXIF": "",
"EXIF": "",
"DEVICE": "",
"IMAGE_SIZE": "",
"FLASH": "",
"FOCAL_LENGTH": "",
"APERTURE": "",
"ISO": "",
"SHOW_ALL": "",
"TWO_FACTOR": "",
"TWO_FACTOR_AUTHENTICATION": "",
"TWO_FACTOR_QR_INSTRUCTION": "",
"ENTER_CODE_MANUALLY": "",
"TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "",
"SCAN_QR_CODE": "",
"CONTINUE": "",
"BACK": "",
"ENABLE_TWO_FACTOR": "",
"ENABLE": "",
"LOST_DEVICE": "",
"INCORRECT_CODE": "",
"RECOVER_TWO_FACTOR": "",
"TWO_FACTOR_INFO": "",
"DISABLE_TWO_FACTOR_LABEL": "",
"UPDATE_TWO_FACTOR_LABEL": "",
"DISABLE": "",
"RECONFIGURE": "",
"UPDATE_TWO_FACTOR": "",
"UPDATE_TWO_FACTOR_MESSAGE": "",
"UPDATE": "",
"DISABLE_TWO_FACTOR": "",
"DISABLE_TWO_FACTOR_MESSAGE": "",
"TWO_FACTOR_SETUP_FAILED": "",
"TWO_FACTOR_SETUP_SUCCESS": "",
"TWO_FACTOR_DISABLE_SUCCESS": "",
"TWO_FACTOR_DISABLE_FAILED": "",
"EXPORT_DATA": "",
"SELECT_FOLDER": "",
"DESTINATION": "",
"START": "",
"EXPORT_IN_PROGRESS": "",
"PAUSE": "",
"RESUME": "",
"MINIMIZE": "",
"LAST_EXPORT_TIME": "",
"SUCCESSFULLY_EXPORTED_FILES": "",
"FAILED_EXPORTED_FILES": "",
"EXPORT_AGAIN": "",
"RETRY_EXPORT": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "",
"RETRY": "",
"SEND_OTT": "",
"EMAIl_ALREADY_OWNED": "",
"EMAIL_UDPATE_SUCCESSFUL": "",
"UPLOAD_FAILED": "",
"ETAGS_BLOCKED": "",
"SKIPPED_VIDEOS_INFO": "",
"LIVE_PHOTOS_DETECTED": "",
"RETRY_FAILED": "",
"FAILED_UPLOADS": "",
"SKIPPED_FILES": "",
"THUMBNAIL_GENERATION_FAILED_UPLOADS": "",
"UNSUPPORTED_FILES": "",
"SUCCESSFUL_UPLOADS": "",
"SKIPPED_INFO": "",
"UNSUPPORTED_INFO": "",
"BLOCKED_UPLOADS": "",
"SKIPPED_VIDEOS": "",
"INPROGRESS_METADATA_EXTRACTION": "",
"INPROGRESS_UPLOADS": "",
"TOO_LARGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_INFO": "",
"TOO_LARGE_INFO": "",
"THUMBNAIL_GENERATION_FAILED_INFO": "",
"UPLOAD_TO_COLLECTION": "",
"UNCATEGORIZED": "",
"MOVE_TO_UNCATEGORIZED": "",
"ARCHIVE": "",
"ARCHIVE_COLLECTION": "",
"ARCHIVE_SECTION_NAME": "",
"ALL_SECTION_NAME": "",
"MOVE_TO_COLLECTION": "",
"UNARCHIVE": "",
"UNARCHIVE_COLLECTION": "",
"MOVE": "",
"ADD": "",
"SORT": "",
"REMOVE": "",
"YES_REMOVE": "",
"CONFIRM_REMOVE": "",
"REMOVE_FROM_COLLECTION": "",
"TRASH": "",
"MOVE_TO_TRASH": "",
"TRASH_FILES_MESSAGE": "",
"TRASH_FILE_MESSAGE": "",
"DELETE_PERMANENTLY": "",
"RESTORE": "",
"CONFIRM_RESTORE": "",
"RESTORE_MESSAGE": "",
"RESTORE_TO_COLLECTION": "",
"EMPTY_TRASH": "",
"EMPTY_TRASH_TITLE": "",
"EMPTY_TRASH_MESSAGE": "",
"LEAVE_SHARED_ALBUM": "",
"LEAVE_ALBUM": "",
"LEAVE_SHARED_ALBUM_TITLE": "",
"LEAVE_SHARED_ALBUM_MESSAGE": "",
"NOT_FILE_OWNER": "",
"CONFIRM_SELF_REMOVE_MESSAGE": "",
"CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE": "",
"SORT_BY_CREATION_TIME_ASCENDING": "",
"SORT_BY_CREATION_TIME_DESCENDING": "",
"SORT_BY_UPDATION_TIME_DESCENDING": "",
"SORT_BY_NAME": "",
"COMPRESS_THUMBNAILS": "",
"THUMBNAIL_REPLACED": "",
"FIX_THUMBNAIL": "",
"FIX_THUMBNAIL_LATER": "",
"REPLACE_THUMBNAIL_NOT_STARTED": "",
"REPLACE_THUMBNAIL_COMPLETED": "",
"REPLACE_THUMBNAIL_NOOP": "",
"REPLACE_THUMBNAIL_COMPLETED_WITH_ERROR": "",
"FIX_CREATION_TIME": "",
"FIX_CREATION_TIME_IN_PROGRESS": "",
"CREATION_TIME_UPDATED": "",
"UPDATE_CREATION_TIME_NOT_STARTED": "",
"UPDATE_CREATION_TIME_COMPLETED": "",
"UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR": "",
"FILE_NAME_CHARACTER_LIMIT": "",
"CAPTION_CHARACTER_LIMIT": "",
"DATE_TIME_ORIGINAL": "",
"DATE_TIME_DIGITIZED": "",
"CUSTOM_TIME": "",
"REOPEN_PLAN_SELECTOR_MODAL": "",
"OPEN_PLAN_SELECTOR_MODAL_FAILED": "",
"COMMENT": "",
"ABUSE_REPORT_DESCRIPTION": "",
"OTHER_REASON_REQUIRES_COMMENTS": "",
"REPORT_SUBMIT_SUCCESS_CONTENT": "",
"REPORT_SUBMIT_SUCCESS_TITLE": "",
"REPORT_SUBMIT_FAILED": "",
"INSTALL": "",
"ALBUM_URL": "",
"SHARING_DETAILS": "",
"MODIFY_SHARING": "",
"NOT_FOUND": "",
"LINK_EXPIRED": "",
"LINK_EXPIRED_MESSAGE": "",
"MANAGE_LINK": "",
"LINK_TOO_MANY_REQUESTS": "",
"DISABLE_PUBLIC_SHARING": "",
"DISABLE_PUBLIC_SHARING_MESSAGE": "",
"FILE_DOWNLOAD": "",
"LINK_PASSWORD_LOCK": "",
"PUBLIC_COLLECT": "",
"LINK_DEVICE_LIMIT": "",
"LINK_EXPIRY": "",
"LINK_EXPIRY_NEVER": "",
"DISABLE_FILE_DOWNLOAD": "",
"DISABLE_FILE_DOWNLOAD_MESSAGE": "",
"ABUSE_REPORT": "",
"ABUSE_REPORT_BUTTON_TEXT": "",
"MALICIOUS_CONTENT": "",
"COPYRIGHT": "",
"ENTER_EMAIL_ADDRESS": "",
"SELECT_REASON": "",
"ENTER_FULL_NAME": "",
"ENTER_DIGITAL_SIGNATURE": "",
"ENTER_ON_BEHALF_OF": "",
"ENTER_ADDRESS": "",
"ENTER_JOB_TITLE": "",
"ENTER_CITY": "",
"ENTER_PHONE": "",
"ENTER_STATE": "",
"ENTER_POSTAL_CODE": "",
"ENTER_COUNTRY": "",
"JUDICIAL_DESCRIPTION": "",
"TERM_1": "",
"TERM_2": "",
"TERM_3": "",
"SHARED_USING": "",
"ENTE_IO": "",
"LIVE": "",
"DISABLE_PASSWORD": "",
"DISABLE_PASSWORD_MESSAGE": "",
"PASSWORD_LOCK": "",
"LOCK": "",
"DOWNLOAD_UPLOAD_LOGS": "",
"CHOOSE_UPLOAD_TYPE": "",
"UPLOAD_FILES": "",
"UPLOAD_DIRS": "",
"UPLOAD_GOOGLE_TAKEOUT": "",
"CANCEL_UPLOADS": "",
"DEDUPLICATE_FILES": "",
"NO_DUPLICATES_FOUND": "",
"CLUB_BY_CAPTURE_TIME": "",
"FILES": "",
"EACH": "",
"DEDUPLICATE_BASED_ON_SIZE": "",
"DEDUPLICATE_BASED_ON_SIZE_AND_CAPTURE_TIME": "",
"STOP_ALL_UPLOADS_MESSAGE": "",
"STOP_UPLOADS_HEADER": "",
"YES_STOP_UPLOADS": "",
"albums_one": "",
"albums_other": "",
"NEW": "",
"VIEW_ALL_ALBUMS": "",
"ALL_ALBUMS": "",
"ALBUMS": "",
"ENDS": "",
"ENTER_TWO_FACTOR_OTP": "",
"CREATE_ACCOUNT": "",
"COPIED": "",
"CANVAS_BLOCKED_TITLE": "",
"CANVAS_BLOCKED_MESSAGE": "",
"WATCH_FOLDERS": "",
"UPGRADE_NOW": "",
"RENEW_NOW": "",
"STORAGE": "",
"USED": "",
"YOU": "",
"FAMILY": "",
"FREE": "",
"OF": "",
"WATCHED_FOLDERS": "",
"NO_FOLDERS_ADDED": "",
"FOLDERS_AUTOMATICALLY_MONITORED": "",
"UPLOAD_NEW_FILES_TO_ENTE": "",
"REMOVE_DELETED_FILES_FROM_ENTE": "",
"ADD_FOLDER": "",
"STOP_WATCHING": "",
"STOP_WATCHING_FOLDER": "",
"STOP_WATCHING_DIALOG_MESSAGE": "",
"YES_STOP": "",
"MONTH_SHORT": "",
"YEAR": "",
"FAMILY_PLAN": "",
"DOWNLOAD_LOGS": "",
"DOWNLOAD_LOGS_MESSAGE": "",
"CHANGE_FOLDER": "",
"TWO_MONTHS_FREE": "",
"GB": "",
"POPULAR": "",
"FREE_PLAN_OPTION_LABEL": "",
"FREE_PLAN_DESCRIPTION": "",
"CURRENT_USAGE": "",
"WEAK_DEVICE": "",
"DRAG_AND_DROP_HINT": "",
"ASK_FOR_FEEDBACK": "",
"SEND_FEEDBACK": "",
"CONFIRM_ACCOUNT_DELETION_TITLE": "",
"CONFIRM_ACCOUNT_DELETION_MESSAGE": "",
"AUTHENTICATE": "",
"UPLOADED_TO_SINGLE_COLLECTION": "",
"UPLOADED_TO_SEPARATE_COLLECTIONS": "",
"NEVERMIND": "",
"UPDATE_AVAILABLE": "",
"UPDATE_INSTALLABLE_MESSAGE": "",
"INSTALL_NOW": "",
"INSTALL_ON_NEXT_LAUNCH": "",
"UPDATE_AVAILABLE_MESSAGE": "",
"DOWNLOAD_AND_INSTALL": "",
"IGNORE_THIS_VERSION": "",
"TODAY": "",
"YESTERDAY": "",
"AT": "",
"NAME_PLACEHOLDER": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "",
"CHOSE_THEME": "",
"ML_SEARCH": "",
"ENABLE_ML_SEARCH_DESCRIPTION": "",
"ML_MORE_DETAILS": "",
"ENABLE_FACE_SEARCH": "",
"ENABLE_FACE_SEARCH_TITLE": "",
"ENABLE_FACE_SEARCH_DESCRIPTION": "",
"DISABLE_BETA": "",
"DISABLE_FACE_SEARCH": "",
"DISABLE_FACE_SEARCH_TITLE": "",
"DISABLE_FACE_SEARCH_DESCRIPTION": "",
"ADVANCED": "",
"FACE_SEARCH_CONFIRMATION": "",
"LABS": "",
"YOURS": "",
"PASSPHRASE_STRENGTH": "",
"PREFERENCES": "",
"LANGUAGE": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST_MESSAGE": "",
"SUBSCRIPTION_VERIFICATION_ERROR": "",
"STORAGE_UNITS": {
"B": "",
"KB": "",
"MB": "",
"GB": "",
"TB": ""
},
"AFTER_TIME": {
"HOUR": "",
"DAY": "",
"WEEK": "",
"MONTH": "",
"YEAR": ""
},
"COPY_LINK": "",
"DONE": "",
"ADD_EMAIL_TITLE": "",
"LINK_SHARE_TITLE": "",
"REMOVE_LINK": "",
"CREATE_PUBLIC_SHARING": "",
"PUBLIC_LINK_CREATED": "",
"PUBLIC_LINK_ENABLED": "",
"COLLECT_PHOTOS": "",
"PUBLIC_COLLECT_SUBTEXT": "",
"STOP_EXPORT": "",
"EXPORT_PROGRESS": "",
"EXPORT_NOTIFICATION": {
"START": "",
"IN_PROGRESS": "",
"FINISH": "",
"UP_TO_DATE": ""
},
"CONTINUOUS_EXPORT": "",
"TOTAL_ITEMS": "",
"PENDING_ITEMS": "",
"EXPORT_STARTING": ""
}

View file

@ -9,16 +9,11 @@
"SIGN_UP": "Signup",
"NEW_USER": "New to ente",
"EXISTING_USER": "Existing user",
"NAME": "Name",
"ENTER_NAME": "Enter name",
"PUBLIC_UPLOADER_NAME_MESSAGE": "Add a name so that your friends know who to thank for these great photos!",
"EMAIL": "Email",
"ENTER_EMAIL": "Enter email address",
"DATA_DISCLAIMER": "We'll never share your data with anyone else.",
"SUBMIT": "Submit",
"EMAIL_ERROR": "Enter a valid email",
"REQUIRED": "Required",
"VERIFY_EMAIL": "Verify email",
"EMAIL_SENT": "Verification code sent to <a>{{email}}</a>",
"CHECK_INBOX": "Please check your inbox (and spam) to complete verification",
"ENTER_OTT": "Verification code",
@ -31,7 +26,6 @@
"SENT": "Sent!",
"PASSWORD": "Password",
"LINK_PASSWORD": "Enter password to unlock the album",
"ENTER_PASSPHRASE": "Enter your password",
"RETURN_PASSPHRASE_HINT": "Password",
"SET_PASSPHRASE": "Set password",
"VERIFY_PASSPHRASE": "Sign in",
@ -47,7 +41,6 @@
"PASSPHRASE_MATCH_ERROR": "Passwords don't match",
"CONSOLE_WARNING_STOP": "STOP!",
"CONSOLE_WARNING_DESC": "This is a browser feature intended for developers. Please don't copy-paste unverified code here.",
"SELECT_COLLECTION": "Select an album to upload to",
"CREATE_COLLECTION": "New album",
"ENTER_ALBUM_NAME": "Album name",
"CLOSE_OPTION": "Close (Esc)",
@ -71,17 +64,14 @@
"4": "Cancelling remaining uploads",
"5": "Backup complete"
},
"UPLOADING_FILES": "File upload",
"FILE_NOT_UPLOADED_LIST": "The following files were not uploaded",
"SUBSCRIPTION_EXPIRED": "Subscription expired",
"SUBSCRIPTION_EXPIRED_MESSAGE": "Your subscription has expired, please <a>renew</a>",
"STORAGE_QUOTA_EXCEEDED": "Storage limit exceeded",
"INITIAL_LOAD_DELAY_WARNING": "First load may take some time",
"USER_DOES_NOT_EXIST": "Sorry, could not find a user with that email",
"UPLOAD_BUTTON_TEXT": "Upload",
"NO_ACCOUNT": "Don't have an account",
"ACCOUNT_EXISTS": "Already have an account",
"ALBUM_NAME": "Album name",
"CREATE": "Create",
"DOWNLOAD": "Download",
"DOWNLOAD_OPTION": "Download (D)",
@ -102,13 +92,10 @@
"TRASH_FILE_TITLE": "Delete file?",
"DELETE_FILES_TITLE": "Delete immediately?",
"DELETE_FILES_MESSAGE": "Selected files will be permanently deleted from your ente account.",
"DELETE_FILE": "Delete files",
"DELETE": "Delete",
"DELETE_OPTION": "Delete (DEL)",
"FAVORITE": "Favorite",
"FAVORITE_OPTION": "Favorite (L)",
"UNFAVORITE_OPTION": "Unfavorite (L)",
"UNFAVORITE": "Unfavorite",
"MULTI_FOLDER_UPLOAD": "Multiple folders detected",
"UPLOAD_STRATEGY_CHOICE": "Would you like to upload them into",
"UPLOAD_STRATEGY_SINGLE_COLLECTION": "A single album",
@ -116,7 +103,6 @@
"UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "Separate albums",
"SESSION_EXPIRED_MESSAGE": "Your session has expired, please login again to continue",
"SESSION_EXPIRED": "Session expired",
"SYNC_FAILED": "Failed to sync with server, please refresh this page",
"PASSWORD_GENERATION_FAILED": "Your browser was unable to generate a strong key that meets ente's encryption standards, please try using the mobile app or another browser",
"CHANGE_PASSWORD": "Change password",
"GO_BACK": "Go back",
@ -139,13 +125,11 @@
"REQUEST_FEATURE": "Request Feature",
"SUPPORT": "Support",
"CONFIRM": "Confirm",
"SKIP_SUBSCRIPTION_PURCHASE": "Continue with free plan",
"CANCEL": "Cancel",
"LOGOUT": "Logout",
"DELETE_ACCOUNT": "Delete account",
"DELETE_ACCOUNT_MESSAGE": "<p>Please send an email to <a>{{emailID}}</a> from your registered email address.</p><p>Your request will be processed within 72 hours.</p>",
"LOGOUT_MESSAGE": "Are you sure you want to logout?",
"CHANGE": "Change",
"CHANGE_EMAIL": "Change email",
"OK": "OK",
"SUCCESS": "Success",
@ -157,9 +141,6 @@
"EXPORT": "Export Data",
"SUBSCRIPTION": "Subscription",
"SUBSCRIBE": "Subscribe",
"SUBSCRIPTION_PLAN": "Subscription plan",
"USAGE_DETAILS": "Usage",
"MANAGE": "Manage",
"MANAGEMENT_PORTAL": "Manage payment method",
"MANAGE_FAMILY_PORTAL": "Manage family",
"LEAVE_FAMILY_PLAN": "Leave family plan",
@ -177,7 +158,6 @@
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "You have exceeded your storage quota, please <a>upgrade</a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>We've received your payment</p><p>Your subscription is valid till <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Your purchase was canceled, please try again if you want to subscribe",
"SUBSCRIPTION_VERIFICATION_FAILED": "We were not able to verify your purchase, verification can take few hours",
"SUBSCRIPTION_PURCHASE_FAILED": "Subscription purchase failed , please try again",
"SUBSCRIPTION_UPDATE_FAILED": "Subscription updated failed , please try again",
"UPDATE_PAYMENT_METHOD_MESSAGE": "We are sorry, payment failed when we tried to charge your card, please update your payment method and try again",
@ -204,22 +184,18 @@
"RENAME_COLLECTION": "Rename album",
"DELETE_COLLECTION_TITLE": "Delete album?",
"DELETE_COLLECTION": "Delete album",
"DELETE_COLLECTION_FAILED": "Album deletion failed, please try again",
"DELETE_COLLECTION_MESSAGE": "Also delete the photos (and videos) present in this album from <a>all</a> other albums they are part of?",
"DELETE_PHOTOS": "Delete photos",
"KEEP_PHOTOS": "Keep photos",
"SHARE": "Share",
"SHARE_COLLECTION": "Share album",
"SHARE_WITH_PEOPLE": "Share with your loved ones",
"SHAREES": "Shared with",
"PUBLIC_URL": "Public link",
"SHARE_WITH_SELF": "Oops, you cannot share with yourself",
"ALREADY_SHARED": "Oops, you're already sharing this with {{email}}",
"SHARING_BAD_REQUEST_ERROR": "Sharing album not allowed",
"SHARING_DISABLED_FOR_FREE_ACCOUNTS": "Sharing is disabled for free accounts",
"DOWNLOAD_COLLECTION": "Download album",
"DOWNLOAD_COLLECTION_MESSAGE": "<p>Are you sure you want to download the complete album?</p><p>All files will be queued for download sequentially</p>",
"DOWNLOAD_COLLECTION_FAILED": "Album downloading failed, please try again",
"CREATE_ALBUM_FAILED": "Failed to create album , please try again",
"SEARCH_RESULTS": "Search results",
"SEARCH_HINT": "Search for albums, dates ...",
@ -235,10 +211,8 @@
"photos_count_one": "1 memory",
"photos_count_other": "{{count}} memories",
"TERMS_AND_CONDITIONS": "I agree to the <a>terms</a> and <b>privacy policy</b>",
"CONFIRM_PASSWORD_NOT_SAVED": "<p>I understand that if I lose my password , I may lose my data since my data is <1>end-to-end encrypted</1> with ente</p>",
"ADD_TO_COLLECTION": "Add to album",
"SELECTED": "selected",
"VIDEO_PLAYBACK_FAILED": "Video format not supported",
"VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD": "This video cannot be played on your browser",
"PEOPLE": "People",
"INDEXING_SCHEDULED": "indexing is scheduled...",
@ -248,41 +222,27 @@
"UNIDENTIFIED_FACES": "unidentified faces",
"OBJECTS": "objects",
"TEXT": "text",
"METADATA": "Metadata",
"INFO": "Info ",
"INFO_OPTION": "Info (I)",
"FILE_ID": "File ID",
"FILE_NAME": "File name",
"CAPTION": "Description",
"CAPTION_PLACEHOLDER": "Add a description",
"CREATION_TIME": "Creation time",
"UPDATED_ON": "Updated on",
"LOCATION": "Location",
"SHOW_ON_MAP": "View on OpenStreetMap",
"DETAILS": "Details",
"VIEW_EXIF": "View all EXIF data",
"NO_EXIF": "No EXIF data",
"EXIF": "EXIF",
"DEVICE": "Device",
"IMAGE_SIZE": "Image size",
"FLASH": "Flash",
"FOCAL_LENGTH": "Focal length",
"APERTURE": "Aperture",
"ISO": "ISO",
"SHOW_ALL": "show all",
"TWO_FACTOR": "Two-factor",
"TWO_FACTOR_AUTHENTICATION": "Two-factor authentication",
"TWO_FACTOR_QR_INSTRUCTION": "Scan the QR code below with your favorite authenticator app",
"ENTER_CODE_MANUALLY": "Enter the code manually",
"TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "Please enter this code in your favorite authenticator app",
"SCAN_QR_CODE": "Scan QR code instead",
"CONTINUE": "Continue",
"BACK": "Back",
"ENABLE_TWO_FACTOR": "Enable two-factor",
"ENABLE": "Enable",
"LOST_DEVICE": "Lost two-factor device",
"INCORRECT_CODE": "Incorrect code",
"RECOVER_TWO_FACTOR": "Recover two-factor",
"TWO_FACTOR_INFO": "Add an additional layer of security by requiring more than your email and password to log in to your account",
"DISABLE_TWO_FACTOR_LABEL": "Disable two-factor authentication",
"UPDATE_TWO_FACTOR_LABEL": "Update your authenticator device",
@ -293,31 +253,17 @@
"UPDATE": "Update",
"DISABLE_TWO_FACTOR": "Disable two-factor",
"DISABLE_TWO_FACTOR_MESSAGE": "Are you sure you want to disable your two-factor authentication",
"TWO_FACTOR_SETUP_FAILED": "Failed to setup two factor, please try again",
"TWO_FACTOR_SETUP_SUCCESS": "Two factor authentication successfully configured",
"TWO_FACTOR_DISABLE_SUCCESS": "Two factor authentication disabled",
"TWO_FACTOR_DISABLE_FAILED": "Failed to disable two factor, please try again",
"EXPORT_DATA": "Export data",
"SELECT_FOLDER": "Select folder",
"DESTINATION": "Destination",
"EXPORT_SIZE": "Export size",
"START": "Start",
"EXPORT_IN_PROGRESS": "Export in progress...",
"PAUSE": "Pause",
"RESUME": "Resume",
"MINIMIZE": "Minimize",
"LAST_EXPORT_TIME": "Last export time",
"SUCCESSFULLY_EXPORTED_FILES": "Successful exports",
"FAILED_EXPORTED_FILES": "Failed exports",
"EXPORT_AGAIN": "Resync",
"RETRY_EXPORT": "Retry failed exports",
"LOCAL_STORAGE_NOT_ACCESSIBLE": "Local storage not accessible",
"LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "Your browser or an addon is blocking ente from saving data into local storage. please try loading this page after switching your browsing mode.",
"RETRY": "Retry",
"SEND_OTT": "Send OTP",
"EMAIl_ALREADY_OWNED": "Email already taken",
"EMAIL_UDPATE_SUCCESSFUL": "Your email has been updated successfully",
"UPLOAD_FAILED": "Upload failed",
"ETAGS_BLOCKED": "<p>We were unable to upload the following files because of your browser configuration.</p><p>Please disable any addons that might be preventing ente from using <code>eTags</code> to upload large files, or use our <a>desktop app</a> for a more reliable import experience.</p>",
"SKIPPED_VIDEOS_INFO": "<p>Presently we do not support adding videos via public links.</p><p>To share videos, please <a>signup</a> for ente and share with the intended recipients using their email.</p>",
"LIVE_PHOTOS_DETECTED": "The photo and video files from your Live Photos have been merged into a single file",
@ -340,7 +286,6 @@
"THUMBNAIL_GENERATION_FAILED_INFO": "These files were uploaded, but unfortunately we could not generate the thumbnails for them.",
"UPLOAD_TO_COLLECTION": "Upload to album",
"UNCATEGORIZED": "Uncategorized",
"MOVE_TO_UNCATEGORIZED": "Move to uncategorized",
"ARCHIVE": "Archive",
"ARCHIVE_COLLECTION": "Archive album",
"ARCHIVE_SECTION_NAME": "Archive",
@ -350,10 +295,8 @@
"UNARCHIVE_COLLECTION": "Unarchive album",
"MOVE": "Move",
"ADD": "Add",
"SORT": "Sort",
"REMOVE": "Remove",
"YES_REMOVE": "Yes, remove",
"CONFIRM_REMOVE": "Confirm removal",
"REMOVE_FROM_COLLECTION": "Remove from album",
"TRASH": "Trash",
"MOVE_TO_TRASH": "Move to trash",
@ -361,8 +304,6 @@
"TRASH_FILE_MESSAGE": "The file will be removed from all albums and moved to trash.",
"DELETE_PERMANENTLY": "Delete permanently",
"RESTORE": "Restore",
"CONFIRM_RESTORE": "Confirm restoration",
"RESTORE_MESSAGE": "Restore selected files ?",
"RESTORE_TO_COLLECTION": "Restore to album",
"EMPTY_TRASH": "Empty trash",
"EMPTY_TRASH_TITLE": "Empty trash?",
@ -375,7 +316,6 @@
"CONFIRM_SELF_REMOVE_MESSAGE": "Selected items will be removed from this album. Items which are only in this album will be moved to Uncategorized.",
"CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE": "Some of the items you are removing were added by other people, and you will lose access to them.",
"SORT_BY_CREATION_TIME_ASCENDING": "Oldest",
"SORT_BY_CREATION_TIME_DESCENDING": "Newest",
"SORT_BY_UPDATION_TIME_DESCENDING": "Last updated",
"SORT_BY_NAME": "Name",
"COMPRESS_THUMBNAILS": "Compress thumbnails",
@ -392,22 +332,13 @@
"UPDATE_CREATION_TIME_NOT_STARTED": "Select the option you want to use",
"UPDATE_CREATION_TIME_COMPLETED": "Successfully updated all files",
"UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR": "File time updation failed for some files, please retry",
"FILE_NAME_CHARACTER_LIMIT": "100 characters max",
"CAPTION_CHARACTER_LIMIT": "5000 characters max",
"DATE_TIME_ORIGINAL": "EXIF:DateTimeOriginal",
"DATE_TIME_DIGITIZED": "EXIF:DateTimeDigitized",
"CUSTOM_TIME": "Custom time",
"REOPEN_PLAN_SELECTOR_MODAL": "Re-open plans",
"OPEN_PLAN_SELECTOR_MODAL_FAILED": "Failed to open plans",
"COMMENT": "Comment",
"ABUSE_REPORT_DESCRIPTION": "Submitting this report will notify the album owner.",
"OTHER_REASON_REQUIRES_COMMENTS": "Reason = other, require a mandatory comment ",
"REPORT_SUBMIT_SUCCESS_CONTENT": "Your report has been submitted",
"REPORT_SUBMIT_SUCCESS_TITLE": "Report sent",
"REPORT_SUBMIT_FAILED": "Failed to sent report, try again",
"INSTALL": "Install",
"ALBUM_URL": "Album url",
"PUBLIC_SHARING": "Public link",
"SHARING_DETAILS": "Sharing details",
"MODIFY_SHARING": "Modify sharing",
"NOT_FOUND": "404 - not found",
@ -415,8 +346,6 @@
"LINK_EXPIRED_MESSAGE": "This link has either expired or been disabled!",
"MANAGE_LINK": "Manage link",
"LINK_TOO_MANY_REQUESTS": "This album is too popular for us to handle!",
"DISABLE_PUBLIC_SHARING": "Disable public sharing",
"DISABLE_PUBLIC_SHARING_MESSAGE": "Are you sure you want to disable public sharing?",
"FILE_DOWNLOAD": "Allow downloads",
"LINK_PASSWORD_LOCK": "Password lock",
"PUBLIC_COLLECT": "Allow adding photos",
@ -425,26 +354,8 @@
"LINK_EXPIRY_NEVER": "Never",
"DISABLE_FILE_DOWNLOAD": "Disable download",
"DISABLE_FILE_DOWNLOAD_MESSAGE": "<p>Are you sure that you want to disable the download button for files?</p><p>Viewers can still take screenshots or save a copy of your photos using external tools.</p>",
"ABUSE_REPORT": "Abuse report",
"ABUSE_REPORT_BUTTON_TEXT": "Report abuse?",
"MALICIOUS_CONTENT": "Contains malicious content",
"COPYRIGHT": "Infringes on the copyright of someone I am authorized to represent",
"ENTER_EMAIL_ADDRESS": "Email*",
"SELECT_REASON": "Select a reason*",
"ENTER_FULL_NAME": "Full name*",
"ENTER_DIGITAL_SIGNATURE": "Typing your full name in this box will act as your digital signature*",
"ENTER_ON_BEHALF_OF": "I am reporting on behalf of*",
"ENTER_ADDRESS": "Address*",
"ENTER_JOB_TITLE": "Job title*",
"ENTER_CITY": "City*",
"ENTER_PHONE": "Phone number*",
"ENTER_STATE": "State*",
"ENTER_POSTAL_CODE": "Zip/postal code*",
"ENTER_COUNTRY": "Country*",
"JUDICIAL_DESCRIPTION": "By checking the following boxes, I state <strong>UNDER PENALTY OF PERJURY </strong>of law that:",
"TERM_1": "I hereby state that I have a good faith belief that the sharing of copyrighted material at the location above is not authorized by the copyright owner, its agent, or the law (e.g., as a fair use). ",
"TERM_2": "I hereby state that the information in this Notice is accurate and, under penalty of perjury, that I am the owner, or authorized to act on behalf of, the owner, of the copyright or of an exclusive right under the copyright that is allegedly infringed. ",
"TERM_3": "I acknowledge that any person who knowingly materially misrepresents that material or activity is infringing may be subject to liability for damages. ",
"SHARED_USING": "Shared using ",
"ENTE_IO": "ente.io",
"LIVE": "LIVE",
@ -453,11 +364,9 @@
"PASSWORD_LOCK": "Password lock",
"LOCK": "Lock",
"DOWNLOAD_UPLOAD_LOGS": "Debug logs",
"CHOOSE_UPLOAD_TYPE": "Upload",
"UPLOAD_FILES": "File",
"UPLOAD_DIRS": "Folder",
"UPLOAD_GOOGLE_TAKEOUT": "Google takeout",
"CANCEL_UPLOADS": "Cancel uploads",
"DEDUPLICATE_FILES": "Deduplicate files",
"AUTHENTICATOR_SECTION": "Authenticator",
"NO_DUPLICATES_FOUND": "You've no duplicate files that can be cleared",
@ -471,11 +380,8 @@
"YES_STOP_UPLOADS": "Yes, stop uploads",
"albums_one": "1 Album",
"albums_other": "{{count}} Albums",
"NEW": "New",
"VIEW_ALL_ALBUMS": "View all Albums",
"ALL_ALBUMS": "All Albums",
"ALBUMS": "Albums",
"ENDS": "Ends",
"ENTER_TWO_FACTOR_OTP": "Enter the 6-digit code from your authenticator app.",
"CREATE_ACCOUNT": "Create account",
"COPIED": "Copied",
@ -531,7 +437,6 @@
"IGNORE_THIS_VERSION": "Ignore this version",
"TODAY": "Today",
"YESTERDAY": "Yesterday",
"AT": "at",
"NAME_PLACEHOLDER": "Name...",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED": "Cannot create albums from file/folder mix",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "<p>You have dragged and dropped a mixture of files and folders.</p><p>Please provide either only files, or only folders when selecting option to create separate albums</p>",
@ -550,7 +455,9 @@
"FACE_SEARCH_CONFIRMATION": "I understand, and wish to allow ente to process face geometry",
"LABS": "Labs",
"YOURS": "yours",
"PASSPHRASE_STRENGTH": "Password strength: {{passwordStrength}}",
"PASSPHRASE_STRENGTH_WEAK": "Password strength: Weak",
"PASSPHRASE_STRENGTH_MODERATE": "Password strength: Moderate",
"PASSPHRASE_STRENGTH_STRONG": "Password strength: Strong",
"PREFERENCES": "Preferences",
"LANGUAGE": "Language",
"EXPORT_DIRECTORY_DOES_NOT_EXIST": "Invalid export directory",
@ -569,5 +476,27 @@
"WEEK": "after a week",
"MONTH": "after a month",
"YEAR": "after a year"
}
}
},
"COPY_LINK": "Copy link",
"DONE": "Done",
"ADD_EMAIL_TITLE": "Share with specific people",
"LINK_SHARE_TITLE": "Or share a link",
"REMOVE_LINK": "Remove link",
"CREATE_PUBLIC_SHARING": "Create public link",
"PUBLIC_LINK_CREATED": "Public link created",
"PUBLIC_LINK_ENABLED": "Public link enabled",
"COLLECT_PHOTOS": "Collect photos",
"PUBLIC_COLLECT_SUBTEXT": "Allow people with the link to also add photos to the shared album.",
"STOP_EXPORT": "Stop",
"EXPORT_PROGRESS": "<a>{{progress.current}} / {{progress.total}}</a> files exported",
"EXPORT_NOTIFICATION": {
"START": "Export started",
"IN_PROGRESS": "Export already in progress",
"FINISH": "Export finished",
"UP_TO_DATE": "No new files to export"
},
"CONTINUOUS_EXPORT": "Sync continuously",
"TOTAL_ITEMS": "Total items",
"PENDING_ITEMS": "Pending items",
"EXPORT_STARTING": "Export starting..."
}

View file

@ -0,0 +1,592 @@
{
"HERO_SLIDE_1_TITLE": "",
"HERO_SLIDE_1": "",
"HERO_SLIDE_2_TITLE": "",
"HERO_SLIDE_2": "",
"HERO_SLIDE_3_TITLE": "",
"HERO_SLIDE_3": "",
"LOGIN": "",
"SIGN_UP": "",
"NEW_USER": "",
"EXISTING_USER": "",
"NAME": "",
"ENTER_NAME": "",
"PUBLIC_UPLOADER_NAME_MESSAGE": "",
"EMAIL": "",
"ENTER_EMAIL": "",
"DATA_DISCLAIMER": "",
"SUBMIT": "",
"EMAIL_ERROR": "",
"REQUIRED": "",
"VERIFY_EMAIL": "",
"EMAIL_SENT": "",
"CHECK_INBOX": "",
"ENTER_OTT": "",
"RESEND_MAIL": "",
"VERIFY": "",
"UNKNOWN_ERROR": "",
"INVALID_CODE": "",
"EXPIRED_CODE": "",
"SENDING": "",
"SENT": "",
"PASSWORD": "",
"LINK_PASSWORD": "",
"ENTER_PASSPHRASE": "",
"RETURN_PASSPHRASE_HINT": "",
"SET_PASSPHRASE": "",
"VERIFY_PASSPHRASE": "",
"INCORRECT_PASSPHRASE": "",
"ENTER_ENC_PASSPHRASE": "",
"PASSPHRASE_DISCLAIMER": "",
"WELCOME_TO_ENTE_HEADING": "",
"WELCOME_TO_ENTE_SUBHEADING": "",
"WHERE_YOUR_BEST_PHOTOS_LIVE": "",
"KEY_GENERATION_IN_PROGRESS_MESSAGE": "",
"PASSPHRASE_HINT": "",
"CONFIRM_PASSPHRASE": "",
"PASSPHRASE_MATCH_ERROR": "",
"CONSOLE_WARNING_STOP": "",
"CONSOLE_WARNING_DESC": "",
"SELECT_COLLECTION": "",
"CREATE_COLLECTION": "",
"ENTER_ALBUM_NAME": "",
"CLOSE_OPTION": "",
"ENTER_FILE_NAME": "",
"CLOSE": "",
"NO": "",
"NOTHING_HERE": "",
"UPLOAD": "",
"IMPORT": "",
"ADD_PHOTOS": "",
"ADD_MORE_PHOTOS": "",
"add_photos_one": "",
"add_photos_other": "",
"SELECT_PHOTOS": "",
"FILE_UPLOAD": "",
"UPLOAD_STAGE_MESSAGE": {
"0": "",
"1": "",
"2": "",
"3": "",
"4": "",
"5": ""
},
"UPLOADING_FILES": "",
"FILE_NOT_UPLOADED_LIST": "",
"SUBSCRIPTION_EXPIRED": "",
"SUBSCRIPTION_EXPIRED_MESSAGE": "",
"STORAGE_QUOTA_EXCEEDED": "",
"INITIAL_LOAD_DELAY_WARNING": "",
"USER_DOES_NOT_EXIST": "",
"UPLOAD_BUTTON_TEXT": "",
"NO_ACCOUNT": "",
"ACCOUNT_EXISTS": "",
"ALBUM_NAME": "",
"CREATE": "",
"DOWNLOAD": "",
"DOWNLOAD_OPTION": "",
"DOWNLOAD_FAVORITES": "",
"DOWNLOAD_UNCATEGORIZED": "",
"COPY_OPTION": "",
"TOGGLE_FULLSCREEN": "",
"ZOOM_IN_OUT": "",
"PREVIOUS": "",
"NEXT": "",
"NO_INTERNET_CONNECTION": "",
"TITLE": "",
"UPLOAD_FIRST_PHOTO": "",
"IMPORT_YOUR_FOLDERS": "",
"UPLOAD_DROPZONE_MESSAGE": "",
"WATCH_FOLDER_DROPZONE_MESSAGE": "",
"TRASH_FILES_TITLE": "",
"TRASH_FILE_TITLE": "",
"DELETE_FILES_TITLE": "",
"DELETE_FILES_MESSAGE": "",
"DELETE_FILE": "",
"DELETE": "",
"DELETE_OPTION": "",
"FAVORITE": "",
"FAVORITE_OPTION": "",
"UNFAVORITE_OPTION": "",
"UNFAVORITE": "",
"MULTI_FOLDER_UPLOAD": "",
"UPLOAD_STRATEGY_CHOICE": "",
"UPLOAD_STRATEGY_SINGLE_COLLECTION": "",
"OR": "",
"UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "",
"SESSION_EXPIRED_MESSAGE": "",
"SESSION_EXPIRED": "",
"SYNC_FAILED": "",
"PASSWORD_GENERATION_FAILED": "",
"CHANGE_PASSWORD": "",
"GO_BACK": "",
"RECOVERY_KEY": "",
"SAVE_LATER": "",
"SAVE": "",
"RECOVERY_KEY_DESCRIPTION": "",
"RECOVER_KEY_GENERATION_FAILED": "",
"KEY_NOT_STORED_DISCLAIMER": "",
"FORGOT_PASSWORD": "",
"RECOVER_ACCOUNT": "",
"RECOVERY_KEY_HINT": "",
"RECOVER": "",
"NO_RECOVERY_KEY": "",
"INCORRECT_RECOVERY_KEY": "",
"SORRY": "",
"NO_RECOVERY_KEY_MESSAGE": "",
"NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "",
"CONTACT_SUPPORT": "",
"REQUEST_FEATURE": "",
"SUPPORT": "",
"CONFIRM": "",
"SKIP_SUBSCRIPTION_PURCHASE": "",
"CANCEL": "",
"LOGOUT": "",
"DELETE_ACCOUNT": "",
"DELETE_ACCOUNT_MESSAGE": "",
"LOGOUT_MESSAGE": "",
"CHANGE": "",
"CHANGE_EMAIL": "",
"OK": "",
"SUCCESS": "",
"ERROR": "",
"MESSAGE": "",
"INSTALL_MOBILE_APP": "",
"DOWNLOAD_APP_MESSAGE": "",
"DOWNLOAD_APP": "",
"EXPORT": "",
"SUBSCRIPTION": "",
"SUBSCRIBE": "",
"SUBSCRIPTION_PLAN": "",
"USAGE_DETAILS": "",
"MANAGE": "",
"MANAGEMENT_PORTAL": "",
"MANAGE_FAMILY_PORTAL": "",
"LEAVE_FAMILY_PLAN": "",
"LEAVE": "",
"LEAVE_FAMILY_CONFIRM": "",
"CHOOSE_PLAN": "",
"MANAGE_PLAN": "",
"ACTIVE": "",
"OFFLINE_MSG": "",
"FREE_SUBSCRIPTION_INFO": "",
"FAMILY_SUBSCRIPTION_INFO": "",
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
"SUBSCRIPTION_VERIFICATION_FAILED": "",
"SUBSCRIPTION_PURCHASE_FAILED": "",
"SUBSCRIPTION_UPDATE_FAILED": "",
"UPDATE_PAYMENT_METHOD_MESSAGE": "",
"STRIPE_AUTHENTICATION_FAILED": "",
"UPDATE_PAYMENT_METHOD": "",
"MONTHLY": "",
"YEARLY": "",
"UPDATE_SUBSCRIPTION_MESSAGE": "",
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",
"REACTIVATE_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_ACTIVATE_SUCCESS": "",
"SUBSCRIPTION_ACTIVATE_FAILED": "",
"SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE": "",
"MAIL_TO_MANAGE_SUBSCRIPTION": "",
"RENAME": "",
"RENAME_FILE": "",
"RENAME_COLLECTION": "",
"DELETE_COLLECTION_TITLE": "",
"DELETE_COLLECTION": "",
"DELETE_COLLECTION_FAILED": "",
"DELETE_COLLECTION_MESSAGE": "",
"DELETE_PHOTOS": "",
"KEEP_PHOTOS": "",
"SHARE": "",
"SHARE_COLLECTION": "",
"SHARE_WITH_PEOPLE": "",
"SHAREES": "",
"PUBLIC_URL": "",
"SHARE_WITH_SELF": "",
"ALREADY_SHARED": "",
"SHARING_BAD_REQUEST_ERROR": "",
"SHARING_DISABLED_FOR_FREE_ACCOUNTS": "",
"DOWNLOAD_COLLECTION": "",
"DOWNLOAD_COLLECTION_MESSAGE": "",
"DOWNLOAD_COLLECTION_FAILED": "",
"CREATE_ALBUM_FAILED": "",
"SEARCH_RESULTS": "",
"SEARCH_HINT": "",
"SEARCH_TYPE": {
"COLLECTION": "",
"LOCATION": "",
"DATE": "",
"FILE_NAME": "",
"THING": "",
"FILE_CAPTION": ""
},
"photos_count_zero": "",
"photos_count_one": "",
"photos_count_other": "",
"TERMS_AND_CONDITIONS": "",
"CONFIRM_PASSWORD_NOT_SAVED": "",
"ADD_TO_COLLECTION": "",
"SELECTED": "",
"VIDEO_PLAYBACK_FAILED": "",
"VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD": "",
"PEOPLE": "",
"INDEXING_SCHEDULED": "",
"ANALYZING_PHOTOS": "",
"INDEXING_PEOPLE": "",
"INDEXING_DONE": "",
"UNIDENTIFIED_FACES": "",
"OBJECTS": "",
"TEXT": "",
"METADATA": "",
"INFO": "",
"INFO_OPTION": "",
"FILE_ID": "",
"FILE_NAME": "",
"CAPTION": "",
"CAPTION_PLACEHOLDER": "",
"CREATION_TIME": "",
"UPDATED_ON": "",
"LOCATION": "",
"SHOW_ON_MAP": "",
"DETAILS": "",
"VIEW_EXIF": "",
"NO_EXIF": "",
"EXIF": "",
"DEVICE": "",
"IMAGE_SIZE": "",
"FLASH": "",
"FOCAL_LENGTH": "",
"APERTURE": "",
"ISO": "",
"SHOW_ALL": "",
"TWO_FACTOR": "",
"TWO_FACTOR_AUTHENTICATION": "",
"TWO_FACTOR_QR_INSTRUCTION": "",
"ENTER_CODE_MANUALLY": "",
"TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "",
"SCAN_QR_CODE": "",
"CONTINUE": "",
"BACK": "",
"ENABLE_TWO_FACTOR": "",
"ENABLE": "",
"LOST_DEVICE": "",
"INCORRECT_CODE": "",
"RECOVER_TWO_FACTOR": "",
"TWO_FACTOR_INFO": "",
"DISABLE_TWO_FACTOR_LABEL": "",
"UPDATE_TWO_FACTOR_LABEL": "",
"DISABLE": "",
"RECONFIGURE": "",
"UPDATE_TWO_FACTOR": "",
"UPDATE_TWO_FACTOR_MESSAGE": "",
"UPDATE": "",
"DISABLE_TWO_FACTOR": "",
"DISABLE_TWO_FACTOR_MESSAGE": "",
"TWO_FACTOR_SETUP_FAILED": "",
"TWO_FACTOR_SETUP_SUCCESS": "",
"TWO_FACTOR_DISABLE_SUCCESS": "",
"TWO_FACTOR_DISABLE_FAILED": "",
"EXPORT_DATA": "",
"SELECT_FOLDER": "",
"DESTINATION": "",
"START": "",
"EXPORT_IN_PROGRESS": "",
"PAUSE": "",
"RESUME": "",
"MINIMIZE": "",
"LAST_EXPORT_TIME": "",
"SUCCESSFULLY_EXPORTED_FILES": "",
"FAILED_EXPORTED_FILES": "",
"EXPORT_AGAIN": "",
"RETRY_EXPORT": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "",
"RETRY": "",
"SEND_OTT": "",
"EMAIl_ALREADY_OWNED": "",
"EMAIL_UDPATE_SUCCESSFUL": "",
"UPLOAD_FAILED": "",
"ETAGS_BLOCKED": "",
"SKIPPED_VIDEOS_INFO": "",
"LIVE_PHOTOS_DETECTED": "",
"RETRY_FAILED": "",
"FAILED_UPLOADS": "",
"SKIPPED_FILES": "",
"THUMBNAIL_GENERATION_FAILED_UPLOADS": "",
"UNSUPPORTED_FILES": "",
"SUCCESSFUL_UPLOADS": "",
"SKIPPED_INFO": "",
"UNSUPPORTED_INFO": "",
"BLOCKED_UPLOADS": "",
"SKIPPED_VIDEOS": "",
"INPROGRESS_METADATA_EXTRACTION": "",
"INPROGRESS_UPLOADS": "",
"TOO_LARGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_INFO": "",
"TOO_LARGE_INFO": "",
"THUMBNAIL_GENERATION_FAILED_INFO": "",
"UPLOAD_TO_COLLECTION": "",
"UNCATEGORIZED": "",
"MOVE_TO_UNCATEGORIZED": "",
"ARCHIVE": "",
"ARCHIVE_COLLECTION": "",
"ARCHIVE_SECTION_NAME": "",
"ALL_SECTION_NAME": "",
"MOVE_TO_COLLECTION": "",
"UNARCHIVE": "",
"UNARCHIVE_COLLECTION": "",
"MOVE": "",
"ADD": "",
"SORT": "",
"REMOVE": "",
"YES_REMOVE": "",
"CONFIRM_REMOVE": "",
"REMOVE_FROM_COLLECTION": "",
"TRASH": "",
"MOVE_TO_TRASH": "",
"TRASH_FILES_MESSAGE": "",
"TRASH_FILE_MESSAGE": "",
"DELETE_PERMANENTLY": "",
"RESTORE": "",
"CONFIRM_RESTORE": "",
"RESTORE_MESSAGE": "",
"RESTORE_TO_COLLECTION": "",
"EMPTY_TRASH": "",
"EMPTY_TRASH_TITLE": "",
"EMPTY_TRASH_MESSAGE": "",
"LEAVE_SHARED_ALBUM": "",
"LEAVE_ALBUM": "",
"LEAVE_SHARED_ALBUM_TITLE": "",
"LEAVE_SHARED_ALBUM_MESSAGE": "",
"NOT_FILE_OWNER": "",
"CONFIRM_SELF_REMOVE_MESSAGE": "",
"CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE": "",
"SORT_BY_CREATION_TIME_ASCENDING": "",
"SORT_BY_CREATION_TIME_DESCENDING": "",
"SORT_BY_UPDATION_TIME_DESCENDING": "",
"SORT_BY_NAME": "",
"COMPRESS_THUMBNAILS": "",
"THUMBNAIL_REPLACED": "",
"FIX_THUMBNAIL": "",
"FIX_THUMBNAIL_LATER": "",
"REPLACE_THUMBNAIL_NOT_STARTED": "",
"REPLACE_THUMBNAIL_COMPLETED": "",
"REPLACE_THUMBNAIL_NOOP": "",
"REPLACE_THUMBNAIL_COMPLETED_WITH_ERROR": "",
"FIX_CREATION_TIME": "",
"FIX_CREATION_TIME_IN_PROGRESS": "",
"CREATION_TIME_UPDATED": "",
"UPDATE_CREATION_TIME_NOT_STARTED": "",
"UPDATE_CREATION_TIME_COMPLETED": "",
"UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR": "",
"FILE_NAME_CHARACTER_LIMIT": "",
"CAPTION_CHARACTER_LIMIT": "",
"DATE_TIME_ORIGINAL": "",
"DATE_TIME_DIGITIZED": "",
"CUSTOM_TIME": "",
"REOPEN_PLAN_SELECTOR_MODAL": "",
"OPEN_PLAN_SELECTOR_MODAL_FAILED": "",
"COMMENT": "",
"ABUSE_REPORT_DESCRIPTION": "",
"OTHER_REASON_REQUIRES_COMMENTS": "",
"REPORT_SUBMIT_SUCCESS_CONTENT": "",
"REPORT_SUBMIT_SUCCESS_TITLE": "",
"REPORT_SUBMIT_FAILED": "",
"INSTALL": "",
"ALBUM_URL": "",
"SHARING_DETAILS": "",
"MODIFY_SHARING": "",
"NOT_FOUND": "",
"LINK_EXPIRED": "",
"LINK_EXPIRED_MESSAGE": "",
"MANAGE_LINK": "",
"LINK_TOO_MANY_REQUESTS": "",
"DISABLE_PUBLIC_SHARING": "",
"DISABLE_PUBLIC_SHARING_MESSAGE": "",
"FILE_DOWNLOAD": "",
"LINK_PASSWORD_LOCK": "",
"PUBLIC_COLLECT": "",
"LINK_DEVICE_LIMIT": "",
"LINK_EXPIRY": "",
"LINK_EXPIRY_NEVER": "",
"DISABLE_FILE_DOWNLOAD": "",
"DISABLE_FILE_DOWNLOAD_MESSAGE": "",
"ABUSE_REPORT": "",
"ABUSE_REPORT_BUTTON_TEXT": "",
"MALICIOUS_CONTENT": "",
"COPYRIGHT": "",
"ENTER_EMAIL_ADDRESS": "",
"SELECT_REASON": "",
"ENTER_FULL_NAME": "",
"ENTER_DIGITAL_SIGNATURE": "",
"ENTER_ON_BEHALF_OF": "",
"ENTER_ADDRESS": "",
"ENTER_JOB_TITLE": "",
"ENTER_CITY": "",
"ENTER_PHONE": "",
"ENTER_STATE": "",
"ENTER_POSTAL_CODE": "",
"ENTER_COUNTRY": "",
"JUDICIAL_DESCRIPTION": "",
"TERM_1": "",
"TERM_2": "",
"TERM_3": "",
"SHARED_USING": "",
"ENTE_IO": "",
"LIVE": "",
"DISABLE_PASSWORD": "",
"DISABLE_PASSWORD_MESSAGE": "",
"PASSWORD_LOCK": "",
"LOCK": "",
"DOWNLOAD_UPLOAD_LOGS": "",
"CHOOSE_UPLOAD_TYPE": "",
"UPLOAD_FILES": "",
"UPLOAD_DIRS": "",
"UPLOAD_GOOGLE_TAKEOUT": "",
"CANCEL_UPLOADS": "",
"DEDUPLICATE_FILES": "",
"NO_DUPLICATES_FOUND": "",
"CLUB_BY_CAPTURE_TIME": "",
"FILES": "",
"EACH": "",
"DEDUPLICATE_BASED_ON_SIZE": "",
"DEDUPLICATE_BASED_ON_SIZE_AND_CAPTURE_TIME": "",
"STOP_ALL_UPLOADS_MESSAGE": "",
"STOP_UPLOADS_HEADER": "",
"YES_STOP_UPLOADS": "",
"albums_one": "",
"albums_other": "",
"NEW": "",
"VIEW_ALL_ALBUMS": "",
"ALL_ALBUMS": "",
"ALBUMS": "",
"ENDS": "",
"ENTER_TWO_FACTOR_OTP": "",
"CREATE_ACCOUNT": "",
"COPIED": "",
"CANVAS_BLOCKED_TITLE": "",
"CANVAS_BLOCKED_MESSAGE": "",
"WATCH_FOLDERS": "",
"UPGRADE_NOW": "",
"RENEW_NOW": "",
"STORAGE": "",
"USED": "",
"YOU": "",
"FAMILY": "",
"FREE": "",
"OF": "",
"WATCHED_FOLDERS": "",
"NO_FOLDERS_ADDED": "",
"FOLDERS_AUTOMATICALLY_MONITORED": "",
"UPLOAD_NEW_FILES_TO_ENTE": "",
"REMOVE_DELETED_FILES_FROM_ENTE": "",
"ADD_FOLDER": "",
"STOP_WATCHING": "",
"STOP_WATCHING_FOLDER": "",
"STOP_WATCHING_DIALOG_MESSAGE": "",
"YES_STOP": "",
"MONTH_SHORT": "",
"YEAR": "",
"FAMILY_PLAN": "",
"DOWNLOAD_LOGS": "",
"DOWNLOAD_LOGS_MESSAGE": "",
"CHANGE_FOLDER": "",
"TWO_MONTHS_FREE": "",
"GB": "",
"POPULAR": "",
"FREE_PLAN_OPTION_LABEL": "",
"FREE_PLAN_DESCRIPTION": "",
"CURRENT_USAGE": "",
"WEAK_DEVICE": "",
"DRAG_AND_DROP_HINT": "",
"ASK_FOR_FEEDBACK": "",
"SEND_FEEDBACK": "",
"CONFIRM_ACCOUNT_DELETION_TITLE": "",
"CONFIRM_ACCOUNT_DELETION_MESSAGE": "",
"AUTHENTICATE": "",
"UPLOADED_TO_SINGLE_COLLECTION": "",
"UPLOADED_TO_SEPARATE_COLLECTIONS": "",
"NEVERMIND": "",
"UPDATE_AVAILABLE": "",
"UPDATE_INSTALLABLE_MESSAGE": "",
"INSTALL_NOW": "",
"INSTALL_ON_NEXT_LAUNCH": "",
"UPDATE_AVAILABLE_MESSAGE": "",
"DOWNLOAD_AND_INSTALL": "",
"IGNORE_THIS_VERSION": "",
"TODAY": "",
"YESTERDAY": "",
"AT": "",
"NAME_PLACEHOLDER": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "",
"CHOSE_THEME": "",
"ML_SEARCH": "",
"ENABLE_ML_SEARCH_DESCRIPTION": "",
"ML_MORE_DETAILS": "",
"ENABLE_FACE_SEARCH": "",
"ENABLE_FACE_SEARCH_TITLE": "",
"ENABLE_FACE_SEARCH_DESCRIPTION": "",
"DISABLE_BETA": "",
"DISABLE_FACE_SEARCH": "",
"DISABLE_FACE_SEARCH_TITLE": "",
"DISABLE_FACE_SEARCH_DESCRIPTION": "",
"ADVANCED": "",
"FACE_SEARCH_CONFIRMATION": "",
"LABS": "",
"YOURS": "",
"PASSPHRASE_STRENGTH": "",
"PREFERENCES": "",
"LANGUAGE": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST_MESSAGE": "",
"SUBSCRIPTION_VERIFICATION_ERROR": "",
"STORAGE_UNITS": {
"B": "",
"KB": "",
"MB": "",
"GB": "",
"TB": ""
},
"AFTER_TIME": {
"HOUR": "",
"DAY": "",
"WEEK": "",
"MONTH": "",
"YEAR": ""
},
"COPY_LINK": "",
"DONE": "",
"ADD_EMAIL_TITLE": "",
"LINK_SHARE_TITLE": "",
"REMOVE_LINK": "",
"CREATE_PUBLIC_SHARING": "",
"PUBLIC_LINK_CREATED": "",
"PUBLIC_LINK_ENABLED": "",
"COLLECT_PHOTOS": "",
"PUBLIC_COLLECT_SUBTEXT": "",
"STOP_EXPORT": "",
"EXPORT_PROGRESS": "",
"EXPORT_NOTIFICATION": {
"START": "",
"IN_PROGRESS": "",
"FINISH": "",
"UP_TO_DATE": ""
},
"CONTINUOUS_EXPORT": "",
"TOTAL_ITEMS": "",
"PENDING_ITEMS": "",
"EXPORT_STARTING": ""
}

View file

@ -1,7 +1,7 @@
{
"HERO_SLIDE_1_TITLE": "<div>Sauvegardes personnelles</div><div>de vos souvenirs</div>",
"HERO_SLIDE_1_TITLE": "<div>Sauvegardes personnelles </div><div>de vos souvenirs</div>",
"HERO_SLIDE_1": "Chiffrement de bout en bout par défaut",
"HERO_SLIDE_2_TITLE": "<div>Sécurisé</div><div>dans un abri antiatomique</div>",
"HERO_SLIDE_2_TITLE": "<div>Sécurisé </div><div>dans un abri antiatomique</div>",
"HERO_SLIDE_2": "Conçu pour survivre",
"HERO_SLIDE_3_TITLE": "<div>Disponible</div><div> partout</div>",
"HERO_SLIDE_3": "Android, iOS, Web, Ordinateur",
@ -19,10 +19,10 @@
"EMAIL_ERROR": "Saisir un e-mail valide",
"REQUIRED": "Nécessaire",
"VERIFY_EMAIL": "Vérifier l'e-mail",
"EMAIL_SENT": "Verification code sent to <a>{{emailID}}</a>",
"EMAIL_SENT": "Verification code sent to <a>{{email}}</a>",
"CHECK_INBOX": "Veuillez consulter votre boite de réception (et indésirables) pour poursuivre la vérification",
"ENTER_OTT": "Code de vérification",
"RESEND_MAIL": "envoyer le code",
"RESEND_MAIL": "Envoyer le code",
"VERIFY": "Vérifier",
"UNKNOWN_ERROR": "Quelque chose s'est mal passé, veuillez recommencer",
"INVALID_CODE": "Code de vérification non valide",
@ -37,7 +37,7 @@
"VERIFY_PASSPHRASE": "Connexion",
"INCORRECT_PASSPHRASE": "Mot de passe non valide",
"ENTER_ENC_PASSPHRASE": "Veuillez saisir un mot de passe que nous pourrons utiliser pour chiffrer vos données",
"PASSPHRASE_DISCLAIMER": "Nous ne stockons pas votre mot de passe, donc si vous le perdez, <strong>nous ne pourrons pas vous aider</strong> à récupérer vosdonnées sans une clé de récupération.",
"PASSPHRASE_DISCLAIMER": "Nous ne stockons pas votre mot de passe, donc si vous le perdez, <strong>nous ne pourrons pas vous aider</strong> à récupérer vos données sans une clé de récupération.",
"WELCOME_TO_ENTE_HEADING": "Bienvenue sur <a/>",
"WELCOME_TO_ENTE_SUBHEADING": "Stockage et partage photo avec cryptage de bout en bout",
"WHERE_YOUR_BEST_PHOTOS_LIVE": "Là où vivent vos meilleures photos",
@ -56,23 +56,25 @@
"NO": "Non",
"NOTHING_HERE": "Il n'y a encore rien à voir ici 👀",
"UPLOAD": "Charger",
"IMPORT": "Import",
"IMPORT": "Importer",
"ADD_PHOTOS": "Ajouter des photos",
"ADD_MORE_PHOTOS": "Ajouter plus de photos",
"add_photos_one": "Ajouter une photo",
"add_photos_other": "Ajouter {{count}} photos",
"SELECT_PHOTOS": "Sélectionner des photos",
"FILE_UPLOAD": "Fichier chargé",
"UPLOAD_STAGE_MESSAGE": {
"0": "Préparation du chargement",
"1": "Lire les fichiers métadonnées de Google",
"2": "{{uploadCounter.finished}} / {{uploadCounter.total}} files metadata extracted",
"3": "{{uploadCounter.finished}} / {{uploadCounter.total}} files backed up",
"2": "Métadonnées des fichiers {{uploadCounter.finished}} / {{uploadCounter.total}} extraites",
"3": "{{uploadCounter.finished}} / {{uploadCounter.total}} fichiers sauvegardés",
"4": "Annulation des chargements restants",
"5": "Sauvegarde terminée"
},
"UPLOADING_FILES": "Chargement de fichiers",
"FILE_NOT_UPLOADED_LIST": "Les fichiers suivants n'ont pas été chargés",
"SUBSCRIPTION_EXPIRED": "Abonnement expiré",
"SUBSCRIPTION_EXPIRED_MESSAGE": "Votre abonnement a expiré, veuillez<a>le renouvelleer</a>",
"SUBSCRIPTION_EXPIRED_MESSAGE": "Votre abonnement a expiré, veuillez <a>le renouveler </a>",
"STORAGE_QUOTA_EXCEEDED": "Limite de stockage atteinte",
"INITIAL_LOAD_DELAY_WARNING": "La première consultation peut prendre du temps",
"USER_DOES_NOT_EXIST": "Désolé, impossible de trouver un utilisateur avec cet e-mail",
@ -93,7 +95,7 @@
"NO_INTERNET_CONNECTION": "Veuillez vérifier votre connexion internet puis réessayer",
"TITLE": "ente Photos",
"UPLOAD_FIRST_PHOTO": "Chargez votre 1ere photo",
"IMPORT_YOUR_FOLDERS": "Import your folders",
"IMPORT_YOUR_FOLDERS": "Importez vos dossiers",
"UPLOAD_DROPZONE_MESSAGE": "Déposez pour sauvegarder vos fichiers",
"WATCH_FOLDER_DROPZONE_MESSAGE": "Déposez pour ajouter un dossier surveillé",
"TRASH_FILES_TITLE": "Supprimer les fichiers?",
@ -128,11 +130,11 @@
"RECOVER_ACCOUNT": "Récupérer le compte",
"RECOVERY_KEY_HINT": "Clé de récupération",
"RECOVER": "Récupérer",
"NO_RECOVERY_KEY": "Pas de clé de récuparation?",
"NO_RECOVERY_KEY": "Pas de clé de récupération?",
"INCORRECT_RECOVERY_KEY": "Clé de récupération non valide",
"SORRY": "Désolé",
"NO_RECOVERY_KEY_MESSAGE": "En raison de notre protocole de chiffrement de bout en bout, vos données ne peuvent être décryptées sans votre mot de passe ou clé de récupération",
"NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "Veuillez envoyer un e-mail à<a>{{emailID}</a> depuis votre adresse enregistrée",
"NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "Veuillez envoyer un e-mail à <a>{{emailID}}</a> depuis votre adresse enregistrée",
"CONTACT_SUPPORT": "Contacter le support",
"REQUEST_FEATURE": "Soumettre une idée",
"SUPPORT": "Support",
@ -141,11 +143,11 @@
"CANCEL": "Annuler",
"LOGOUT": "Déconnexion",
"DELETE_ACCOUNT": "Supprimer le compte",
"DELETE_ACCOUNT_MESSAGE": "<p>Veuillez envoyer un e-mail à <1>account-deletion@ente.io</1> depuis votre adresse enregistrée.</p><p>Votre demande sera traitée dans les 72 heures.</p>",
"DELETE_ACCOUNT_MESSAGE": "<p>Veuillez envoyer un e-mail à <a>{{emailID}}</a>depuis Votre adresse enregistrée.</p><p> Votre demande sera traitée dans les 72 heures.</p>",
"LOGOUT_MESSAGE": "Voulez-vous vraiment vous déconnecter?",
"CHANGE": "Modifier",
"CHANGE_EMAIL": "Modifier l'e-mail",
"OK": "OK",
"OK": "Ok",
"SUCCESS": "Parfait",
"ERROR": "Erreur",
"MESSAGE": "Message",
@ -169,11 +171,11 @@
"OFFLINE_MSG": "Vous êtes hors-ligne, les mémoires cache sont affichées",
"FREE_SUBSCRIPTION_INFO": "Vous êtes sur le plan <strong>gratuit</strong> qui expire le {{date, dateTime}}",
"FAMILY_SUBSCRIPTION_INFO": "Vous êtes sur le plan famille géré par",
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Renouveller le {{date, dateTime}}",
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "Renouveler le {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "Pris fin le {{date, dateTime}}",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "Votre abonnement sera annulé le {{date, dateTime}}",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "Vous avez dépassé votre quota de stockage,, veuillez <a> mettre à niveau </a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>Nous avons reçu votre paiement</p><p>Votre abonnement est valide jusqu'au <strong>{{date, dateTime}}</strong></p>",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "Vous avez dépassé votre quota de stockage, veuillez <a> mettre à niveau </a>",
"SUBSCRIPTION_PURCHASE_SUCCESS": "<p>Nous avons reçu votre paiement </p><p>Votre abonnement est valide jusqu'au <strong>{{date, dateTime}}</strong></p>",
"SUBSCRIPTION_PURCHASE_CANCELLED": "Votre achat est annulé, veuillez réessayer si vous souhaitez vous abonner",
"SUBSCRIPTION_VERIFICATION_FAILED": "Nous ne sommes pas encore en mesure de vérifier votre achat, cela peut prendre quelques heures",
"SUBSCRIPTION_PURCHASE_FAILED": "Échec lors de l'achat de l'abonnement, veuillez réessayer",
@ -211,7 +213,7 @@
"SHARE_WITH_PEOPLE": "Partager avec vos proches",
"SHAREES": "Partager avec",
"PUBLIC_URL": "Lien public",
"SHARE_WITH_SELF": "Oups, vous ne pouvez pas partager avec vous même",
"SHARE_WITH_SELF": "Oups, vous ne pouvez pas partager avec vous-même",
"ALREADY_SHARED": "Oups, vous partager déjà cela avec {{email}}",
"SHARING_BAD_REQUEST_ERROR": "Partage d'album non autorisé",
"SHARING_DISABLED_FOR_FREE_ACCOUNTS": "Le partage est désactivé pour les comptes gratuits",
@ -230,22 +232,22 @@
"FILE_CAPTION": "Description"
},
"photos_count_zero": "Pas de souvenirs",
"photos_count_one": "1 mémoire",
"photos_count_one": "1 souvenir",
"photos_count_other": "{{count}} souvenirs",
"TERMS_AND_CONDITIONS": "I agree to the <a>terms</a> and <b>privacy policy</b>",
"TERMS_AND_CONDITIONS": "J'accepte les <a>conditions</a> et la <b>politique de confidentialité</b>",
"CONFIRM_PASSWORD_NOT_SAVED": "<p>Je comprend que si je perd le mot de passe,je peux perdre mes données puisque mes données sont{' '}<1>chiffrées de bout en bout</1>avec ente</p>",
"ADD_TO_COLLECTION": "Ajouter à l'album",
"SELECTED": "sélectionné",
"SELECTED": "Sélectionné",
"VIDEO_PLAYBACK_FAILED": "Le format vidéo n'est pas supporté",
"VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD": "Cette vidéo ne peut pas être lue sur votre navigateur",
"PEOPLE": "People",
"INDEXING_SCHEDULED": "indexing is scheduled...",
"ANALYZING_PHOTOS": "analyzing new photos {{indexStatus.nSyncedFiles}} of {{indexStatus.nTotalFiles}} done)...",
"INDEXING_PEOPLE": "indexing people in {{indexStatus.nSyncedFiles}} photos...",
"INDEXING_DONE": "indexed {{indexStatus.nSyncedFiles}} photos",
"UNIDENTIFIED_FACES": "unidentified faces",
"OBJECTS": "objects",
"TEXT": "text",
"PEOPLE": "Visages",
"INDEXING_SCHEDULED": "L'indexation est planifiée...",
"ANALYZING_PHOTOS": "analyse des nouvelles photos {{indexStatus.nSyncedFiles}} sur {{indexStatus.nTotalFiles}} effectué)...",
"INDEXING_PEOPLE": "indexation des visages dans {{indexStatus.nSyncedFiles}} photos...",
"INDEXING_DONE": "{{indexStatus.nSyncedFiles}} photos indexées",
"UNIDENTIFIED_FACES": "visages non-identifiés",
"OBJECTS": "objets",
"TEXT": "texte",
"METADATA": "Metadonnées",
"INFO": "Info ",
"INFO_OPTION": "Info (I)",
@ -298,7 +300,6 @@
"EXPORT_DATA": "Exporter les données",
"SELECT_FOLDER": "Sélectionner un dossier",
"DESTINATION": "Destination",
"EXPORT_SIZE": "Taille d'export",
"START": "Démarrer",
"EXPORT_IN_PROGRESS": "Export en cours...",
"PAUSE": "Pause",
@ -405,7 +406,6 @@
"REPORT_SUBMIT_FAILED": "Échec lors de l'envoi du commentaire, veuillez réessayer",
"INSTALL": "Installer",
"ALBUM_URL": "Lien de l'album",
"PUBLIC_SHARING": "Lien public",
"SHARING_DETAILS": "Détails du partage",
"MODIFY_SHARING": "Modifier le partage",
"NOT_FOUND": "404 - non trouvé",
@ -454,11 +454,11 @@
"CHOOSE_UPLOAD_TYPE": "Charger",
"UPLOAD_FILES": "Fichier",
"UPLOAD_DIRS": "Dossier",
"UPLOAD_GOOGLE_TAKEOUT": "Google takeout",
"UPLOAD_GOOGLE_TAKEOUT": "Google Takeout",
"CANCEL_UPLOADS": "Annuler les chargements",
"DEDUPLICATE_FILES": "Déduplication de fichiers",
"NO_DUPLICATES_FOUND": "Vous n'avez aucun fichier dédupliqué pouvant être nettoyé",
"CLUB_BY_CAPTURE_TIME": "Club by capture time",
"CLUB_BY_CAPTURE_TIME": "Durée de la capture par club",
"FILES": "Fichiers",
"EACH": "Chacun",
"DEDUPLICATE_BASED_ON_SIZE": "Les fichiers suivants ont été clubbed, basé sur leurs tailles, veuillez corriger et supprimer les objets que vous pensez être dupliqués",
@ -466,13 +466,13 @@
"STOP_ALL_UPLOADS_MESSAGE": "Êtes-vous certains de vouloir arrêter tous les chargements en cours?",
"STOP_UPLOADS_HEADER": "Arrêter les chargements?",
"YES_STOP_UPLOADS": "Oui, arrêter tout",
"albums_one": "1 Album",
"albums_other": "{{count}} Albums",
"albums_one": "1 album",
"albums_other": "{{count}} albums",
"NEW": "Nouveau",
"VIEW_ALL_ALBUMS": "Voir tous les albums",
"ALL_ALBUMS": "Tous les albums",
"ALBUMS": "Albums",
"ENDS": "Ends",
"ENDS": "Fin",
"ENTER_TWO_FACTOR_OTP": "Saisir le code à 6 caractères de votre appli d'authentification.",
"CREATE_ACCOUNT": "Créer un compte",
"COPIED": "Copieé",
@ -534,25 +534,25 @@
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "<p>Vous avez glissé déposé un mélange de fichiers et dossiers.</p><p>Veuillez sélectionner soit uniquement des fichiers, ou des dossiers lors du choix d'options pour créer des albums séparés</p>",
"CHOSE_THEME": "Choisir un thème",
"ML_SEARCH": "ML search (beta)",
"ENABLE_ML_SEARCH_DESCRIPTION": "<p>This will enable on-device machine learning and face search which will start analyzing your uploaded photos locally.</p><p>For the first run after login or enabling this feature, it will download all images on local device to analyze them. So please only enable this if you are ok with bandwidth and local processing of all images in your photo library.</p><p>If this is the first time you're enabling this, we'll also ask your permission to process face data.</p>",
"ML_MORE_DETAILS": "More details",
"ENABLE_FACE_SEARCH": "Enable face search",
"ENABLE_FACE_SEARCH_TITLE": "Enable face search?",
"ENABLE_ML_SEARCH_DESCRIPTION": "<p>Ceci activera l'apprentissage automatique sur l'appareil et la recherche faciale qui commencera à analyser vos photos chargées.</p><p>Pour la première exécution après la connexion ou l'activation de cette fonctionnalité, cela téléchargera toutes les images sur l'appareil local pour les analyser. Veuillez donc activer ceci uniquement si vous avez de la bande passante et le traitement local de toutes les images dans votre photothèque.</p><p>Si c'est la première fois que vous activez ceci, nous vous demanderons également la permission de traiter les données faciales.</p>",
"ML_MORE_DETAILS": "Plus de détails",
"ENABLE_FACE_SEARCH": "Activer la recherche faciale",
"ENABLE_FACE_SEARCH_TITLE": "Activer la recherche faciale ?",
"ENABLE_FACE_SEARCH_DESCRIPTION": "<p>If you enable face search, ente will extract face geometry from your photos. This will happen on your device, and any generated biometric data will be end-to-encrypted.</p><p><a>Please click here for more details about this feature in our privacy policy</a></p>",
"DISABLE_BETA": "Disable beta",
"DISABLE_FACE_SEARCH": "Disable face search",
"DISABLE_FACE_SEARCH_TITLE": "Disable face search?",
"DISABLE_BETA": "Désactiver la bêta",
"DISABLE_FACE_SEARCH": "Désactiver la recherche faciale",
"DISABLE_FACE_SEARCH_TITLE": "Désactiver la recherche faciale ?",
"DISABLE_FACE_SEARCH_DESCRIPTION": "<p>ente will stop processing face geometry, and will also disable ML search (beta)</p><p>You can reenable face search again if you wish, so this operation is safe</p>",
"ADVANCED": "Advanced",
"FACE_SEARCH_CONFIRMATION": "I understand, and wish to allow ente to process face geometry",
"ADVANCED": "Avancé",
"FACE_SEARCH_CONFIRMATION": "Je comprends, et je souhaite permettre à ente de traiter la géométrie faciale",
"LABS": "Labs",
"YOURS": "Le vôtre",
"PASSPHRASE_STRENGTH": "Password strength: {{passwordStrength}}",
"PASSPHRASE_STRENGTH": "Force du mot de passe : {{passwordStrength}}",
"PREFERENCES": "Préférences",
"LANGUAGE": "Langue",
"EXPORT_DIRECTORY_DOES_NOT_EXIST": "Dossier d'export invalide",
"EXPORT_DIRECTORY_DOES_NOT_EXIST_MESSAGE": "<p> Le dossier d'export que vous avez sélectionné n'existe pas </p><p>Veuillez sélectionner un dossier valide</p>",
"SUBSCRIPTION_VERIFICATION_ERROR": "Subscription verification failed",
"SUBSCRIPTION_VERIFICATION_ERROR": "Échec de la vérification de l'abonnement",
"STORAGE_UNITS": {
"B": "o",
"KB": "Ko",
@ -566,5 +566,27 @@
"WEEK": "dans une semaine",
"MONTH": "dans un mois",
"YEAR": "dans un an"
}
},
"COPY_LINK": "Copier le lien",
"DONE": "Terminé",
"ADD_EMAIL_TITLE": "Partager avec des personnes spécifiques",
"LINK_SHARE_TITLE": "Ou partager un lien",
"REMOVE_LINK": "Supprimer le lien",
"CREATE_PUBLIC_SHARING": "Créer un lien public",
"PUBLIC_LINK_CREATED": "Lien public créé",
"PUBLIC_LINK_ENABLED": "Lien public activé",
"COLLECT_PHOTOS": "Récupérer les photos",
"PUBLIC_COLLECT_SUBTEXT": "Autoriser les personnes ayant le lien d'ajouter des photos à l'album partagé.",
"STOP_EXPORT": "Stop",
"EXPORT_PROGRESS": "<a>{{progress.current}} / {{progress.total}}</a> fichiers exportés",
"EXPORT_NOTIFICATION": {
"START": "L'export a démarré",
"IN_PROGRESS": "Un export est déjà en cours",
"FINISH": "Export terminé",
"UP_TO_DATE": "Aucun nouveau fichier à exporter"
},
"CONTINUOUS_EXPORT": "Synchronisation en continu",
"TOTAL_ITEMS": "Total d'objets",
"PENDING_ITEMS": "Objets en attente",
"EXPORT_STARTING": "Démarrage de l'export..."
}

View file

@ -0,0 +1,592 @@
{
"HERO_SLIDE_1_TITLE": "",
"HERO_SLIDE_1": "",
"HERO_SLIDE_2_TITLE": "",
"HERO_SLIDE_2": "",
"HERO_SLIDE_3_TITLE": "",
"HERO_SLIDE_3": "",
"LOGIN": "",
"SIGN_UP": "",
"NEW_USER": "",
"EXISTING_USER": "",
"NAME": "",
"ENTER_NAME": "",
"PUBLIC_UPLOADER_NAME_MESSAGE": "",
"EMAIL": "",
"ENTER_EMAIL": "",
"DATA_DISCLAIMER": "",
"SUBMIT": "",
"EMAIL_ERROR": "",
"REQUIRED": "",
"VERIFY_EMAIL": "",
"EMAIL_SENT": "",
"CHECK_INBOX": "",
"ENTER_OTT": "",
"RESEND_MAIL": "",
"VERIFY": "",
"UNKNOWN_ERROR": "",
"INVALID_CODE": "",
"EXPIRED_CODE": "",
"SENDING": "",
"SENT": "",
"PASSWORD": "",
"LINK_PASSWORD": "",
"ENTER_PASSPHRASE": "",
"RETURN_PASSPHRASE_HINT": "",
"SET_PASSPHRASE": "",
"VERIFY_PASSPHRASE": "",
"INCORRECT_PASSPHRASE": "",
"ENTER_ENC_PASSPHRASE": "",
"PASSPHRASE_DISCLAIMER": "",
"WELCOME_TO_ENTE_HEADING": "",
"WELCOME_TO_ENTE_SUBHEADING": "",
"WHERE_YOUR_BEST_PHOTOS_LIVE": "",
"KEY_GENERATION_IN_PROGRESS_MESSAGE": "",
"PASSPHRASE_HINT": "",
"CONFIRM_PASSPHRASE": "",
"PASSPHRASE_MATCH_ERROR": "",
"CONSOLE_WARNING_STOP": "",
"CONSOLE_WARNING_DESC": "",
"SELECT_COLLECTION": "",
"CREATE_COLLECTION": "",
"ENTER_ALBUM_NAME": "",
"CLOSE_OPTION": "",
"ENTER_FILE_NAME": "",
"CLOSE": "",
"NO": "",
"NOTHING_HERE": "",
"UPLOAD": "",
"IMPORT": "",
"ADD_PHOTOS": "",
"ADD_MORE_PHOTOS": "",
"add_photos_one": "",
"add_photos_other": "",
"SELECT_PHOTOS": "",
"FILE_UPLOAD": "",
"UPLOAD_STAGE_MESSAGE": {
"0": "",
"1": "",
"2": "",
"3": "",
"4": "",
"5": ""
},
"UPLOADING_FILES": "",
"FILE_NOT_UPLOADED_LIST": "",
"SUBSCRIPTION_EXPIRED": "",
"SUBSCRIPTION_EXPIRED_MESSAGE": "",
"STORAGE_QUOTA_EXCEEDED": "",
"INITIAL_LOAD_DELAY_WARNING": "",
"USER_DOES_NOT_EXIST": "",
"UPLOAD_BUTTON_TEXT": "",
"NO_ACCOUNT": "",
"ACCOUNT_EXISTS": "",
"ALBUM_NAME": "",
"CREATE": "",
"DOWNLOAD": "",
"DOWNLOAD_OPTION": "",
"DOWNLOAD_FAVORITES": "",
"DOWNLOAD_UNCATEGORIZED": "",
"COPY_OPTION": "",
"TOGGLE_FULLSCREEN": "",
"ZOOM_IN_OUT": "",
"PREVIOUS": "",
"NEXT": "",
"NO_INTERNET_CONNECTION": "",
"TITLE": "",
"UPLOAD_FIRST_PHOTO": "",
"IMPORT_YOUR_FOLDERS": "",
"UPLOAD_DROPZONE_MESSAGE": "",
"WATCH_FOLDER_DROPZONE_MESSAGE": "",
"TRASH_FILES_TITLE": "",
"TRASH_FILE_TITLE": "",
"DELETE_FILES_TITLE": "",
"DELETE_FILES_MESSAGE": "",
"DELETE_FILE": "",
"DELETE": "",
"DELETE_OPTION": "",
"FAVORITE": "",
"FAVORITE_OPTION": "",
"UNFAVORITE_OPTION": "",
"UNFAVORITE": "",
"MULTI_FOLDER_UPLOAD": "",
"UPLOAD_STRATEGY_CHOICE": "",
"UPLOAD_STRATEGY_SINGLE_COLLECTION": "",
"OR": "",
"UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "",
"SESSION_EXPIRED_MESSAGE": "",
"SESSION_EXPIRED": "",
"SYNC_FAILED": "",
"PASSWORD_GENERATION_FAILED": "",
"CHANGE_PASSWORD": "",
"GO_BACK": "",
"RECOVERY_KEY": "",
"SAVE_LATER": "",
"SAVE": "",
"RECOVERY_KEY_DESCRIPTION": "",
"RECOVER_KEY_GENERATION_FAILED": "",
"KEY_NOT_STORED_DISCLAIMER": "",
"FORGOT_PASSWORD": "",
"RECOVER_ACCOUNT": "",
"RECOVERY_KEY_HINT": "",
"RECOVER": "",
"NO_RECOVERY_KEY": "",
"INCORRECT_RECOVERY_KEY": "",
"SORRY": "",
"NO_RECOVERY_KEY_MESSAGE": "",
"NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "",
"CONTACT_SUPPORT": "",
"REQUEST_FEATURE": "",
"SUPPORT": "",
"CONFIRM": "",
"SKIP_SUBSCRIPTION_PURCHASE": "",
"CANCEL": "",
"LOGOUT": "",
"DELETE_ACCOUNT": "",
"DELETE_ACCOUNT_MESSAGE": "",
"LOGOUT_MESSAGE": "",
"CHANGE": "",
"CHANGE_EMAIL": "",
"OK": "",
"SUCCESS": "",
"ERROR": "",
"MESSAGE": "",
"INSTALL_MOBILE_APP": "",
"DOWNLOAD_APP_MESSAGE": "",
"DOWNLOAD_APP": "",
"EXPORT": "",
"SUBSCRIPTION": "",
"SUBSCRIBE": "",
"SUBSCRIPTION_PLAN": "",
"USAGE_DETAILS": "",
"MANAGE": "",
"MANAGEMENT_PORTAL": "",
"MANAGE_FAMILY_PORTAL": "",
"LEAVE_FAMILY_PLAN": "",
"LEAVE": "",
"LEAVE_FAMILY_CONFIRM": "",
"CHOOSE_PLAN": "",
"MANAGE_PLAN": "",
"ACTIVE": "",
"OFFLINE_MSG": "",
"FREE_SUBSCRIPTION_INFO": "",
"FAMILY_SUBSCRIPTION_INFO": "",
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
"SUBSCRIPTION_VERIFICATION_FAILED": "",
"SUBSCRIPTION_PURCHASE_FAILED": "",
"SUBSCRIPTION_UPDATE_FAILED": "",
"UPDATE_PAYMENT_METHOD_MESSAGE": "",
"STRIPE_AUTHENTICATION_FAILED": "",
"UPDATE_PAYMENT_METHOD": "",
"MONTHLY": "",
"YEARLY": "",
"UPDATE_SUBSCRIPTION_MESSAGE": "",
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",
"REACTIVATE_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_ACTIVATE_SUCCESS": "",
"SUBSCRIPTION_ACTIVATE_FAILED": "",
"SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE": "",
"MAIL_TO_MANAGE_SUBSCRIPTION": "",
"RENAME": "",
"RENAME_FILE": "",
"RENAME_COLLECTION": "",
"DELETE_COLLECTION_TITLE": "",
"DELETE_COLLECTION": "",
"DELETE_COLLECTION_FAILED": "",
"DELETE_COLLECTION_MESSAGE": "",
"DELETE_PHOTOS": "",
"KEEP_PHOTOS": "",
"SHARE": "",
"SHARE_COLLECTION": "",
"SHARE_WITH_PEOPLE": "",
"SHAREES": "",
"PUBLIC_URL": "",
"SHARE_WITH_SELF": "",
"ALREADY_SHARED": "",
"SHARING_BAD_REQUEST_ERROR": "",
"SHARING_DISABLED_FOR_FREE_ACCOUNTS": "",
"DOWNLOAD_COLLECTION": "",
"DOWNLOAD_COLLECTION_MESSAGE": "",
"DOWNLOAD_COLLECTION_FAILED": "",
"CREATE_ALBUM_FAILED": "",
"SEARCH_RESULTS": "",
"SEARCH_HINT": "",
"SEARCH_TYPE": {
"COLLECTION": "",
"LOCATION": "",
"DATE": "",
"FILE_NAME": "",
"THING": "",
"FILE_CAPTION": ""
},
"photos_count_zero": "",
"photos_count_one": "",
"photos_count_other": "",
"TERMS_AND_CONDITIONS": "",
"CONFIRM_PASSWORD_NOT_SAVED": "",
"ADD_TO_COLLECTION": "",
"SELECTED": "",
"VIDEO_PLAYBACK_FAILED": "",
"VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD": "",
"PEOPLE": "",
"INDEXING_SCHEDULED": "",
"ANALYZING_PHOTOS": "",
"INDEXING_PEOPLE": "",
"INDEXING_DONE": "",
"UNIDENTIFIED_FACES": "",
"OBJECTS": "",
"TEXT": "",
"METADATA": "",
"INFO": "",
"INFO_OPTION": "",
"FILE_ID": "",
"FILE_NAME": "",
"CAPTION": "",
"CAPTION_PLACEHOLDER": "",
"CREATION_TIME": "",
"UPDATED_ON": "",
"LOCATION": "",
"SHOW_ON_MAP": "",
"DETAILS": "",
"VIEW_EXIF": "",
"NO_EXIF": "",
"EXIF": "",
"DEVICE": "",
"IMAGE_SIZE": "",
"FLASH": "",
"FOCAL_LENGTH": "",
"APERTURE": "",
"ISO": "",
"SHOW_ALL": "",
"TWO_FACTOR": "",
"TWO_FACTOR_AUTHENTICATION": "",
"TWO_FACTOR_QR_INSTRUCTION": "",
"ENTER_CODE_MANUALLY": "",
"TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "",
"SCAN_QR_CODE": "",
"CONTINUE": "",
"BACK": "",
"ENABLE_TWO_FACTOR": "",
"ENABLE": "",
"LOST_DEVICE": "",
"INCORRECT_CODE": "",
"RECOVER_TWO_FACTOR": "",
"TWO_FACTOR_INFO": "",
"DISABLE_TWO_FACTOR_LABEL": "",
"UPDATE_TWO_FACTOR_LABEL": "",
"DISABLE": "",
"RECONFIGURE": "",
"UPDATE_TWO_FACTOR": "",
"UPDATE_TWO_FACTOR_MESSAGE": "",
"UPDATE": "",
"DISABLE_TWO_FACTOR": "",
"DISABLE_TWO_FACTOR_MESSAGE": "",
"TWO_FACTOR_SETUP_FAILED": "",
"TWO_FACTOR_SETUP_SUCCESS": "",
"TWO_FACTOR_DISABLE_SUCCESS": "",
"TWO_FACTOR_DISABLE_FAILED": "",
"EXPORT_DATA": "",
"SELECT_FOLDER": "",
"DESTINATION": "",
"START": "",
"EXPORT_IN_PROGRESS": "",
"PAUSE": "",
"RESUME": "",
"MINIMIZE": "",
"LAST_EXPORT_TIME": "",
"SUCCESSFULLY_EXPORTED_FILES": "",
"FAILED_EXPORTED_FILES": "",
"EXPORT_AGAIN": "",
"RETRY_EXPORT": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "",
"RETRY": "",
"SEND_OTT": "",
"EMAIl_ALREADY_OWNED": "",
"EMAIL_UDPATE_SUCCESSFUL": "",
"UPLOAD_FAILED": "",
"ETAGS_BLOCKED": "",
"SKIPPED_VIDEOS_INFO": "",
"LIVE_PHOTOS_DETECTED": "",
"RETRY_FAILED": "",
"FAILED_UPLOADS": "",
"SKIPPED_FILES": "",
"THUMBNAIL_GENERATION_FAILED_UPLOADS": "",
"UNSUPPORTED_FILES": "",
"SUCCESSFUL_UPLOADS": "",
"SKIPPED_INFO": "",
"UNSUPPORTED_INFO": "",
"BLOCKED_UPLOADS": "",
"SKIPPED_VIDEOS": "",
"INPROGRESS_METADATA_EXTRACTION": "",
"INPROGRESS_UPLOADS": "",
"TOO_LARGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_INFO": "",
"TOO_LARGE_INFO": "",
"THUMBNAIL_GENERATION_FAILED_INFO": "",
"UPLOAD_TO_COLLECTION": "",
"UNCATEGORIZED": "",
"MOVE_TO_UNCATEGORIZED": "",
"ARCHIVE": "",
"ARCHIVE_COLLECTION": "",
"ARCHIVE_SECTION_NAME": "",
"ALL_SECTION_NAME": "",
"MOVE_TO_COLLECTION": "",
"UNARCHIVE": "",
"UNARCHIVE_COLLECTION": "",
"MOVE": "",
"ADD": "",
"SORT": "",
"REMOVE": "",
"YES_REMOVE": "",
"CONFIRM_REMOVE": "",
"REMOVE_FROM_COLLECTION": "",
"TRASH": "",
"MOVE_TO_TRASH": "",
"TRASH_FILES_MESSAGE": "",
"TRASH_FILE_MESSAGE": "",
"DELETE_PERMANENTLY": "",
"RESTORE": "",
"CONFIRM_RESTORE": "",
"RESTORE_MESSAGE": "",
"RESTORE_TO_COLLECTION": "",
"EMPTY_TRASH": "",
"EMPTY_TRASH_TITLE": "",
"EMPTY_TRASH_MESSAGE": "",
"LEAVE_SHARED_ALBUM": "",
"LEAVE_ALBUM": "",
"LEAVE_SHARED_ALBUM_TITLE": "",
"LEAVE_SHARED_ALBUM_MESSAGE": "",
"NOT_FILE_OWNER": "",
"CONFIRM_SELF_REMOVE_MESSAGE": "",
"CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE": "",
"SORT_BY_CREATION_TIME_ASCENDING": "",
"SORT_BY_CREATION_TIME_DESCENDING": "",
"SORT_BY_UPDATION_TIME_DESCENDING": "",
"SORT_BY_NAME": "",
"COMPRESS_THUMBNAILS": "",
"THUMBNAIL_REPLACED": "",
"FIX_THUMBNAIL": "",
"FIX_THUMBNAIL_LATER": "",
"REPLACE_THUMBNAIL_NOT_STARTED": "",
"REPLACE_THUMBNAIL_COMPLETED": "",
"REPLACE_THUMBNAIL_NOOP": "",
"REPLACE_THUMBNAIL_COMPLETED_WITH_ERROR": "",
"FIX_CREATION_TIME": "",
"FIX_CREATION_TIME_IN_PROGRESS": "",
"CREATION_TIME_UPDATED": "",
"UPDATE_CREATION_TIME_NOT_STARTED": "",
"UPDATE_CREATION_TIME_COMPLETED": "",
"UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR": "",
"FILE_NAME_CHARACTER_LIMIT": "",
"CAPTION_CHARACTER_LIMIT": "",
"DATE_TIME_ORIGINAL": "",
"DATE_TIME_DIGITIZED": "",
"CUSTOM_TIME": "",
"REOPEN_PLAN_SELECTOR_MODAL": "",
"OPEN_PLAN_SELECTOR_MODAL_FAILED": "",
"COMMENT": "",
"ABUSE_REPORT_DESCRIPTION": "",
"OTHER_REASON_REQUIRES_COMMENTS": "",
"REPORT_SUBMIT_SUCCESS_CONTENT": "",
"REPORT_SUBMIT_SUCCESS_TITLE": "",
"REPORT_SUBMIT_FAILED": "",
"INSTALL": "",
"ALBUM_URL": "",
"SHARING_DETAILS": "",
"MODIFY_SHARING": "",
"NOT_FOUND": "",
"LINK_EXPIRED": "",
"LINK_EXPIRED_MESSAGE": "",
"MANAGE_LINK": "",
"LINK_TOO_MANY_REQUESTS": "",
"DISABLE_PUBLIC_SHARING": "",
"DISABLE_PUBLIC_SHARING_MESSAGE": "",
"FILE_DOWNLOAD": "",
"LINK_PASSWORD_LOCK": "",
"PUBLIC_COLLECT": "",
"LINK_DEVICE_LIMIT": "",
"LINK_EXPIRY": "",
"LINK_EXPIRY_NEVER": "",
"DISABLE_FILE_DOWNLOAD": "",
"DISABLE_FILE_DOWNLOAD_MESSAGE": "",
"ABUSE_REPORT": "",
"ABUSE_REPORT_BUTTON_TEXT": "",
"MALICIOUS_CONTENT": "",
"COPYRIGHT": "",
"ENTER_EMAIL_ADDRESS": "",
"SELECT_REASON": "",
"ENTER_FULL_NAME": "",
"ENTER_DIGITAL_SIGNATURE": "",
"ENTER_ON_BEHALF_OF": "",
"ENTER_ADDRESS": "",
"ENTER_JOB_TITLE": "",
"ENTER_CITY": "",
"ENTER_PHONE": "",
"ENTER_STATE": "",
"ENTER_POSTAL_CODE": "",
"ENTER_COUNTRY": "",
"JUDICIAL_DESCRIPTION": "",
"TERM_1": "",
"TERM_2": "",
"TERM_3": "",
"SHARED_USING": "",
"ENTE_IO": "",
"LIVE": "",
"DISABLE_PASSWORD": "",
"DISABLE_PASSWORD_MESSAGE": "",
"PASSWORD_LOCK": "",
"LOCK": "",
"DOWNLOAD_UPLOAD_LOGS": "",
"CHOOSE_UPLOAD_TYPE": "",
"UPLOAD_FILES": "",
"UPLOAD_DIRS": "",
"UPLOAD_GOOGLE_TAKEOUT": "",
"CANCEL_UPLOADS": "",
"DEDUPLICATE_FILES": "",
"NO_DUPLICATES_FOUND": "",
"CLUB_BY_CAPTURE_TIME": "",
"FILES": "",
"EACH": "",
"DEDUPLICATE_BASED_ON_SIZE": "",
"DEDUPLICATE_BASED_ON_SIZE_AND_CAPTURE_TIME": "",
"STOP_ALL_UPLOADS_MESSAGE": "",
"STOP_UPLOADS_HEADER": "",
"YES_STOP_UPLOADS": "",
"albums_one": "",
"albums_other": "",
"NEW": "",
"VIEW_ALL_ALBUMS": "",
"ALL_ALBUMS": "",
"ALBUMS": "",
"ENDS": "",
"ENTER_TWO_FACTOR_OTP": "",
"CREATE_ACCOUNT": "",
"COPIED": "",
"CANVAS_BLOCKED_TITLE": "",
"CANVAS_BLOCKED_MESSAGE": "",
"WATCH_FOLDERS": "",
"UPGRADE_NOW": "",
"RENEW_NOW": "",
"STORAGE": "",
"USED": "",
"YOU": "",
"FAMILY": "",
"FREE": "",
"OF": "",
"WATCHED_FOLDERS": "",
"NO_FOLDERS_ADDED": "",
"FOLDERS_AUTOMATICALLY_MONITORED": "",
"UPLOAD_NEW_FILES_TO_ENTE": "",
"REMOVE_DELETED_FILES_FROM_ENTE": "",
"ADD_FOLDER": "",
"STOP_WATCHING": "",
"STOP_WATCHING_FOLDER": "",
"STOP_WATCHING_DIALOG_MESSAGE": "",
"YES_STOP": "",
"MONTH_SHORT": "",
"YEAR": "",
"FAMILY_PLAN": "",
"DOWNLOAD_LOGS": "",
"DOWNLOAD_LOGS_MESSAGE": "",
"CHANGE_FOLDER": "",
"TWO_MONTHS_FREE": "",
"GB": "",
"POPULAR": "",
"FREE_PLAN_OPTION_LABEL": "",
"FREE_PLAN_DESCRIPTION": "",
"CURRENT_USAGE": "",
"WEAK_DEVICE": "",
"DRAG_AND_DROP_HINT": "",
"ASK_FOR_FEEDBACK": "",
"SEND_FEEDBACK": "",
"CONFIRM_ACCOUNT_DELETION_TITLE": "",
"CONFIRM_ACCOUNT_DELETION_MESSAGE": "",
"AUTHENTICATE": "",
"UPLOADED_TO_SINGLE_COLLECTION": "",
"UPLOADED_TO_SEPARATE_COLLECTIONS": "",
"NEVERMIND": "",
"UPDATE_AVAILABLE": "",
"UPDATE_INSTALLABLE_MESSAGE": "",
"INSTALL_NOW": "",
"INSTALL_ON_NEXT_LAUNCH": "",
"UPDATE_AVAILABLE_MESSAGE": "",
"DOWNLOAD_AND_INSTALL": "",
"IGNORE_THIS_VERSION": "",
"TODAY": "",
"YESTERDAY": "",
"AT": "",
"NAME_PLACEHOLDER": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "",
"CHOSE_THEME": "",
"ML_SEARCH": "",
"ENABLE_ML_SEARCH_DESCRIPTION": "",
"ML_MORE_DETAILS": "",
"ENABLE_FACE_SEARCH": "",
"ENABLE_FACE_SEARCH_TITLE": "",
"ENABLE_FACE_SEARCH_DESCRIPTION": "",
"DISABLE_BETA": "",
"DISABLE_FACE_SEARCH": "",
"DISABLE_FACE_SEARCH_TITLE": "",
"DISABLE_FACE_SEARCH_DESCRIPTION": "",
"ADVANCED": "",
"FACE_SEARCH_CONFIRMATION": "",
"LABS": "",
"YOURS": "",
"PASSPHRASE_STRENGTH": "",
"PREFERENCES": "",
"LANGUAGE": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST_MESSAGE": "",
"SUBSCRIPTION_VERIFICATION_ERROR": "",
"STORAGE_UNITS": {
"B": "",
"KB": "",
"MB": "",
"GB": "",
"TB": ""
},
"AFTER_TIME": {
"HOUR": "",
"DAY": "",
"WEEK": "",
"MONTH": "",
"YEAR": ""
},
"COPY_LINK": "",
"DONE": "",
"ADD_EMAIL_TITLE": "",
"LINK_SHARE_TITLE": "",
"REMOVE_LINK": "",
"CREATE_PUBLIC_SHARING": "",
"PUBLIC_LINK_CREATED": "",
"PUBLIC_LINK_ENABLED": "",
"COLLECT_PHOTOS": "",
"PUBLIC_COLLECT_SUBTEXT": "",
"STOP_EXPORT": "",
"EXPORT_PROGRESS": "",
"EXPORT_NOTIFICATION": {
"START": "",
"IN_PROGRESS": "",
"FINISH": "",
"UP_TO_DATE": ""
},
"CONTINUOUS_EXPORT": "",
"TOTAL_ITEMS": "",
"PENDING_ITEMS": "",
"EXPORT_STARTING": ""
}

View file

@ -0,0 +1,592 @@
{
"HERO_SLIDE_1_TITLE": "<div>Privé back-ups</div><div>voor uw herinneringen</div>",
"HERO_SLIDE_1": "Standaard end-to-end versleuteld",
"HERO_SLIDE_2_TITLE": "<div>Veilig opgeslagen</div><div>in een kernbunker</div>",
"HERO_SLIDE_2": "Ontworpen om levenslang mee te gaan",
"HERO_SLIDE_3_TITLE": "<div>Overal</div><div> beschikbaar</div>",
"HERO_SLIDE_3": "Android, iOS, Web, Desktop",
"LOGIN": "Inloggen",
"SIGN_UP": "Registreren",
"NEW_USER": "Nieuw bij ente",
"EXISTING_USER": "Bestaande gebruiker",
"NAME": "Naam",
"ENTER_NAME": "Naam invoeren",
"PUBLIC_UPLOADER_NAME_MESSAGE": "Voeg een naam toe zodat je vrienden weten wie ze moeten bedanken voor deze geweldige foto's!",
"EMAIL": "E-mail",
"ENTER_EMAIL": "Vul e-mailadres in",
"DATA_DISCLAIMER": "We geven jouw data nooit door aan derden.",
"SUBMIT": "Verzenden",
"EMAIL_ERROR": "Vul een geldig e-mailadres in",
"REQUIRED": "Vereist",
"VERIFY_EMAIL": "Bevestig e-mail",
"EMAIL_SENT": "Verificatiecode verzonden naar <a>{{email}}</a>",
"CHECK_INBOX": "Controleer je inbox (en spam) om verificatie te voltooien",
"ENTER_OTT": "Verificatiecode",
"RESEND_MAIL": "Code opnieuw versturen",
"VERIFY": "Verifiëren",
"UNKNOWN_ERROR": "Er is iets fout gegaan, probeer het opnieuw",
"INVALID_CODE": "Ongeldige verificatiecode",
"EXPIRED_CODE": "Uw verificatiecode is verlopen",
"SENDING": "Verzenden...",
"SENT": "Verzonden!",
"PASSWORD": "Wachtwoord",
"LINK_PASSWORD": "Voer wachtwoord in om het album te ontgrendelen",
"ENTER_PASSPHRASE": "Voer je wachtwoord in",
"RETURN_PASSPHRASE_HINT": "Wachtwoord",
"SET_PASSPHRASE": "Wachtwoord instellen",
"VERIFY_PASSPHRASE": "Aanmelden",
"INCORRECT_PASSPHRASE": "Onjuist wachtwoord",
"ENTER_ENC_PASSPHRASE": "Voer een wachtwoord in dat we kunnen gebruiken om je gegevens te versleutelen",
"PASSPHRASE_DISCLAIMER": "We slaan je wachtwoord niet op, dus als je het vergeet, <strong>zullen we u niet kunnen helpen </strong>uw data te herstellen zonder een herstelcode.",
"WELCOME_TO_ENTE_HEADING": "Welkom bij <a/>",
"WELCOME_TO_ENTE_SUBHEADING": "Foto opslag en delen met end to end encryptie",
"WHERE_YOUR_BEST_PHOTOS_LIVE": "Waar je beste foto's leven",
"KEY_GENERATION_IN_PROGRESS_MESSAGE": "Encryptiecodes worden gegenereerd...",
"PASSPHRASE_HINT": "Wachtwoord",
"CONFIRM_PASSPHRASE": "Wachtwoord bevestigen",
"PASSPHRASE_MATCH_ERROR": "Wachtwoorden komen niet overeen",
"CONSOLE_WARNING_STOP": "STOP!",
"CONSOLE_WARNING_DESC": "Dit is een browserfunctie bedoeld voor ontwikkelaars. Gelieve hier geen niet-geverifieerde code te kopiëren/plakken.",
"SELECT_COLLECTION": "Selecteer een album om de foto's naar te uploaden",
"CREATE_COLLECTION": "Nieuw album",
"ENTER_ALBUM_NAME": "Album naam",
"CLOSE_OPTION": "Sluiten (Esc)",
"ENTER_FILE_NAME": "",
"CLOSE": "",
"NO": "",
"NOTHING_HERE": "",
"UPLOAD": "",
"IMPORT": "",
"ADD_PHOTOS": "",
"ADD_MORE_PHOTOS": "",
"add_photos_one": "",
"add_photos_other": "",
"SELECT_PHOTOS": "",
"FILE_UPLOAD": "",
"UPLOAD_STAGE_MESSAGE": {
"0": "",
"1": "",
"2": "",
"3": "",
"4": "",
"5": ""
},
"UPLOADING_FILES": "",
"FILE_NOT_UPLOADED_LIST": "",
"SUBSCRIPTION_EXPIRED": "",
"SUBSCRIPTION_EXPIRED_MESSAGE": "",
"STORAGE_QUOTA_EXCEEDED": "",
"INITIAL_LOAD_DELAY_WARNING": "",
"USER_DOES_NOT_EXIST": "",
"UPLOAD_BUTTON_TEXT": "",
"NO_ACCOUNT": "",
"ACCOUNT_EXISTS": "",
"ALBUM_NAME": "",
"CREATE": "",
"DOWNLOAD": "",
"DOWNLOAD_OPTION": "",
"DOWNLOAD_FAVORITES": "",
"DOWNLOAD_UNCATEGORIZED": "",
"COPY_OPTION": "",
"TOGGLE_FULLSCREEN": "",
"ZOOM_IN_OUT": "",
"PREVIOUS": "",
"NEXT": "",
"NO_INTERNET_CONNECTION": "",
"TITLE": "",
"UPLOAD_FIRST_PHOTO": "",
"IMPORT_YOUR_FOLDERS": "",
"UPLOAD_DROPZONE_MESSAGE": "",
"WATCH_FOLDER_DROPZONE_MESSAGE": "",
"TRASH_FILES_TITLE": "",
"TRASH_FILE_TITLE": "",
"DELETE_FILES_TITLE": "",
"DELETE_FILES_MESSAGE": "",
"DELETE_FILE": "",
"DELETE": "",
"DELETE_OPTION": "",
"FAVORITE": "",
"FAVORITE_OPTION": "",
"UNFAVORITE_OPTION": "",
"UNFAVORITE": "",
"MULTI_FOLDER_UPLOAD": "",
"UPLOAD_STRATEGY_CHOICE": "",
"UPLOAD_STRATEGY_SINGLE_COLLECTION": "",
"OR": "",
"UPLOAD_STRATEGY_COLLECTION_PER_FOLDER": "",
"SESSION_EXPIRED_MESSAGE": "",
"SESSION_EXPIRED": "",
"SYNC_FAILED": "",
"PASSWORD_GENERATION_FAILED": "",
"CHANGE_PASSWORD": "",
"GO_BACK": "",
"RECOVERY_KEY": "",
"SAVE_LATER": "",
"SAVE": "",
"RECOVERY_KEY_DESCRIPTION": "",
"RECOVER_KEY_GENERATION_FAILED": "",
"KEY_NOT_STORED_DISCLAIMER": "",
"FORGOT_PASSWORD": "",
"RECOVER_ACCOUNT": "",
"RECOVERY_KEY_HINT": "",
"RECOVER": "",
"NO_RECOVERY_KEY": "",
"INCORRECT_RECOVERY_KEY": "",
"SORRY": "",
"NO_RECOVERY_KEY_MESSAGE": "",
"NO_TWO_FACTOR_RECOVERY_KEY_MESSAGE": "",
"CONTACT_SUPPORT": "",
"REQUEST_FEATURE": "",
"SUPPORT": "",
"CONFIRM": "",
"SKIP_SUBSCRIPTION_PURCHASE": "",
"CANCEL": "",
"LOGOUT": "",
"DELETE_ACCOUNT": "",
"DELETE_ACCOUNT_MESSAGE": "",
"LOGOUT_MESSAGE": "",
"CHANGE": "",
"CHANGE_EMAIL": "",
"OK": "",
"SUCCESS": "",
"ERROR": "",
"MESSAGE": "",
"INSTALL_MOBILE_APP": "",
"DOWNLOAD_APP_MESSAGE": "",
"DOWNLOAD_APP": "",
"EXPORT": "",
"SUBSCRIPTION": "",
"SUBSCRIBE": "",
"SUBSCRIPTION_PLAN": "",
"USAGE_DETAILS": "",
"MANAGE": "",
"MANAGEMENT_PORTAL": "",
"MANAGE_FAMILY_PORTAL": "",
"LEAVE_FAMILY_PLAN": "",
"LEAVE": "",
"LEAVE_FAMILY_CONFIRM": "",
"CHOOSE_PLAN": "",
"MANAGE_PLAN": "",
"ACTIVE": "",
"OFFLINE_MSG": "",
"FREE_SUBSCRIPTION_INFO": "",
"FAMILY_SUBSCRIPTION_INFO": "",
"RENEWAL_ACTIVE_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_STATUS": "",
"RENEWAL_CANCELLED_SUBSCRIPTION_INFO": "",
"STORAGE_QUOTA_EXCEEDED_SUBSCRIPTION_INFO": "",
"SUBSCRIPTION_PURCHASE_SUCCESS": "",
"SUBSCRIPTION_PURCHASE_CANCELLED": "",
"SUBSCRIPTION_VERIFICATION_FAILED": "",
"SUBSCRIPTION_PURCHASE_FAILED": "",
"SUBSCRIPTION_UPDATE_FAILED": "",
"UPDATE_PAYMENT_METHOD_MESSAGE": "",
"STRIPE_AUTHENTICATION_FAILED": "",
"UPDATE_PAYMENT_METHOD": "",
"MONTHLY": "",
"YEARLY": "",
"UPDATE_SUBSCRIPTION_MESSAGE": "",
"UPDATE_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION": "",
"CANCEL_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_CANCEL_FAILED": "",
"SUBSCRIPTION_CANCEL_SUCCESS": "",
"REACTIVATE_SUBSCRIPTION": "",
"REACTIVATE_SUBSCRIPTION_MESSAGE": "",
"SUBSCRIPTION_ACTIVATE_SUCCESS": "",
"SUBSCRIPTION_ACTIVATE_FAILED": "",
"SUBSCRIPTION_PURCHASE_SUCCESS_TITLE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE": "",
"CANCEL_SUBSCRIPTION_ON_MOBILE_MESSAGE": "",
"MAIL_TO_MANAGE_SUBSCRIPTION": "",
"RENAME": "",
"RENAME_FILE": "",
"RENAME_COLLECTION": "",
"DELETE_COLLECTION_TITLE": "",
"DELETE_COLLECTION": "",
"DELETE_COLLECTION_FAILED": "",
"DELETE_COLLECTION_MESSAGE": "",
"DELETE_PHOTOS": "",
"KEEP_PHOTOS": "",
"SHARE": "",
"SHARE_COLLECTION": "",
"SHARE_WITH_PEOPLE": "",
"SHAREES": "",
"PUBLIC_URL": "",
"SHARE_WITH_SELF": "",
"ALREADY_SHARED": "",
"SHARING_BAD_REQUEST_ERROR": "",
"SHARING_DISABLED_FOR_FREE_ACCOUNTS": "",
"DOWNLOAD_COLLECTION": "",
"DOWNLOAD_COLLECTION_MESSAGE": "",
"DOWNLOAD_COLLECTION_FAILED": "",
"CREATE_ALBUM_FAILED": "",
"SEARCH_RESULTS": "",
"SEARCH_HINT": "",
"SEARCH_TYPE": {
"COLLECTION": "",
"LOCATION": "",
"DATE": "",
"FILE_NAME": "",
"THING": "",
"FILE_CAPTION": ""
},
"photos_count_zero": "",
"photos_count_one": "",
"photos_count_other": "",
"TERMS_AND_CONDITIONS": "",
"CONFIRM_PASSWORD_NOT_SAVED": "",
"ADD_TO_COLLECTION": "",
"SELECTED": "",
"VIDEO_PLAYBACK_FAILED": "",
"VIDEO_PLAYBACK_FAILED_DOWNLOAD_INSTEAD": "",
"PEOPLE": "",
"INDEXING_SCHEDULED": "",
"ANALYZING_PHOTOS": "",
"INDEXING_PEOPLE": "",
"INDEXING_DONE": "",
"UNIDENTIFIED_FACES": "",
"OBJECTS": "",
"TEXT": "",
"METADATA": "",
"INFO": "",
"INFO_OPTION": "",
"FILE_ID": "",
"FILE_NAME": "",
"CAPTION": "",
"CAPTION_PLACEHOLDER": "",
"CREATION_TIME": "",
"UPDATED_ON": "",
"LOCATION": "",
"SHOW_ON_MAP": "",
"DETAILS": "",
"VIEW_EXIF": "",
"NO_EXIF": "",
"EXIF": "",
"DEVICE": "",
"IMAGE_SIZE": "",
"FLASH": "",
"FOCAL_LENGTH": "",
"APERTURE": "",
"ISO": "",
"SHOW_ALL": "",
"TWO_FACTOR": "",
"TWO_FACTOR_AUTHENTICATION": "",
"TWO_FACTOR_QR_INSTRUCTION": "",
"ENTER_CODE_MANUALLY": "",
"TWO_FACTOR_MANUAL_CODE_INSTRUCTION": "",
"SCAN_QR_CODE": "",
"CONTINUE": "",
"BACK": "",
"ENABLE_TWO_FACTOR": "",
"ENABLE": "",
"LOST_DEVICE": "",
"INCORRECT_CODE": "",
"RECOVER_TWO_FACTOR": "",
"TWO_FACTOR_INFO": "",
"DISABLE_TWO_FACTOR_LABEL": "",
"UPDATE_TWO_FACTOR_LABEL": "",
"DISABLE": "",
"RECONFIGURE": "",
"UPDATE_TWO_FACTOR": "",
"UPDATE_TWO_FACTOR_MESSAGE": "",
"UPDATE": "",
"DISABLE_TWO_FACTOR": "",
"DISABLE_TWO_FACTOR_MESSAGE": "",
"TWO_FACTOR_SETUP_FAILED": "",
"TWO_FACTOR_SETUP_SUCCESS": "",
"TWO_FACTOR_DISABLE_SUCCESS": "",
"TWO_FACTOR_DISABLE_FAILED": "",
"EXPORT_DATA": "",
"SELECT_FOLDER": "",
"DESTINATION": "",
"START": "",
"EXPORT_IN_PROGRESS": "",
"PAUSE": "",
"RESUME": "",
"MINIMIZE": "",
"LAST_EXPORT_TIME": "",
"SUCCESSFULLY_EXPORTED_FILES": "",
"FAILED_EXPORTED_FILES": "",
"EXPORT_AGAIN": "",
"RETRY_EXPORT": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE": "",
"LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE": "",
"RETRY": "",
"SEND_OTT": "",
"EMAIl_ALREADY_OWNED": "",
"EMAIL_UDPATE_SUCCESSFUL": "",
"UPLOAD_FAILED": "",
"ETAGS_BLOCKED": "",
"SKIPPED_VIDEOS_INFO": "",
"LIVE_PHOTOS_DETECTED": "",
"RETRY_FAILED": "",
"FAILED_UPLOADS": "",
"SKIPPED_FILES": "",
"THUMBNAIL_GENERATION_FAILED_UPLOADS": "",
"UNSUPPORTED_FILES": "",
"SUCCESSFUL_UPLOADS": "",
"SKIPPED_INFO": "",
"UNSUPPORTED_INFO": "",
"BLOCKED_UPLOADS": "",
"SKIPPED_VIDEOS": "",
"INPROGRESS_METADATA_EXTRACTION": "",
"INPROGRESS_UPLOADS": "",
"TOO_LARGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_UPLOADS": "",
"LARGER_THAN_AVAILABLE_STORAGE_INFO": "",
"TOO_LARGE_INFO": "",
"THUMBNAIL_GENERATION_FAILED_INFO": "",
"UPLOAD_TO_COLLECTION": "",
"UNCATEGORIZED": "",
"MOVE_TO_UNCATEGORIZED": "",
"ARCHIVE": "",
"ARCHIVE_COLLECTION": "",
"ARCHIVE_SECTION_NAME": "",
"ALL_SECTION_NAME": "",
"MOVE_TO_COLLECTION": "",
"UNARCHIVE": "",
"UNARCHIVE_COLLECTION": "",
"MOVE": "",
"ADD": "",
"SORT": "",
"REMOVE": "",
"YES_REMOVE": "",
"CONFIRM_REMOVE": "",
"REMOVE_FROM_COLLECTION": "",
"TRASH": "",
"MOVE_TO_TRASH": "",
"TRASH_FILES_MESSAGE": "",
"TRASH_FILE_MESSAGE": "",
"DELETE_PERMANENTLY": "",
"RESTORE": "",
"CONFIRM_RESTORE": "",
"RESTORE_MESSAGE": "",
"RESTORE_TO_COLLECTION": "",
"EMPTY_TRASH": "",
"EMPTY_TRASH_TITLE": "",
"EMPTY_TRASH_MESSAGE": "",
"LEAVE_SHARED_ALBUM": "",
"LEAVE_ALBUM": "",
"LEAVE_SHARED_ALBUM_TITLE": "",
"LEAVE_SHARED_ALBUM_MESSAGE": "",
"NOT_FILE_OWNER": "",
"CONFIRM_SELF_REMOVE_MESSAGE": "",
"CONFIRM_SELF_AND_OTHER_REMOVE_MESSAGE": "",
"SORT_BY_CREATION_TIME_ASCENDING": "",
"SORT_BY_CREATION_TIME_DESCENDING": "",
"SORT_BY_UPDATION_TIME_DESCENDING": "",
"SORT_BY_NAME": "",
"COMPRESS_THUMBNAILS": "",
"THUMBNAIL_REPLACED": "",
"FIX_THUMBNAIL": "",
"FIX_THUMBNAIL_LATER": "",
"REPLACE_THUMBNAIL_NOT_STARTED": "",
"REPLACE_THUMBNAIL_COMPLETED": "",
"REPLACE_THUMBNAIL_NOOP": "",
"REPLACE_THUMBNAIL_COMPLETED_WITH_ERROR": "",
"FIX_CREATION_TIME": "",
"FIX_CREATION_TIME_IN_PROGRESS": "",
"CREATION_TIME_UPDATED": "",
"UPDATE_CREATION_TIME_NOT_STARTED": "",
"UPDATE_CREATION_TIME_COMPLETED": "",
"UPDATE_CREATION_TIME_COMPLETED_WITH_ERROR": "",
"FILE_NAME_CHARACTER_LIMIT": "",
"CAPTION_CHARACTER_LIMIT": "",
"DATE_TIME_ORIGINAL": "",
"DATE_TIME_DIGITIZED": "",
"CUSTOM_TIME": "",
"REOPEN_PLAN_SELECTOR_MODAL": "",
"OPEN_PLAN_SELECTOR_MODAL_FAILED": "",
"COMMENT": "",
"ABUSE_REPORT_DESCRIPTION": "",
"OTHER_REASON_REQUIRES_COMMENTS": "",
"REPORT_SUBMIT_SUCCESS_CONTENT": "",
"REPORT_SUBMIT_SUCCESS_TITLE": "",
"REPORT_SUBMIT_FAILED": "",
"INSTALL": "",
"ALBUM_URL": "",
"SHARING_DETAILS": "",
"MODIFY_SHARING": "",
"NOT_FOUND": "",
"LINK_EXPIRED": "",
"LINK_EXPIRED_MESSAGE": "",
"MANAGE_LINK": "",
"LINK_TOO_MANY_REQUESTS": "",
"DISABLE_PUBLIC_SHARING": "",
"DISABLE_PUBLIC_SHARING_MESSAGE": "",
"FILE_DOWNLOAD": "",
"LINK_PASSWORD_LOCK": "",
"PUBLIC_COLLECT": "",
"LINK_DEVICE_LIMIT": "",
"LINK_EXPIRY": "",
"LINK_EXPIRY_NEVER": "",
"DISABLE_FILE_DOWNLOAD": "",
"DISABLE_FILE_DOWNLOAD_MESSAGE": "",
"ABUSE_REPORT": "",
"ABUSE_REPORT_BUTTON_TEXT": "",
"MALICIOUS_CONTENT": "",
"COPYRIGHT": "",
"ENTER_EMAIL_ADDRESS": "",
"SELECT_REASON": "",
"ENTER_FULL_NAME": "",
"ENTER_DIGITAL_SIGNATURE": "",
"ENTER_ON_BEHALF_OF": "",
"ENTER_ADDRESS": "",
"ENTER_JOB_TITLE": "",
"ENTER_CITY": "",
"ENTER_PHONE": "",
"ENTER_STATE": "",
"ENTER_POSTAL_CODE": "",
"ENTER_COUNTRY": "",
"JUDICIAL_DESCRIPTION": "",
"TERM_1": "",
"TERM_2": "",
"TERM_3": "",
"SHARED_USING": "",
"ENTE_IO": "",
"LIVE": "",
"DISABLE_PASSWORD": "",
"DISABLE_PASSWORD_MESSAGE": "",
"PASSWORD_LOCK": "",
"LOCK": "",
"DOWNLOAD_UPLOAD_LOGS": "",
"CHOOSE_UPLOAD_TYPE": "",
"UPLOAD_FILES": "",
"UPLOAD_DIRS": "",
"UPLOAD_GOOGLE_TAKEOUT": "",
"CANCEL_UPLOADS": "",
"DEDUPLICATE_FILES": "",
"NO_DUPLICATES_FOUND": "",
"CLUB_BY_CAPTURE_TIME": "",
"FILES": "",
"EACH": "",
"DEDUPLICATE_BASED_ON_SIZE": "",
"DEDUPLICATE_BASED_ON_SIZE_AND_CAPTURE_TIME": "",
"STOP_ALL_UPLOADS_MESSAGE": "",
"STOP_UPLOADS_HEADER": "",
"YES_STOP_UPLOADS": "",
"albums_one": "",
"albums_other": "",
"NEW": "",
"VIEW_ALL_ALBUMS": "",
"ALL_ALBUMS": "",
"ALBUMS": "",
"ENDS": "",
"ENTER_TWO_FACTOR_OTP": "",
"CREATE_ACCOUNT": "",
"COPIED": "",
"CANVAS_BLOCKED_TITLE": "",
"CANVAS_BLOCKED_MESSAGE": "",
"WATCH_FOLDERS": "",
"UPGRADE_NOW": "",
"RENEW_NOW": "",
"STORAGE": "",
"USED": "",
"YOU": "",
"FAMILY": "",
"FREE": "",
"OF": "",
"WATCHED_FOLDERS": "",
"NO_FOLDERS_ADDED": "",
"FOLDERS_AUTOMATICALLY_MONITORED": "",
"UPLOAD_NEW_FILES_TO_ENTE": "",
"REMOVE_DELETED_FILES_FROM_ENTE": "",
"ADD_FOLDER": "",
"STOP_WATCHING": "",
"STOP_WATCHING_FOLDER": "",
"STOP_WATCHING_DIALOG_MESSAGE": "",
"YES_STOP": "",
"MONTH_SHORT": "",
"YEAR": "",
"FAMILY_PLAN": "",
"DOWNLOAD_LOGS": "",
"DOWNLOAD_LOGS_MESSAGE": "",
"CHANGE_FOLDER": "",
"TWO_MONTHS_FREE": "",
"GB": "",
"POPULAR": "",
"FREE_PLAN_OPTION_LABEL": "",
"FREE_PLAN_DESCRIPTION": "",
"CURRENT_USAGE": "",
"WEAK_DEVICE": "",
"DRAG_AND_DROP_HINT": "",
"ASK_FOR_FEEDBACK": "",
"SEND_FEEDBACK": "",
"CONFIRM_ACCOUNT_DELETION_TITLE": "",
"CONFIRM_ACCOUNT_DELETION_MESSAGE": "",
"AUTHENTICATE": "",
"UPLOADED_TO_SINGLE_COLLECTION": "",
"UPLOADED_TO_SEPARATE_COLLECTIONS": "",
"NEVERMIND": "",
"UPDATE_AVAILABLE": "",
"UPDATE_INSTALLABLE_MESSAGE": "",
"INSTALL_NOW": "",
"INSTALL_ON_NEXT_LAUNCH": "",
"UPDATE_AVAILABLE_MESSAGE": "",
"DOWNLOAD_AND_INSTALL": "",
"IGNORE_THIS_VERSION": "",
"TODAY": "",
"YESTERDAY": "",
"AT": "",
"NAME_PLACEHOLDER": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED": "",
"ROOT_LEVEL_FILE_WITH_FOLDER_NOT_ALLOWED_MESSAGE": "",
"CHOSE_THEME": "",
"ML_SEARCH": "",
"ENABLE_ML_SEARCH_DESCRIPTION": "",
"ML_MORE_DETAILS": "",
"ENABLE_FACE_SEARCH": "",
"ENABLE_FACE_SEARCH_TITLE": "",
"ENABLE_FACE_SEARCH_DESCRIPTION": "",
"DISABLE_BETA": "",
"DISABLE_FACE_SEARCH": "",
"DISABLE_FACE_SEARCH_TITLE": "",
"DISABLE_FACE_SEARCH_DESCRIPTION": "",
"ADVANCED": "",
"FACE_SEARCH_CONFIRMATION": "",
"LABS": "",
"YOURS": "",
"PASSPHRASE_STRENGTH": "",
"PREFERENCES": "",
"LANGUAGE": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST": "",
"EXPORT_DIRECTORY_DOES_NOT_EXIST_MESSAGE": "",
"SUBSCRIPTION_VERIFICATION_ERROR": "",
"STORAGE_UNITS": {
"B": "",
"KB": "",
"MB": "",
"GB": "",
"TB": ""
},
"AFTER_TIME": {
"HOUR": "",
"DAY": "",
"WEEK": "",
"MONTH": "",
"YEAR": ""
},
"COPY_LINK": "",
"DONE": "",
"ADD_EMAIL_TITLE": "",
"LINK_SHARE_TITLE": "",
"REMOVE_LINK": "",
"CREATE_PUBLIC_SHARING": "",
"PUBLIC_LINK_CREATED": "",
"PUBLIC_LINK_ENABLED": "",
"COLLECT_PHOTOS": "",
"PUBLIC_COLLECT_SUBTEXT": "",
"STOP_EXPORT": "",
"EXPORT_PROGRESS": "",
"EXPORT_NOTIFICATION": {
"START": "",
"IN_PROGRESS": "",
"FINISH": "",
"UP_TO_DATE": ""
},
"CONTINUOUS_EXPORT": "",
"TOTAL_ITEMS": "",
"PENDING_ITEMS": "",
"EXPORT_STARTING": ""
}

56
scripts/purge_unused_strings.sh Executable file
View file

@ -0,0 +1,56 @@
#!/bin/bash
# Set the path to the JSON file and folder
json_file_path="./public/locales/en/translation.json"
folder_path="./src"
tab_width=4
# Check if jq and grep are installed
if ! command -v jq &> /dev/null || ! command -v grep &> /dev/null
then
echo "jq or grep command not found. Please install jq and grep."
exit
fi
# Recursive function to check for keys in nested JSON objects
check_keys() {
local keys="$1"
local parent_key="$2"
for key in $keys
do
local full_key=""
if [[ -z $parent_key ]]; then
full_key="$key"
else
full_key="$parent_key.$key"
fi
local children_keys=$(jq -r --arg key "$key" 'select(.[$key] | type == "object") | .[$key] | keys[]' "$json_file_path")
if [ -n "$children_keys" ]; then
# check first if the key is not in the ignore list
check_keys "$children_keys" "$full_key"
else
if ! grep -rqE "'$full_key'|\"$full_key\"" "$folder_path"; then
# Remove the key from the JSON file
# echo the command to remove the key from the JSON file
jq "del(.$(echo $full_key | sed 's/\./"."/g' | sed 's/^/"/' | sed 's/$/"/'))" "$json_file_path" > "$json_file_path.tmp" && mv "$json_file_path.tmp" "$json_file_path"
echo "Removing key \"$full_key\" from the JSON file"
else
echo "Key \"$full_key\" is being used."
fi
fi
done
}
# Get the top-level keys from the JSON file
keys=$(jq -r 'keys[]' "$json_file_path")
# Loop through the keys and recursively check for nested keys
check_keys "$keys" ""
# Format the updated JSON using the specified tab width
jq --indent "$tab_width" '.' "$json_file_path" > "$json_file_path.tmp" && mv "$json_file_path.tmp" "$json_file_path"
echo "Done checking for missing keys."

View file

@ -41,7 +41,7 @@ function ChangeEmailForm() {
ottInputRef.current?.focus();
}, 250);
} catch (e) {
setFieldError('email', t('EMAIl_ALREADY_OWNED}'));
setFieldError('email', t('EMAIl_ALREADY_OWNED'));
}
setLoading(false);
};

View file

@ -1,16 +1,13 @@
import EmailShare from './emailShare';
import React, { useContext } from 'react';
import React from 'react';
import { Collection } from 'types/collection';
import DialogTitleWithCloseButton, {
dialogCloseHandler,
} from 'components/DialogBox/TitleWithCloseButton';
import DialogContent from '@mui/material/DialogContent';
import { Divider } from '@mui/material';
import { CollectionShareContainer } from './container';
import { EnteDrawer } from 'components/EnteDrawer';
import PublicShare from './publicShare';
import { AppContext } from 'pages/_app';
import WorkspacesIcon from '@mui/icons-material/Workspaces';
import { t } from 'i18next';
import MenuSectionTitle from 'components/Menu/MenuSectionTitle';
import { DialogProps, Stack } from '@mui/material';
import Titlebar from 'components/Titlebar';
interface Props {
open: boolean;
@ -19,30 +16,48 @@ interface Props {
}
function CollectionShare(props: Props) {
const { isMobile } = useContext(AppContext);
const handleClose = dialogCloseHandler({
onClose: props.onClose,
});
const handleRootClose = () => {
props.onClose();
};
const handleDrawerClose: DialogProps['onClose'] = (_, reason) => {
if (reason === 'backdropClick') {
handleRootClose();
} else {
props.onClose();
}
};
if (!props.collection) {
return <></>;
}
return (
<>
<CollectionShareContainer
<EnteDrawer
anchor="right"
open={props.open}
onClose={handleClose}
fullScreen={isMobile}>
<DialogTitleWithCloseButton onClose={handleClose}>
{t('SHARE_COLLECTION')}
</DialogTitleWithCloseButton>
<DialogContent>
<EmailShare collection={props.collection} />
<Divider />
<PublicShare collection={props.collection} />
</DialogContent>
</CollectionShareContainer>
onClose={handleDrawerClose}
BackdropProps={{
sx: { '&&&': { backgroundColor: 'transparent' } },
}}>
<Stack spacing={'4px'} py={'12px'}>
<Titlebar
onClose={props.onClose}
title={t('SHARE_COLLECTION')}
onRootClose={handleRootClose}
/>
<Stack py={'20px'} px={'8px'}>
<MenuSectionTitle
title={t('ADD_EMAIL_TITLE')}
icon={<WorkspacesIcon />}
/>
<EmailShare collection={props.collection} />
<PublicShare
collection={props.collection}
onRootClose={handleRootClose}
/>
</Stack>
</Stack>
</EnteDrawer>
</>
);
}

View file

@ -0,0 +1,101 @@
import { Stack, Typography } from '@mui/material';
import { GalleryContext } from 'pages/gallery';
import React, { useContext, useState } from 'react';
import { t } from 'i18next';
import {
createShareableURL,
updateShareableURL,
} from 'services/collectionService';
import { Collection, PublicURL } from 'types/collection';
import { handleSharingErrors } from 'utils/error/ui';
import { EnteMenuItem } from 'components/Menu/menuItem';
import PublicIcon from '@mui/icons-material/Public';
interface Iprops {
collection: Collection;
setPublicShareProp: (value: PublicURL) => void;
setCopyLinkModalView: (value: boolean) => void;
}
import LinkIcon from '@mui/icons-material/Link';
import { EnteMenuItemGroup } from 'components/Menu/menuItemGroup';
import MenuSectionTitle from 'components/Menu/MenuSectionTitle';
import EnteMenuItemDivider from 'components/Menu/menuItemDivider';
export default function EnablePublicShareOptions({
collection,
setPublicShareProp,
setCopyLinkModalView,
}: Iprops) {
const galleryContext = useContext(GalleryContext);
const [sharableLinkError, setSharableLinkError] = useState(null);
const createSharableURLHelper = async () => {
try {
setSharableLinkError(null);
galleryContext.setBlockingLoad(true);
const publicURL = await createShareableURL(collection);
setPublicShareProp(publicURL);
setCopyLinkModalView(true);
galleryContext.syncWithRemote(false, true);
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
const createCollectPhotoShareableURLHelper = async () => {
try {
setSharableLinkError(null);
galleryContext.setBlockingLoad(true);
const publicURL = await createShareableURL(collection);
await updateShareableURL({
collectionID: collection.id,
enableCollect: true,
});
setPublicShareProp(publicURL);
setCopyLinkModalView(true);
galleryContext.syncWithRemote(false, true);
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
return (
<Stack>
<MenuSectionTitle
title={t('LINK_SHARE_TITLE')}
icon={<PublicIcon />}
/>
<EnteMenuItemGroup>
<EnteMenuItem
startIcon={<LinkIcon />}
color="primary"
onClick={createSharableURLHelper}>
{t('CREATE_PUBLIC_SHARING')}
</EnteMenuItem>
<EnteMenuItemDivider hasIcon />
<EnteMenuItem
startIcon={<LinkIcon />}
color="primary"
onClick={createCollectPhotoShareableURLHelper}>
{t('COLLECT_PHOTOS')}
</EnteMenuItem>
</EnteMenuItemGroup>
{sharableLinkError && (
<Typography
textAlign={'center'}
variant="body2"
sx={{
color: (theme) => theme.palette.danger.main,
mt: 0.5,
}}>
{sharableLinkError}
</Typography>
)}
</Stack>
);
}

View file

@ -1,104 +0,0 @@
import { Box, Typography } from '@mui/material';
import { FlexWrapper } from 'components/Container';
import { GalleryContext } from 'pages/gallery';
import { AppContext } from 'pages/_app';
import React, { useContext, useState } from 'react';
import { t } from 'i18next';
import {
createShareableURL,
deleteShareableURL,
} from 'services/collectionService';
import { Collection, PublicURL } from 'types/collection';
import { handleSharingErrors } from 'utils/error/ui';
import PublicShareSwitch from './switch';
interface Iprops {
collection: Collection;
publicShareActive: boolean;
setPublicShareProp: (value: PublicURL) => void;
}
export default function PublicShareControl({
collection,
publicShareActive,
setPublicShareProp,
}: Iprops) {
const appContext = useContext(AppContext);
const galleryContext = useContext(GalleryContext);
const [sharableLinkError, setSharableLinkError] = useState(null);
const createSharableURLHelper = async () => {
try {
appContext.startLoading();
const publicURL = await createShareableURL(collection);
setPublicShareProp(publicURL);
await galleryContext.syncWithRemote(false, true);
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
appContext.finishLoading();
}
};
const disablePublicSharing = async () => {
try {
appContext.startLoading();
await deleteShareableURL(collection);
setPublicShareProp(null);
await galleryContext.syncWithRemote(false, true);
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
appContext.finishLoading();
}
};
const confirmDisablePublicSharing = () => {
appContext.setDialogMessage({
title: t('DISABLE_PUBLIC_SHARING'),
content: t('DISABLE_PUBLIC_SHARING_MESSAGE'),
close: { text: t('CANCEL') },
proceed: {
text: t('DISABLE'),
action: disablePublicSharing,
variant: 'danger',
},
});
};
const handleCollectionPublicSharing = () => {
setSharableLinkError(null);
if (publicShareActive) {
confirmDisablePublicSharing();
} else {
createSharableURLHelper();
}
};
return (
<Box mt={3}>
<FlexWrapper>
<FlexWrapper>{t('PUBLIC_SHARING')}</FlexWrapper>
<PublicShareSwitch
color="accent"
sx={{
ml: 2,
}}
checked={publicShareActive}
onChange={handleCollectionPublicSharing}
/>
</FlexWrapper>
{sharableLinkError && (
<Typography
variant="body2"
sx={{
color: (theme) => theme.palette.danger.main,
mt: 0.5,
}}>
{sharableLinkError}
</Typography>
)}
</Box>
);
}

View file

@ -0,0 +1,58 @@
import DialogBoxBase from 'components/DialogBox/base';
import {
DialogActions,
Button,
Typography,
DialogContent,
Box,
} from '@mui/material';
import VerticallyCentered from 'components/Container';
import Check from '@mui/icons-material/Check';
import { t } from 'i18next';
interface Iprops {
open: boolean;
onClose: () => void;
handleCancel: () => void;
copyToClipboardHelper: () => void;
}
export default function CopyLinkModal({
open,
onClose,
handleCancel,
copyToClipboardHelper,
}: Iprops) {
return (
<DialogBoxBase
open={open}
onClose={onClose}
disablePortal
BackdropProps={{ sx: { position: 'absolute' } }}
sx={{ position: 'absolute' }}
PaperProps={{
sx: { p: 1 },
}}>
<DialogContent>
<VerticallyCentered>
<Typography fontWeight={'bold'}>
{t('PUBLIC_LINK_CREATED')}
</Typography>
<Box pt={2}>
<Check sx={{ fontSize: '48px' }} />
</Box>
</VerticallyCentered>
</DialogContent>
<DialogActions>
<Button onClick={handleCancel} color="secondary" size={'large'}>
{t('DONE')}
</Button>
<Button
onClick={copyToClipboardHelper}
size={'large'}
color="primary"
autoFocus>
{t('COPY_LINK')}
</Button>
</DialogActions>
</DialogBoxBase>
);
}

View file

@ -1,17 +1,20 @@
import React, { useEffect, useState } from 'react';
import { Collection, PublicURL } from 'types/collection';
import { appendCollectionKeyToShareURL } from 'utils/collection';
import PublicShareControl from './control';
import PublicShareLink from './link';
import PublicShareManage from './manage';
import EnablePublicShareOptions from './EnablePublicShareOptions';
import CopyLinkModal from './copyLinkModal';
import ManagePublicShare from './managePublicShare';
export default function PublicShare({
collection,
onRootClose,
}: {
collection: Collection;
onRootClose: () => void;
}) {
const [publicShareUrl, setPublicShareUrl] = useState<string>(null);
const [publicShareProp, setPublicShareProp] = useState<PublicURL>(null);
const [copyLinkModalView, setCopyLinkModalView] = useState(false);
useEffect(() => {
if (collection.publicURLs?.length) {
@ -31,24 +34,38 @@ export default function PublicShare({
}
}, [publicShareProp]);
const copyToClipboardHelper = () => {
navigator.clipboard.writeText(publicShareUrl);
handleCancel();
};
const handleCancel = () => {
setCopyLinkModalView(false);
};
return (
<>
<PublicShareControl
setPublicShareProp={setPublicShareProp}
collection={collection}
publicShareActive={!!publicShareProp}
/>
{publicShareProp && (
<>
<PublicShareLink publicShareUrl={publicShareUrl} />
<PublicShareManage
publicShareProp={publicShareProp}
collection={collection}
setPublicShareProp={setPublicShareProp}
/>
</>
{publicShareProp ? (
<ManagePublicShare
publicShareProp={publicShareProp}
setPublicShareProp={setPublicShareProp}
collection={collection}
publicShareUrl={publicShareUrl}
onRootClose={onRootClose}
copyToClipboardHelper={copyToClipboardHelper}
/>
) : (
<EnablePublicShareOptions
setPublicShareProp={setPublicShareProp}
collection={collection}
setCopyLinkModalView={setCopyLinkModalView}
/>
)}
<CopyLinkModal
open={copyLinkModalView}
onClose={handleCancel}
handleCancel={handleCancel}
copyToClipboardHelper={copyToClipboardHelper}
/>
</>
);
}

View file

@ -1,11 +0,0 @@
import { Box } from '@mui/material';
import CodeBlock from 'components/CodeBlock';
import React from 'react';
export default function PublicShareLink({ publicShareUrl }) {
return (
<Box mt={2} mb={3}>
<CodeBlock wordBreak={'break-all'} code={publicShareUrl} />
</Box>
);
}

View file

@ -1,22 +1,27 @@
import { Box, Typography } from '@mui/material';
import React from 'react';
import ChevronRight from '@mui/icons-material/ChevronRight';
import { DialogProps, Stack } from '@mui/material';
import { EnteDrawer } from 'components/EnteDrawer';
import { EnteMenuItem } from 'components/Menu/menuItem';
import { EnteMenuItemGroup } from 'components/Menu/menuItemGroup';
import Titlebar from 'components/Titlebar';
import { t } from 'i18next';
import Select from 'react-select';
import { DropdownStyle } from 'styles/dropdown';
import React, { useMemo, useState } from 'react';
import { Collection, PublicURL, UpdatePublicURL } from 'types/collection';
import { getDeviceLimitOptions } from 'utils/collection';
import { OptionWithDivider } from './selectComponents/OptionWithDivider';
import EnteMenuItemDivider from 'components/Menu/menuItemDivider';
interface Iprops {
publicShareProp: PublicURL;
collection: Collection;
updatePublicShareURLHelper: (req: UpdatePublicURL) => Promise<void>;
onRootClose: () => void;
}
export function ManageDeviceLimit({
publicShareProp,
collection,
publicShareProp,
updatePublicShareURLHelper,
onRootClose,
}: Iprops) {
const updateDeviceLimit = async (newLimit: number) => {
return updatePublicShareURLHelper({
@ -24,24 +29,68 @@ export function ManageDeviceLimit({
deviceLimit: newLimit,
});
};
const [isChangeDeviceLimitVisible, setIsChangeDeviceLimitVisible] =
useState(false);
const deviceLimitOptions = useMemo(() => getDeviceLimitOptions(), []);
const closeDeviceLimitChangeModal = () =>
setIsChangeDeviceLimitVisible(false);
const openDeviceLimitChangeModalView = () =>
setIsChangeDeviceLimitVisible(true);
const changeDeviceLimitValue = (value: number) => async () => {
await updateDeviceLimit(value);
setIsChangeDeviceLimitVisible(false);
};
const handleDrawerClose: DialogProps['onClose'] = (_, reason) => {
if (reason === 'backdropClick') {
onRootClose();
} else {
closeDeviceLimitChangeModal();
}
};
return (
<Box>
<Typography mb={0.5}>{t('LINK_DEVICE_LIMIT')}</Typography>
<Select
menuPosition="fixed"
options={getDeviceLimitOptions()}
components={{
Option: OptionWithDivider,
}}
isSearchable={false}
value={{
label: publicShareProp?.deviceLimit.toString(),
value: publicShareProp?.deviceLimit,
}}
onChange={(e) => updateDeviceLimit(e.value)}
styles={DropdownStyle}
/>
</Box>
<>
<EnteMenuItem
onClick={openDeviceLimitChangeModalView}
endIcon={<ChevronRight />}
subText={String(publicShareProp.deviceLimit)}>
{t('LINK_DEVICE_LIMIT')}
</EnteMenuItem>
<EnteDrawer
anchor="right"
open={isChangeDeviceLimitVisible}
onClose={handleDrawerClose}>
<Stack spacing={'4px'} py={'12px'}>
<Titlebar
onClose={closeDeviceLimitChangeModal}
title={t('LINK_DEVICE_LIMIT')}
onRootClose={onRootClose}
/>
<Stack py={'20px'} px={'8px'} spacing={'32px'}>
<EnteMenuItemGroup>
{deviceLimitOptions.map((item, index) => (
<>
<EnteMenuItem
key={item.label}
onClick={changeDeviceLimitValue(
item.value
)}>
{item.label}
</EnteMenuItem>
{index !==
deviceLimitOptions.length - 1 && (
<EnteMenuItemDivider />
)}
</>
))}
</EnteMenuItemGroup>
</Stack>
</Stack>
</EnteDrawer>
</>
);
}

View file

@ -1,11 +1,9 @@
import { Box, Typography } from '@mui/material';
import { EnteMenuItem } from 'components/Menu/menuItem';
import { AppContext } from 'pages/_app';
import React, { useContext } from 'react';
import { Trans } from 'react-i18next';
import { t } from 'i18next';
import { PublicURL, Collection, UpdatePublicURL } from 'types/collection';
import PublicShareSwitch from '../switch';
interface Iprops {
publicShareProp: PublicURL;
collection: Collection;
@ -47,12 +45,11 @@ export function ManageDownloadAccess({
});
};
return (
<Box>
<Typography mb={0.5}>{t('FILE_DOWNLOAD')}</Typography>
<PublicShareSwitch
checked={publicShareProp?.enableDownload ?? true}
onChange={handleFileDownloadSetting}
/>
</Box>
<EnteMenuItem
checked={publicShareProp?.enableDownload ?? true}
onClick={handleFileDownloadSetting}
hasSwitch>
{t('FILE_DOWNLOAD')}
</EnteMenuItem>
);
}

View file

@ -4,30 +4,51 @@ import { ManageLinkExpiry } from './linkExpiry';
import { Stack, Typography } from '@mui/material';
import { GalleryContext } from 'pages/gallery';
import React, { useContext, useState } from 'react';
import { updateShareableURL } from 'services/collectionService';
import { Collection, PublicURL, UpdatePublicURL } from 'types/collection';
import { sleep } from 'utils/common';
import {
ManageSectionLabel,
ManageSectionOptions,
} from '../../styledComponents';
deleteShareableURL,
updateShareableURL,
} from 'services/collectionService';
import { Collection, PublicURL, UpdatePublicURL } from 'types/collection';
import { ManageDownloadAccess } from './downloadAccess';
import { handleSharingErrors } from 'utils/error/ui';
import { SetPublicShareProp } from 'types/publicCollection';
import { ManagePublicCollect } from './publicCollect';
import { EnteDrawer } from 'components/EnteDrawer';
import RemoveCircleOutline from '@mui/icons-material/RemoveCircleOutline';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import { EnteMenuItem } from 'components/Menu/menuItem';
import { t } from 'i18next';
import { EnteMenuItemGroup } from 'components/Menu/menuItemGroup';
import { DialogProps } from '@mui/material';
import Titlebar from 'components/Titlebar';
import EnteMenuItemDivider from 'components/Menu/menuItemDivider';
interface Iprops {
publicShareProp: PublicURL;
collection: Collection;
setPublicShareProp: SetPublicShareProp;
open: boolean;
onClose: () => void;
onRootClose: () => void;
publicShareUrl: string;
}
export default function PublicShareManage({
export default function ManagePublicShareOptions({
publicShareProp,
collection,
setPublicShareProp,
open,
onClose,
onRootClose,
publicShareUrl,
}: Iprops) {
const handleDrawerClose: DialogProps['onClose'] = (_, reason) => {
if (reason === 'backdropClick') {
onRootClose();
} else {
onClose();
}
};
const galleryContext = useContext(GalleryContext);
const [sharableLinkError, setSharableLinkError] = useState(null);
@ -44,74 +65,100 @@ export default function PublicShareManage({
galleryContext.setBlockingLoad(false);
}
};
const scrollToEnd = (e) => {
const lastOptionRow: Element =
e.currentTarget.nextElementSibling.lastElementChild;
const main = async (lastOptionRow: Element) => {
await sleep(0);
lastOptionRow.scrollIntoView(true);
};
main(lastOptionRow);
const disablePublicSharing = async () => {
try {
galleryContext.setBlockingLoad(true);
await deleteShareableURL(collection);
setPublicShareProp(null);
onClose();
} catch (e) {
const errorMessage = handleSharingErrors(e);
setSharableLinkError(errorMessage);
} finally {
galleryContext.setBlockingLoad(false);
}
};
const copyToClipboardHelper = (text: string) => () => {
navigator.clipboard.writeText(text);
};
return (
<>
<details>
<ManageSectionLabel onClick={scrollToEnd}>
{t('MANAGE_LINK')}
</ManageSectionLabel>
<ManageSectionOptions>
<Stack spacing={1.5}>
<ManageLinkExpiry
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManageDeviceLimit
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManagePublicCollect
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManageDownloadAccess
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManageLinkPassword
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<EnteDrawer anchor="right" open={open} onClose={handleDrawerClose}>
<Stack spacing={'4px'} py={'12px'}>
<Titlebar
onClose={onClose}
title={t('SHARE_COLLECTION')}
onRootClose={onRootClose}
/>
<Stack py={'20px'} px={'8px'} spacing={'32px'}>
<Stack spacing={3}>
<ManagePublicCollect
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<ManageLinkExpiry
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
onRootClose={onRootClose}
/>
<EnteMenuItemGroup>
<ManageDeviceLimit
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
onRootClose={onRootClose}
/>
<EnteMenuItemDivider />
<ManageDownloadAccess
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
<EnteMenuItemDivider />
<ManageLinkPassword
collection={collection}
publicShareProp={publicShareProp}
updatePublicShareURLHelper={
updatePublicShareURLHelper
}
/>
</EnteMenuItemGroup>
<EnteMenuItem
startIcon={<ContentCopyIcon />}
onClick={copyToClipboardHelper(publicShareUrl)}>
{t('COPY_LINK')}
</EnteMenuItem>
<EnteMenuItem
color="danger"
startIcon={<RemoveCircleOutline />}
onClick={disablePublicSharing}>
{t('REMOVE_LINK')}
</EnteMenuItem>
</Stack>
{sharableLinkError && (
<Typography
textAlign={'center'}
variant="body2"
sx={{
color: (theme) => theme.palette.danger.main,
mt: 0.5,
}}>
{sharableLinkError}
</Typography>
)}
</Stack>
{sharableLinkError && (
<Typography
textAlign={'center'}
variant="body2"
sx={{
color: (theme) => theme.palette.danger.main,
mt: 0.5,
}}>
{sharableLinkError}
</Typography>
)}
</ManageSectionOptions>
</details>
</Stack>
</EnteDrawer>
</>
);
}

View file

@ -1,52 +1,103 @@
import { Box, Typography } from '@mui/material';
import React from 'react';
import Select from 'react-select';
import { linkExpiryStyle } from 'styles/linkExpiry';
import ChevronRight from '@mui/icons-material/ChevronRight';
import { DialogProps, Stack } from '@mui/material';
import { EnteDrawer } from 'components/EnteDrawer';
import { EnteMenuItem } from 'components/Menu/menuItem';
import React, { useMemo, useState } from 'react';
import { PublicURL, Collection, UpdatePublicURL } from 'types/collection';
import { shareExpiryOptions } from 'utils/collection';
import { t } from 'i18next';
import { EnteMenuItemGroup } from 'components/Menu/menuItemGroup';
import { formatDateTime } from 'utils/time/format';
import { OptionWithDivider } from './selectComponents/OptionWithDivider';
import Titlebar from 'components/Titlebar';
import EnteMenuItemDivider from 'components/Menu/menuItemDivider';
interface Iprops {
publicShareProp: PublicURL;
collection: Collection;
updatePublicShareURLHelper: (req: UpdatePublicURL) => Promise<void>;
onRootClose: () => void;
}
export function ManageLinkExpiry({
publicShareProp,
collection,
updatePublicShareURLHelper,
onRootClose,
}: Iprops) {
const updateDeviceExpiry = async (optionFn) => {
return updatePublicShareURLHelper({
collectionID: collection.id,
validTill: optionFn(),
validTill: optionFn,
});
};
const [shareExpiryOptionsModalView, setShareExpiryOptionsModalView] =
useState(false);
const shareExpireOption = useMemo(() => shareExpiryOptions(), []);
const closeShareExpiryOptionsModalView = () =>
setShareExpiryOptionsModalView(false);
const openShareExpiryOptionsModalView = () =>
setShareExpiryOptionsModalView(true);
const changeShareExpiryValue = (value: number) => async () => {
await updateDeviceExpiry(value);
publicShareProp.validTill = value;
setShareExpiryOptionsModalView(false);
};
const handleDrawerClose: DialogProps['onClose'] = (_, reason) => {
if (reason === 'backdropClick') {
onRootClose();
} else {
closeShareExpiryOptionsModalView();
}
};
return (
<Box>
<Typography mb={0.5}>{t('LINK_EXPIRY')}</Typography>
<Select
menuPosition="fixed"
options={shareExpiryOptions()}
isSearchable={false}
value={null}
components={{
Option: OptionWithDivider,
}}
placeholder={
<>
<EnteMenuItem
onClick={openShareExpiryOptionsModalView}
endIcon={<ChevronRight />}
subText={
publicShareProp?.validTill
? formatDateTime(publicShareProp?.validTill / 1000)
: t('LINK_EXPIRY_NEVER')
}
onChange={(e) => {
updateDeviceExpiry(e.value);
}}
styles={linkExpiryStyle}
/>
</Box>
}>
{t('LINK_EXPIRY')}
</EnteMenuItem>
<EnteDrawer
anchor="right"
open={shareExpiryOptionsModalView}
onClose={handleDrawerClose}>
<Stack spacing={'4px'} py={'12px'}>
<Titlebar
onClose={closeShareExpiryOptionsModalView}
title={t('LINK_EXPIRY')}
onRootClose={onRootClose}
/>
<Stack py={'20px'} px={'8px'} spacing={'32px'}>
<EnteMenuItemGroup>
{shareExpireOption.map((item, index) => (
<>
<EnteMenuItem
key={item.value()}
onClick={changeShareExpiryValue(
item.value()
)}>
{item.label}
</EnteMenuItem>
{index !== shareExpireOption.length - 1 && (
<EnteMenuItemDivider />
)}
</>
))}
</EnteMenuItemGroup>
</Stack>
</Stack>
</EnteDrawer>
</>
);
}

View file

@ -1,9 +1,8 @@
import { Box, Typography } from '@mui/material';
import { AppContext } from 'pages/_app';
import React, { useContext, useState } from 'react';
import { PublicURL, Collection, UpdatePublicURL } from 'types/collection';
import { PublicLinkSetPassword } from './setPassword';
import PublicShareSwitch from '../../switch';
import { EnteMenuItem } from 'components/Menu/menuItem';
import { t } from 'i18next';
interface Iprops {
@ -49,13 +48,12 @@ export function ManageLinkPassword({
return (
<>
<Box>
<Typography mb={0.5}> {t('LINK_PASSWORD_LOCK')}</Typography>
<PublicShareSwitch
checked={!!publicShareProp?.passwordEnabled}
onChange={handlePasswordChangeSetting}
/>
</Box>
<EnteMenuItem
onClick={handlePasswordChangeSetting}
checked={!!publicShareProp?.passwordEnabled}
hasSwitch>
{t('LINK_PASSWORD_LOCK')}
</EnteMenuItem>
<PublicLinkSetPassword
open={changePasswordView}
onClose={closeConfigurePassword}

View file

@ -1,8 +1,9 @@
import { Box, Typography } from '@mui/material';
import { Stack } from '@mui/material';
import { EnteMenuItem } from 'components/Menu/menuItem';
import React from 'react';
import { t } from 'i18next';
import { PublicURL, Collection, UpdatePublicURL } from 'types/collection';
import PublicShareSwitch from '../switch';
import MenuSectionTitle from 'components/Menu/MenuSectionTitle';
interface Iprops {
publicShareProp: PublicURL;
@ -23,12 +24,15 @@ export function ManagePublicCollect({
};
return (
<Box>
<Typography mb={0.5}>{t('PUBLIC_COLLECT')}</Typography>
<PublicShareSwitch
checked={publicShareProp?.enableCollect}
onChange={handleFileDownloadSetting}
/>
</Box>
<Stack>
<EnteMenuItem
onClick={handleFileDownloadSetting}
color="primary"
hasSwitch
checked={publicShareProp?.enableCollect}>
{t('PUBLIC_COLLECT')}
</EnteMenuItem>
<MenuSectionTitle title={t('PUBLIC_COLLECT_SUBTEXT')} />
</Stack>
);
}

View file

@ -0,0 +1,67 @@
import { Stack, Typography } from '@mui/material';
import { EnteMenuItem } from 'components/Menu/menuItem';
import EnteMenuItemDivider from 'components/Menu/menuItemDivider';
import { EnteMenuItemGroup } from 'components/Menu/menuItemGroup';
import { Collection, PublicURL } from 'types/collection';
import ManagePublicShareOptions from './manage';
import PublicIcon from '@mui/icons-material/Public';
import ContentCopyIcon from '@mui/icons-material/ContentCopyOutlined';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import { SetPublicShareProp } from 'types/publicCollection';
import LinkIcon from '@mui/icons-material/Link';
import { useState } from 'react';
import { t } from 'i18next';
interface Iprops {
publicShareProp: PublicURL;
collection: Collection;
setPublicShareProp: SetPublicShareProp;
onRootClose: () => void;
publicShareUrl: string;
copyToClipboardHelper: () => void;
}
export default function ManagePublicShare({
publicShareProp,
setPublicShareProp,
collection,
onRootClose,
publicShareUrl,
copyToClipboardHelper,
}: Iprops) {
const [manageShareView, setManageShareView] = useState(false);
const closeManageShare = () => setManageShareView(false);
const openManageShare = () => setManageShareView(true);
return (
<>
<Stack>
<Typography color="text.secondary" variant="body2" padding={1}>
<PublicIcon style={{ fontSize: 17, marginRight: 8 }} />
{t('PUBLIC_LINK_ENABLED')}
</Typography>
<EnteMenuItemGroup>
<EnteMenuItem
startIcon={<ContentCopyIcon />}
onClick={copyToClipboardHelper}>
{t('COPY_LINK')}
</EnteMenuItem>
<EnteMenuItemDivider hasIcon={true} />
<EnteMenuItem
startIcon={<LinkIcon />}
endIcon={<ChevronRightIcon />}
onClick={openManageShare}>
{t('MANAGE_LINK')}
</EnteMenuItem>
</EnteMenuItemGroup>
</Stack>
<ManagePublicShareOptions
open={manageShareView}
onClose={closeManageShare}
onRootClose={onRootClose}
publicShareProp={publicShareProp}
collection={collection}
setPublicShareProp={setPublicShareProp}
publicShareUrl={publicShareUrl}
/>
</>
);
}

View file

@ -1,7 +1,7 @@
import { Box } from '@mui/material';
import { styled } from '@mui/material';
import { Overlay } from 'components/Container';
import { SpecialPadding } from 'styles/SpecialPadding';
import { IMAGE_CONTAINER_MAX_WIDTH, MIN_COLUMNS } from 'constants/gallery';
export const CollectionListWrapper = styled(Box)`
position: relative;
overflow: hidden;
@ -10,7 +10,10 @@ export const CollectionListWrapper = styled(Box)`
`;
export const CollectionListBarWrapper = styled(Box)`
${SpecialPadding}
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) {
padding: 0 4px;
}
margin-bottom: 16px;
border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
`;

View file

@ -27,10 +27,6 @@ export const Row = styled('div')`
flex: 1;
`;
export const Label = styled('div')<{ width?: string }>`
width: ${(props) => props.width ?? '70%'};
color: ${(props) => props.theme.palette.text.secondary};
`;
export const Value = styled('div')<{ width?: string }>`
display: flex;
justify-content: flex-start;
@ -77,3 +73,11 @@ export const IconButtonWithBG = styled(IconButton)(({ theme }) => ({
export const HorizontalFlex = styled(Box)({
display: 'flex',
});
export const VerticalFlex = styled(HorizontalFlex)({
flexDirection: 'column',
});
export const VerticallyCenteredFlex = styled(HorizontalFlex)({
alignItems: 'center',
});

View file

@ -0,0 +1,126 @@
import React from 'react';
import {
Box,
Breakpoint,
Button,
Dialog,
DialogProps,
Stack,
Typography,
} from '@mui/material';
import { t } from 'i18next';
import { dialogCloseHandler } from 'components/DialogBox/TitleWithCloseButton';
import { DialogBoxAttributesV2 } from 'types/dialogBox';
type IProps = React.PropsWithChildren<
Omit<DialogProps, 'onClose' | 'maxSize'> & {
onClose: () => void;
attributes: DialogBoxAttributesV2;
size?: Breakpoint;
titleCloseButton?: boolean;
}
>;
export default function DialogBoxV2({
attributes,
children,
open,
onClose,
...props
}: IProps) {
if (!attributes) {
return <></>;
}
const handleClose = dialogCloseHandler({
staticBackdrop: attributes.staticBackdrop,
nonClosable: attributes.nonClosable,
onClose: onClose,
});
return (
<Dialog
open={open}
onClose={handleClose}
{...props}
PaperProps={{
sx: {
padding: '8px 12px',
maxWidth: '360px',
},
}}>
<Stack spacing={'36px'} p={'16px'}>
<Stack spacing={'19px'}>
{attributes.icon && (
<Box
sx={{
'& > svg': {
fontSize: '32px',
},
}}>
{attributes.icon}
</Box>
)}
{attributes.title && (
<Typography variant="h4" fontWeight={'bold'}>
{attributes.title}
</Typography>
)}
{children ||
(attributes?.content && (
<Typography color="text.secondary">
{attributes.content}
</Typography>
))}
</Stack>
<Stack
spacing={'8px'}
direction={
attributes.buttonDirection === 'row'
? 'row-reverse'
: 'column'
}
flex={1}>
{attributes.proceed && (
<Button
size="large"
color={attributes.proceed?.variant}
onClick={() => {
attributes.proceed.action();
onClose();
}}
disabled={attributes.proceed.disabled}>
{attributes.proceed.text}
</Button>
)}
{attributes.close && (
<Button
size="large"
color={attributes.close?.variant ?? 'secondary'}
onClick={() => {
attributes.close.action &&
attributes.close?.action();
onClose();
}}>
{attributes.close?.text ?? t('OK')}
</Button>
)}
{attributes.buttons &&
attributes.buttons.map((b) => (
<Button
size="large"
key={b.text}
color={b.variant}
onClick={() => {
b.action();
onClose();
}}
disabled={b.disabled}>
{b.text}
</Button>
))}
</Stack>
</Stack>
</Dialog>
);
}

View file

@ -0,0 +1,105 @@
import ExpandMore from '@mui/icons-material/ExpandMore';
import {
Box,
MenuItem,
Select,
SelectChangeEvent,
Stack,
Typography,
TypographyTypeMap,
} from '@mui/material';
export interface DropdownOption<T> {
label: string;
value: T;
}
interface Iprops<T> {
label: string;
labelProps: TypographyTypeMap['props'];
options: DropdownOption<T>[];
message?: string;
selectedValue: string;
setSelectedValue: (selectedValue: T) => void;
placeholder?: string;
}
export default function DropdownInput<T extends string>({
label,
labelProps,
options,
message,
selectedValue,
placeholder,
setSelectedValue,
}: Iprops<T>) {
return (
<Stack spacing={'4px'}>
<Typography {...labelProps}>{label}</Typography>
<Select
IconComponent={ExpandMore}
displayEmpty
variant="standard"
MenuProps={{
MenuListProps: {
sx: (theme) => ({
backgroundColor: theme.palette.background.overPaper,
'.MuiMenuItem-root ': {
color: theme.palette.text.secondary,
},
'&& > .Mui-selected': {
background: theme.palette.background.overPaper,
color: theme.palette.text.primary,
},
}),
},
}}
sx={(theme) => ({
'::before , ::after': {
borderBottom: 'none !important',
},
'.MuiSelect-select': {
background: theme.palette.fill.dark,
borderRadius: '8px',
},
'&&& .MuiSelect-select': {
p: '12px 36px 12px 16px',
},
'.MuiSelect-icon': {
mr: '12px',
color: theme.palette.stroke.muted,
},
})}
renderValue={(selected) => {
return !selected?.length ? (
<Box color={'text.secondary'}>{placeholder ?? ''}</Box>
) : (
options.find((o) => o.value === selected).label
);
}}
value={selectedValue}
onChange={(event: SelectChangeEvent) => {
setSelectedValue(event.target.value as T);
}}>
{options.map((option, index) => (
<MenuItem
key={option.label}
divider={index !== options.length - 1}
value={option.value}
sx={{
px: '16px',
py: '14px',
color: (theme) => theme.palette.primary.main,
}}>
{option.label}
</MenuItem>
))}
</Select>
{message && (
<Typography px={'8px'} color={'text.secondary'}>
{message}
</Typography>
)}
</Stack>
);
}

View file

@ -1,5 +1,4 @@
import { Drawer } from '@mui/material';
import styled from 'styled-components';
import { Drawer, styled } from '@mui/material';
export const EnteDrawer = styled(Drawer)(({ theme }) => ({
'& .MuiPaper-root': {

View file

@ -1,74 +1,53 @@
import { Button, DialogActions, DialogContent, Stack } from '@mui/material';
import {
Button,
DialogActions,
DialogContent,
Stack,
Typography,
} from '@mui/material';
import React from 'react';
import { t } from 'i18next';
import { ExportStats } from 'types/export';
import { formatDateTime } from 'utils/time/format';
import { FlexWrapper, Label, Value } from './Container';
import { ComfySpan } from './ExportInProgress';
import { SpaceBetweenFlex } from './Container';
interface Props {
pendingFileCount: number;
onHide: () => void;
lastExportTime: number;
exportStats: ExportStats;
exportFiles: () => void;
retryFailed: () => void;
startExport: () => void;
}
export default function ExportFinished(props: Props) {
const totalFiles = props.exportStats.failed + props.exportStats.success;
return (
<>
<DialogContent>
<Stack spacing={2.5}>
<FlexWrapper>
<Label width="40%">{t('LAST_EXPORT_TIME')}</Label>
<Value width="60%">
<Stack pr={2}>
<SpaceBetweenFlex minHeight={'48px'}>
<Typography color={'text.secondary'}>
{t('PENDING_ITEMS')}
</Typography>
<Typography>{props.pendingFileCount}</Typography>
</SpaceBetweenFlex>
<SpaceBetweenFlex minHeight={'48px'}>
<Typography color="text.secondary">
{t('LAST_EXPORT_TIME')}
</Typography>
<Typography>
{formatDateTime(props.lastExportTime)}
</Value>
</FlexWrapper>
<FlexWrapper>
<Label width="40%">
{t('SUCCESSFULLY_EXPORTED_FILES')}
</Label>
<Value width="60%">
<ComfySpan>
{props.exportStats.success} / {totalFiles}
</ComfySpan>
</Value>
</FlexWrapper>
{props.exportStats.failed > 0 && (
<FlexWrapper>
<Label width="40%">
{t('FAILED_EXPORTED_FILES')}
</Label>
<Value width="60%">
<ComfySpan>
{props.exportStats.failed} / {totalFiles}
</ComfySpan>
</Value>
</FlexWrapper>
)}
</Typography>
</SpaceBetweenFlex>
</Stack>
</DialogContent>
<DialogActions>
{props.exportStats.failed !== 0 ? (
<Button
size="large"
color="accent"
onClick={props.retryFailed}>
{t('RETRY_EXPORT')}
</Button>
) : (
<Button
size="large"
color="primary"
onClick={props.exportFiles}>
{t('EXPORT_AGAIN')}
</Button>
)}
<Button color="secondary" size="large" onClick={props.onHide}>
{t('CLOSE')}
</Button>
<Button
size="large"
color="primary"
onClick={props.startExport}>
{t('EXPORT_AGAIN')}
</Button>
</DialogActions>
</>
);

View file

@ -11,8 +11,10 @@ import { ExportStage } from 'constants/export';
import VerticallyCentered, { FlexWrapper } from './Container';
import { ProgressBar } from 'react-bootstrap';
import { t } from 'i18next';
import { Trans } from 'react-i18next';
export const ComfySpan = styled('span')`
padding: 0 0.5rem;
word-spacing: 1rem;
color: #ddd;
`;
@ -20,65 +22,57 @@ export const ComfySpan = styled('span')`
interface Props {
exportStage: ExportStage;
exportProgress: ExportProgress;
resumeExport: () => void;
cancelExport: () => void;
pauseExport: () => void;
stopExport: () => void;
closeExportDialog: () => void;
}
export default function ExportInProgress(props: Props) {
const isLoading = props.exportProgress.total === 0;
return (
<>
<DialogContent>
<VerticallyCentered>
<Box mb={1.5}>
<ComfySpan>
{' '}
{props.exportProgress.current} /{' '}
{props.exportProgress.total}{' '}
</ComfySpan>{' '}
<span>
{' '}
files exported{' '}
{props.exportStage === ExportStage.PAUSED &&
`(paused)`}
</span>
{isLoading ? (
t('EXPORT_STARTING')
) : (
<Trans
i18nKey={'EXPORT_PROGRESS'}
components={{
a: <ComfySpan />,
}}
values={{
progress: props.exportProgress,
}}
/>
)}
</Box>
<FlexWrapper px={1}>
<ProgressBar
style={{ width: '100%' }}
now={Math.round(
(props.exportProgress.current * 100) /
props.exportProgress.total
)}
animated={
!(props.exportStage === ExportStage.PAUSED)
now={
isLoading
? 100
: Math.round(
(props.exportProgress.current * 100) /
props.exportProgress.total
)
}
animated
variant="upload-progress-bar"
/>
</FlexWrapper>
</VerticallyCentered>
</DialogContent>
<DialogActions>
{props.exportStage === ExportStage.PAUSED ? (
<Button
size="large"
onClick={props.resumeExport}
color="accent">
{t('RESUME')}
</Button>
) : (
<Button
size="large"
onClick={props.pauseExport}
color="primary">
{t('PAUSE')}
</Button>
)}
<Button
color="secondary"
size="large"
onClick={props.cancelExport}
color="secondary">
{t('CANCEL')}
onClick={props.closeExportDialog}>
{t('CLOSE')}
</Button>
<Button size="large" color="danger" onClick={props.stopExport}>
{t('STOP_EXPORT')}
</Button>
</DialogActions>
</>

View file

@ -1,47 +1,41 @@
import isElectron from 'is-electron';
import React, { useEffect, useMemo, useState, useContext } from 'react';
import React, { useEffect, useState, useContext } from 'react';
import exportService from 'services/exportService';
import { ExportProgress, ExportStats } from 'types/export';
import { getLocalFiles } from 'services/fileService';
import { User } from 'types/user';
import { ExportProgress, ExportSettings, FileExportStats } from 'types/export';
import {
Box,
Button,
Dialog,
DialogContent,
Divider,
Stack,
styled,
Switch,
Tooltip,
Typography,
} from '@mui/material';
import { sleep } from 'utils/common';
import { getExportRecordFileUID } from 'utils/export';
import { logError } from 'utils/sentry';
import { getData, LS_KEYS, setData } from 'utils/storage/localStorage';
import { FlexWrapper, Label, Value } from './Container';
import { SpaceBetweenFlex, VerticallyCenteredFlex } from './Container';
import ExportFinished from './ExportFinished';
import ExportInit from './ExportInit';
import ExportInProgress from './ExportInProgress';
import FolderIcon from '@mui/icons-material/Folder';
import { ExportStage, ExportType } from 'constants/export';
import EnteSpinner from './EnteSpinner';
import { ExportStage } from 'constants/export';
import DialogTitleWithCloseButton from './DialogBox/TitleWithCloseButton';
import MoreHoriz from '@mui/icons-material/MoreHoriz';
import OverflowMenu from './OverflowMenu/menu';
import { OverflowMenuOption } from './OverflowMenu/option';
import { convertBytesToHumanReadable } from 'utils/file/size';
import { CustomError } from 'utils/error';
import { getLocalUserDetails } from 'utils/user';
import { AppContext } from 'pages/_app';
import { getExportDirectoryDoesNotExistMessage } from 'utils/ui';
import { addLogLine } from 'utils/logging';
import { t } from 'i18next';
import LinkButton from './pages/gallery/LinkButton';
import { CustomError } from 'utils/error';
const ExportFolderPathContainer = styled('span')`
const ExportFolderPathContainer = styled(LinkButton)`
width: 262px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
/* Beginning of string */
direction: rtl;
text-align: left;
@ -53,17 +47,16 @@ interface Props {
}
export default function ExportModal(props: Props) {
const appContext = useContext(AppContext);
const userDetails = useMemo(() => getLocalUserDetails(), []);
const [exportStage, setExportStage] = useState(ExportStage.INIT);
const [exportFolder, setExportFolder] = useState('');
const [exportSize, setExportSize] = useState('');
const [continuousExport, setContinuousExport] = useState(false);
const [exportProgress, setExportProgress] = useState<ExportProgress>({
current: 0,
total: 0,
});
const [exportStats, setExportStats] = useState<ExportStats>({
failed: 0,
success: 0,
const [fileExportStats, setFileExportStats] = useState<FileExportStats>({
totalCount: 0,
pendingCount: 0,
});
const [lastExportTime, setLastExportTime] = useState(0);
@ -75,43 +68,53 @@ export default function ExportModal(props: Props) {
return;
}
try {
setExportFolder(getData(LS_KEYS.EXPORT)?.folder);
exportService.electronAPIs.registerStopExportListener(
stopExportHandler
);
exportService.electronAPIs.registerPauseExportListener(
pauseExportHandler
);
exportService.electronAPIs.registerResumeExportListener(
resumeExportHandler
);
exportService.electronAPIs.registerRetryFailedExportListener(
retryFailedExportHandler
);
const exportSettings: ExportSettings = getData(LS_KEYS.EXPORT);
setExportFolder(exportSettings?.folder);
setContinuousExport(exportSettings?.continuousExport);
syncFileCounts();
} catch (e) {
logError(e, 'error in exportModal');
}
}, []);
useEffect(() => {
if (!props.show) {
return;
}
if (exportService.isExportInProgress()) {
setExportStage(ExportStage.INPROGRESS);
}
syncFileCounts();
}, [props.show]);
useEffect(() => {
try {
if (continuousExport) {
exportService.enableContinuousExport(startExport);
} else {
exportService.disableContinuousExport();
}
} catch (e) {
logError(e, 'error handling continuousExport change');
}
}, [continuousExport]);
useEffect(() => {
if (!exportFolder) {
return;
}
const main = async () => {
try {
const exportInfo = await exportService.getExportRecord();
setExportStage(exportInfo?.stage ?? ExportStage.INIT);
setLastExportTime(exportInfo?.lastAttemptTimestamp);
setExportProgress(
exportInfo?.progress ?? { current: 0, total: 0 }
);
setExportStats({
success: exportInfo?.exportedFiles?.length ?? 0,
failed: exportInfo?.failedFiles?.length ?? 0,
});
if (exportInfo?.stage === ExportStage.INPROGRESS) {
await resumeExport();
const exportRecord = await exportService.getExportRecord();
if (!exportRecord) {
setExportStage(ExportStage.INIT);
return;
}
setExportStage(exportRecord.stage);
setLastExportTime(exportRecord.lastAttemptTimestamp);
await syncFileCounts();
if (exportRecord.stage === ExportStage.INPROGRESS) {
await startExport();
}
} catch (e) {
logError(e, 'error handling exportFolder change');
@ -120,62 +123,27 @@ export default function ExportModal(props: Props) {
void main();
}, [exportFolder]);
useEffect(() => {
if (!props.show) {
return;
}
const main = async () => {
const user: User = getData(LS_KEYS.USER);
if (exportStage === ExportStage.FINISHED) {
try {
const localFiles = await getLocalFiles();
const userPersonalFiles = localFiles.filter(
(file) => file.ownerID === user?.id
);
const exportRecord = await exportService.getExportRecord();
const exportedFileCnt = exportRecord.exportedFiles?.length;
const failedFilesCnt = exportRecord.failedFiles?.length;
const syncedFilesCnt = userPersonalFiles.length;
if (syncedFilesCnt > exportedFileCnt + failedFilesCnt) {
await updateExportProgress({
current: exportedFileCnt + failedFilesCnt,
total: syncedFilesCnt,
});
const exportFileUIDs = new Set([
...exportRecord.exportedFiles,
...exportRecord.failedFiles,
]);
const unExportedFiles = userPersonalFiles.filter(
(file) =>
!exportFileUIDs.has(
getExportRecordFileUID(file)
)
);
await exportService.addFilesQueuedRecord(
exportFolder,
unExportedFiles
);
await updateExportStage(ExportStage.PAUSED);
}
} catch (e) {
setExportStage(ExportStage.INIT);
logError(e, 'error while updating exportModal on reopen');
}
}
};
void main();
}, [props.show]);
useEffect(() => {
setExportSize(convertBytesToHumanReadable(userDetails?.usage));
}, [userDetails]);
// =============
// STATE UPDATERS
// ==============
const updateExportFolder = (newFolder: string) => {
const exportSettings: ExportSettings = getData(LS_KEYS.EXPORT);
const updatedExportSettings: ExportSettings = {
...exportSettings,
folder: newFolder,
};
setData(LS_KEYS.EXPORT, updatedExportSettings);
setExportFolder(newFolder);
setData(LS_KEYS.EXPORT, { folder: newFolder });
};
const updateContinuousExport = (updatedContinuousExport: boolean) => {
const exportSettings: ExportSettings = getData(LS_KEYS.EXPORT);
const updatedExportSettings: ExportSettings = {
...exportSettings,
continuousExport: updatedContinuousExport,
};
setData(LS_KEYS.EXPORT, updatedExportSettings);
setContinuousExport(updatedContinuousExport);
};
const updateExportStage = async (newStage: ExportStage) => {
@ -190,70 +158,65 @@ export default function ExportModal(props: Props) {
});
};
const updateExportProgress = async (newProgress: ExportProgress) => {
setExportProgress(newProgress);
await exportService.updateExportRecord({ progress: newProgress });
};
// ======================
// HELPER FUNCTIONS
// =========================
// =======================
const preExportRun = async () => {
const exportFolder = getData(LS_KEYS.EXPORT)?.folder;
if (!exportFolder) {
await selectExportDirectory();
}
const exportFolderExists = exportService.exists(exportFolder);
if (!exportFolderExists) {
appContext.setDialogMessage(
getExportDirectoryDoesNotExistMessage()
);
return;
throw Error(CustomError.EXPORT_FOLDER_DOES_NOT_EXIST);
}
await updateExportStage(ExportStage.INPROGRESS);
await sleep(100);
};
const postExportRun = async (exportResult?: { paused?: boolean }) => {
if (!exportResult?.paused) {
await updateExportStage(ExportStage.FINISHED);
await sleep(100);
await updateExportTime(Date.now());
await syncExportStatsWithRecord();
}
};
const selectExportDirectory = async () => {
const newFolder = await exportService.selectExportDirectory();
if (newFolder) {
updateExportFolder(newFolder);
} else {
throw Error(CustomError.REQUEST_CANCELLED);
}
const postExportRun = async () => {
await updateExportStage(ExportStage.FINISHED);
await updateExportTime(Date.now());
await syncFileCounts();
};
const syncExportStatsWithRecord = async () => {
const exportRecord = await exportService.getExportRecord();
const failed = exportRecord?.failedFiles?.length ?? 0;
const success = exportRecord?.exportedFiles?.length ?? 0;
setExportStats({ failed, success });
const syncFileCounts = async () => {
try {
const fileExportStats = await exportService.getFileExportStats();
setFileExportStats(fileExportStats);
} catch (e) {
logError(e, 'error updating file counts');
}
};
// =============
// UI functions
// =============
const handleChangeExportDirectoryClick = () => {
void exportService.changeExportDirectory(updateExportFolder);
};
const handleOpenExportDirectoryClick = () => {
void exportService.openExportDirectory(exportFolder);
};
const toggleContinuousExport = () => {
try {
updateContinuousExport(!continuousExport);
} catch (e) {
logError(e, 'toggleContinuousExport failed');
}
};
const startExport = async () => {
try {
await preExportRun();
await updateExportProgress({ current: 0, total: 0 });
const exportResult = await exportService.exportFiles(
updateExportProgress,
ExportType.NEW
);
await postExportRun(exportResult);
setExportProgress({ current: 0, total: 0 });
await exportService.exportFiles(setExportProgress);
await postExportRun();
} catch (e) {
if (e.message !== CustomError.REQUEST_CANCELLED) {
if (e.message !== CustomError.EXPORT_FOLDER_DOES_NOT_EXIST) {
logError(e, 'startExport failed');
}
}
@ -264,120 +227,7 @@ export default function ExportModal(props: Props) {
exportService.stopRunningExport();
await postExportRun();
} catch (e) {
if (e.message !== CustomError.REQUEST_CANCELLED) {
logError(e, 'stopExport failed');
}
}
};
const pauseExport = async () => {
try {
await updateExportStage(ExportStage.PAUSED);
exportService.pauseRunningExport();
await postExportRun({ paused: true });
} catch (e) {
if (e.message !== CustomError.REQUEST_CANCELLED) {
logError(e, 'pauseExport failed');
}
}
};
const resumeExport = async () => {
try {
const exportRecord = await exportService.getExportRecord();
await preExportRun();
const pausedStageProgress = exportRecord.progress;
setExportProgress(pausedStageProgress);
addLogLine(
`resuming export, pausedStageProgress: ${JSON.stringify(
pausedStageProgress
)}`
);
const updateExportStatsWithOffset = (progress: ExportProgress) =>
updateExportProgress({
current: pausedStageProgress.current + progress.current,
total: pausedStageProgress.current + progress.total,
});
const exportResult = await exportService.exportFiles(
updateExportStatsWithOffset,
ExportType.PENDING
);
await postExportRun(exportResult);
} catch (e) {
if (e.message !== CustomError.REQUEST_CANCELLED) {
logError(e, 'resumeExport failed');
}
}
};
const retryFailedExport = async () => {
try {
await preExportRun();
await updateExportProgress({
current: 0,
total: exportStats.failed,
});
const exportResult = await exportService.exportFiles(
updateExportProgress,
ExportType.RETRY_FAILED
);
await postExportRun(exportResult);
} catch (e) {
if (e.message !== CustomError.REQUEST_CANCELLED) {
logError(e, 'retryFailedExport failed');
}
}
};
const startExportHandler = () => {
void startExport();
};
const stopExportHandler = () => {
void stopExport();
};
const pauseExportHandler = () => {
void pauseExport();
};
const resumeExportHandler = () => {
void resumeExport();
};
const retryFailedExportHandler = () => {
void retryFailedExport();
};
const ExportDynamicContent = () => {
switch (exportStage) {
case ExportStage.INIT:
return <ExportInit startExport={startExportHandler} />;
case ExportStage.INPROGRESS:
case ExportStage.PAUSED:
return (
<ExportInProgress
exportStage={exportStage}
exportProgress={exportProgress}
resumeExport={resumeExportHandler}
cancelExport={stopExportHandler}
pauseExport={pauseExportHandler}
/>
);
case ExportStage.FINISHED:
return (
<ExportFinished
onHide={props.onHide}
lastExportTime={lastExportTime}
exportStats={exportStats}
exportFiles={startExportHandler}
retryFailed={retryFailedExportHandler}
/>
);
default:
return <></>;
logError(e, 'stopExport failed');
}
};
@ -387,71 +237,80 @@ export default function ExportModal(props: Props) {
{t('EXPORT_DATA')}
</DialogTitleWithCloseButton>
<DialogContent>
<Stack spacing={2}>
<ExportDirectory
exportFolder={exportFolder}
selectExportDirectory={selectExportDirectory}
exportStage={exportStage}
/>
<ExportSize exportSize={exportSize} />
</Stack>
<ExportDirectory
exportFolder={exportFolder}
changeExportDirectory={handleChangeExportDirectoryClick}
exportStage={exportStage}
openExportDirectory={handleOpenExportDirectoryClick}
/>
<ContinuousExport
continuousExport={continuousExport}
toggleContinuousExport={toggleContinuousExport}
/>
<SpaceBetweenFlex minHeight={'48px'} pr={'16px'}>
<Typography color="text.secondary">
{t('TOTAL_ITEMS')}
</Typography>
<Typography color="text.secondary">
{fileExportStats.totalCount}
</Typography>
</SpaceBetweenFlex>
</DialogContent>
<Divider />
<ExportDynamicContent />
<ExportDynamicContent
exportStage={exportStage}
startExport={startExport}
stopExport={stopExport}
onHide={props.onHide}
lastExportTime={lastExportTime}
pendingFileCount={fileExportStats.pendingCount}
exportProgress={exportProgress}
/>
</Dialog>
);
}
function ExportDirectory({ exportFolder, selectExportDirectory, exportStage }) {
function ExportDirectory({
exportFolder,
changeExportDirectory,
exportStage,
openExportDirectory,
}) {
return (
<FlexWrapper>
<Label width="30%">{t('DESTINATION')}</Label>
<Value width="70%">
<SpaceBetweenFlex minHeight={'48px'}>
<Typography color="text.secondary" mr={'16px'}>
{t('DESTINATION')}
</Typography>
<>
{!exportFolder ? (
<Button color={'accent'} onClick={selectExportDirectory}>
<Button color={'accent'} onClick={changeExportDirectory}>
{t('SELECT_FOLDER')}
</Button>
) : (
<>
<Tooltip title={exportFolder}>
<ExportFolderPathContainer>
{exportFolder}
</ExportFolderPathContainer>
</Tooltip>
{(exportStage === ExportStage.FINISHED ||
exportStage === ExportStage.INIT) && (
<VerticallyCenteredFlex>
<ExportFolderPathContainer
onClick={openExportDirectory}>
<Tooltip title={exportFolder}>
<span>{exportFolder}</span>
</Tooltip>
</ExportFolderPathContainer>
{exportStage === ExportStage.FINISHED ||
exportStage === ExportStage.INIT ? (
<ExportDirectoryOption
selectExportDirectory={selectExportDirectory}
changeExportDirectory={changeExportDirectory}
/>
) : (
<Box sx={{ width: '16px' }} />
)}
</>
</VerticallyCenteredFlex>
)}
</Value>
</FlexWrapper>
</>
</SpaceBetweenFlex>
);
}
function ExportSize({ exportSize }) {
return (
<FlexWrapper>
<Label width="30%">{t('EXPORT_SIZE')} </Label>
<Value width="70%">
{exportSize ? `${exportSize}` : <EnteSpinner />}
</Value>
</FlexWrapper>
);
}
function ExportDirectoryOption({ selectExportDirectory }) {
const handleClick = () => {
try {
selectExportDirectory();
} catch (e) {
if (e.message !== CustomError.REQUEST_CANCELLED) {
logError(e, 'startExport failed');
}
}
};
function ExportDirectoryOption({ changeExportDirectory }) {
return (
<OverflowMenu
triggerButtonProps={{
@ -462,10 +321,72 @@ function ExportDirectoryOption({ selectExportDirectory }) {
ariaControls={'export-option'}
triggerButtonIcon={<MoreHoriz />}>
<OverflowMenuOption
onClick={handleClick}
onClick={changeExportDirectory}
startIcon={<FolderIcon />}>
{t('CHANGE_FOLDER')}
</OverflowMenuOption>
</OverflowMenu>
);
}
function ContinuousExport({ continuousExport, toggleContinuousExport }) {
return (
<SpaceBetweenFlex minHeight={'48px'}>
<Typography color="text.secondary">
{t('CONTINUOUS_EXPORT')}
</Typography>
<Box>
<Switch
color="accent"
checked={continuousExport}
onChange={toggleContinuousExport}
/>
</Box>
</SpaceBetweenFlex>
);
}
const ExportDynamicContent = ({
exportStage,
startExport,
stopExport,
onHide,
lastExportTime,
pendingFileCount,
exportProgress,
}: {
exportStage: ExportStage;
startExport: () => void;
stopExport: () => void;
onHide: () => void;
lastExportTime: number;
pendingFileCount: number;
exportProgress: ExportProgress;
}) => {
switch (exportStage) {
case ExportStage.INIT:
return <ExportInit startExport={startExport} />;
case ExportStage.INPROGRESS:
return (
<ExportInProgress
exportStage={exportStage}
exportProgress={exportProgress}
stopExport={stopExport}
closeExportDialog={onHide}
/>
);
case ExportStage.FINISHED:
return (
<ExportFinished
onHide={onHide}
lastExportTime={lastExportTime}
pendingFileCount={pendingFileCount}
startExport={startExport}
/>
);
default:
return <></>;
}
};

View file

@ -1,19 +1,18 @@
import React, { useState, useEffect } from 'react';
import styled from 'styled-components';
import { styled } from '@mui/material';
import { imageBitmapToBlob } from 'utils/image';
import { logError } from 'utils/sentry';
import { getBlobFromCache } from 'utils/storage/cache';
export const Image = styled.img``;
export const FaceCropsRow = styled.div`
export const FaceCropsRow = styled('div')`
& > img {
width: 256px;
height: 256px;
}
`;
export const FaceImagesRow = styled.div`
export const FaceImagesRow = styled('div')`
& > img {
width: 112px;
height: 112px;
@ -92,9 +91,5 @@ export function ImageBlobView(props: { blob: Blob }) {
}
}, [props.blob]);
return (
<>
<Image src={imgUrl}></Image>
</>
);
return <img src={imgUrl} />;
}

View file

@ -24,7 +24,8 @@ export {};
// import mlIDbStorage from 'utils/storage/mlIDbStorage';
// import { getFaceCropBlobFromStorage } from 'utils/machineLearning/faceCrop';
// import { PeopleList } from './PeopleList';
// import styled from 'styled-components';
// import { styled } from '@mui/material';
// import { RawNodeDatum } from 'react-d3-tree/lib/types/common';
// import { DebugInfo, mstToBinaryTree } from 'hdbscan';
// import { toD3Tree } from 'utils/machineLearning/clustering';
@ -70,7 +71,7 @@ export {};
// );
// }
// const D3ImageContainer = styled.div`
// const D3ImageContainer = styled('div')`
// & > img {
// width: 100%;
// height: 100%;

View file

@ -5,7 +5,7 @@ import {
getPeopleList,
getUnidentifiedFaces,
} from 'utils/machineLearning';
import styled from 'styled-components';
import { styled } from '@mui/material';
import { EnteFile } from 'types/file';
import { ImageCacheView } from './ImageViews';
import { CACHES } from 'constants/cache';
@ -14,7 +14,7 @@ import { addLogLine } from 'utils/logging';
import { logError } from 'utils/sentry';
import { t } from 'i18next';
const FaceChipContainer = styled.div`
const FaceChipContainer = styled('div')`
display: flex;
flex-wrap: wrap;
justify-content: center;
@ -24,7 +24,7 @@ const FaceChipContainer = styled.div`
overflow: auto;
`;
const FaceChip = styled.div<{ clickable?: boolean }>`
const FaceChip = styled('div')<{ clickable?: boolean }>`
width: 112px;
height: 112px;
margin: 5px;

View file

@ -0,0 +1,91 @@
import { MenuItem, ButtonProps, Typography, Box } from '@mui/material';
import PublicShareSwitch from 'components/Collections/CollectionShare/publicShare/switch';
import {
FluidContainer,
HorizontalFlex,
SpaceBetweenFlex,
} from 'components/Container';
import { DotSeparator } from 'components/Sidebar/styledComponents';
import React from 'react';
interface Iprops {
onClick: () => void;
color?: ButtonProps['color'];
startIcon?: React.ReactNode;
endIcon?: React.ReactNode;
subText?: string;
children?: any;
hasSwitch?: boolean;
checked?: boolean;
}
export function EnteMenuItem({
onClick,
color = 'primary',
startIcon,
endIcon,
subText,
children,
hasSwitch = false,
checked,
}: Iprops) {
const handleClick = () => {
onClick();
};
return (
<MenuItem
onClick={handleClick}
sx={{
minWidth: '220px',
color: (theme) => theme.palette[color].main,
backgroundColor: (theme) => theme.palette.background.overPaper,
padding: 2,
'& .MuiSvgIcon-root': {
fontSize: '20px',
},
borderRadius: '8px',
}}>
<SpaceBetweenFlex>
<HorizontalFlex>
{startIcon && (
<Box
sx={{
padding: 0,
marginRight: 1.5,
}}>
{startIcon}
</Box>
)}
<Typography variant="button">{children}</Typography>
{subText && (
<FluidContainer
sx={{
color: 'text.secondary',
fontSize: '14px',
}}>
<DotSeparator style={{ fontSize: 8 }} />
{subText}
</FluidContainer>
)}
</HorizontalFlex>
<HorizontalFlex>
{endIcon && (
<Box
sx={{
marginLeft: 1,
}}>
{endIcon}
</Box>
)}
{hasSwitch && (
<PublicShareSwitch
checked={checked}
onChange={handleClick}
/>
)}
</HorizontalFlex>
</SpaceBetweenFlex>
</MenuItem>
);
}

View file

@ -0,0 +1,16 @@
import { Divider } from '@mui/material';
interface Iprops {
hasIcon?: boolean;
}
export default function EnteMenuItemDivider({ hasIcon = false }: Iprops) {
return (
<Divider
sx={{
'&&&': {
my: 0,
ml: hasIcon ? '48px' : '16px',
},
}}
/>
);
}

View file

@ -0,0 +1,16 @@
import { styled } from '@mui/material';
export const EnteMenuItemGroup = styled('div')(
({ theme }) => `
& > .MuiMenuItem-root:not(:last-of-type) {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
& > .MuiMenuItem-root:not(:first-of-type) {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
background-color: ${theme.palette.background.overPaper};
border-radius: 4px;
`
);

View file

@ -1,6 +1,6 @@
import { FlexWrapper } from 'components/Container';
import { styled } from '@mui/material';
import { SpecialPadding } from 'styles/SpecialPadding';
import { IMAGE_CONTAINER_MAX_WIDTH, MIN_COLUMNS } from 'constants/gallery';
const NavbarBase = styled(FlexWrapper)`
min-height: 64px;
position: sticky;
@ -10,7 +10,10 @@ const NavbarBase = styled(FlexWrapper)`
border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
background-color: ${({ theme }) => theme.palette.background.default};
margin-bottom: 16px;
${SpecialPadding}
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) {
padding: 0 4px;
}
`;
export default NavbarBase;

View file

@ -28,7 +28,9 @@ export const PasswordStrengthHint = ({
})}
textAlign={'left'}
flex={1}>
{password ? t('PASSPHRASE_STRENGTH', { passwordStrength }) : ''}
{password
? t('PASSPHRASE_STRENGTH', { context: passwordStrength })
: ''}
</Typography>
</FlexWrapper>
);

View file

@ -19,7 +19,6 @@ import { DeduplicateContext } from 'pages/deduplicate';
import { FlexWrapper } from './Container';
import { Typography } from '@mui/material';
import { GalleryContext } from 'pages/gallery';
import { SpecialPadding } from 'styles/SpecialPadding';
import { formatDate } from 'utils/time/format';
import { Trans } from 'react-i18next';
import { t } from 'i18next';
@ -111,7 +110,10 @@ const ListContainer = styled(Box)<{
grid-column-gap: ${GAP_BTW_TILES}px;
width: 100%;
color: #fff;
${SpecialPadding}
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) {
padding: 0 4px;
}
`;
const ListItemContainer = styled(FlexWrapper)<{ span: number }>`

View file

@ -1,9 +0,0 @@
import React from 'react';
import { Label, Row, Value } from 'components/Container';
export const RenderInfoItem = (label: string, value: string | JSX.Element) => (
<Row>
<Label width="30%">{label}</Label>
<Value width="70%">{value}</Value>
</Row>
);

View file

@ -4,10 +4,13 @@ import {
FluidContainer,
} from 'components/Container';
import { css, styled } from '@mui/material';
import { SpecialPadding } from 'styles/SpecialPadding';
import { IMAGE_CONTAINER_MAX_WIDTH, MIN_COLUMNS } from 'constants/gallery';
export const SearchBarWrapper = styled(FlexWrapper)`
${SpecialPadding}
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) {
padding: 0 4px;
}
`;
export const SearchMobileBox = styled(FluidContainer)`

View file

@ -1,9 +1,8 @@
import { OptionWithDivider } from 'components/Collections/CollectionShare/publicShare/manage/selectComponents/OptionWithDivider';
import DropdownInput, { DropdownOption } from 'components/DropdownInput';
import { Language } from 'constants/locale';
import { useLocalState } from 'hooks/useLocalState';
import { t } from 'i18next';
import { useRouter } from 'next/router';
import Select from 'react-select';
import { DropdownStyle } from 'styles/dropdown';
import { getBestPossibleUserLocale } from 'utils/i18n';
import { LS_KEYS } from 'utils/storage/localStorage';
@ -16,7 +15,7 @@ const getLocaleDisplayName = (l: Language) => {
}
};
const getLanguageOptions = () => {
const getLanguageOptions = (): DropdownOption<Language>[] => {
return Object.values(Language).map((lang) => ({
label: getLocaleDisplayName(lang),
value: lang,
@ -37,19 +36,12 @@ export const LanguageSelector = () => {
};
return (
<Select
menuPosition="fixed"
<DropdownInput
options={getLanguageOptions()}
components={{
Option: OptionWithDivider,
}}
isSearchable={false}
value={{
label: getLocaleDisplayName(userLocale),
value: userLocale,
}}
onChange={(e) => updateCurrentLocale(e.value)}
styles={DropdownStyle}
label={t('LANGUAGE')}
labelProps={{ color: 'text.secondary' }}
selectedValue={userLocale}
setSelectedValue={updateCurrentLocale}
/>
);
};

View file

@ -1,7 +1,6 @@
import ChevronRight from '@mui/icons-material/ChevronRight';
import { Box, DialogProps, Stack } from '@mui/material';
import { EnteDrawer } from 'components/EnteDrawer';
import MenuSectionTitle from 'components/Menu/MenuSectionTitle';
import Titlebar from 'components/Titlebar';
import isElectron from 'is-electron';
import { useState } from 'react';
@ -46,10 +45,7 @@ export default function Preferences({ open, onClose, onRootClose }) {
/>
<Box px={'8px'}>
<Stack py="20px" spacing="24px">
<Box>
<MenuSectionTitle title={t('LANGUAGE')} />
<LanguageSelector />
</Box>
<LanguageSelector />
{isElectron() && (
<SidebarButton
variant="contained"

View file

@ -33,7 +33,7 @@ export default function UserNameInputDialog({
initialValue={uploaderName}
callback={handleSubmit}
placeholder={t('NAME_PLACEHOLDER')}
buttonText={t('add_photos', { count: toUploadFilesCount })}
buttonText={t('add_photos', { count: toUploadFilesCount ?? 0 })}
fieldType="text"
blockButton
secondaryButtonAction={onClose}

View file

@ -1,7 +1,7 @@
export const ENCRYPTION_CHUNK_SIZE = 4 * 1024 * 1024;
export enum PasswordStrength {
WEAK,
MODERATE,
STRONG,
WEAK = 'WEAK',
MODERATE = 'MODERATE',
STRONG = 'STRONG',
}

View file

@ -1,28 +1,11 @@
export const ENTE_METADATA_FOLDER = 'metadata';
export enum ExportNotification {
START = 'Export started',
IN_PROGRESS = 'Export already in progress',
FINISH = 'Export finished',
FAILED = 'Export failed',
ABORT = 'Export aborted',
PAUSE = 'Export paused',
UP_TO_DATE = `No new files to export`,
}
export enum RecordType {
SUCCESS = 'success',
FAILED = 'failed',
}
export enum ExportStage {
INIT,
INPROGRESS,
PAUSED,
FINISHED,
}
export enum ExportType {
NEW,
PENDING,
RETRY_FAILED,
INIT = 0,
INPROGRESS = 1,
FINISHED = 3,
}

View file

@ -5,11 +5,13 @@ export function useLocalState<T>(
key: LS_KEYS,
initialValue?: T
): [T, Dispatch<SetStateAction<T>>] {
const [value, setValue] = useState<T>();
const [value, setValue] = useState<T>(initialValue);
useEffect(() => {
const { value } = getData(key) ?? {};
setValue(value ?? initialValue);
if (value) {
setValue(value);
}
}, []);
useEffect(() => {

View file

@ -25,9 +25,11 @@ import { styled, ThemeProvider } from '@mui/material/styles';
import darkThemeOptions from 'themes/darkThemeOptions';
import lightThemeOptions from 'themes/lightThemeOptions';
import { CssBaseline, useMediaQuery } from '@mui/material';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import * as types from 'styled-components/cssprop'; // need to css prop on styled component
import { SetDialogBoxAttributes, DialogBoxAttributes } from 'types/dialogBox';
import {
SetDialogBoxAttributes,
DialogBoxAttributes,
DialogBoxAttributesV2,
} from 'types/dialogBox';
import {
getFamilyPortalRedirectURL,
getRoadmapRedirectURL,
@ -56,6 +58,10 @@ import { SetTheme } from 'types/theme';
import { useLocalState } from 'hooks/useLocalState';
import { THEME_COLOR } from 'constants/theme';
import { setupI18n } from 'i18n';
import createEmotionCache from 'themes/createEmotionCache';
import { CacheProvider, EmotionCache } from '@emotion/react';
import { AppProps } from 'next/app';
import DialogBoxV2 from 'components/DialogBoxV2';
export const MessageContainer = styled('div')`
background-color: #111;
@ -94,6 +100,7 @@ type AppContextType = {
theme: THEME_COLOR;
setTheme: SetTheme;
somethingWentWrong: () => void;
setDialogBoxAttributesV2: (attributes: DialogBoxAttributesV2) => void;
};
export enum FLASH_MESSAGE_TYPE {
@ -115,7 +122,19 @@ const redirectMap = new Map([
const APP_TITLE = 'ente Photos';
export default function App({ Component, err }) {
// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache();
export interface EnteAppProps extends AppProps {
emotionCache?: EmotionCache;
}
export default function App(props) {
const {
Component,
emotionCache = clientSideEmotionCache,
pageProps,
} = props;
const router = useRouter();
const [isI18nReady, setIsI18nReady] = useState<boolean>(false);
const [loading, setLoading] = useState(false);
@ -131,7 +150,11 @@ export default function App({ Component, err }) {
const isLoadingBarRunning = useRef(false);
const loadingBar = useRef(null);
const [dialogMessage, setDialogMessage] = useState<DialogBoxAttributes>();
const [dialogBoxAttributeV2, setDialogBoxAttributesV2] =
useState<DialogBoxAttributesV2>();
useState<DialogBoxAttributes>(null);
const [messageDialogView, setMessageDialogView] = useState(false);
const [dialogBoxV2View, setDialogBoxV2View] = useState(false);
const [isFolderSyncRunning, setIsFolderSyncRunning] = useState(false);
const [watchFolderView, setWatchFolderView] = useState(false);
const [watchFolderFiles, setWatchFolderFiles] = useState<FileList>(null);
@ -281,6 +304,10 @@ export default function App({ Component, err }) {
setMessageDialogView(true);
}, [dialogMessage]);
useEffect(() => {
setDialogBoxV2View(true);
}, [dialogBoxV2View]);
useEffect(() => {
setNotificationView(true);
}, [notificationAttributes]);
@ -314,6 +341,7 @@ export default function App({ Component, err }) {
};
const closeMessageDialog = () => setMessageDialogView(false);
const closeDialogBoxV2 = () => setDialogBoxV2View(false);
const somethingWentWrong = () =>
setDialogMessage({
@ -323,7 +351,7 @@ export default function App({ Component, err }) {
});
return (
<>
<CacheProvider value={emotionCache}>
<Head>
<title>{isI18nReady ? t('TITLE') : APP_TITLE}</title>
<meta
@ -372,6 +400,12 @@ export default function App({ Component, err }) {
onClose={closeMessageDialog}
attributes={dialogMessage}
/>
<DialogBoxV2
sx={{ zIndex: 1600 }}
open={dialogBoxV2View}
onClose={closeDialogBoxV2}
attributes={dialogBoxAttributeV2}
/>
<Notification
open={notificationView}
onClose={closeNotification}
@ -403,6 +437,7 @@ export default function App({ Component, err }) {
theme,
setTheme,
somethingWentWrong,
setDialogBoxAttributesV2,
}}>
{loading || !isI18nReady ? (
<VerticallyCentered>
@ -411,10 +446,10 @@ export default function App({ Component, err }) {
</EnteSpinner>
</VerticallyCentered>
) : (
<Component err={err} setLoading={setLoading} />
<Component setLoading={setLoading} {...pageProps} />
)}
</AppContext.Provider>
</ThemeProvider>
</>
</CacheProvider>
);
}

View file

@ -1,66 +1,110 @@
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
import Document, {
Html,
Head,
Main,
NextScript,
DocumentProps,
DocumentContext,
} from 'next/document';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
import createEmotionServer from '@emotion/server/create-instance';
import { AppType } from 'next/app';
import createEmotionCache from 'themes/createEmotionCache';
import { EnteAppProps } from './_app';
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
render() {
return (
<Html lang="en">
<Head>
<meta
name="description"
content="ente is a privacy focussed photo storage service that offers end-to-end encryption."
/>
<link
rel="icon"
href="/images/favicon.png"
type="image/png"
/>
<link rel="manifest" href="manifest.json" />
<link rel="apple-touch-icon" href="/images/ente/512.png" />
<meta name="theme-color" content="#111" />
<link
rel="icon"
type="image/png"
href="/images/favicon.png"
/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
interface EnteDocumentProps extends DocumentProps {
emotionStyleTags: JSX.Element[];
}
export default function EnteDocument({ emotionStyleTags }: EnteDocumentProps) {
return (
<Html lang="en">
<Head>
<meta
name="description"
content="ente is a privacy focussed photo storage service that offers end-to-end encryption."
/>
<link rel="icon" href="/images/favicon.png" type="image/png" />
<link rel="manifest" href="manifest.json" />
<link rel="apple-touch-icon" href="/images/ente/512.png" />
<meta name="theme-color" content="#111" />
<link rel="icon" type="image/png" href="/images/favicon.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black"
/>
{emotionStyleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with static-site generation (SSG).
EnteDocument.getInitialProps = async (ctx: DocumentContext) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
const originalRenderPage = ctx.renderPage;
// You can consider sharing the same Emotion cache between all the SSR requests to speed up performance.
// However, be aware that it can have global side effects.
const cache = createEmotionCache();
// eslint-disable-next-line @typescript-eslint/unbound-method
const { extractCriticalToChunks } = createEmotionServer(cache);
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (
App: React.ComponentType<
React.ComponentProps<AppType> & EnteAppProps
>
) =>
function EnhanceApp(props) {
return <App emotionCache={cache} {...props} />;
},
});
const initialProps = await Document.getInitialProps(ctx);
// This is important. It prevents Emotion to render invalid HTML.
// See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
const emotionStyles = extractCriticalToChunks(initialProps.html);
const emotionStyleTags = emotionStyles.styles.map((style) => (
<style
data-emotion={`${style.key} ${style.ids.join(' ')}`}
key={style.key}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: style.css }}
/>
));
return {
...initialProps,
emotionStyleTags,
};
};

View file

@ -1,8 +1,6 @@
import { runningInBrowser } from 'utils/common';
import {
getExportQueuedFiles,
getExportFailedFiles,
getFilesUploadedAfterLastExport,
getUnExportedFiles,
dedupe,
getGoogleLikeMetadataFile,
getExportRecordFileUID,
@ -15,7 +13,6 @@ import {
getOldFileMetadataSavePath,
getExportedFiles,
getMetadataFolderPath,
getCollectionsCreatedAfterLastExport,
getCollectionsRenamedAfterLastExport,
getCollectionIDPathMapFromExportRecord,
} from 'utils/export';
@ -34,6 +31,7 @@ import { decodeMotionPhoto } from './motionPhotoService';
import {
generateStreamFromArrayBuffer,
getFileExtension,
getPersonalFiles,
mergeMetadata,
} from 'utils/file';
@ -41,62 +39,147 @@ import { updateFileCreationDateInEXIF } from './upload/exifService';
import QueueProcessor from './queueProcessor';
import { Collection } from 'types/collection';
import {
ExportProgress,
CollectionIDNameMap,
CollectionIDPathMap,
ExportProgress,
ExportRecord,
ExportRecordV1,
FileExportStats,
} from 'types/export';
import { User } from 'types/user';
import { FILE_TYPE, TYPE_JPEG, TYPE_JPG } from 'constants/file';
import { ExportType, ExportNotification, RecordType } from 'constants/export';
import { RecordType } from 'constants/export';
import { ElectronAPIs } from 'types/electron';
import { CustomError } from 'utils/error';
import { addLogLine } from 'utils/logging';
import { t } from 'i18next';
import { eventBus, Events } from './events';
import { getCollectionNameMap } from 'utils/collection';
const LATEST_EXPORT_VERSION = 1;
const EXPORT_RECORD_FILE_NAME = 'export_status.json';
class ExportService {
electronAPIs: ElectronAPIs;
export const ENTE_EXPORT_DIRECTORY = 'ente Photos';
private exportInProgress: Promise<{ paused: boolean }> = null;
class ExportService {
private electronAPIs: ElectronAPIs;
private exportInProgress: Promise<void> = null;
private exportRecordUpdater = new QueueProcessor<void>(1);
private stopExport: boolean = false;
private pauseExport: boolean = false;
private allElectronAPIsExist: boolean = false;
private fileReader: FileReader = null;
private continuousExportEventHandler: () => void;
constructor() {
this.electronAPIs = runningInBrowser() && window['ElectronAPIs'];
this.allElectronAPIsExist = !!this.electronAPIs?.exists;
}
async selectExportDirectory() {
async changeExportDirectory(callback: (newExportDir: string) => void) {
try {
return await this.electronAPIs.selectRootDirectory();
const newRootDir = await this.electronAPIs.selectRootDirectory();
if (!newRootDir) {
return;
}
const newExportDir = `${newRootDir}/${ENTE_EXPORT_DIRECTORY}`;
await this.electronAPIs.checkExistsAndCreateDir(newExportDir);
callback(newExportDir);
} catch (e) {
logError(e, 'failed to selectExportDirectory ');
logError(e, 'changeExportDirectory failed');
}
}
async openExportDirectory(exportFolder: string) {
try {
await this.electronAPIs.openDirectory(exportFolder);
} catch (e) {
logError(e, 'openExportDirectory failed');
}
}
enableContinuousExport(startExport: () => Promise<void>) {
try {
if (this.continuousExportEventHandler) {
addLogLine('continuous export already enabled');
return;
}
const reRunNeeded = { current: false };
this.continuousExportEventHandler = async () => {
try {
addLogLine('continuous export triggered');
if (this.exportInProgress) {
addLogLine('export in progress, scheduling re-run');
reRunNeeded.current = true;
return;
}
await startExport();
if (reRunNeeded.current) {
reRunNeeded.current = false;
addLogLine('re-running export');
setTimeout(this.continuousExportEventHandler, 0);
}
} catch (e) {
logError(e, 'continuous export failed');
}
};
this.continuousExportEventHandler();
eventBus.addListener(
Events.LOCAL_FILES_UPDATED,
this.continuousExportEventHandler
);
} catch (e) {
logError(e, 'failed to enableContinuousExport ');
throw e;
}
}
disableContinuousExport() {
try {
if (!this.continuousExportEventHandler) {
addLogLine('continuous export already disabled');
return;
}
eventBus.removeListener(
Events.LOCAL_FILES_UPDATED,
this.continuousExportEventHandler
);
this.continuousExportEventHandler = null;
} catch (e) {
logError(e, 'failed to disableContinuousExport');
throw e;
}
}
getFileExportStats = async (): Promise<FileExportStats> => {
try {
const exportRecord = await this.getExportRecord();
const userPersonalFiles = await getPersonalFiles();
const unExportedFiles = getUnExportedFiles(
userPersonalFiles,
exportRecord
);
return {
totalCount: userPersonalFiles.length,
pendingCount: unExportedFiles.length,
};
} catch (e) {
logError(e, 'getUpdateFileLists failed');
throw e;
}
};
stopRunningExport() {
this.stopExport = true;
}
pauseRunningExport() {
this.pauseExport = true;
}
async exportFiles(
updateProgress: (progress: ExportProgress) => Promise<void>,
exportType: ExportType
) {
async exportFiles(updateProgress: (progress: ExportProgress) => void) {
try {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
if (this.exportInProgress) {
this.electronAPIs.sendNotification(
ExportNotification.IN_PROGRESS
t('EXPORT_NOTIFICATION.IN_PROGRESS')
);
return await this.exportInProgress;
}
this.electronAPIs.showOnTray('starting export');
const exportDir = getData(LS_KEYS.EXPORT)?.folder;
if (!exportDir) {
// no-export folder set
@ -104,7 +187,6 @@ class ExportService {
}
const user: User = getData(LS_KEYS.USER);
let filesToExport: EnteFile[];
const localFiles = await getLocalFiles();
const userPersonalFiles = localFiles
.filter((file) => file.ownerID === user?.id)
@ -130,48 +212,25 @@ class ExportService {
}
const exportRecord = await this.getExportRecord(exportDir);
addLogLine(
`export stats -> progress: ${JSON.stringify(
exportRecord.progress
)} stage:${exportRecord.stage} queuedFilesCount: ${
exportRecord?.queuedFiles?.length
} exportedFiles: ${exportRecord?.exportedFiles?.length}
failedFiles: ${exportRecord?.failedFiles?.length}`
const filesToExport = getUnExportedFiles(
userPersonalFiles,
exportRecord
);
if (exportType === ExportType.NEW) {
filesToExport = getFilesUploadedAfterLastExport(
userPersonalFiles,
exportRecord
);
} else if (exportType === ExportType.RETRY_FAILED) {
filesToExport = getExportFailedFiles(
userPersonalFiles,
exportRecord
);
} else {
filesToExport = getExportQueuedFiles(
userPersonalFiles,
exportRecord
);
}
addLogLine(
`starting export, type: ${exportType}, filesToExportCount: ${filesToExport?.length}, userPersonalFileCount: ${userPersonalFiles?.length}`
`starting export, filesToExportCount: ${filesToExport?.length}, userPersonalFileCount: ${userPersonalFiles?.length}`
);
const collectionIDPathMap: CollectionIDPathMap =
getCollectionIDPathMapFromExportRecord(exportRecord);
const newCollections = getCollectionsCreatedAfterLastExport(
userCollections,
exportRecord
);
const collectionIDNameMap = getCollectionNameMap(collections);
const renamedCollections = getCollectionsRenamedAfterLastExport(
userCollections,
exportRecord
);
this.exportInProgress = this.fileExporter(
filesToExport,
newCollections,
collectionIDNameMap,
renamedCollections,
collectionIDPathMap,
updateProgress,
@ -189,20 +248,13 @@ class ExportService {
async fileExporter(
files: EnteFile[],
newCollections: Collection[],
collectionIDNameMap: CollectionIDNameMap,
renamedCollections: Collection[],
collectionIDPathMap: CollectionIDPathMap,
updateProgress: (progress: ExportProgress) => Promise<void>,
updateProgress: (progress: ExportProgress) => void,
exportDir: string
): Promise<{ paused: boolean }> {
): Promise<void> {
try {
if (newCollections?.length) {
await this.createNewCollectionFolders(
newCollections,
exportDir,
collectionIDPathMap
);
}
if (
renamedCollections?.length &&
this.checkAllElectronAPIsExists()
@ -215,44 +267,37 @@ class ExportService {
}
if (!files?.length) {
this.electronAPIs.sendNotification(
ExportNotification.UP_TO_DATE
t('EXPORT_NOTIFICATION.UP_TO_DATE')
);
return { paused: false };
return;
}
this.stopExport = false;
this.pauseExport = false;
await this.addFilesQueuedRecord(exportDir, files);
const failedFileCount = 0;
this.electronAPIs.showOnTray({
export_progress: `0 / ${files.length} files exported`,
});
await updateProgress({
current: 0,
total: files.length,
});
this.electronAPIs.sendNotification(ExportNotification.START);
for (const [index, file] of files.entries()) {
if (this.stopExport || this.pauseExport) {
if (this.pauseExport) {
this.electronAPIs.showOnTray({
export_progress: `${index} / ${files.length} files exported (paused)`,
paused: true,
});
}
this.electronAPIs.sendNotification(t('EXPORT_NOTIFICATION.START'));
let success = 0;
for (const file of files) {
if (this.stopExport) {
break;
}
const collectionPath = collectionIDPathMap.get(
file.collectionID
);
try {
let collectionPath = collectionIDPathMap.get(
file.collectionID
);
if (!collectionPath || !this.exists(collectionPath)) {
collectionPath = await this.createNewCollectionFolder(
exportDir,
file.collectionID,
collectionIDNameMap,
collectionIDPathMap
);
}
await this.downloadAndSave(file, collectionPath);
await this.addFileExportedRecord(
exportDir,
file,
RecordType.SUCCESS
);
success++;
updateProgress({ current: success, total: files.length });
} catch (e) {
logError(e, 'export failed for a file');
if (
@ -267,42 +312,17 @@ class ExportService {
RecordType.FAILED
);
}
this.electronAPIs.showOnTray({
export_progress: `${index + 1} / ${
files.length
} files exported`,
});
await updateProgress({
current: index + 1,
total: files.length,
});
}
if (this.stopExport) {
this.electronAPIs.sendNotification(ExportNotification.ABORT);
this.electronAPIs.showOnTray();
} else if (this.pauseExport) {
this.electronAPIs.sendNotification(ExportNotification.PAUSE);
return { paused: true };
} else if (failedFileCount > 0) {
this.electronAPIs.sendNotification(ExportNotification.FAILED);
this.electronAPIs.showOnTray({
retry_export: `Retry failed exports`,
});
} else {
this.electronAPIs.sendNotification(ExportNotification.FINISH);
this.electronAPIs.showOnTray();
if (!this.stopExport) {
this.electronAPIs.sendNotification(
t('EXPORT_NOTIFICATION.FINISH')
);
}
return { paused: false };
} catch (e) {
logError(e, 'fileExporter failed');
throw e;
}
}
async addFilesQueuedRecord(folder: string, files: EnteFile[]) {
const exportRecord = await this.getExportRecord(folder);
exportRecord.queuedFiles = files.map(getExportRecordFileUID);
await this.updateExportRecord(exportRecord, folder);
}
async addFileExportedRecord(
folder: string,
@ -312,29 +332,13 @@ class ExportService {
try {
const fileUID = getExportRecordFileUID(file);
const exportRecord = await this.getExportRecord(folder);
exportRecord.queuedFiles = exportRecord.queuedFiles.filter(
(queuedFilesUID) => queuedFilesUID !== fileUID
);
if (type === RecordType.SUCCESS) {
if (!exportRecord.exportedFiles) {
exportRecord.exportedFiles = [];
}
exportRecord.exportedFiles.push(fileUID);
exportRecord.failedFiles &&
(exportRecord.failedFiles = exportRecord.failedFiles.filter(
(FailedFileUID) => FailedFileUID !== fileUID
));
} else {
if (!exportRecord.failedFiles) {
exportRecord.failedFiles = [];
}
if (!exportRecord.failedFiles.find((x) => x === fileUID)) {
exportRecord.failedFiles.push(fileUID);
}
}
exportRecord.exportedFiles = dedupe(exportRecord.exportedFiles);
exportRecord.queuedFiles = dedupe(exportRecord.queuedFiles);
exportRecord.failedFiles = dedupe(exportRecord.failedFiles);
await this.updateExportRecord(exportRecord, folder);
} catch (e) {
logError(e, 'addFileExportedRecord failed');
@ -344,7 +348,7 @@ class ExportService {
async addCollectionExportedRecord(
folder: string,
collection: Collection,
collectionID: number,
collectionFolderPath: string
) {
const exportRecord = await this.getExportRecord(folder);
@ -353,20 +357,23 @@ class ExportService {
}
exportRecord.exportedCollectionPaths = {
...exportRecord.exportedCollectionPaths,
[collection.id]: collectionFolderPath,
[collectionID]: collectionFolderPath,
};
await this.updateExportRecord(exportRecord, folder);
}
async updateExportRecord(newData: ExportRecord, folder?: string) {
async updateExportRecord(newData: Partial<ExportRecord>, folder?: string) {
const response = this.exportRecordUpdater.queueUpRequest(() =>
this.updateExportRecordHelper(folder, newData)
);
await response.promise;
}
async updateExportRecordHelper(folder: string, newData: ExportRecord) {
async updateExportRecordHelper(
folder: string,
newData: Partial<ExportRecord>
) {
try {
if (!folder) {
folder = getData(LS_KEYS.EXPORT)?.folder;
@ -389,49 +396,45 @@ class ExportService {
folder = getData(LS_KEYS.EXPORT)?.folder;
}
if (!folder) {
throw Error(CustomError.NO_EXPORT_FOLDER_SELECTED);
return null;
}
const exportFolderExists = this.exists(folder);
if (!exportFolderExists) {
throw Error(CustomError.EXPORT_FOLDER_DOES_NOT_EXIST);
return null;
}
const recordFile = await this.electronAPIs.getExportRecord(
`${folder}/${EXPORT_RECORD_FILE_NAME}`
);
if (recordFile) {
return JSON.parse(recordFile);
} else {
return {} as ExportRecord;
}
return JSON.parse(recordFile);
} catch (e) {
logError(e, 'export Record JSON parsing failed ');
throw e;
}
}
async createNewCollectionFolders(
newCollections: Collection[],
async createNewCollectionFolder(
exportFolder: string,
collectionID: number,
collectionIDNameMap: CollectionIDNameMap,
collectionIDPathMap: CollectionIDPathMap
) {
for (const collection of newCollections) {
const collectionFolderPath = getUniqueCollectionFolderPath(
exportFolder,
collection
);
await this.electronAPIs.checkExistsAndCreateCollectionDir(
collectionFolderPath
);
await this.electronAPIs.checkExistsAndCreateCollectionDir(
getMetadataFolderPath(collectionFolderPath)
);
await this.addCollectionExportedRecord(
exportFolder,
collection,
collectionFolderPath
);
collectionIDPathMap.set(collection.id, collectionFolderPath);
}
const collectionName = collectionIDNameMap.get(collectionID);
const collectionFolderPath = getUniqueCollectionFolderPath(
exportFolder,
collectionID,
collectionName
);
await this.electronAPIs.checkExistsAndCreateDir(collectionFolderPath);
await this.electronAPIs.checkExistsAndCreateDir(
getMetadataFolderPath(collectionFolderPath)
);
await this.addCollectionExportedRecord(
exportFolder,
collectionID,
collectionFolderPath
);
collectionIDPathMap.set(collectionID, collectionFolderPath);
return collectionFolderPath;
}
async renameCollectionFolders(
renamedCollections: Collection[],
@ -445,7 +448,8 @@ class ExportService {
const newCollectionFolderPath = getUniqueCollectionFolderPath(
exportFolder,
collection
collection.id,
collection.name
);
await this.electronAPIs.checkExistsAndRename(
oldCollectionFolderPath,
@ -454,7 +458,7 @@ class ExportService {
await this.addCollectionExportedRecord(
exportFolder,
collection,
collection.id,
newCollectionFolderPath
);
collectionIDPathMap.set(collection.id, newCollectionFolderPath);
@ -571,10 +575,10 @@ class ExportService {
private async migrateExport(
exportDir: string,
collections: Collection[],
allFiles: EnteFile[]
files: EnteFile[]
) {
const exportRecord = await this.getExportRecord(exportDir);
const currentVersion = exportRecord?.version ?? 0;
let currentVersion = exportRecord?.version ?? 0;
if (currentVersion === 0) {
const collectionIDPathMap = new Map<number, string>();
@ -584,12 +588,19 @@ class ExportService {
collectionIDPathMap
);
await this.migrateFiles(
getExportedFiles(allFiles, exportRecord),
getExportedFiles(files, exportRecord),
collectionIDPathMap
);
currentVersion++;
await this.updateExportRecord({
version: LATEST_EXPORT_VERSION,
version: currentVersion,
});
}
if (currentVersion === 1) {
await this.removeDeprecatedExportRecordProperties();
currentVersion++;
await this.updateExportRecord({
version: currentVersion,
});
}
}
@ -606,11 +617,13 @@ class ExportService {
for (const collection of collections) {
const oldCollectionFolderPath = getOldCollectionFolderPath(
exportDir,
collection
collection.id,
collection.name
);
const newCollectionFolderPath = getUniqueCollectionFolderPath(
exportDir,
collection
collection.id,
collection.name
);
collectionIDPathMap.set(collection.id, newCollectionFolderPath);
if (this.electronAPIs.exists(oldCollectionFolderPath)) {
@ -620,7 +633,7 @@ class ExportService {
);
await this.addCollectionExportedRecord(
exportDir,
collection,
collection.id,
newCollectionFolderPath
);
}
@ -670,5 +683,19 @@ class ExportService {
);
}
}
private async removeDeprecatedExportRecordProperties() {
const exportRecord = (await this.getExportRecord()) as ExportRecordV1;
if (exportRecord?.queuedFiles) {
exportRecord.queuedFiles = undefined;
}
if (exportRecord?.progress) {
exportRecord.progress = undefined;
}
if (exportRecord?.failedFiles) {
exportRecord.failedFiles = undefined;
}
await this.updateExportRecord(exportRecord);
}
}
export default new ExportService();

View file

@ -1,9 +0,0 @@
import { IMAGE_CONTAINER_MAX_WIDTH, MIN_COLUMNS } from 'constants/gallery';
import { css } from 'styled-components';
export const SpecialPadding = css`
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * MIN_COLUMNS}px) {
padding: 0 4px;
}
`;

View file

@ -0,0 +1,19 @@
import createCache from '@emotion/cache';
const isBrowser = typeof document !== 'undefined';
// On the client side, Create a meta tag at the top of the <head> and set it as insertionPoint.
// This assures that MUI styles are loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export default function createEmotionCache() {
let insertionPoint;
if (isBrowser) {
const emotionInsertionPoint = document.querySelector<HTMLMetaElement>(
'meta[name="emotion-insertion-point"]'
);
insertionPoint = emotionInsertionPoint ?? undefined;
}
return createCache({ key: 'mui-style', insertionPoint });
}

View file

@ -180,7 +180,7 @@ const darkThemeOptions = createTheme({
},
styleOverrides: {
root: {
padding: '12px 16px',
padding: '14px 16px',
borderRadius: '4px',
},
startIcon: {

View file

@ -14,7 +14,7 @@ export interface DialogBoxAttributes {
proceed?: {
text: string;
action: () => void;
variant: ButtonProps['color'];
variant?: ButtonProps['color'];
disabled?: boolean;
};
secondary?: {
@ -28,3 +28,39 @@ export interface DialogBoxAttributes {
export type SetDialogBoxAttributes = React.Dispatch<
React.SetStateAction<DialogBoxAttributes>
>;
export interface DialogBoxAttributesV2 {
icon?: React.ReactNode;
title?: string;
staticBackdrop?: boolean;
nonClosable?: boolean;
content?: any;
close?: {
text?: string;
variant?: ButtonProps['color'];
action?: () => void;
};
proceed?: {
text: string;
action: () => void;
variant?: ButtonProps['color'];
disabled?: boolean;
};
secondary?: {
text: string;
action: () => void;
variant?: ButtonProps['color'];
disabled?: boolean;
};
buttons?: {
text: string;
action: () => void;
variant: ButtonProps['color'];
disabled?: boolean;
}[];
buttonDirection?: 'row' | 'column';
}
export type SetDialogBoxAttributesV2 = React.Dispatch<
React.SetStateAction<DialogBoxAttributesV2>
>;

View file

@ -9,7 +9,7 @@ export interface AppUpdateInfo {
export interface ElectronAPIs {
exists: (path: string) => boolean;
checkExistsAndCreateCollectionDir: (dirPath: string) => Promise<void>;
checkExistsAndCreateDir: (dirPath: string) => Promise<void>;
checkExistsAndRename: (
oldDirPath: string,
newDirPath: string
@ -21,11 +21,6 @@ export interface ElectronAPIs {
saveFileToDisk: (path: string, file: any) => Promise<void>;
selectRootDirectory: () => Promise<string>;
sendNotification: (content: string) => void;
showOnTray: (content?: any) => void;
registerResumeExportListener: (resumeExport: () => void) => void;
registerStopExportListener: (abortExport: () => void) => void;
registerPauseExportListener: (pauseExport: () => void) => void;
registerRetryFailedExportListener: (retryFailedExport: () => void) => void;
getExportRecord: (filePath: string) => Promise<string>;
setExportRecord: (filePath: string, data: string) => Promise<void>;
showUploadFilesDialog: () => Promise<ElectronFile[]>;
@ -94,4 +89,5 @@ export interface ElectronAPIs {
) => Promise<Uint8Array>;
logRendererProcessMemoryUsage: (message: string) => Promise<void>;
registerForegroundEventListener: (onForeground: () => void) => void;
openDirectory: (dirPath: string) => Promise<void>;
}

View file

@ -1,5 +1,6 @@
import { ExportStage } from 'constants/export';
export type CollectionIDNameMap = Map<number, string>;
export type CollectionIDPathMap = Map<number, string>;
export interface ExportProgress {
current: number;
@ -8,12 +9,12 @@ export interface ExportProgress {
export interface ExportedCollectionPaths {
[collectionID: number]: string;
}
export interface ExportStats {
failed: number;
success: number;
export interface FileExportStats {
totalCount: number;
pendingCount: number;
}
export interface ExportRecord {
export interface ExportRecordV1 {
version?: number;
stage?: ExportStage;
lastAttemptTimestamp?: number;
@ -23,3 +24,16 @@ export interface ExportRecord {
failedFiles?: string[];
exportedCollectionPaths?: ExportedCollectionPaths;
}
export interface ExportRecord {
version: number;
stage: ExportStage;
lastAttemptTimestamp: number;
exportedFiles: string[];
exportedCollectionPaths: ExportedCollectionPaths;
}
export interface ExportSettings {
folder: string;
continuousExport: boolean;
}

View file

@ -264,3 +264,11 @@ export function isValidMoveTarget(
!isIncomingShare(targetCollection, user)
);
}
export function getCollectionNameMap(
collections: Collection[]
): Map<number, string> {
return new Map<number, string>(
collections.map((collection) => [collection.id, collection.name])
);
}

View file

@ -16,7 +16,7 @@ export const handleSharingErrors = (error) => {
errorMessage = t('USER_DOES_NOT_EXIST');
break;
default:
errorMessage = parsedError.message;
errorMessage = `${t('UNKNOWN_ERROR')} ${parsedError.message}`;
}
return errorMessage;
};

View file

@ -13,20 +13,6 @@ import { formatDateTimeShort } from 'utils/time/format';
export const getExportRecordFileUID = (file: EnteFile) =>
`${file.id}_${file.collectionID}_${file.updationTime}`;
export const getExportQueuedFiles = (
allFiles: EnteFile[],
exportRecord: ExportRecord
) => {
const queuedFiles = new Set(exportRecord?.queuedFiles);
const unExportedFiles = allFiles.filter((file) => {
if (queuedFiles.has(getExportRecordFileUID(file))) {
return true;
}
return false;
});
return unExportedFiles;
};
export const getCollectionsCreatedAfterLastExport = (
collections: Collection[],
exportRecord: ExportRecord
@ -79,7 +65,7 @@ export const getCollectionsRenamedAfterLastExport = (
return renamedCollections;
};
export const getFilesUploadedAfterLastExport = (
export const getUnExportedFiles = (
allFiles: EnteFile[],
exportRecord: ExportRecord
) => {
@ -107,20 +93,6 @@ export const getExportedFiles = (
return exportedFiles;
};
export const getExportFailedFiles = (
allFiles: EnteFile[],
exportRecord: ExportRecord
) => {
const failedFiles = new Set(exportRecord?.failedFiles);
const filesToExport = allFiles.filter((file) => {
if (failedFiles.has(getExportRecordFileUID(file))) {
return true;
}
return false;
});
return filesToExport;
};
export const dedupe = (files: string[]) => {
const fileSet = new Set(files);
return Array.from(fileSet);
@ -166,16 +138,17 @@ export const sanitizeName = (name: string) =>
export const getUniqueCollectionFolderPath = (
dir: string,
collection: Collection
collectionID: number,
collectionName: string
): string => {
if (!exportService.checkAllElectronAPIsExists()) {
return getOldCollectionFolderPath(dir, collection);
return getOldCollectionFolderPath(dir, collectionID, collectionName);
}
let collectionFolderPath = `${dir}/${sanitizeName(collection.name)}`;
let collectionFolderPath = `${dir}/${sanitizeName(collectionName)}`;
let count = 1;
while (exportService.exists(collectionFolderPath)) {
collectionFolderPath = `${dir}/${sanitizeName(
collection.name
collectionName
)}(${count})`;
count++;
}
@ -224,8 +197,9 @@ export const getFileSavePath = (
export const getOldCollectionFolderPath = (
dir: string,
collection: Collection
) => `${dir}/${collection.id}_${oldSanitizeName(collection.name)}`;
collectionID: number,
collectionName: string
) => `${dir}/${collectionID}_${oldSanitizeName(collectionName)}`;
export const getOldFileSavePath = (
collectionFolderPath: string,

View file

@ -31,6 +31,7 @@ import { addLogLine } from 'utils/logging';
import { CustomError } from 'utils/error';
import { convertBytesToHumanReadable } from './size';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import { getLocalFiles } from 'services/fileService';
const WAIT_TIME_IMAGE_CONVERSION = 30 * 1000;
@ -578,3 +579,12 @@ export function getLatestVersionFiles(files: EnteFile[]) {
(file) => !file.isDeleted
);
}
export async function getPersonalFiles() {
const files = await getLocalFiles();
const user: User = getData(LS_KEYS.USER);
if (!user?.id) {
throw Error('user missing');
}
return files.filter((file) => file.ownerID === user.id);
}

View file

@ -1,8 +1,5 @@
{
"compilerOptions": {
"paths": {
"@mui/styled-engine": ["./node_modules/@mui/styled-engine-sc"]
},
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext", "webworker"],
"allowJs": true,
@ -23,8 +20,9 @@
"jsx": "preserve",
"baseUrl": "./src",
"downlevelIteration": true,
"jsxImportSource": "@emotion/react",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules", "out", ".next", "thirdparty"]
}

612
yarn.lock
View file

@ -2,71 +2,86 @@
# yarn lockfile v1
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5":
"@babel/code-frame@^7.0.0":
version "7.14.5"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz"
integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
dependencies:
"@babel/highlight" "^7.14.5"
"@babel/generator@^7.15.4":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz"
integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==
"@babel/code-frame@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
dependencies:
"@babel/types" "^7.15.4"
"@babel/highlight" "^7.18.6"
"@babel/generator@^7.21.3":
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce"
integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==
dependencies:
"@babel/types" "^7.21.3"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.0.0":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz"
integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==
"@babel/helper-annotate-as-pure@^7.16.0":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
dependencies:
"@babel/types" "^7.15.4"
"@babel/types" "^7.18.6"
"@babel/helper-function-name@^7.15.4":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz"
integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==
"@babel/helper-environment-visitor@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
"@babel/helper-function-name@^7.21.0":
version "7.21.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4"
integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==
dependencies:
"@babel/helper-get-function-arity" "^7.15.4"
"@babel/template" "^7.15.4"
"@babel/types" "^7.15.4"
"@babel/template" "^7.20.7"
"@babel/types" "^7.21.0"
"@babel/helper-get-function-arity@^7.15.4":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz"
integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==
"@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
dependencies:
"@babel/types" "^7.15.4"
"@babel/types" "^7.18.6"
"@babel/helper-hoist-variables@^7.15.4":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz"
integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
dependencies:
"@babel/types" "^7.15.4"
"@babel/types" "^7.18.6"
"@babel/helper-module-imports@^7.0.0":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz"
integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==
"@babel/helper-split-export-declaration@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
dependencies:
"@babel/types" "^7.15.4"
"@babel/types" "^7.18.6"
"@babel/helper-split-export-declaration@^7.15.4":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz"
integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==
dependencies:
"@babel/types" "^7.15.4"
"@babel/helper-string-parser@^7.19.4":
version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9":
"@babel/helper-validator-identifier@^7.14.5":
version "7.16.7"
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
version "7.19.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
"@babel/highlight@^7.14.5":
version "7.14.5"
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz"
@ -76,18 +91,34 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.15.4":
version "7.15.6"
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz"
integrity sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==
"@babel/highlight@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
dependencies:
"@babel/helper-validator-identifier" "^7.18.6"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7":
"@babel/parser@^7.20.7", "@babel/parser@^7.21.3":
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3"
integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==
"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.5", "@babel/runtime@^7.13.8", "@babel/runtime@^7.14.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz"
integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.6", "@babel/runtime@^7.21.0":
version "7.21.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.17.2":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
@ -95,13 +126,6 @@
dependencies:
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.20.6":
version "7.21.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673"
integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.20.7":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd"
@ -109,36 +133,38 @@
dependencies:
regenerator-runtime "^0.13.11"
"@babel/template@^7.15.4":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz"
integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==
"@babel/template@^7.20.7":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8"
integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==
dependencies:
"@babel/code-frame" "^7.14.5"
"@babel/parser" "^7.15.4"
"@babel/types" "^7.15.4"
"@babel/code-frame" "^7.18.6"
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
"@babel/traverse@^7.4.5":
version "7.15.4"
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz"
integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67"
integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==
dependencies:
"@babel/code-frame" "^7.14.5"
"@babel/generator" "^7.15.4"
"@babel/helper-function-name" "^7.15.4"
"@babel/helper-hoist-variables" "^7.15.4"
"@babel/helper-split-export-declaration" "^7.15.4"
"@babel/parser" "^7.15.4"
"@babel/types" "^7.15.4"
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.21.3"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.21.0"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.21.3"
"@babel/types" "^7.21.3"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.15.4":
version "7.15.6"
resolved "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz"
integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==
"@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.3":
version "7.21.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05"
integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==
dependencies:
"@babel/helper-validator-identifier" "^7.14.9"
"@babel/helper-string-parser" "^7.19.4"
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@date-io/core@^2.14.0":
@ -174,23 +200,52 @@
dependencies:
"@date-io/core" "^2.14.0"
"@emotion/cache@^11.4.0":
version "11.4.0"
resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.4.0.tgz"
integrity sha512-Zx70bjE7LErRO9OaZrhf22Qye1y4F7iDl+ITjet0J+i+B88PrAOBkKvaAWhxsZf72tDLajwCgfCjJ2dvH77C3g==
"@emotion/babel-plugin@^11.10.6":
version "11.10.6"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz#a68ee4b019d661d6f37dec4b8903255766925ead"
integrity sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==
dependencies:
"@emotion/memoize" "^0.7.4"
"@emotion/sheet" "^1.0.0"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
stylis "^4.0.3"
"@babel/helper-module-imports" "^7.16.7"
"@babel/runtime" "^7.18.3"
"@emotion/hash" "^0.9.0"
"@emotion/memoize" "^0.8.0"
"@emotion/serialize" "^1.1.1"
babel-plugin-macros "^3.1.0"
convert-source-map "^1.5.0"
escape-string-regexp "^4.0.0"
find-root "^1.1.0"
source-map "^0.5.7"
stylis "4.1.3"
"@emotion/cache@^11.10.5", "@emotion/cache@^11.4.0":
version "11.10.5"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.5.tgz#c142da9351f94e47527ed458f7bbbbe40bb13c12"
integrity sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==
dependencies:
"@emotion/memoize" "^0.8.0"
"@emotion/sheet" "^1.2.1"
"@emotion/utils" "^1.2.0"
"@emotion/weak-memoize" "^0.3.0"
stylis "4.1.3"
"@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
"@emotion/is-prop-valid@^1.1.0", "@emotion/is-prop-valid@^1.1.2":
"@emotion/hash@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7"
integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==
"@emotion/is-prop-valid@^1.1.0", "@emotion/is-prop-valid@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83"
integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==
dependencies:
"@emotion/memoize" "^0.8.0"
"@emotion/is-prop-valid@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz#34ad6e98e871aa6f7a20469b602911b8b11b3a95"
integrity sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==
@ -202,20 +257,26 @@
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
"@emotion/react@^11.1.1":
version "11.4.1"
resolved "https://registry.npmjs.org/@emotion/react/-/react-11.4.1.tgz"
integrity sha512-pRegcsuGYj4FCdZN6j5vqCALkNytdrKw3TZMekTzNXixRg4wkLsU5QEaBG5LC6l01Vppxlp7FE3aTHpIG5phLg==
"@emotion/memoize@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
"@emotion/react@^11.1.1", "@emotion/react@^11.10.6":
version "11.10.6"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.6.tgz#dbe5e650ab0f3b1d2e592e6ab1e006e75fd9ac11"
integrity sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==
dependencies:
"@babel/runtime" "^7.13.10"
"@emotion/cache" "^11.4.0"
"@emotion/serialize" "^1.0.2"
"@emotion/sheet" "^1.0.2"
"@emotion/utils" "^1.0.0"
"@emotion/weak-memoize" "^0.2.5"
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.10.6"
"@emotion/cache" "^11.10.5"
"@emotion/serialize" "^1.1.1"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
"@emotion/utils" "^1.2.0"
"@emotion/weak-memoize" "^0.3.0"
hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.0.0", "@emotion/serialize@^1.0.2":
"@emotion/serialize@^1.0.0":
version "1.0.2"
resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz"
integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==
@ -226,14 +287,47 @@
"@emotion/utils" "^1.0.0"
csstype "^3.0.2"
"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.2.tgz"
integrity sha512-QQPB1B70JEVUHuNtzjHftMGv6eC3Y9wqavyarj4x4lg47RACkeSfNo5pxIOKizwS9AEFLohsqoaxGQj4p0vSIw==
"@emotion/serialize@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.1.tgz#0595701b1902feded8a96d293b26be3f5c1a5cf0"
integrity sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==
dependencies:
"@emotion/hash" "^0.9.0"
"@emotion/memoize" "^0.8.0"
"@emotion/unitless" "^0.8.0"
"@emotion/utils" "^1.2.0"
csstype "^3.0.2"
"@emotion/server@^11.10.0":
version "11.10.0"
resolved "https://registry.yarnpkg.com/@emotion/server/-/server-11.10.0.tgz#3edc075b672c75426f682d56aadc6404fb1f6648"
integrity sha512-MTvJ21JPo9aS02GdjFW4nhdwOi2tNNpMmAM/YED0pkxzjDNi5WbiTwXqaCnvLc2Lr8NFtjhT0az1vTJyLIHYcw==
dependencies:
"@emotion/utils" "^1.2.0"
html-tokenize "^2.0.0"
multipipe "^1.0.2"
through "^2.3.8"
"@emotion/sheet@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.1.tgz#0767e0305230e894897cadb6c8df2c51e61a6c2c"
integrity sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==
"@emotion/styled@^11.10.6":
version "11.10.6"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.6.tgz#d886afdc51ef4d66c787ebde848f3cc8b117ebba"
integrity sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.10.6"
"@emotion/is-prop-valid" "^1.2.0"
"@emotion/serialize" "^1.1.1"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.0"
"@emotion/utils" "^1.2.0"
"@emotion/stylis@^0.8.4":
version "0.8.5"
resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz"
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
"@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5":
@ -241,15 +335,30 @@
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/unitless@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db"
integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==
"@emotion/use-insertion-effect-with-fallbacks@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df"
integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==
"@emotion/utils@^1.0.0":
version "1.0.0"
resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz"
integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
"@emotion/weak-memoize@^0.2.5":
version "0.2.5"
resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
"@emotion/utils@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
"@emotion/weak-memoize@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb"
integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==
"@eslint/eslintrc@^1.4.1":
version "1.4.1"
@ -285,6 +394,38 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@jridgewell/gen-mapping@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.17"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==
dependencies:
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@mui/base@5.0.0-alpha.77":
version "5.0.0-alpha.77"
resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.77.tgz#a88985597708c354520579e4f76e617b29f8f593"
@ -333,13 +474,13 @@
"@mui/utils" "^5.6.1"
prop-types "^15.7.2"
"@mui/styled-engine-sc@^5.6.1", "@mui/styled-engine@^5.6.1", "@mui/styled-engine@npm:@mui/styled-engine-sc@latest":
name "@mui/styled-engine"
version "5.6.1"
resolved "https://registry.yarnpkg.com/@mui/styled-engine-sc/-/styled-engine-sc-5.6.1.tgz#d9505c005eeefa5c7d7ef9c03e63324db889ee09"
integrity sha512-BMY5Pb8YgOxvvwg9s6mPeDgzha4244/KgRmHvTVPBmvqypbiLPApR6SNyYON+1/3kLHt3TpmxrlRY3jPiZF2QQ==
"@mui/styled-engine@^5.6.1":
version "5.11.11"
resolved "https://registry.yarnpkg.com/@mui/styled-engine-sc/-/styled-engine-sc-5.11.11.tgz#030882bf991bd11e1a46efba7382ccbfdf7826d2"
integrity sha512-6+HsfcKHlhjQklDoEup7Itl+Xgn+BCsqEpIdIIhlxED4YlOZ38xghxIKrx78XFZznTorbhAspUgDDKIaB5vDMg==
dependencies:
prop-types "^15.7.2"
"@babel/runtime" "^7.21.0"
prop-types "^15.8.1"
"@mui/system@^5.6.2":
version "5.6.2"
@ -770,14 +911,6 @@
resolved "https://registry.npmjs.org/@types/debounce-promise/-/debounce-promise-3.1.4.tgz"
integrity sha512-9SEVY3nsz+uMN2DwDocftB5TAgZe7D0cOzxxRhpotWs6T4QFqRaTXpXbOSzbk31/7iYcfCkJJPwWGzTxyuGhCg==
"@types/hoist-non-react-statics@*":
version "3.3.1"
resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz"
integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
dependencies:
"@types/react" "*"
hoist-non-react-statics "^3.3.0"
"@types/http-proxy@^1.17.5":
version "1.17.9"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a"
@ -965,15 +1098,6 @@
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==
"@types/styled-components@^5.1.25":
version "5.1.25"
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.25.tgz#0177c4ab5fa7c6ed0565d36f597393dae3f380ad"
integrity sha512-fgwl+0Pa8pdkwXRoVPP9JbqF0Ivo9llnmsm+7TCI330kbPIFd9qv1Lrhr37shf4tnxCOSu+/IgqM7uJXLWZZNQ==
dependencies:
"@types/hoist-non-react-statics" "*"
"@types/react" "*"
csstype "^3.0.2"
"@types/trusted-types@^2.0.2":
version "2.0.2"
resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz"
@ -1305,20 +1429,30 @@ axobject-query@^3.1.1:
dependencies:
deep-equal "^2.0.5"
"babel-plugin-styled-components@>= 1.12.0":
version "1.13.2"
resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.2.tgz"
integrity sha512-Vb1R3d4g+MUfPQPVDMCGjm3cDocJEUTR7Xq7QS95JWWeksN1wdFRYpD2kulDgI3Huuaf1CZd+NK4KQmqUFh5dA==
babel-plugin-macros@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
dependencies:
"@babel/helper-annotate-as-pure" "^7.0.0"
"@babel/helper-module-imports" "^7.0.0"
"@babel/runtime" "^7.12.5"
cosmiconfig "^7.0.0"
resolve "^1.19.0"
"babel-plugin-styled-components@>= 1.12.0":
version "2.0.7"
resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.0.7.tgz#c81ef34b713f9da2b7d3f5550df0d1e19e798086"
integrity sha512-i7YhvPgVqRKfoQ66toiZ06jPNA3p6ierpfUuEWxNF+fV27Uv5gxBkf8KZLHUCc1nFA9j6+80pYoIpqCeyW3/bA==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.0"
"@babel/helper-module-imports" "^7.16.0"
babel-plugin-syntax-jsx "^6.18.0"
lodash "^4.17.11"
picomatch "^2.3.0"
babel-plugin-syntax-jsx@^6.18.0:
version "6.18.0"
resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz"
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
integrity sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==
balanced-match@^1.0.0:
version "1.0.2"
@ -1374,6 +1508,11 @@ bs58@^4.0.1:
dependencies:
base-x "^3.0.2"
buffer-from@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0"
integrity sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
@ -1388,9 +1527,9 @@ callsites@^3.0.0:
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
camelize@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz"
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
version "1.0.1"
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
caniuse-lite@^1.0.30001406:
version "1.0.30001444"
@ -1518,6 +1657,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
convert-source-map@^1.5.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
cookie@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz"
@ -1580,13 +1724,13 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz"
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
css-to-react-native@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz"
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
version "3.2.0"
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
dependencies:
camelize "^1.0.0"
css-color-keywords "^1.0.0"
@ -1627,7 +1771,7 @@ debounce-promise@^3.1.2:
resolved "https://registry.npmjs.org/debounce-promise/-/debounce-promise-3.1.2.tgz"
integrity sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg==
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
debug@4, debug@^4.1.1, debug@^4.3.1:
version "4.3.2"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
@ -1641,7 +1785,7 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4.3.2, debug@^4.3.4:
debug@^4.1.0, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -1745,6 +1889,13 @@ dom-helpers@^5.0.1, dom-helpers@^5.2.0, dom-helpers@^5.2.1:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
duplexer2@^0.1.2:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==
dependencies:
readable-stream "^2.0.2"
duplexer@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@ -2239,6 +2390,11 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
@ -2411,7 +2567,7 @@ glob@7.1.7, glob@^7.1.3:
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
globals@^13.19.0:
@ -2592,6 +2748,17 @@ html-parse-stringify@^3.0.1:
dependencies:
void-elements "3.1.0"
html-tokenize@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-tokenize/-/html-tokenize-2.0.1.tgz#c3b2ea6e2837d4f8c06693393e9d2a12c960be5f"
integrity sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==
dependencies:
buffer-from "~0.1.1"
inherits "~2.0.1"
minimist "~1.2.5"
readable-stream "~1.0.27-1"
through2 "~0.4.1"
http-proxy-middleware@^1.0.5:
version "1.3.1"
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz#43700d6d9eecb7419bf086a128d0f7205d9eb665"
@ -2695,7 +2862,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -2978,6 +3145,11 @@ is-wsl@^2.2.0:
dependencies:
is-docker "^2.0.0"
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==
isarray@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
@ -3017,7 +3189,7 @@ js-yaml@^4.1.0:
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json-parse-even-better-errors@^2.3.0:
@ -3295,7 +3467,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2:
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.5:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
@ -3347,6 +3519,14 @@ ms@2.1.2, ms@^2.1.1:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
multipipe@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
integrity sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==
dependencies:
duplexer2 "^0.1.2"
object-assign "^4.1.0"
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
@ -3461,6 +3641,11 @@ object-keys@^1.0.12, object-keys@^1.1.1:
resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
object-keys@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336"
integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==
object.assign@^4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz"
@ -3673,7 +3858,7 @@ picomatch@^2.2.3:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
picomatch@^2.3.1:
picomatch@^2.3.0, picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
@ -3696,9 +3881,9 @@ pngjs@^3.4.0:
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
postcss-value-parser@^4.0.2:
version "4.1.0"
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz"
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@8.4.14:
version "8.4.14"
@ -3737,16 +3922,7 @@ prop-types-extra@^1.1.0:
react-is "^16.3.2"
warning "^4.0.0"
prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
prop-types@^15.8.1:
prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -3755,6 +3931,15 @@ prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"
prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
property-expr@^2.0.2:
version "2.0.4"
resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz"
@ -3854,7 +4039,7 @@ react-i18next@^12.2.0:
react-input-autosize@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz"
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-3.0.0.tgz#6b5898c790d4478d69420b55441fcc31d5c50a85"
integrity sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==
dependencies:
prop-types "^15.5.8"
@ -3908,7 +4093,7 @@ react-popper@^2.2.5:
react-select@^4.3.1:
version "4.3.1"
resolved "https://registry.npmjs.org/react-select/-/react-select-4.3.1.tgz"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-4.3.1.tgz#389fc07c9bc7cf7d3c377b7a05ea18cd7399cb81"
integrity sha512-HBBd0dYwkF5aZk1zP81Wx5UsLIIT2lSvAY2JiJo199LjoLHoivjn9//KsmvQMEFGNhe58xyuOITjfxKCcGc62Q==
dependencies:
"@babel/runtime" "^7.12.0"
@ -3929,7 +4114,17 @@ react-top-loading-bar@^2.0.1:
resolved "https://registry.npmjs.org/react-top-loading-bar/-/react-top-loading-bar-2.0.1.tgz"
integrity sha512-wkRlK9Rte4TU817GDcjlsCoDOxrrnvsNvK609FKyio0EIrmmqjQDz5DB8HbN88CHNZBy5Lh/OBALc03ioWFPuQ==
react-transition-group@^4.3.0, react-transition-group@^4.4.1, react-transition-group@^4.4.2:
react-transition-group@^4.3.0:
version "4.4.5"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-transition-group@^4.4.1, react-transition-group@^4.4.2:
version "4.4.2"
resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz"
integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==
@ -3959,6 +4154,19 @@ react@^18.2.0:
dependencies:
loose-envify "^1.1.0"
readable-stream@^2.0.2:
version "2.3.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^2.0.6, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz"
@ -3981,6 +4189,16 @@ readable-stream@^3.6.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-stream@~1.0.17, readable-stream@~1.0.27-1:
version "1.0.34"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "0.0.1"
string_decoder "~0.10.x"
readable-web-to-node-stream@^3.0.0:
version "3.0.2"
resolved "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz"
@ -4022,15 +4240,7 @@ resolve-from@^4.0.0:
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve@^1.20.0:
version "1.20.0"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
resolve@^1.22.1:
resolve@^1.19.0, resolve@^1.22.1:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@ -4039,6 +4249,14 @@ resolve@^1.22.1:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^1.20.0:
version "1.20.0"
resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
path-parse "^1.0.6"
resolve@^2.0.0-next.4:
version "2.0.0-next.4"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660"
@ -4175,7 +4393,7 @@ sha.js@^2.4.0, sha.js@^2.4.8:
shallowequal@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz"
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
shebang-command@^2.0.0:
@ -4251,10 +4469,10 @@ source-map-js@^1.0.2:
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
source-map@^0.5.0:
source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
stop-iteration-iterator@^1.0.0:
version "1.0.0"
@ -4349,6 +4567,11 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
@ -4417,9 +4640,9 @@ strtok3@^6.2.4:
peek-readable "^4.0.1"
styled-components@^5.3.5:
version "5.3.5"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.5.tgz#a750a398d01f1ca73af16a241dec3da6deae5ec4"
integrity sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==
version "5.3.9"
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.9.tgz#641af2a8bb89904de708c71b439caa9633e8f0ba"
integrity sha512-Aj3kb13B75DQBo2oRwRa/APdB5rSmwUfN5exyarpX+x/tlM/rwZA2vVk2vQgVSP6WKaZJHWwiFrzgHt+CLtB4A==
dependencies:
"@babel/helper-module-imports" "^7.0.0"
"@babel/traverse" "^7.4.5"
@ -4439,10 +4662,10 @@ styled-jsx@5.1.1:
dependencies:
client-only "0.0.1"
stylis@^4.0.3:
version "4.0.10"
resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.10.tgz"
integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg==
stylis@4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7"
integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
@ -4486,6 +4709,14 @@ text-table@^0.2.0:
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
through2@~0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b"
integrity sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==
dependencies:
readable-stream "~1.0.17"
xtend "~2.1.1"
through@^2.3.8:
version "2.3.8"
resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
@ -4856,6 +5087,13 @@ xml-js@^1.6.11:
dependencies:
sax "^1.2.4"
xtend@~2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b"
integrity sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==
dependencies:
object-keys "~0.4.0"
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"