diff --git a/internal_packages/link-tracking/lib/link-tracking-button.jsx b/internal_packages/link-tracking/lib/link-tracking-button.jsx
index 9435e080a..df3d7b4d4 100644
--- a/internal_packages/link-tracking/lib/link-tracking-button.jsx
+++ b/internal_packages/link-tracking/lib/link-tracking-button.jsx
@@ -29,7 +29,7 @@ export default class LinkTrackingButton extends React.Component {
iconName="icon-composer-linktracking.png"
pluginId={PLUGIN_ID}
pluginName={PLUGIN_NAME}
- metadataKey="tracked"
+ metadataEnabledValue={{"tracked": true}}
stickyToggle
errorMessage={this._errorMessage}
draftClientId={this.props.draftClientId} />
diff --git a/internal_packages/link-tracking/lib/link-tracking-composer-extension.es6 b/internal_packages/link-tracking/lib/link-tracking-composer-extension.es6
index 5aa933275..e407a4631 100644
--- a/internal_packages/link-tracking/lib/link-tracking-composer-extension.es6
+++ b/internal_packages/link-tracking/lib/link-tracking-composer-extension.es6
@@ -42,6 +42,7 @@ export default class LinkTrackingComposerExtension extends ComposerExtension {
// save the link info to draft metadata
metadata.uid = messageUid;
metadata.links = links;
+
Actions.setMetadata(draft, PLUGIN_ID, metadata);
}
}
diff --git a/internal_packages/link-tracking/lib/link-tracking-icon.jsx b/internal_packages/link-tracking/lib/link-tracking-icon.jsx
deleted file mode 100644
index f65f28e6a..000000000
--- a/internal_packages/link-tracking/lib/link-tracking-icon.jsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import {React} from 'nylas-exports'
-import {RetinaImg} from 'nylas-component-kit'
-import {PLUGIN_ID} from './link-tracking-constants'
-
-const sum = (array, extractFn) => array.reduce( (a, b) => a + extractFn(b), 0 );
-
-
-export default class LinkTrackingIcon extends React.Component {
-
- static displayName = 'LinkTrackingIcon';
-
- static propTypes = {
- thread: React.PropTypes.object.isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = this._getStateFromThread(props.thread);
- }
-
- componentWillReceiveProps(newProps) {
- this.setState(this._getStateFromThread(newProps.thread));
- }
-
- _getStateFromThread(thread) {
- const messages = thread.metadata;
- // Pull a list of metadata for all messages
- const metadataObjs = messages.map(msg => msg.metadataForPluginId(PLUGIN_ID)).filter(meta => meta);
- if (metadataObjs.length) {
- // If there's metadata, return the total number of link clicks in the most recent metadata
- const mostRecentMetadata = metadataObjs.pop();
- return {
- clicks: sum(mostRecentMetadata.links || [], link => link.click_count || 0),
- };
- }
- return {clicks: null};
- }
-
-
- _renderIcon = () => {
- return this.state.clicks == null ? "" : this._getIcon(this.state.clicks);
- };
-
- _getIcon(clicks) {
- return (
- 0 ? "clicked" : ""}
- name="icon-composer-linktracking.png"
- mode={RetinaImg.Mode.ContentIsMask} />
- {clicks > 0 ? clicks : ""}
- )
- }
-
- render() {
- return (
- {this._renderIcon()}
-
)
- }
-}
diff --git a/internal_packages/link-tracking/lib/link-tracking-panel.jsx b/internal_packages/link-tracking/lib/link-tracking-panel.jsx
deleted file mode 100644
index fa7a40331..000000000
--- a/internal_packages/link-tracking/lib/link-tracking-panel.jsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import {React} from 'nylas-exports'
-import {PLUGIN_ID} from './link-tracking-constants'
-
-
-export default class LinkTrackingPanel extends React.Component {
- static displayName = 'LinkTrackingPanel';
-
- static propTypes = {
- message: React.PropTypes.object.isRequired,
- };
-
- constructor(props) {
- super(props);
- this.state = this._getStateFromMessage(props.message)
- }
-
- componentWillReceiveProps(newProps) {
- this.setState(this._getStateFromMessage(newProps.message));
- }
-
- _getStateFromMessage(message) {
- const metadata = message.metadataForPluginId(PLUGIN_ID);
- return metadata ? {links: metadata.links} : {};
- }
-
- _renderContents() {
- return this.state.links.map(link => {
- return (
- {link.url} |
- {link.click_count + " clicks"} |
-
)
- })
- }
-
- render() {
- if (this.state.links) {
- return (
-
Link Tracking Enabled
-
-
- {this._renderContents()}
-
-
-
);
- }
- return ;
- }
-}
diff --git a/internal_packages/link-tracking/lib/main.es6 b/internal_packages/link-tracking/lib/main.es6
index 43d1ae0b0..5fca88586 100644
--- a/internal_packages/link-tracking/lib/main.es6
+++ b/internal_packages/link-tracking/lib/main.es6
@@ -1,9 +1,6 @@
import request from 'request';
-import {ComponentRegistry, DatabaseStore, Message, ExtensionRegistry, Actions} from 'nylas-exports';
+import {ComponentRegistry, ExtensionRegistry, Actions} from 'nylas-exports';
import LinkTrackingButton from './link-tracking-button';
-// TODO what's up with these components?
-// import LinkTrackingIcon from './link-tracking-icon';
-// import LinkTrackingPanel from './link-tracking-panel';
import LinkTrackingComposerExtension from './link-tracking-composer-extension';
import LinkTrackingMessageExtension from './link-tracking-message-extension';
import {PLUGIN_ID, PLUGIN_URL} from './link-tracking-constants';
@@ -11,41 +8,36 @@ import {PLUGIN_ID, PLUGIN_URL} from './link-tracking-constants';
const post = Promise.promisify(request.post, {multiArgs: true});
-function afterDraftSend({draftClientId}) {
+function afterDraftSend({message}) {
// only run this handler in the main window
if (!NylasEnv.isMainWindow()) return;
- // query for the message
- DatabaseStore.findBy(Message, {clientId: draftClientId}).then((message) => {
- // grab message metadata, if any
- const metadata = message.metadataForPluginId(PLUGIN_ID);
- // get the uid from the metadata, if present
- if (metadata) {
- const uid = metadata.uid;
+ // grab message metadata, if any
+ const metadata = message.metadataForPluginId(PLUGIN_ID);
+ if (metadata) {
+ // get the uid from the metadata, if present
+ const uid = metadata.uid;
- // post the uid and message id pair to the plugin server
- const data = {uid: uid, message_id: message.id};
- const serverUrl = `${PLUGIN_URL}/plugins/register-message`;
- return post({
- url: serverUrl,
- body: JSON.stringify(data),
- }).then( ([response, responseBody]) => {
- if (response.statusCode !== 200) {
- throw new Error(`Link Tracking server error ${response.statusCode} at ${serverUrl}: ${responseBody}`);
- }
- return responseBody;
- }).catch(error => {
- NylasEnv.showErrorDialog("There was a problem contacting the Link Tracking server! This message will not have link tracking");
- Promise.reject(error);
- });
- }
- });
+ // post the uid and message id pair to the plugin server
+ const data = {uid: uid, message_id: message.id};
+ const serverUrl = `${PLUGIN_URL}/plugins/register-message`;
+
+ post({
+ url: serverUrl,
+ body: JSON.stringify(data),
+ }).then( ([response, responseBody]) => {
+ if (response.statusCode !== 200) {
+ throw new Error(`Link Tracking server error ${response.statusCode} at ${serverUrl}: ${responseBody}`);
+ }
+ }).catch(error => {
+ NylasEnv.showErrorDialog("There was a problem contacting the Link Tracking server! This message will not have link tracking");
+ Promise.reject(error);
+ });
+ }
}
export function activate() {
ComponentRegistry.register(LinkTrackingButton, {role: 'Composer:ActionButton'});
- // ComponentRegistry.register(LinkTrackingIcon, {role: 'ThreadListIcon'});
- // ComponentRegistry.register(LinkTrackingPanel, {role: 'message:BodyHeader'});
ExtensionRegistry.Composer.register(LinkTrackingComposerExtension);
ExtensionRegistry.MessageView.register(LinkTrackingMessageExtension);
this._unlistenSendDraftSuccess = Actions.sendDraftSuccess.listen(afterDraftSend);
@@ -55,8 +47,6 @@ export function serialize() {}
export function deactivate() {
ComponentRegistry.unregister(LinkTrackingButton);
- // ComponentRegistry.unregister(LinkTrackingIcon);
- // ComponentRegistry.unregister(LinkTrackingPanel);
ExtensionRegistry.Composer.unregister(LinkTrackingComposerExtension);
ExtensionRegistry.MessageView.unregister(LinkTrackingMessageExtension);
this._unlistenSendDraftSuccess()
diff --git a/internal_packages/open-tracking/lib/main.es6 b/internal_packages/open-tracking/lib/main.es6
index 0a3fcd418..820d1dab7 100644
--- a/internal_packages/open-tracking/lib/main.es6
+++ b/internal_packages/open-tracking/lib/main.es6
@@ -1,5 +1,5 @@
import request from 'request';
-import {ComponentRegistry, ExtensionRegistry, DatabaseStore, Message, Actions} from 'nylas-exports';
+import {ComponentRegistry, ExtensionRegistry, Actions} from 'nylas-exports';
import OpenTrackingButton from './open-tracking-button';
import OpenTrackingIcon from './open-tracking-icon';
import OpenTrackingMessageStatus from './open-tracking-message-status';
@@ -9,39 +9,33 @@ import {PLUGIN_ID, PLUGIN_URL} from './open-tracking-constants'
const post = Promise.promisify(request.post, {multiArgs: true});
-function afterDraftSend({draftClientId}) {
+function afterDraftSend({message}) {
// only run this handler in the main window
if (!NylasEnv.isMainWindow()) return;
- // query for the message
- DatabaseStore.findBy(Message, {clientId: draftClientId}).then((message) => {
- // grab message metadata, if any
- const metadata = message.metadataForPluginId(PLUGIN_ID);
+ // grab message metadata, if any
+ const metadata = message.metadataForPluginId(PLUGIN_ID);
- // get the uid from the metadata, if present
- if (metadata) {
- const uid = metadata.uid;
+ // get the uid from the metadata, if present
+ if (metadata) {
+ const uid = metadata.uid;
- // set metadata against the message
- Actions.setMetadata(message, PLUGIN_ID, {open_count: 0, open_data: []});
+ // post the uid and message id pair to the plugin server
+ const data = {uid: uid, message_id: message.id, thread_id: 1};
+ const serverUrl = `${PLUGIN_URL}/plugins/register-message`;
- // post the uid and message id pair to the plugin server
- const data = {uid: uid, message_id: message.id, thread_id: 1};
- const serverUrl = `${PLUGIN_URL}/plugins/register-message`;
- return post({
- url: serverUrl,
- body: JSON.stringify(data),
- }).then(([response, responseBody]) => {
- if (response.statusCode !== 200) {
- throw new Error();
- }
- return responseBody;
- }).catch(error => {
- NylasEnv.showErrorDialog("There was a problem contacting the Open Tracking server! This message will not have open tracking :(");
- Promise.reject(error);
- });
- }
- });
+ post({
+ url: serverUrl,
+ body: JSON.stringify(data),
+ }).then(([response, responseBody]) => {
+ if (response.statusCode !== 200) {
+ throw new Error(responseBody);
+ }
+ }).catch(error => {
+ NylasEnv.showErrorDialog(`There was a problem saving your open tracking settings. This message will not have open tracking. ${error.message}`);
+ Promise.reject(error);
+ });
+ }
}
export function activate() {
diff --git a/internal_packages/open-tracking/lib/open-tracking-button.jsx b/internal_packages/open-tracking/lib/open-tracking-button.jsx
index d7a2aed8a..3fa74ebad 100644
--- a/internal_packages/open-tracking/lib/open-tracking-button.jsx
+++ b/internal_packages/open-tracking/lib/open-tracking-button.jsx
@@ -2,6 +2,7 @@
import {React, APIError, NylasAPI} from 'nylas-exports'
import {MetadataComposerToggleButton} from 'nylas-component-kit'
import {PLUGIN_ID, PLUGIN_NAME} from './open-tracking-constants'
+import uuid from 'node-uuid';
export default class OpenTrackingButton extends React.Component {
static displayName = 'OpenTrackingButton';
@@ -23,13 +24,19 @@ export default class OpenTrackingButton extends React.Component {
}
render() {
+ const enabledValue = {
+ uid: uuid.v4().replace(/-/g, ""),
+ open_count: 0,
+ open_data: [],
+ };
+
return (
diff --git a/internal_packages/open-tracking/lib/open-tracking-composer-extension.es6 b/internal_packages/open-tracking/lib/open-tracking-composer-extension.es6
index d99ca9269..f4c45004a 100644
--- a/internal_packages/open-tracking/lib/open-tracking-composer-extension.es6
+++ b/internal_packages/open-tracking/lib/open-tracking-composer-extension.es6
@@ -1,5 +1,4 @@
-import uuid from 'node-uuid';
-import {ComposerExtension, Actions, QuotedHTMLTransformer} from 'nylas-exports';
+import {ComposerExtension, QuotedHTMLTransformer} from 'nylas-exports';
import {PLUGIN_ID, PLUGIN_URL} from './open-tracking-constants';
@@ -17,11 +16,8 @@ export default class OpenTrackingComposerExtension extends ComposerExtension {
// grab message metadata, if any
const metadata = draft.metadataForPluginId(PLUGIN_ID);
if (metadata) {
- // generate a UID
- const uid = uuid.v4().replace(/-/g, "");
-
// insert a tracking pixel into the message
- const serverUrl = `${PLUGIN_URL}/open/${draft.accountId}/${uid}`;
+ const serverUrl = `${PLUGIN_URL}/open/${draft.accountId}/${metadata.uid}`;
const img = ``;
const draftBody = new DraftBody(draft);
draftBody.unquoted = draftBody.unquoted + "
" + img;
@@ -29,10 +25,6 @@ export default class OpenTrackingComposerExtension extends ComposerExtension {
// save the draft
session.changes.add({body: draftBody.body});
session.changes.commit();
-
- // save the uid to draft metadata
- metadata.uid = uid;
- Actions.setMetadata(draft, PLUGIN_ID, metadata);
}
}
}
diff --git a/spec/tasks/send-draft-spec.coffee b/spec/tasks/send-draft-spec.coffee
index 578b7b6ac..9753d3fd2 100644
--- a/spec/tasks/send-draft-spec.coffee
+++ b/spec/tasks/send-draft-spec.coffee
@@ -115,7 +115,8 @@ describe "SendDraftTask", ->
waitsForPromise =>
@task.performRemote().then =>
args = Actions.sendDraftSuccess.calls[0].args[0]
- expect(args.draftClientId).toBe @draft.clientId
+ expect(args.message instanceof Message).toBe(true)
+ expect(args.messageClientId).toBe(@draft.clientId)
it "should play a sound", ->
spyOn(NylasEnv.config, "get").andReturn true
diff --git a/src/components/contenteditable/extended-selection.coffee b/src/components/contenteditable/extended-selection.coffee
index 5e8af4cc9..2ea0c1039 100644
--- a/src/components/contenteditable/extended-selection.coffee
+++ b/src/components/contenteditable/extended-selection.coffee
@@ -52,6 +52,7 @@ class ExtendedSelection
selectFromTo: (from, to) ->
fromNode = @findNodeAt(from)
toNode = @findNodeAt(to)
+ return unless fromNode and toNode
@setBaseAndExtent(fromNode, 0, toNode, (toNode.length ? 0))
selectFromToWithIndex: (from, fromIndex, to, toIndex) ->
@@ -59,6 +60,7 @@ class ExtendedSelection
toNode = @findNodeAt(to)
if (not _.isNumber(fromIndex)) or (not _.isNumber(toIndex))
throw @_errBadUsage()
+ return unless fromNode and toNode
@setBaseAndExtent(fromNode, fromIndex, toNode, toIndex)
exportSelection: -> new ExportedSelection(@rawSelection, @scopeNode)
diff --git a/src/components/metadata-composer-toggle-button.jsx b/src/components/metadata-composer-toggle-button.jsx
index 021aaf93a..76d922dce 100644
--- a/src/components/metadata-composer-toggle-button.jsx
+++ b/src/components/metadata-composer-toggle-button.jsx
@@ -12,7 +12,7 @@ export default class MetadataComposerToggleButton extends React.Component {
iconName: React.PropTypes.string,
pluginId: React.PropTypes.string.isRequired,
pluginName: React.PropTypes.string.isRequired,
- metadataKey: React.PropTypes.string.isRequired,
+ metadataEnabledValue: React.PropTypes.object.isRequired,
stickyToggle: React.PropTypes.bool,
errorMessage: React.PropTypes.func.isRequired,
draftClientId: React.PropTypes.string.isRequired,
@@ -55,21 +55,19 @@ export default class MetadataComposerToggleButton extends React.Component {
if (!metadata) {
if (!this.state.isSetup) {
if (this._isDefaultOn()) {
- this._setMetadataValueTo(true)
+ this._setEnabled(true)
}
this.setState({isSetup: true})
}
} else {
- this.setState({enabled: metadata.tracked, isSetup: true});
+ this.setState({enabled: true, isSetup: true});
}
};
- _setMetadataValueTo(enabled) {
- const newValue = {}
- newValue[this.props.metadataKey] = enabled
+ _setEnabled(enabled) {
+ const metadataValue = enabled ? this.props.metadataEnabledValue : null;
this.setState({enabled, pending: true});
- const metadataValue = enabled ? newValue : null
- // write metadata into the draft to indicate tracked state
+
return DraftStore.sessionForClientId(this.props.draftClientId).then((session)=> {
const draft = session.draft();
@@ -108,7 +106,7 @@ export default class MetadataComposerToggleButton extends React.Component {
if (this.props.stickyToggle) {
NylasEnv.config.set(this._configKey(), !this.state.enabled)
}
- this._setMetadataValueTo(!this.state.enabled)
+ this._setEnabled(!this.state.enabled)
};
render() {
diff --git a/src/flux/tasks/send-draft.coffee b/src/flux/tasks/send-draft.coffee
index 2f3def9a6..32871901c 100644
--- a/src/flux/tasks/send-draft.coffee
+++ b/src/flux/tasks/send-draft.coffee
@@ -199,7 +199,7 @@ class SendDraftTask extends Task
Actions.queueTask(task)
)
- Actions.sendDraftSuccess draftClientId: @message.clientId
+ Actions.sendDraftSuccess(message: @message, messageClientId: @message.clientId)
# Play the sending sound
if NylasEnv.config.get("core.sending.sounds")