Remove work window, connect to CPP

This commit is contained in:
Ben Gotow 2017-06-20 00:33:18 -07:00
parent a5afcf17ee
commit 48fbe1fbac
11 changed files with 138 additions and 85 deletions

View file

@ -190,19 +190,18 @@ export default class Application extends EventEmitter {
}
openWindowsForTokenState() {
const accounts = this.config.get('nylas.accounts');
const hasAccount = accounts && accounts.length > 0;
const hasN1ID = this._getNylasId();
// const accounts = this.config.get('nylas.accounts');
// const hasAccount = accounts && accounts.length > 0;
// const hasN1ID = this._getNylasId();
if (hasAccount && hasN1ID) {
this.windowManager.ensureWindow(WindowManager.MAIN_WINDOW);
this.windowManager.ensureWindow(WindowManager.WORK_WINDOW);
} else {
this.windowManager.ensureWindow(WindowManager.ONBOARDING_WINDOW, {
title: "Welcome to Nylas Mail",
});
this.windowManager.ensureWindow(WindowManager.WORK_WINDOW);
}
// TODO BEN
// if (hasAccount && hasN1ID) {
this.windowManager.ensureWindow(WindowManager.MAIN_WINDOW);
// } else {
// this.windowManager.ensureWindow(WindowManager.ONBOARDING_WINDOW, {
// title: "Welcome to Nylas Mail",
// });
// }
}
_getNylasId() {
@ -503,7 +502,8 @@ export default class Application extends EventEmitter {
});
ipcMain.on('ensure-worker-window', () => {
this.windowManager.ensureWindow(WindowManager.WORK_WINDOW)
// TODO BG
// this.windowManager.ensureWindow(WindowManager.WORK_WINDOW)
})
ipcMain.on('inline-style-parse', (event, {html, key}) => {
@ -571,14 +571,15 @@ export default class Application extends EventEmitter {
});
ipcMain.on('action-bridge-rebroadcast-to-work', (event, ...args) => {
const workWindow = this.windowManager.get(WindowManager.WORK_WINDOW)
if (!workWindow || !workWindow.browserWindow.webContents) {
return;
}
if (BrowserWindow.fromWebContents(event.sender) === workWindow) {
return;
}
workWindow.browserWindow.webContents.send('action-bridge-message', ...args);
// TODO BG
// const workWindow = this.windowManager.get(WindowManager.WORK_WINDOW)
// if (!workWindow || !workWindow.browserWindow.webContents) {
// return;
// }
// if (BrowserWindow.fromWebContents(event.sender) === workWindow) {
// return;
// }
// workWindow.browserWindow.webContents.send('action-bridge-message', ...args);
});
ipcMain.on('write-text-to-selection-clipboard', (event, selectedText) => {
@ -596,7 +597,8 @@ export default class Application extends EventEmitter {
});
ipcMain.on('new-account-added', () => {
this.windowManager.ensureWindow(WindowManager.WORK_WINDOW)
// TODO BEN
// this.windowManager.ensureWindow(WindowManager.WORK_WINDOW)
});
ipcMain.on('run-in-window', (event, params) => {
@ -605,7 +607,6 @@ export default class Application extends EventEmitter {
this._sourceWindows[params.taskId] = sourceWindow
const targetWindowKey = {
work: WindowManager.WORK_WINDOW,
main: WindowManager.MAIN_WINDOW,
}[params.window];
if (!targetWindowKey) {

View file

@ -3,7 +3,6 @@ import {app} from 'electron';
import WindowLauncher from './window-launcher';
const MAIN_WINDOW = "default"
const WORK_WINDOW = "work"
const SPEC_WINDOW = "spec"
const ONBOARDING_WINDOW = "onboarding"
// const CALENDAR_WINDOW = "calendar"
@ -195,17 +194,6 @@ export default class WindowManager {
initializeInBackground: this.initializeInBackground,
};
coreWinOpts[WindowManager.WORK_WINDOW] = {
windowKey: WindowManager.WORK_WINDOW,
windowType: WindowManager.WORK_WINDOW,
coldStartOnly: true, // It's a secondary window, but not a hot window
title: "Activity",
hidden: true,
neverClose: true,
width: 800,
height: 400,
}
coreWinOpts[WindowManager.ONBOARDING_WINDOW] = {
windowKey: WindowManager.ONBOARDING_WINDOW,
windowType: WindowManager.ONBOARDING_WINDOW,
@ -238,7 +226,6 @@ export default class WindowManager {
}
WindowManager.MAIN_WINDOW = MAIN_WINDOW;
WindowManager.WORK_WINDOW = WORK_WINDOW;
WindowManager.SPEC_WINDOW = SPEC_WINDOW;
// WindowManager.CALENDAR_WINDOW = CALENDAR_WINDOW;
WindowManager.ONBOARDING_WINDOW = ONBOARDING_WINDOW;

View file

@ -0,0 +1,84 @@
import _ from 'underscore';
import net from 'net';
import fs from 'fs';
import Actions from './actions';
import DatabaseStore from './stores/database-store';
import DatabaseChangeRecord from './stores/database-change-record';
import Utils from './models/utils';
const Message = {
DATABASE_STORE_TRIGGER: 'db-store-trigger',
};
const printToConsole = false;
class ActionBridgeCPP {
constructor() {
if (!NylasEnv.isMainWindow()) {
// maybe bind as listener?
return;
}
try {
fs.unlinkSync('/tmp/cmail.sock');
} catch (err) {
console.info(err);
}
// This server listens on a Unix socket at /var/run/mysocket
const unixServer = net.createServer((c) => {
// Do something with the client connection
console.log('client connected');
c.on('data', (d) => {
this.onIncomingMessage(d.toString());
});
c.on('end', () => {
console.log('client disconnected');
});
c.write('hello\r\n');
c.pipe(c);
});
unixServer.listen('/tmp/cmail.sock', () => {
console.log('server bound');
});
function shutdown() {
unixServer.close(); // socket file is automatically removed here
process.exit();
}
this._readBuffer = '';
process.on('SIGINT', shutdown);
}
onIncomingMessage(message) {
console.log(message);
this._readBuffer += message;
const msgs = this._readBuffer.split('\n');
this._readBuffer = msgs.pop();
for (const msg of msgs) {
const {type, model} = JSON.parse(msg, Utils.registeredObjectReviver);
DatabaseStore.triggeringFromActionBridge = true;
DatabaseStore.trigger(new DatabaseChangeRecord({type, objects: [model]}));
DatabaseStore.triggeringFromActionBridge = false;
}
}
onBeforeUnload(readyToUnload) {
// Unfortunately, if you call ipc.send and then immediately close the window,
// Electron won't actually send the message. To work around this, we wait an
// arbitrary amount of time before closing the window after the last IPC event
// was sent. https://github.com/atom/electron/issues/4366
if (this.ipcLastSendTime && Date.now() - this.ipcLastSendTime < 100) {
setTimeout(readyToUnload, 100);
return false;
}
return true;
}
}
export default ActionBridgeCPP;

View file

@ -106,8 +106,8 @@ export default class Category extends Model {
static additionalSQLiteConfig = {
setup: () => {
return [
'CREATE INDEX IF NOT EXISTS CategoryNameIndex ON Category(account_id,name)',
'CREATE UNIQUE INDEX IF NOT EXISTS CategoryClientIndex ON Category(client_id)',
'CREATE INDEX IF NOT EXISTS CategoryNameIndex ON Category(accountId,name)',
'CREATE UNIQUE INDEX IF NOT EXISTS CategoryClientIndex ON Category(id)',
];
},
};

View file

@ -79,7 +79,6 @@ export default class Contact extends Model {
isSearchIndexed: Attributes.Boolean({
queryable: true,
modelKey: 'isSearchIndexed',
jsonKey: 'is_search_indexed',
defaultValue: false,
}),
@ -88,7 +87,6 @@ export default class Contact extends Model {
// these operations would be way too slow on large FTS tables.
searchIndexId: Attributes.Number({
modelKey: 'searchIndexId',
jsonKey: 'search_index_id',
}),
});
@ -96,8 +94,8 @@ export default class Contact extends Model {
setup: () => {
return [
'CREATE INDEX IF NOT EXISTS ContactEmailIndex ON Contact(email)',
'CREATE INDEX IF NOT EXISTS ContactAccountEmailIndex ON Contact(account_id, email)',
'CREATE INDEX IF NOT EXISTS ContactIsSearchIndexedIndex ON `Contact` (is_search_indexed, id)',
'CREATE INDEX IF NOT EXISTS ContactAccountEmailIndex ON Contact(accountId, email)',
'CREATE INDEX IF NOT EXISTS ContactIsSearchIndexedIndex ON `Contact` (isSearchIndexed, id)',
];
},
};

View file

@ -130,7 +130,7 @@ export default class Event extends Model {
static additionalSQLiteConfig = {
setup: () => {
return [
'CREATE UNIQUE INDEX IF NOT EXISTS EventClientIndex ON Event(client_id)',
'CREATE UNIQUE INDEX IF NOT EXISTS EventClientIndex ON Event(id)',
'CREATE INDEX IF NOT EXISTS EventIsSearchIndexedIndex ON `Event` (is_search_indexed, id)',
];
},

View file

@ -93,7 +93,6 @@ export default class Message extends ModelWithMetadata {
replyTo: Attributes.Collection({
modelKey: 'replyTo',
jsonKey: 'reply_to',
itemClass: Contact,
}),
@ -153,12 +152,10 @@ export default class Message extends ModelWithMetadata {
threadId: Attributes.ServerId({
queryable: true,
modelKey: 'threadId',
jsonKey: 'thread_id',
}),
messageIdHeader: Attributes.ServerId({
modelKey: 'messageIdHeader',
jsonKey: 'message_id_header',
}),
subject: Attributes.String({
@ -167,13 +164,11 @@ export default class Message extends ModelWithMetadata {
draft: Attributes.Boolean({
modelKey: 'draft',
jsonKey: 'draft',
queryable: true,
}),
pristine: Attributes.Boolean({
modelKey: 'pristine',
jsonKey: 'pristine',
queryable: false,
}),
@ -184,7 +179,6 @@ export default class Message extends ModelWithMetadata {
replyToMessageId: Attributes.ServerId({
modelKey: 'replyToMessageId',
jsonKey: 'reply_to_message_id',
}),
categories: Attributes.Collection({
@ -199,10 +193,10 @@ export default class Message extends ModelWithMetadata {
static additionalSQLiteConfig = {
setup: () => [
`CREATE INDEX IF NOT EXISTS MessageListThreadIndex ON Message(thread_id, date ASC)`,
`CREATE UNIQUE INDEX IF NOT EXISTS MessageDraftIndex ON Message(client_id)`,
`CREATE INDEX IF NOT EXISTS MessageListThreadIndex ON Message(threadId, date ASC)`,
`CREATE UNIQUE INDEX IF NOT EXISTS MessageDraftIndex ON Message(id)`,
`CREATE INDEX IF NOT EXISTS MessageListDraftIndex ON \
Message(account_id, date DESC) WHERE draft = 1`,
Message(accountId, date DESC) WHERE draft = 1`,
`CREATE INDEX IF NOT EXISTS MessageListUnifiedDraftIndex ON \
Message(date DESC) WHERE draft = 1`,
`CREATE UNIQUE INDEX IF NOT EXISTS MessageBodyIndex ON MessageBody(id)`,

View file

@ -31,11 +31,13 @@ Section: Models
###
class Model
Object.defineProperty @prototype, "id",
Object.defineProperty @prototype, "clientId",
enumerable: false
get: -> @serverId ? @clientId
set: ->
throw new Error("You may not directly set the ID of an object. Set either the `clientId` or the `serverId` instead.")
get: -> @id
Object.defineProperty @prototype, "serverId",
enumerable: false
get: -> @id
@attributes:
# Lookups will go through the custom getter.
@ -43,22 +45,12 @@ class Model
queryable: true
modelKey: 'id'
'clientId': Attributes.String
queryable: true
modelKey: 'clientId'
jsonKey: 'client_id'
'serverId': Attributes.ServerId
modelKey: 'serverId'
jsonKey: 'server_id'
'object': Attributes.String
modelKey: 'object'
'accountId': Attributes.ServerId
queryable: true
modelKey: 'accountId'
jsonKey: 'account_id'
@naturalSortOrder: -> null

View file

@ -85,31 +85,27 @@ class Thread extends ModelWithMetadata {
}),
hasAttachments: Attributes.Boolean({
modelKey: 'has_attachments',
modelKey: 'hasAttachments',
}),
lastMessageReceivedTimestamp: Attributes.DateTime({
queryable: true,
modelKey: 'lastMessageReceivedTimestamp',
jsonKey: 'last_message_received_timestamp',
}),
lastMessageSentTimestamp: Attributes.DateTime({
queryable: true,
modelKey: 'lastMessageSentTimestamp',
jsonKey: 'last_message_sent_timestamp',
}),
inAllMail: Attributes.Boolean({
queryable: true,
modelKey: 'inAllMail',
jsonKey: 'in_all_mail',
}),
isSearchIndexed: Attributes.Boolean({
queryable: true,
modelKey: 'isSearchIndexed',
jsonKey: 'is_search_indexed',
defaultValue: false,
loadFromColumn: true,
}),
@ -119,7 +115,6 @@ class Thread extends ModelWithMetadata {
// these operations would be way too slow on large FTS tables.
searchIndexId: Attributes.Number({
modelKey: 'searchIndexId',
jsonKey: 'search_index_id',
}),
})
@ -138,26 +133,26 @@ class Thread extends ModelWithMetadata {
'CREATE UNIQUE INDEX IF NOT EXISTS ThreadCountsIndex ON `ThreadCounts` (category_id DESC)',
// ThreadContact
'CREATE INDEX IF NOT EXISTS ThreadContactDateIndex ON `ThreadContact` (last_message_received_timestamp DESC, value, id)',
'CREATE INDEX IF NOT EXISTS ThreadContactDateIndex ON `ThreadContact` (lastMessageReceivedTimestamp DESC, value, id)',
// ThreadCategory
'CREATE INDEX IF NOT EXISTS ThreadListCategoryIndex ON `ThreadCategory` (last_message_received_timestamp DESC, value, in_all_mail, unread, id)',
'CREATE INDEX IF NOT EXISTS ThreadListCategorySentIndex ON `ThreadCategory` (last_message_sent_timestamp DESC, value, in_all_mail, unread, id)',
'CREATE INDEX IF NOT EXISTS ThreadListCategoryIndex ON `ThreadCategory` (lastMessageReceivedTimestamp DESC, value, inAllMail, unread, id)',
'CREATE INDEX IF NOT EXISTS ThreadListCategorySentIndex ON `ThreadCategory` (lastMessageSentTimestamp DESC, value, inAllMail, unread, id)',
// Thread: General index
'CREATE INDEX IF NOT EXISTS ThreadDateIndex ON `Thread` (last_message_received_timestamp DESC)',
'CREATE INDEX IF NOT EXISTS ThreadClientIdIndex ON `Thread` (client_id)',
'CREATE INDEX IF NOT EXISTS ThreadDateIndex ON `Thread` (lastMessageReceivedTimestamp DESC)',
'CREATE INDEX IF NOT EXISTS ThreadClientIdIndex ON `Thread` (id)',
// Thread: Partial indexes for specific views
'CREATE INDEX IF NOT EXISTS ThreadUnreadIndex ON `Thread` (account_id, last_message_received_timestamp DESC) WHERE unread = 1 AND in_all_mail = 1',
'CREATE INDEX IF NOT EXISTS ThreadUnifiedUnreadIndex ON `Thread` (last_message_received_timestamp DESC) WHERE unread = 1 AND in_all_mail = 1',
'CREATE INDEX IF NOT EXISTS ThreadUnreadIndex ON `Thread` (accountId, lastMessageReceivedTimestamp DESC) WHERE unread = 1 AND inAllMail = 1',
'CREATE INDEX IF NOT EXISTS ThreadUnifiedUnreadIndex ON `Thread` (lastMessageReceivedTimestamp DESC) WHERE unread = 1 AND inAllMail = 1',
'DROP INDEX IF EXISTS `Thread`.ThreadStarIndex',
'CREATE INDEX IF NOT EXISTS ThreadStarredIndex ON `Thread` (account_id, last_message_received_timestamp DESC) WHERE starred = 1 AND in_all_mail = 1',
'CREATE INDEX IF NOT EXISTS ThreadUnifiedStarredIndex ON `Thread` (last_message_received_timestamp DESC) WHERE starred = 1 AND in_all_mail = 1',
'CREATE INDEX IF NOT EXISTS ThreadStarredIndex ON `Thread` (accountId, lastMessageReceivedTimestamp DESC) WHERE starred = 1 AND inAllMail = 1',
'CREATE INDEX IF NOT EXISTS ThreadUnifiedStarredIndex ON `Thread` (lastMessageReceivedTimestamp DESC) WHERE starred = 1 AND inAllMail = 1',
'CREATE INDEX IF NOT EXISTS ThreadIsSearchIndexedIndex ON `Thread` (is_search_indexed, id)',
'CREATE INDEX IF NOT EXISTS ThreadIsSearchIndexedLastMessageReceivedIndex ON `Thread` (is_search_indexed, last_message_received_timestamp)',
'CREATE INDEX IF NOT EXISTS ThreadIsSearchIndexedIndex ON `Thread` (isSearchIndexed, id)',
'CREATE INDEX IF NOT EXISTS ThreadIsSearchIndexedLastMessageReceivedIndex ON `Thread` (isSearchIndexed, lastMessageReceivedTimestamp)',
],
}

View file

@ -129,7 +129,7 @@ class DatabaseStore extends NylasStore {
const app = remote.getGlobal('application')
const phase = app.databasePhase()
if (phase === DatabasePhase.Setup && NylasEnv.isWorkWindow()) {
if (phase === DatabasePhase.Setup && NylasEnv.isMainWindow()) {
await this._openDatabase()
this._checkDatabaseVersion({allowUnset: true}, () => {
this._runDatabaseSetup(() => {
@ -163,7 +163,7 @@ class DatabaseStore extends NylasStore {
// database schema to prepare those tables. This method may be called
// extremely frequently as new models are added when packages load.
refreshDatabaseSchema() {
if (!NylasEnv.isWorkWindow()) {
if (!NylasEnv.isMainWindow()) {
return Promise.resolve();
}
const app = remote.getGlobal('application');

View file

@ -172,6 +172,7 @@ export default class NylasEnvConstructor {
const ThemeManager = require('./theme-manager');
const StyleManager = require('./style-manager');
const ActionBridge = require('./flux/action-bridge').default;
const ActionBridgeCPP = require('./flux/action-bridge-cpp').default;
const MenuManager = require('./menu-manager').default;
const {devMode, benchmarkMode, safeMode, resourcePath, configDirPath, windowType} = this.getLoadSettings();
@ -229,6 +230,7 @@ export default class NylasEnvConstructor {
this.globalWindowEmitter = new Emitter();
if (!this.inSpecMode()) {
this.actionBridgeCpp = new ActionBridgeCPP();
this.actionBridge = new ActionBridge(ipcRenderer);
}