2016-02-04 07:06:52 +08:00
|
|
|
// This file cannot be Coffeescript because it loads before the
|
|
|
|
// Coffeescript interpreter. Note that it runs in both browser and
|
|
|
|
// renderer processes.
|
fix(drafts): Various improvements and fixes to drafts, draft state management
Summary:
This diff contains a few major changes:
1. Scribe is no longer used for the text editor. It's just a plain contenteditable region. The toolbar items (bold, italic, underline) still work. Scribe was causing React inconcistency issues in the following scenario:
- View thread with draft, edit draft
- Move to another thread
- Move back to thread with draft
- Move to another thread. Notice that one or more messages from thread with draft are still there.
There may be a way to fix this, but I tried for hours and there are Github Issues open on it's repository asking for React compatibility, so it may be fixed soon. For now contenteditable is working great.
2. Action.saveDraft() is no longer debounced in the DraftStore. Instead, firing that action causes the save to happen immediately, and the DraftStoreProxy has a new "DraftChangeSet" class which is responsbile for batching saves as the user interacts with the ComposerView. There are a couple big wins here:
- In the future, we may want to be able to call Action.saveDraft() in other situations and it should behave like a normal action. We may also want to expose the DraftStoreProxy as an easy way of backing interactive draft UI.
- Previously, when you added a contact to To/CC/BCC, this happened:
<input> -> Action.saveDraft -> (delay!!) -> Database -> DraftStore -> DraftStoreProxy -> View Updates
Increasing the delay to something reasonable like 200msec meant there was 200msec of lag before you saw the new view state.
To fix this, I created a new class called DraftChangeSet which is responsible for accumulating changes as they're made and firing Action.saveDraft. "Adding" a change to the change set also causes the Draft provided by the DraftStoreProxy to change immediately (the changes are a temporary layer on top of the database object). This means no delay while changes are being applied. There's a better explanation in the source!
This diff includes a few minor fixes as well:
1. Draft.state is gone—use Message.object = draft instead
2. String model attributes should never be null
3. Pre-send checks that can cancel draft send
4. Put the entire curl history and task queue into feedback reports
5. Cache localIds for extra speed
6. Move us up to latest React
Test Plan: No new tests - once we lock down this new design I'll write tests for the DraftChangeSet
Reviewers: evan
Reviewed By: evan
Differential Revision: https://review.inboxapp.com/D1125
2015-02-04 08:24:31 +08:00
|
|
|
|
2015-11-07 04:20:01 +08:00
|
|
|
var ErrorLogger, _, fs, path, app, os, remote;
|
2015-05-20 08:02:46 +08:00
|
|
|
os = require('os');
|
|
|
|
fs = require('fs-plus');
|
|
|
|
path = require('path');
|
2016-05-17 02:31:08 +08:00
|
|
|
ipcRenderer = null;
|
2015-05-20 08:02:46 +08:00
|
|
|
if (process.type === 'renderer') {
|
2016-05-17 02:31:08 +08:00
|
|
|
ipcRenderer = require('electron').ipcRenderer;
|
2016-01-30 06:23:52 +08:00
|
|
|
remote = require('electron').remote;
|
2016-05-13 04:59:20 +08:00
|
|
|
app = remote.app;
|
2015-05-20 08:02:46 +08:00
|
|
|
} else {
|
2016-05-13 04:59:20 +08:00
|
|
|
app = require('electron').app;
|
2015-05-20 08:02:46 +08:00
|
|
|
}
|
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
// A globally available ErrorLogger that can report errors to various
|
|
|
|
// sources and enhance error functionality.
|
|
|
|
//
|
|
|
|
// This runs in both the backend browser process and each and every
|
|
|
|
// renderer process.
|
|
|
|
//
|
|
|
|
// This is available as `global.errorLogger` in the backend browser
|
|
|
|
// process.
|
|
|
|
//
|
|
|
|
// It is available at `NylasEnv.errorLogger` in each renderer process.
|
|
|
|
// You should almost always use `NylasEnv.reportError` in the renderer
|
|
|
|
// processes instead of manually accessing the `errorLogger`
|
|
|
|
//
|
|
|
|
// The errorLogger will report errors to a log file as well as to 3rd
|
|
|
|
// party reporting services if enabled.
|
|
|
|
module.exports = ErrorLogger = (function() {
|
2015-05-22 05:41:30 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
function ErrorLogger(args) {
|
|
|
|
this.reportError = this.reportError.bind(this)
|
|
|
|
this.inSpecMode = args.inSpecMode
|
|
|
|
this.inDevMode = args.inDevMode
|
|
|
|
this.resourcePath = args.resourcePath
|
2015-05-22 05:41:30 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
this._extendErrorObject()
|
2015-07-03 01:15:31 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
this._extendNativeConsole()
|
2015-07-03 01:15:31 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
this.extensions = this._setupErrorLoggerExtensions(args)
|
fix(drafts): Various improvements and fixes to drafts, draft state management
Summary:
This diff contains a few major changes:
1. Scribe is no longer used for the text editor. It's just a plain contenteditable region. The toolbar items (bold, italic, underline) still work. Scribe was causing React inconcistency issues in the following scenario:
- View thread with draft, edit draft
- Move to another thread
- Move back to thread with draft
- Move to another thread. Notice that one or more messages from thread with draft are still there.
There may be a way to fix this, but I tried for hours and there are Github Issues open on it's repository asking for React compatibility, so it may be fixed soon. For now contenteditable is working great.
2. Action.saveDraft() is no longer debounced in the DraftStore. Instead, firing that action causes the save to happen immediately, and the DraftStoreProxy has a new "DraftChangeSet" class which is responsbile for batching saves as the user interacts with the ComposerView. There are a couple big wins here:
- In the future, we may want to be able to call Action.saveDraft() in other situations and it should behave like a normal action. We may also want to expose the DraftStoreProxy as an easy way of backing interactive draft UI.
- Previously, when you added a contact to To/CC/BCC, this happened:
<input> -> Action.saveDraft -> (delay!!) -> Database -> DraftStore -> DraftStoreProxy -> View Updates
Increasing the delay to something reasonable like 200msec meant there was 200msec of lag before you saw the new view state.
To fix this, I created a new class called DraftChangeSet which is responsible for accumulating changes as they're made and firing Action.saveDraft. "Adding" a change to the change set also causes the Draft provided by the DraftStoreProxy to change immediately (the changes are a temporary layer on top of the database object). This means no delay while changes are being applied. There's a better explanation in the source!
This diff includes a few minor fixes as well:
1. Draft.state is gone—use Message.object = draft instead
2. String model attributes should never be null
3. Pre-send checks that can cancel draft send
4. Put the entire curl history and task queue into feedback reports
5. Cache localIds for extra speed
6. Move us up to latest React
Test Plan: No new tests - once we lock down this new design I'll write tests for the DraftChangeSet
Reviewers: evan
Reviewed By: evan
Differential Revision: https://review.inboxapp.com/D1125
2015-02-04 08:24:31 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
if (this.inSpecMode) { return }
|
2015-06-16 09:29:59 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
this._cleanOldLogFiles();
|
|
|
|
this._setupNewLogFile();
|
|
|
|
this._hookProcessOutputsToLogFile();
|
|
|
|
}
|
fix(drafts): Various improvements and fixes to drafts, draft state management
Summary:
This diff contains a few major changes:
1. Scribe is no longer used for the text editor. It's just a plain contenteditable region. The toolbar items (bold, italic, underline) still work. Scribe was causing React inconcistency issues in the following scenario:
- View thread with draft, edit draft
- Move to another thread
- Move back to thread with draft
- Move to another thread. Notice that one or more messages from thread with draft are still there.
There may be a way to fix this, but I tried for hours and there are Github Issues open on it's repository asking for React compatibility, so it may be fixed soon. For now contenteditable is working great.
2. Action.saveDraft() is no longer debounced in the DraftStore. Instead, firing that action causes the save to happen immediately, and the DraftStoreProxy has a new "DraftChangeSet" class which is responsbile for batching saves as the user interacts with the ComposerView. There are a couple big wins here:
- In the future, we may want to be able to call Action.saveDraft() in other situations and it should behave like a normal action. We may also want to expose the DraftStoreProxy as an easy way of backing interactive draft UI.
- Previously, when you added a contact to To/CC/BCC, this happened:
<input> -> Action.saveDraft -> (delay!!) -> Database -> DraftStore -> DraftStoreProxy -> View Updates
Increasing the delay to something reasonable like 200msec meant there was 200msec of lag before you saw the new view state.
To fix this, I created a new class called DraftChangeSet which is responsible for accumulating changes as they're made and firing Action.saveDraft. "Adding" a change to the change set also causes the Draft provided by the DraftStoreProxy to change immediately (the changes are a temporary layer on top of the database object). This means no delay while changes are being applied. There's a better explanation in the source!
This diff includes a few minor fixes as well:
1. Draft.state is gone—use Message.object = draft instead
2. String model attributes should never be null
3. Pre-send checks that can cancel draft send
4. Put the entire curl history and task queue into feedback reports
5. Cache localIds for extra speed
6. Move us up to latest React
Test Plan: No new tests - once we lock down this new design I'll write tests for the DraftChangeSet
Reviewers: evan
Reviewed By: evan
Differential Revision: https://review.inboxapp.com/D1125
2015-02-04 08:24:31 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////// PUBLIC METHODS //////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
ErrorLogger.prototype.reportError = function(error, extra) {
|
|
|
|
if (!error) { error = {stack: ""} }
|
|
|
|
this._appendLog(error.stack)
|
|
|
|
if (extra) { this._appendLog(extra) }
|
2016-05-17 02:31:08 +08:00
|
|
|
if (process.type === "renderer") {
|
|
|
|
var errorJSON = JSON.stringify(error);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* We synchronously send all errors to the backend main process.
|
|
|
|
*
|
|
|
|
* This is important because errors can frequently happen right
|
|
|
|
* before a renderer window is closing. Since error reporting hits
|
|
|
|
* APIs and is asynchronous it's possible for the window to be
|
|
|
|
* destroyed before the report makes it.
|
|
|
|
*
|
|
|
|
* This is a rare use of `sendSync` to ensure the command has made
|
|
|
|
* it before the window closes.
|
|
|
|
*/
|
|
|
|
ipcRenderer.sendSync("report-error", {errorJSON: errorJSON, extra: extra})
|
|
|
|
|
|
|
|
} else {
|
|
|
|
var nslog = require('nslog');
|
|
|
|
this._notifyExtensions("reportError", error, extra)
|
|
|
|
nslog(error.stack)
|
|
|
|
}
|
2016-02-04 07:06:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorLogger.prototype.openLogs = function() {
|
2016-04-14 06:35:01 +08:00
|
|
|
var shell = require('electron').shell;
|
2016-02-04 07:06:52 +08:00
|
|
|
shell.openItem(this._logPath());
|
|
|
|
};
|
|
|
|
|
|
|
|
ErrorLogger.prototype.apiDebug = function(error) {
|
|
|
|
this._appendLog(error, error.statusCode, error.message);
|
|
|
|
this._notifyExtensions("onDidLogAPIError", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////// PRIVATE METHODS //////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
2015-11-07 04:20:01 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._extendNativeConsole = function(args) {
|
|
|
|
console.debug = this._consoleDebug.bind(this)
|
2015-06-16 09:29:59 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
if (process.type === 'browser' && process.platform === 'darwin') {
|
|
|
|
var nslog = require('nslog');
|
|
|
|
console.log = nslog;
|
|
|
|
console.error = nslog;
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
2016-02-04 07:06:52 +08:00
|
|
|
}
|
2015-06-16 09:29:59 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
// globally define Error.toJSON. This allows us to pass errors via IPC
|
|
|
|
// and through the Action Bridge. Note:they are not re-inflated into
|
|
|
|
// Error objects automatically.
|
|
|
|
ErrorLogger.prototype._extendErrorObject = function(args) {
|
|
|
|
Object.defineProperty(Error.prototype, 'toJSON', {
|
|
|
|
value: function () {
|
|
|
|
var alt = {};
|
|
|
|
|
|
|
|
Object.getOwnPropertyNames(this).forEach(function (key) {
|
|
|
|
alt[key] = this[key];
|
|
|
|
}, this);
|
|
|
|
|
|
|
|
return alt;
|
|
|
|
},
|
|
|
|
configurable: true
|
|
|
|
});
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._setupErrorLoggerExtensions = function(args) {
|
2015-11-07 04:20:01 +08:00
|
|
|
var extension, extensionConstructor, extensionPath, extensions, extensionsPath, i, len, ref;
|
|
|
|
if (args == null) {
|
|
|
|
args = {};
|
|
|
|
}
|
|
|
|
extensions = [];
|
|
|
|
extensionsPath = path.join(args.resourcePath, 'src', 'error-logger-extensions');
|
|
|
|
ref = fs.listSync(extensionsPath);
|
|
|
|
for (i = 0, len = ref.length; i < len; i++) {
|
|
|
|
extensionPath = ref[i];
|
|
|
|
if (path.basename(extensionPath)[0] === '.') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
extensionConstructor = require(extensionPath);
|
|
|
|
if (!(typeof extensionConstructor === "function")) {
|
|
|
|
throw new Error("Logger Extensions must return an extension constructor");
|
|
|
|
}
|
|
|
|
extension = new extensionConstructor({
|
|
|
|
inSpecMode: args.inSpecMode,
|
|
|
|
inDevMode: args.inDevMode,
|
|
|
|
resourcePath: args.resourcePath
|
|
|
|
});
|
|
|
|
extensions.push(extension);
|
|
|
|
}
|
|
|
|
return extensions;
|
|
|
|
};
|
fix(drafts): Various improvements and fixes to drafts, draft state management
Summary:
This diff contains a few major changes:
1. Scribe is no longer used for the text editor. It's just a plain contenteditable region. The toolbar items (bold, italic, underline) still work. Scribe was causing React inconcistency issues in the following scenario:
- View thread with draft, edit draft
- Move to another thread
- Move back to thread with draft
- Move to another thread. Notice that one or more messages from thread with draft are still there.
There may be a way to fix this, but I tried for hours and there are Github Issues open on it's repository asking for React compatibility, so it may be fixed soon. For now contenteditable is working great.
2. Action.saveDraft() is no longer debounced in the DraftStore. Instead, firing that action causes the save to happen immediately, and the DraftStoreProxy has a new "DraftChangeSet" class which is responsbile for batching saves as the user interacts with the ComposerView. There are a couple big wins here:
- In the future, we may want to be able to call Action.saveDraft() in other situations and it should behave like a normal action. We may also want to expose the DraftStoreProxy as an easy way of backing interactive draft UI.
- Previously, when you added a contact to To/CC/BCC, this happened:
<input> -> Action.saveDraft -> (delay!!) -> Database -> DraftStore -> DraftStoreProxy -> View Updates
Increasing the delay to something reasonable like 200msec meant there was 200msec of lag before you saw the new view state.
To fix this, I created a new class called DraftChangeSet which is responsible for accumulating changes as they're made and firing Action.saveDraft. "Adding" a change to the change set also causes the Draft provided by the DraftStoreProxy to change immediately (the changes are a temporary layer on top of the database object). This means no delay while changes are being applied. There's a better explanation in the source!
This diff includes a few minor fixes as well:
1. Draft.state is gone—use Message.object = draft instead
2. String model attributes should never be null
3. Pre-send checks that can cancel draft send
4. Put the entire curl history and task queue into feedback reports
5. Cache localIds for extra speed
6. Move us up to latest React
Test Plan: No new tests - once we lock down this new design I'll write tests for the DraftChangeSet
Reviewers: evan
Reviewed By: evan
Differential Revision: https://review.inboxapp.com/D1125
2015-02-04 08:24:31 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._logPath = function() {
|
|
|
|
var tmpPath = app.getPath('temp');
|
|
|
|
|
|
|
|
var logpid = process.pid;
|
|
|
|
if (process.type === 'renderer') {
|
|
|
|
logpid = remote.process.pid + "." + process.pid;
|
|
|
|
}
|
|
|
|
return path.join(tmpPath, 'Nylas-N1-' + logpid + '.log');
|
|
|
|
}
|
|
|
|
|
2015-06-16 09:29:59 +08:00
|
|
|
// If we're the browser process, remove log files that are more than
|
|
|
|
// two days old. These log files get pretty big because we're logging
|
|
|
|
// so verbosely.
|
2015-11-07 04:20:01 +08:00
|
|
|
ErrorLogger.prototype._cleanOldLogFiles = function() {
|
2015-05-20 08:02:46 +08:00
|
|
|
if (process.type === 'browser') {
|
2016-02-04 07:06:52 +08:00
|
|
|
var tmpPath = app.getPath('temp');
|
2015-05-20 08:02:46 +08:00
|
|
|
fs.readdir(tmpPath, function(err, files) {
|
|
|
|
if (err) {
|
|
|
|
console.error(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-28 07:35:38 +08:00
|
|
|
var logFilter = new RegExp("Nylas-N1-[.0-9]*.log$");
|
2015-05-20 08:02:46 +08:00
|
|
|
files.forEach(function(file) {
|
|
|
|
if (logFilter.test(file) === true) {
|
|
|
|
var filepath = path.join(tmpPath, file);
|
|
|
|
fs.stat(filepath, function(err, stats) {
|
|
|
|
var lastModified = new Date(stats['mtime']);
|
|
|
|
var fileAge = Date.now() - lastModified.getTime();
|
|
|
|
if (fileAge > (1000 * 60 * 60 * 24 * 2)) { // two days
|
|
|
|
fs.unlink(filepath);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
|
|
|
|
2015-11-07 04:20:01 +08:00
|
|
|
ErrorLogger.prototype._setupNewLogFile = function() {
|
2015-05-20 08:02:46 +08:00
|
|
|
// Open a file write stream to log output from this process
|
2016-02-04 07:06:52 +08:00
|
|
|
console.log("Streaming log data to "+this._logPath());
|
2015-05-20 08:02:46 +08:00
|
|
|
|
|
|
|
this.loghost = os.hostname();
|
2016-02-04 07:06:52 +08:00
|
|
|
this.logstream = fs.createWriteStream(this._logPath(), {
|
2015-05-20 08:02:46 +08:00
|
|
|
flags: 'a',
|
|
|
|
encoding: 'utf8',
|
|
|
|
fd: null,
|
|
|
|
mode: 0666
|
|
|
|
});
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
2015-05-20 08:02:46 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._hookProcessOutputsToLogFile = function() {
|
2015-06-16 09:29:59 +08:00
|
|
|
var self = this;
|
2015-05-20 08:02:46 +08:00
|
|
|
// Override stdout and stderr to pipe their output to the file
|
|
|
|
// in addition to calling through to the existing implementation
|
|
|
|
function hook_process_output(channel, callback) {
|
|
|
|
var old_write = process[channel].write;
|
|
|
|
process[channel].write = (function(write) {
|
|
|
|
return function(string, encoding, fd) {
|
|
|
|
write.apply(process[channel], arguments)
|
|
|
|
callback(string, encoding, fd)
|
|
|
|
}
|
|
|
|
})(process[channel].write)
|
|
|
|
|
|
|
|
// Return a function that can be used to undo this change
|
|
|
|
return function() {
|
|
|
|
process[channel].write = old_write
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
hook_process_output('stdout', function(string, encoding, fd) {
|
2016-02-04 07:06:52 +08:00
|
|
|
self._appendLog.apply(self, [string]);
|
2015-05-20 08:02:46 +08:00
|
|
|
});
|
|
|
|
hook_process_output('stderr', function(string, encoding, fd) {
|
2016-02-04 07:06:52 +08:00
|
|
|
self._appendLog.apply(self, [string]);
|
2015-05-20 08:02:46 +08:00
|
|
|
});
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
2015-05-20 08:02:46 +08:00
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._notifyExtensions = function() {
|
2015-11-07 04:20:01 +08:00
|
|
|
var command, args;
|
|
|
|
command = arguments[0]
|
|
|
|
args = 2 <= arguments.length ? Array.prototype.slice.call(arguments, 1) : [];
|
|
|
|
for (var i=0; i < this.extensions.length; i++) {
|
|
|
|
extension = this.extensions[i]
|
|
|
|
extension[command].apply(this, args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-16 09:29:59 +08:00
|
|
|
// Create a new console.debug option, which takes `true` (print)
|
|
|
|
// or `false`, don't print in console as the first parameter.
|
|
|
|
// This makes it easy for developers to turn on and off
|
|
|
|
// "verbose console" mode.
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._consoleDebug = function() {
|
2015-06-16 09:29:59 +08:00
|
|
|
var args = [];
|
|
|
|
var showIt = arguments[0];
|
|
|
|
for (var ii = 1; ii < arguments.length; ii++) {
|
|
|
|
args.push(arguments[ii]);
|
|
|
|
}
|
perf(thread-list): Tailored SQLite indexes, ListTabular / ScrollRegion optimizations galore
Summary:
Allow Database models to create indexes, but don't autocreate bad ones
fix minor bug in error-reporter
Fix index on message list to make thread list lookups use proper index
Developer bar ignores state changes unless it's open
DatabaseView now asks for metadata for a set of items rather than calling a function for every item. Promise.props was cute but we really needed to make a single database query for all message metadata.
New "in" matcher so you can say `thread_id IN (1,2,3)`
Add .scroll-region-content-inner which is larger than the viewport by 1 page size, and uses transform(0,0,0) trick
ScrollRegion exposes `onScrollEnd` so listTabular, et al don't need to re-implement it with more timers. Also removing requestAnimationFrame which was causing us to request scrollTop when it was not ready, and caching the values of...
...clientHeight/scrollHeight while scrolling is in-flight
Updating rendered content 10 rows at a time (RangeChunkSize) was a bad idea. Instead, add every row in a render: pass as it comes in (less work all the time vs more work intermittently). Also remove bad requestAnimationFrame, and prevent calls to...
...updateRangeState from triggering additional calls to updateRangeState by removing `componentDidUpdate => updateRangeState `
Turning off hover (pointer-events:none) is now standard in ScrollRegion
Loading text in the scroll tooltip, instead of random date shown
Handle query parse errors by catching error and throwing a better more explanatory error
Replace "quick action" retina images with background images to make React render easier
Replace hasTagId with a faster implementation which doesn't call functions and doesn't build a temporary array
Print query durations when printing to console instead of only in metadata
Remove headers from support from ListTabular, we'll never use it
Making columns part of state was a good idea but changing the array causes the entire ListTabular to re-render. To avoid this, be smarter about updating columns. This logic could potentially go in `componentDidReceiveProps` too.
Fix specs and add 6 more for new database store functionality
Test Plan: Run 6 new specs. More in the works?
Reviewers: evan
Reviewed By: evan
Differential Revision: https://phab.nylas.com/D1651
2015-06-18 11:12:48 +08:00
|
|
|
if ((this.inDevMode === true) && (showIt === true)) {
|
|
|
|
console.log.apply(console, args);
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
2016-02-04 07:06:52 +08:00
|
|
|
this._appendLog.apply(this, [args]);
|
2015-06-16 09:29:59 +08:00
|
|
|
}
|
|
|
|
|
2016-02-04 07:06:52 +08:00
|
|
|
ErrorLogger.prototype._appendLog = function(obj) {
|
2015-06-16 09:29:59 +08:00
|
|
|
if (this.inSpecMode) { return };
|
|
|
|
|
2015-05-20 08:02:46 +08:00
|
|
|
try {
|
|
|
|
var message = JSON.stringify({
|
|
|
|
host: this.loghost,
|
|
|
|
timestamp: (new Date()).toISOString(),
|
|
|
|
payload: obj
|
|
|
|
})+"\n";
|
|
|
|
|
|
|
|
this.logstream.write(message, 'utf8', function (err) {
|
|
|
|
if (err) {
|
2015-11-07 04:20:01 +08:00
|
|
|
console.error("ErrorLogger: Unable to write to the log stream!" + err.toString());
|
2015-05-20 08:02:46 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (err) {
|
2015-11-07 04:20:01 +08:00
|
|
|
console.error("ErrorLogger: Unable to write to the log stream." + err.toString());
|
2015-05-20 08:02:46 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-11-07 04:20:01 +08:00
|
|
|
return ErrorLogger;
|
fix(drafts): Various improvements and fixes to drafts, draft state management
Summary:
This diff contains a few major changes:
1. Scribe is no longer used for the text editor. It's just a plain contenteditable region. The toolbar items (bold, italic, underline) still work. Scribe was causing React inconcistency issues in the following scenario:
- View thread with draft, edit draft
- Move to another thread
- Move back to thread with draft
- Move to another thread. Notice that one or more messages from thread with draft are still there.
There may be a way to fix this, but I tried for hours and there are Github Issues open on it's repository asking for React compatibility, so it may be fixed soon. For now contenteditable is working great.
2. Action.saveDraft() is no longer debounced in the DraftStore. Instead, firing that action causes the save to happen immediately, and the DraftStoreProxy has a new "DraftChangeSet" class which is responsbile for batching saves as the user interacts with the ComposerView. There are a couple big wins here:
- In the future, we may want to be able to call Action.saveDraft() in other situations and it should behave like a normal action. We may also want to expose the DraftStoreProxy as an easy way of backing interactive draft UI.
- Previously, when you added a contact to To/CC/BCC, this happened:
<input> -> Action.saveDraft -> (delay!!) -> Database -> DraftStore -> DraftStoreProxy -> View Updates
Increasing the delay to something reasonable like 200msec meant there was 200msec of lag before you saw the new view state.
To fix this, I created a new class called DraftChangeSet which is responsible for accumulating changes as they're made and firing Action.saveDraft. "Adding" a change to the change set also causes the Draft provided by the DraftStoreProxy to change immediately (the changes are a temporary layer on top of the database object). This means no delay while changes are being applied. There's a better explanation in the source!
This diff includes a few minor fixes as well:
1. Draft.state is gone—use Message.object = draft instead
2. String model attributes should never be null
3. Pre-send checks that can cancel draft send
4. Put the entire curl history and task queue into feedback reports
5. Cache localIds for extra speed
6. Move us up to latest React
Test Plan: No new tests - once we lock down this new design I'll write tests for the DraftChangeSet
Reviewers: evan
Reviewed By: evan
Differential Revision: https://review.inboxapp.com/D1125
2015-02-04 08:24:31 +08:00
|
|
|
|
|
|
|
})();
|