diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7e662a15..3fe4507ef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Changelog - Added acceptance tests for node update notification with apply and postpone update scenarios ([PR 977](https://github.com/input-output-hk/daedalus/pull/977)) - Added acceptance tests for maximum wallets limit ([PR 979](https://github.com/input-output-hk/daedalus/pull/979)) - Added acceptance tests for the About dialog ([PR 975](https://github.com/input-output-hk/daedalus/pull/975)) +- Improved compress/download logs handling ([PR 995](https://github.com/input-output-hk/daedalus/pull/995)) ## 0.10.1 ======= diff --git a/source/common/fileName.js b/source/common/fileName.js new file mode 100644 index 0000000000..a6f8926414 --- /dev/null +++ b/source/common/fileName.js @@ -0,0 +1,13 @@ +// @flow +import moment from 'moment'; + +export const generateFileNameWithTimestamp = (prefix: string = 'logs', fileType: string = 'zip') => + `${prefix}-${moment.utc().format('YYYY-MM-DDTHHmmss.0SSS')}Z.${fileType}`; + +export const isFileNameWithTimestamp = (prefix: string = 'logs', fileType: string = 'zip') => (fileName: string) => + fileName.match(RegExp(`(${prefix}-)([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{6}.0[0-9]{3}Z)(.${fileType})`)); + +export const getPathSlash = (path: string) => ((path.indexOf('/') > -1) ? '/' : '\\'); + +export const extractFileNameFromPath = (path: string) => + path.substr(path.lastIndexOf(getPathSlash(path)) + 1); diff --git a/source/common/ipc-api.js b/source/common/ipc-api.js index 23bc59f3e9..ef24dd1c4e 100644 --- a/source/common/ipc-api.js +++ b/source/common/ipc-api.js @@ -20,13 +20,6 @@ export const COMPRESS_LOGS = { ERROR: `${COMPRESS_LOGS_CHANNEL}-error`, }; -const DELETE_COMPRESSED_LOGS_CHANNEL = 'delete-compressed-logs'; -export const DELETE_COMPRESSED_LOGS = { - REQUEST: DELETE_COMPRESSED_LOGS_CHANNEL, - SUCCESS: `${DELETE_COMPRESSED_LOGS_CHANNEL}-success`, - ERROR: `${DELETE_COMPRESSED_LOGS_CHANNEL}-error`, -}; - const DOWNLOAD_LOGS_CHANNEL = 'download-logs'; export const DOWNLOAD_LOGS = { REQUEST: DOWNLOAD_LOGS_CHANNEL, diff --git a/source/main/ipc-api/compress-logs.js b/source/main/ipc-api/compress-logs.js index d36a5236c0..eb40eb6e72 100644 --- a/source/main/ipc-api/compress-logs.js +++ b/source/main/ipc-api/compress-logs.js @@ -9,10 +9,8 @@ import { Logger, stringifyError } from '../../common/logging'; import { COMPRESS_LOGS } from '../../common/ipc-api'; export default () => { - ipcMain.on(COMPRESS_LOGS.REQUEST, (event, logs) => { + ipcMain.on(COMPRESS_LOGS.REQUEST, (event, logs, compressedFileName) => { const sender = event.sender; - const compressedFileName = 'logs.zip'; - const outputPath = path.join(appLogsFolderPath, compressedFileName); const output = fs.createWriteStream(outputPath); const archive = archiver('zip', { diff --git a/source/main/ipc-api/delete-compressed-logs.js b/source/main/ipc-api/delete-compressed-logs.js deleted file mode 100644 index deb19117c3..0000000000 --- a/source/main/ipc-api/delete-compressed-logs.js +++ /dev/null @@ -1,19 +0,0 @@ -// @flow -import { ipcMain } from 'electron'; -import fs from 'fs'; -import { Logger, stringifyError } from '../../common/logging'; -import { DELETE_COMPRESSED_LOGS } from '../../common/ipc-api'; - -export default () => { - ipcMain.on(DELETE_COMPRESSED_LOGS.REQUEST, (event, file) => { - const sender = event.sender; - try { - fs.unlinkSync(file); - Logger.info('DELETE_COMPRESSED_LOGS.SUCCESS'); - return sender.send(DELETE_COMPRESSED_LOGS.SUCCESS); - } catch (error) { - Logger.error('DELETE_COMPRESSED_LOGS.ERROR: ' + stringifyError(error)); - return sender.send(DELETE_COMPRESSED_LOGS.ERROR, error); - } - }); -}; diff --git a/source/main/ipc-api/index.js b/source/main/ipc-api/index.js index 7bf401e993..286fa1408c 100644 --- a/source/main/ipc-api/index.js +++ b/source/main/ipc-api/index.js @@ -1,6 +1,5 @@ // @flow import compressLogsApi from './compress-logs'; -import deleteCompressedLogsApi from './delete-compressed-logs'; import downloadLogsApi from './download-logs'; import getLogsApi from './get-logs'; import parseRedemptionCodeApi from './parse-redemption-code-from-pdf'; @@ -10,7 +9,6 @@ import loadAsset from './load-asset'; export default (params: any) => { compressLogsApi(); - deleteCompressedLogsApi(); downloadLogsApi(); getLogsApi(); parseRedemptionCodeApi(); diff --git a/source/main/utils/setupLogging.js b/source/main/utils/setupLogging.js index ab00008413..9433edaa31 100644 --- a/source/main/utils/setupLogging.js +++ b/source/main/utils/setupLogging.js @@ -1,8 +1,10 @@ +import fs from 'fs'; import path from 'path'; import log from 'electron-log'; import moment from 'moment'; import ensureDirectoryExists from './ensureDirectoryExists'; -import { pubLogsFolderPath, APP_NAME } from '../config'; +import { pubLogsFolderPath, appLogsFolderPath, APP_NAME } from '../config'; +import { isFileNameWithTimestamp } from '../../common/fileName'; const isTest = process.env.NODE_ENV === 'test'; @@ -19,4 +21,18 @@ export const setupLogging = () => { const formattedDate = moment.utc(msg.date).format('YYYY-MM-DDTHH:mm:ss.0SSS'); return `[${formattedDate}Z] [${msg.level}] ${msg.data}`; }; + + // Removes existing compressed logs + fs.readdir(appLogsFolderPath, (err, files) => { + files + .filter(isFileNameWithTimestamp()) + .forEach((logFileName) => { + const logFile = path.join(appLogsFolderPath, logFileName); + try { + fs.unlinkSync(logFile); + } catch (error) { + console.error(`Compressed log file "${logFile}" deletion failed: ${error}`); + } + }); + }); }; diff --git a/source/renderer/app/actions/profile-actions.js b/source/renderer/app/actions/profile-actions.js index ca8e53fd3a..6d0b7a90c7 100644 --- a/source/renderer/app/actions/profile-actions.js +++ b/source/renderer/app/actions/profile-actions.js @@ -5,14 +5,13 @@ import Action from './lib/Action'; export default class ProfileActions { acceptTermsOfUse: Action = new Action(); - compressLogs: Action<{ logs: Object }> = new Action(); getLogs: Action = new Action(); - downloadLogs: Action<{ destination: string, fresh?: boolean }> = new Action(); - deleteCompressedLogs: Action = new Action(); - resetBugReportDialog: Action = new Action(); + getLogsAndCompress: Action = new Action(); sendBugReport: Action<{ - email: string, subject: string, problem: string, compressedLog: ?string, + email: string, subject: string, problem: string, compressedLogsFile: ?string, }> = new Action(); + resetBugReportDialog: Action = new Action(); + downloadLogs: Action<{ fileName: string, destination: string, fresh?: boolean }> = new Action(); updateLocale: Action<{ locale: string }> = new Action(); updateTheme: Action<{ theme: string }> = new Action(); } diff --git a/source/renderer/app/api/ada/sendAdaBugReport.js b/source/renderer/app/api/ada/sendAdaBugReport.js index 0beac6b649..9c9590f4d8 100644 --- a/source/renderer/app/api/ada/sendAdaBugReport.js +++ b/source/renderer/app/api/ada/sendAdaBugReport.js @@ -9,7 +9,7 @@ export type SendAdaBugReportRequestParams = { email: string, subject: string, problem: string, - compressedLog: string, + compressedLogsFile: string, }, application: string, }; @@ -17,7 +17,7 @@ export type SendAdaBugReportRequestParams = { export const sendAdaBugReport = ( { requestFormData, application }: SendAdaBugReportRequestParams ): Promise<{}> => { - const { email, subject, problem, compressedLog } = requestFormData; + const { email, subject, problem, compressedLogsFile } = requestFormData; const reportUrl = url.parse(environment.REPORT_URL); let platform; @@ -45,7 +45,7 @@ export const sendAdaBugReport = ( version: environment.version, build: environment.build, os: platform, - compressedLog, + compressedLogsFile, date: moment().format('YYYY-MM-DDTHH:mm:ss'), magic: 2000000000, type: { diff --git a/source/renderer/app/api/etc/sendEtcBugReport.js b/source/renderer/app/api/etc/sendEtcBugReport.js index 1ebca02ee1..45b9652c3f 100644 --- a/source/renderer/app/api/etc/sendEtcBugReport.js +++ b/source/renderer/app/api/etc/sendEtcBugReport.js @@ -9,7 +9,7 @@ export type SendEtcBugReportRequestParams = { email: string, subject: string, problem: string, - compressedLog: string, + compressedLogsFile: string, }, application: string, }; @@ -17,7 +17,7 @@ export type SendEtcBugReportRequestParams = { export const sendEtcBugReport = ( { requestFormData, application }: SendEtcBugReportRequestParams ): Promise<{}> => { - const { email, subject, problem, compressedLog } = requestFormData; + const { email, subject, problem, compressedLogsFile } = requestFormData; const reportUrl = url.parse(environment.REPORT_URL); let platform; @@ -45,7 +45,7 @@ export const sendEtcBugReport = ( version: environment.version, build: environment.build, os: platform, - compressedLog, + compressedLogsFile, date: moment().format('YYYY-MM-DDTHH:mm:ss'), magic: 2000000000, type: { diff --git a/source/renderer/app/api/lib/reportRequest.js b/source/renderer/app/api/lib/reportRequest.js index abb91b0b9d..405b55f5d8 100644 --- a/source/renderer/app/api/lib/reportRequest.js +++ b/source/renderer/app/api/lib/reportRequest.js @@ -1,6 +1,7 @@ import http from 'http'; import FormData from 'form-data/lib/form_data'; import fs from 'fs'; +import { extractFileNameFromPath } from '../../../../common/fileName'; export type RequestOptions = { hostname: string, @@ -38,9 +39,10 @@ function typedHttpRequest( formData.append('payload', JSON.stringify(payload)); // prepare file stream (attachment) - if (payload.compressedLog) { - const stream = fs.createReadStream(payload.compressedLog); - formData.append('logs.zip', stream); + if (payload.compressedLogsFile) { + const stream = fs.createReadStream(payload.compressedLogsFile); + const fileName = extractFileNameFromPath(payload.compressedLogsFile); + formData.append(fileName, stream); } options.headers = formData.getHeaders(); diff --git a/source/renderer/app/components/profile/bug-report/BugReportDialog.js b/source/renderer/app/components/profile/bug-report/BugReportDialog.js index f7a5abad7a..a370aa095e 100644 --- a/source/renderer/app/components/profile/bug-report/BugReportDialog.js +++ b/source/renderer/app/components/profile/bug-report/BugReportDialog.js @@ -118,22 +118,20 @@ const messages = defineMessages({ type Props = { logFiles: LogFiles, - compressedLog: ?string, onCancel: Function, onSubmit: Function, onSubmitManually: Function, onDownload: Function, onGetLogs: Function, - onCompressLogs: Function, - onDeleteCompressedLogs: Function, - isSubmitting: boolean, - isCompressing: boolean, + onGetLogsAndCompress: Function, isDownloading?: boolean, + isSubmittingBugReport?: boolean, error: ?LocalizableError, }; type State = { - showLogs: boolean, + attachLogs: boolean, + compressedLogsFile: ?string, }; @observer @@ -144,19 +142,23 @@ export default class BugReportDialog extends Component { }; state = { - showLogs: true, + attachLogs: true, + compressedLogsFile: null, }; componentWillMount() { this.props.onGetLogs(); - this.props.onDeleteCompressedLogs(); } componentWillReceiveProps(nextProps: Object) { - const commpressionFilesChanged = this.props.compressedLog !== nextProps.compressedLog; - if (nextProps.compressedLog && commpressionFilesChanged && !nextProps.isDownloading) { - // proceed to submit when ipc rendered successfully return compressed files - this.submit(nextProps.compressedLog); + const compressedLogsFileChanged = ( + !this.props.compressedLogsFile && + !!nextProps.compressedLogsFile + ); + const { compressedLogsFile } = this.state; + if (compressedLogsFile) return false; + if (nextProps.compressedLogsFile && compressedLogsFileChanged && !nextProps.isDownloading) { + this.setState({ compressedLogsFile: nextProps.compressedLogsFile }, this.submit); } } @@ -206,40 +208,36 @@ export default class BugReportDialog extends Component { }, }); - submit = (compressedLog: ?string) => { + submit = () => { this.form.submit({ onSuccess: (form) => { - const { logFiles } = this.props; - const logsExist = get(logFiles, ['files'], []).length > 0; - + const { attachLogs, compressedLogsFile } = this.state; + if (attachLogs && !compressedLogsFile) { + this.props.onGetLogsAndCompress(); + return false; + } const { email, subject, problem } = form.values(); const data = { - email, subject, problem, compressedLog + email, subject, problem, compressedLogsFile }; - - if (this.state.showLogs && logsExist && !compressedLog) { - // submit request with commpressed logs files - this.props.onCompressLogs(this.props.logFiles); - } else { - // regular submit - this.props.onSubmit(data); - } + this.props.onSubmit(data); }, onError: () => {}, }); }; handleLogsSwitchToggle = (value: boolean) => { - this.setState({ showLogs: value }); + this.setState({ attachLogs: value }); }; + onClose = () => !this.props.isSubmittingBugReport && this.props.onCancel(); + render() { const { intl } = this.context; - const { showLogs } = this.state; + const { attachLogs } = this.state; const { form } = this; const { - onCancel, isSubmitting, isCompressing, - logFiles, error, onDownload, isDownloading, + logFiles, error, onDownload, isDownloading, isSubmittingBugReport } = this.props; const submitManuallyLink = intl.formatMessage(messages.submitManuallyLink); @@ -250,12 +248,12 @@ export default class BugReportDialog extends Component { const attachedLogsClasses = classnames([ styles.attachedLogs, - (showLogs && logFiles) ? styles.show : null, + (attachLogs && logFiles) ? styles.show : null, ]); const submitButtonClasses = classnames([ 'submitButton', - (isSubmitting || isCompressing) ? styles.isSubmitting : null, + isSubmittingBugReport ? styles.isSubmitting : null, ]); const downloadButtonClasses = classnames([ @@ -272,8 +270,8 @@ export default class BugReportDialog extends Component { className: submitButtonClasses, label: this.context.intl.formatMessage(messages.submitButtonLabel), primary: true, - disabled: isSubmitting, - onClick: this.submit.bind(this, null), + disabled: isSubmittingBugReport, + onClick: this.submit, }, ]; @@ -299,8 +297,13 @@ export default class BugReportDialog extends Component { title={intl.formatMessage(messages.title)} actions={!error ? actions : alternativeActions} closeOnOverlayClick - onClose={onCancel} - closeButton={} + onClose={this.onClose} + closeButton={ + + } > {error ? (
@@ -356,7 +359,7 @@ export default class BugReportDialog extends Component { } />
diff --git a/source/renderer/app/components/settings/categories/SupportSettings.scss b/source/renderer/app/components/settings/categories/SupportSettings.scss index da570b777b..8111a3fa51 100644 --- a/source/renderer/app/components/settings/categories/SupportSettings.scss +++ b/source/renderer/app/components/settings/categories/SupportSettings.scss @@ -32,7 +32,6 @@ button { cursor: pointer; - letter-spacing: 1px; } p { diff --git a/source/renderer/app/components/widgets/DialogCloseButton.js b/source/renderer/app/components/widgets/DialogCloseButton.js index 274ed22835..f532d53219 100644 --- a/source/renderer/app/components/widgets/DialogCloseButton.js +++ b/source/renderer/app/components/widgets/DialogCloseButton.js @@ -6,14 +6,19 @@ import styles from './DialogCloseButton.scss'; type Props = { onClose: Function, icon?: string, + disabled?: boolean }; export default class DialogCloseButton extends Component { render() { - const { onClose, icon } = this.props; + const { onClose, icon, disabled } = this.props; return ( - ); diff --git a/source/renderer/app/components/widgets/DialogCloseButton.scss b/source/renderer/app/components/widgets/DialogCloseButton.scss index cc238043f7..1bb5384482 100644 --- a/source/renderer/app/components/widgets/DialogCloseButton.scss +++ b/source/renderer/app/components/widgets/DialogCloseButton.scss @@ -11,3 +11,9 @@ } } } + +.disabled { + @extend .component; + cursor: default; + opacity: .5; +} diff --git a/source/renderer/app/containers/profile/dialogs/BugReportDialogContainer.js b/source/renderer/app/containers/profile/dialogs/BugReportDialogContainer.js index 78f7b106bb..c2ccf713f6 100644 --- a/source/renderer/app/containers/profile/dialogs/BugReportDialogContainer.js +++ b/source/renderer/app/containers/profile/dialogs/BugReportDialogContainer.js @@ -5,6 +5,7 @@ import { get } from 'lodash'; import { observer, inject } from 'mobx-react'; import BugReportDialog from '../../../components/profile/bug-report/BugReportDialog'; import type { InjectedProps } from '../../../types/injectedPropsType'; +import { generateFileNameWithTimestamp } from '../../../../../common/fileName'; const shell = require('electron').shell; @@ -14,16 +15,19 @@ export default class BugReportDialogContainer extends Component { static defaultProps = { actions: null, stores: null }; onSubmit = (values: { - email: string, subject: string, problem: string, compressedLog: ?string + email: string, subject: string, problem: string, compressedLogsFile: ?string }) => { this.props.actions.profile.sendBugReport.trigger(values); }; onDownload = () => { + const fileName = generateFileNameWithTimestamp(); const destination = remote.dialog.showSaveDialog({ - defaultPath: 'logs.zip', + defaultPath: fileName, }); - if (destination) this.props.actions.profile.downloadLogs.trigger({ destination }); + if (destination) { + this.props.actions.profile.downloadLogs.trigger({ fileName, destination, fresh: true }); + } }; onSubmitManually = (link: string) => { @@ -36,37 +40,32 @@ export default class BugReportDialogContainer extends Component { render() { const { actions, stores } = this.props; - const { getLogs, compressLogs, deleteCompressedLogs } = actions.profile; + const { getLogs, getLogsAndCompress } = actions.profile; const { logFiles, - compressedLog, - isCompressing, - sendBugReport, - compressedFileDownload, + compressedLogsFile, + compressedLogsStatus, + isSubmittingBugReport, error, } = stores.profile; return ( { + getLogsAndCompress.trigger({ logs }); + }} onGetLogs={() => { getLogs.trigger(); }} - onCompressLogs={(logs) => { - compressLogs.trigger({ logs }); - }} - onDeleteCompressedLogs={() => { - deleteCompressedLogs.trigger(); - }} /> ); } diff --git a/source/renderer/app/containers/settings/categories/SupportSettingsPage.js b/source/renderer/app/containers/settings/categories/SupportSettingsPage.js index bb699c2713..d695fb18ad 100644 --- a/source/renderer/app/containers/settings/categories/SupportSettingsPage.js +++ b/source/renderer/app/containers/settings/categories/SupportSettingsPage.js @@ -5,6 +5,7 @@ import { remote } from 'electron'; import SupportSettings from '../../../components/settings/categories/SupportSettings'; import type { InjectedProps } from '../../../types/injectedPropsType'; import BugReportDialog from '../../../components/profile/bug-report/BugReportDialog'; +import { generateFileNameWithTimestamp } from '../../../../../common/fileName'; const shell = require('electron').shell; @@ -25,10 +26,13 @@ export default class SupportSettingsPage extends Component { }; handleDownloadLogs = () => { + const fileName = generateFileNameWithTimestamp(); const destination = remote.dialog.showSaveDialog({ - defaultPath: 'logs.zip', + defaultPath: fileName, }); - if (destination) this.props.actions.profile.downloadLogs.trigger({ destination, fresh: true }); + if (destination) { + this.props.actions.profile.downloadLogs.trigger({ fileName, destination, fresh: true }); + } }; render() { diff --git a/source/renderer/app/stores/ProfileStore.js b/source/renderer/app/stores/ProfileStore.js index 5a07cd3892..5201dc17ee 100644 --- a/source/renderer/app/stores/ProfileStore.js +++ b/source/renderer/app/stores/ProfileStore.js @@ -9,11 +9,12 @@ import Request from './lib/LocalizedRequest'; import environment from '../../../common/environment'; import { THEMES } from '../themes/index'; import { ROUTES } from '../routes-config'; -import { GET_LOGS, DOWNLOAD_LOGS, COMPRESS_LOGS, DELETE_COMPRESSED_LOGS } from '../../../common/ipc-api'; +import { GET_LOGS, DOWNLOAD_LOGS, COMPRESS_LOGS } from '../../../common/ipc-api'; import LocalizableError from '../i18n/LocalizableError'; import globalMessages from '../i18n/global-messages'; import { WalletSupportRequestLogsCompressError } from '../i18n/errors'; -import type { LogFiles, CompressedFileDownload } from '../types/LogTypes'; +import type { LogFiles, CompressedLogStatus } from '../types/LogTypes'; +import { generateFileNameWithTimestamp } from '../../../common/fileName'; export default class SettingsStore extends Store { @@ -45,9 +46,9 @@ export default class SettingsStore extends Store { @observable sendBugReport: Request = new Request(this.api[environment.API].sendBugReport); @observable error: ?LocalizableError = null; @observable logFiles: LogFiles = {}; - @observable compressedLog: ?string = null; - @observable isCompressing: boolean = false; - @observable compressedFileDownload: CompressedFileDownload = {}; + @observable compressedLogsFile: ?string = null; + @observable compressedLogsStatus: CompressedLogStatus = {}; + @observable isSubmittingBugReport: boolean = false; /* eslint-enable max-len */ setup() { @@ -55,11 +56,10 @@ export default class SettingsStore extends Store { this.actions.profile.acceptTermsOfUse.listen(this._acceptTermsOfUse); this.actions.profile.updateTheme.listen(this._updateTheme); this.actions.profile.getLogs.listen(this._getLogs); + this.actions.profile.getLogsAndCompress.listen(this._getLogsAndCompress); + this.actions.profile.sendBugReport.listen(this._sendBugReport); this.actions.profile.resetBugReportDialog.listen(this._resetBugReportDialog); this.actions.profile.downloadLogs.listen(this._downloadLogs); - this.actions.profile.compressLogs.listen(this._compressLogs); - this.actions.profile.deleteCompressedLogs.listen(this._deleteCompressedFiles); - this.actions.profile.sendBugReport.listen(this._sendBugReport); ipcRenderer.on(GET_LOGS.SUCCESS, this._onGetLogsSuccess); ipcRenderer.on(DOWNLOAD_LOGS.SUCCESS, this._onDownloadLogsSuccess); ipcRenderer.on(COMPRESS_LOGS.SUCCESS, this._onCompressLogsSuccess); @@ -95,12 +95,16 @@ export default class SettingsStore extends Store { @computed get hasLoadedCurrentLocale(): boolean { return ( - this.getProfileLocaleRequest.wasExecuted && this.getProfileLocaleRequest.result !== null + this.getProfileLocaleRequest.wasExecuted && + this.getProfileLocaleRequest.result !== null ); } @computed get isCurrentLocaleSet(): boolean { - return (this.getProfileLocaleRequest.result !== null && this.getProfileLocaleRequest.result !== ''); + return ( + this.getProfileLocaleRequest.result !== null && + this.getProfileLocaleRequest.result !== '' + ); } @computed get currentTheme(): string { @@ -113,11 +117,17 @@ export default class SettingsStore extends Store { } @computed get isCurrentThemeSet(): boolean { - return (this.getThemeRequest.result !== null && this.getThemeRequest.result !== ''); + return ( + this.getThemeRequest.result !== null && + this.getThemeRequest.result !== '' + ); } @computed get hasLoadedCurrentTheme(): boolean { - return (this.getThemeRequest.wasExecuted && this.getThemeRequest.result !== null); + return ( + this.getThemeRequest.wasExecuted && + this.getThemeRequest.result !== null + ); } @computed get termsOfUse(): string { @@ -138,7 +148,10 @@ export default class SettingsStore extends Store { @computed get isSettingsPage(): boolean { const { currentRoute } = this.stores.app; - return includes(ROUTES.PROFILE, currentRoute) || includes(ROUTES.SETTINGS, currentRoute); + return ( + includes(ROUTES.PROFILE, currentRoute) || + includes(ROUTES.SETTINGS, currentRoute) + ); } _updateLocale = async ({ locale }: { locale: string }) => { @@ -201,82 +214,87 @@ export default class SettingsStore extends Store { ipcRenderer.send(GET_LOGS.REQUEST); }; - _resetBugReportDialog = () => { - this._deleteCompressedFiles(); - this._reset(); - this.actions.dialogs.closeActiveDialog.trigger(); - }; - - _downloadLogs = action(({ destination, fresh }) => { - this.compressedFileDownload = { - inProgress: true, - destination, - }; - - if (this.compressedLog && fresh !== true) { - // logs already compressed, trigger download - ipcRenderer.send(DOWNLOAD_LOGS.REQUEST, this.compressedLog, destination); - } else { - // start process: getLogs -> compressLogs -> downloadLogs (again) - this._getLogs(); + _onGetLogsSuccess = action((event, files) => { + this.logFiles = files; + const { isDownloading } = this.compressedLogsStatus; + if (isDownloading || this.isSubmittingBugReport) { + this._compressLogs({ logs: files }); } }); - _onGetLogsSuccess = action((event, res) => { - this.logFiles = res; - if (this.compressedFileDownload.inProgress) { - this._compressLogs({ logs: res }); - } - }); - - _onDownloadLogsSuccess = action(() => { - this.compressedFileDownload = {}; + _getLogsAndCompress = action(() => { + this.compressedLogsStatus = { + fileName: generateFileNameWithTimestamp(), + }; + this.isSubmittingBugReport = true; + this._getLogs(); }); _compressLogs = action(({ logs }) => { - this.isCompressing = true; - ipcRenderer.send(COMPRESS_LOGS.REQUEST, toJS(logs)); + const { fileName = generateFileNameWithTimestamp() } = this.compressedLogsStatus; + ipcRenderer.send(COMPRESS_LOGS.REQUEST, toJS(logs), fileName); }); - _onCompressLogsSuccess = action((event, res) => { - this.isCompressing = false; - this.compressedLog = res; - if (this.compressedFileDownload.inProgress) { - this._downloadLogs({ destination: this.compressedFileDownload.destination }); + _onCompressLogsSuccess = action((event, file) => { + this.compressedLogsFile = file; + const { isDownloading, destination, fileName } = this.compressedLogsStatus; + if (isDownloading) { + this._downloadLogs({ destination, fileName }); } }); _onCompressLogsError = action(() => { + this.isSubmittingBugReport = false; this.error = new WalletSupportRequestLogsCompressError(); }); - _sendBugReport = action(({ email, subject, problem, compressedLog } : { + _sendBugReport = action(({ email, subject, problem, compressedLogsFile } : { email: string, subject: string, problem: string, - compressedLog: ?string, + compressedLogsFile: ?string, }) => { + this.isSubmittingBugReport = true; this.sendBugReport.execute({ - email, subject, problem, compressedLog, + email, subject, problem, compressedLogsFile, }) .then(action(() => { this._resetBugReportDialog(); })) .catch(action((error) => { + this.isSubmittingBugReport = false; this.error = error; })); }); - _deleteCompressedFiles = action(() => { - if (this.compressedLog) { - ipcRenderer.send(DELETE_COMPRESSED_LOGS.REQUEST, this.compressedLog); - this.compressedLog = null; + _resetBugReportDialog = () => { + this._reset(); + this.actions.dialogs.closeActiveDialog.trigger(); + }; + + _downloadLogs = action(({ fileName, destination, fresh }) => { + this.compressedLogsStatus = { + isDownloading: true, + destination, + fileName, + }; + if (this.compressedLogsFile && fresh !== true) { + // logs already compressed, trigger the download + ipcRenderer.send(DOWNLOAD_LOGS.REQUEST, this.compressedLogsFile, destination); + } else { + // start process: getLogs -> compressLogs -> downloadLogs (again) + this._getLogs(); } }); + _onDownloadLogsSuccess = action(() => { + this.compressedLogsStatus = {}; + }); + @action _reset = () => { this.error = null; - this.compressedLog = null; - this.compressedFileDownload = {}; + this.compressedLogsFile = null; + this.compressedLogsStatus = {}; + this.isSubmittingBugReport = false; }; } diff --git a/source/renderer/app/types/LogTypes.js b/source/renderer/app/types/LogTypes.js index ecf57c167c..2e256dd61c 100644 --- a/source/renderer/app/types/LogTypes.js +++ b/source/renderer/app/types/LogTypes.js @@ -10,7 +10,8 @@ export type CompressedLogs = { originalFile: string, } | {}; -export type CompressedFileDownload = { - inProgress?: boolean, +export type CompressedLogStatus = { + fileName?: string, destination?: string, + isDownloading?: boolean, };