[client-app] Measure and report times for removing labels from threads

Summary:
This commit adds new actions, `applyCategoryToThreads` and `removeCategoryFromThreads`
to be proxied and measured through the ThreadListActionsStore. These are called when
labels are added or removed via the category picker or by removing using
the label icon.

For now, we are only interested in timing actions that remove threads
from the inbox.

Test Plan: manual + reenabled unit tests for category-picker

Reviewers: spang, evan, halla

Reviewed By: halla

Differential Revision: https://phab.nylas.com/D3989
This commit is contained in:
Juan Tejada 2017-02-21 09:17:30 -08:00
parent fb85db0964
commit 6dbbf1e094
7 changed files with 66 additions and 36 deletions

View file

@ -191,29 +191,26 @@ export default class CategoryPickerPopover extends Component {
NylasEnv.showErrorDialog({title: "Error", message: `Could not create ${categoryType}.`})
return;
}
const applyTask = TaskFactory.taskForApplyingCategory({
Actions.applyCategoryToThreads({
source: "Category Picker: New Category",
threads: threads,
category: cat,
categoryToApply: cat,
})
Actions.queueTask(applyTask)
})
})
Actions.queueTask(syncbackTask)
} else if (item.usage === threads.length) {
const applyTask = TaskFactory.taskForRemovingCategory({
Actions.removeCategoryFromThreads({
source: "Category Picker: Existing Category",
threads: threads,
category: item.category,
categoryToRemove: item.category,
})
Actions.queueTask(applyTask)
} else {
const applyTask = TaskFactory.taskForApplyingCategory({
Actions.applyCategoryToThreads({
source: "Category Picker: Existing Category",
threads: threads,
category: item.category,
categoryToApply: item.category,
})
Actions.queueTask(applyTask)
}
if (account.usesFolders()) {
// In case we are drilled down into a message

View file

@ -20,7 +20,7 @@ CategoryPickerPopover = require('../lib/category-picker-popover').default
{Categories} = require 'nylas-observables'
xdescribe 'CategoryPickerPopover', ->
describe 'CategoryPickerPopover', ->
beforeEach ->
CategoryStore._categoryCache = {}
@ -125,9 +125,10 @@ xdescribe 'CategoryPickerPopover', ->
describe "_onSelectCategory", ->
beforeEach ->
setupForCreateNew.call @, "folder"
spyOn(TaskFactory, 'taskForRemovingCategory').andCallThrough()
spyOn(TaskFactory, 'taskForApplyingCategory').andCallThrough()
spyOn(Actions, "applyCategoryToThreads")
spyOn(Actions, "removeCategoryFromThreads")
spyOn(Actions, "queueTask")
spyOn(Actions, "queueTasks")
it "closes the popover", ->
@picker._onSelectCategory { usage: 0, category: "asdf" }
@ -140,10 +141,10 @@ xdescribe 'CategoryPickerPopover', ->
usage: 1
@picker._onSelectCategory(input)
expect(TaskFactory.taskForRemovingCategory).toHaveBeenCalledWith
expect(Actions.removeCategoryFromThreads).toHaveBeenCalledWith
threads: [@testThread]
category: "asdf"
expect(Actions.queueTask).toHaveBeenCalled()
source: 'Category Picker: Existing Category'
categoryToRemove: "asdf"
describe "when selecting a category not on all the selected items", ->
it "fires a task to add the category", ->
@ -152,10 +153,10 @@ xdescribe 'CategoryPickerPopover', ->
usage: 0
@picker._onSelectCategory(input)
expect(TaskFactory.taskForApplyingCategory).toHaveBeenCalledWith
expect(Actions.applyCategoryToThreads).toHaveBeenCalledWith
source: 'Category Picker: Existing Category'
threads: [@testThread]
category: "asdf"
expect(Actions.queueTask).toHaveBeenCalled()
categoryToApply: "asdf"
describe "when selecting a new category", ->
beforeEach ->
@ -195,9 +196,10 @@ xdescribe 'CategoryPickerPopover', ->
resolveSave()
waitsFor ->
TaskFactory.taskForApplyingCategory.calls.length is 1
Actions.applyCategoryToThreads.calls.length is 1
runs ->
expect(TaskFactory.taskForApplyingCategory).toHaveBeenCalledWith
expect(Actions.applyCategoryToThreads).toHaveBeenCalledWith
source: 'Category Picker: New Category'
threads: [@testThread]
category: category
categoryToApply: category

View file

@ -87,11 +87,9 @@ class MailImportantIcon extends React.Component
source = "Important Icon"
if !isImportant
task = TaskFactory.taskForApplyingCategory({threads, category, source})
Actions.applyCategoryToThreads({threads, categoryToApply: category, source})
else
task = TaskFactory.taskForRemovingCategory({threads, category, source})
Actions.queueTask(task)
Actions.removeCategoryFromThreads({threads, categoryToRemove: category, source})
# Don't trigger the thread row click
event.stopPropagation()

View file

@ -5,7 +5,6 @@ import MessageStore from '../flux/stores/message-store';
import AccountStore from '../flux/stores/account-store';
import {MailLabel} from './mail-label';
import Actions from '../flux/actions';
import ChangeLabelsTask from '../flux/tasks/change-labels-task';
import InjectedComponentSet from './injected-component-set';
const LabelComponentCache = {};
@ -21,12 +20,11 @@ export default class MailLabelSet extends React.Component {
};
_onRemoveLabel(label) {
const task = new ChangeLabelsTask({
Actions.removeCategoryFromThreads({
source: "Label Remove Icon",
thread: this.props.thread,
labelsToRemove: [label],
threads: [this.props.thread],
categoryToRemove: label,
});
Actions.queueTask(task);
}
render() {

View file

@ -569,6 +569,8 @@ class Actions {
static archiveThreads = ActionScopeWindow;
static removeThreadsFromView = ActionScopeWindow;
static moveThreadsToPerspective = ActionScopeWindow;
static applyCategoryToThreads = ActionScopeWindow;
static removeCategoryFromThreads = ActionScopeWindow;
static threadListDidUpdate = ActionScopeWindow;
}

View file

@ -168,6 +168,10 @@ export default class Category extends Model {
return !this.isStandardCategory() && !this.isHiddenCategory();
}
isInbox() {
return this.name === 'inbox'
}
isArchive() {
return ['all', 'archive'].includes(this.name);
}

View file

@ -16,9 +16,12 @@ class ThreadListActionsStore extends NylasStore {
}
activate() {
if (!NylasEnv.isMainWindow()) { return }
this.listenTo(Actions.archiveThreads, this._onArchiveThreads)
this.listenTo(Actions.removeThreadsFromView, this._onRemoveThreadsFromView)
this.listenTo(Actions.moveThreadsToPerspective, this._onMoveThreadsToPerspective)
this.listenTo(Actions.removeCategoryFromThreads, this._onRemoveCategoryFromThreads)
this.listenTo(Actions.applyCategoryToThreads, this._onApplyCategoryToThreads)
this.listenTo(Actions.threadListDidUpdate, this._onThreadListDidUpdate)
}
@ -75,7 +78,7 @@ class ThreadListActionsStore extends NylasStore {
_onArchiveThreads = ({threads, source} = {}) => {
if (threads.length === 0) { return }
this._setNewTimer({threads, source, action: 'remove-from-view', targetCategory: 'archive'})
this._setNewTimer({threads, source, action: 'remove-threads-from-list', targetCategory: 'archive'})
const tasks = TaskFactory.tasksForArchiving({threads, source})
Actions.queueTasks(tasks)
}
@ -94,13 +97,12 @@ class ThreadListActionsStore extends NylasStore {
// from the inbox
if (currentPerspective.isInbox()) {
// TODO figure out the `targetCategory`
this._setNewTimer({threads, source, action: 'remove-from-view'})
this._setNewTimer({threads, source, action: 'remove-threads-from-list'})
}
Actions.queueTasks(tasks)
}
_onMoveThreadsToPerspective = ({targetPerspective, threadIds}) => {
_onMoveThreadsToPerspective = ({targetPerspective, threadIds} = {}) => {
const currentPerspective = FocusedPerspectiveStore.current()
// For now, we are only interested in timing actions that remove threads
@ -117,12 +119,39 @@ class ThreadListActionsStore extends NylasStore {
threadIds,
targetCategory,
source: "Dragged to Sidebar",
action: 'remove-from-view',
action: 'remove-threads-from-list',
})
}
targetPerspective.receiveThreads(threadIds)
}
_onApplyCategoryToThreads = ({threads, source, categoryToApply} = {}) => {
const task = TaskFactory.taskForApplyingCategory({
threads,
source,
category: categoryToApply,
})
Actions.queueTask(task)
}
_onRemoveCategoryFromThreads = ({threads, source, categoryToRemove} = {}) => {
// For now, we are only interested in timing actions that remove threads
// from the inbox
if (categoryToRemove.isInbox()) {
this._setNewTimer({
source,
threads,
targetCategory: 'archive',
action: 'remove-threads-from-list',
})
}
const task = TaskFactory.taskForRemovingCategory({
threads,
source,
category: categoryToRemove,
})
Actions.queueTask(task)
}
}
export default new ThreadListActionsStore()