<commit_before>import NylasStore from 'nylas-store'
import {MetricsReporter} from 'isomorphic-core'
import Actions from '../actions'
import Utils from '../models/utils'
import TaskFactory from '../tasks/task-factory'
import AccountStore from '../stores/account-store'
import IdentityStore from '../stores/identity-store'
import FocusedPerspectiveStore from '../stores/focused-perspective-store'


class ThreadListActionsStore extends NylasStore {

  constructor() {
    super()
    this._timers = new Map()
  }

  activate() {
    if (!NylasEnv.isMainWindow()) { return }
    this.listenTo(Actions.archiveThreads, this._onArchiveThreads)
    this.listenTo(Actions.trashThreads, this._onTrashThreads)
    this.listenTo(Actions.markAsSpamThreads, this._onMarkAsSpamThreads)
    this.listenTo(Actions.toggleStarredThreads, this._onToggleStarredThreads)
    this.listenTo(Actions.toggleUnreadThreads, this._onToggleUnreadThreads)
    this.listenTo(Actions.setUnreadThreads, this._onSetUnreadThreads)
    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)
  }

  deactivate() {
    this.stopListeningToAll()
  }

  _onThreadListDidUpdate = (threads) => {
    const updatedAt = Date.now()
    const identity = IdentityStore.identity()
    if (!identity) { return }

    // accountId is irrelevant for metrics reporting but we need to include
    // one in order to make a NylasAPIRequest to our /ingest-metrics endpoint
    const accountId = AccountStore.accounts()[0]

    const nylasId = identity.id
    const threadIdsInList = new Set(threads.map(t => t.id))

    for (const [timerId, timerData] of this._timers.entries()) {
      const {threadIds, source, action, targetCategory} = timerData
      const threadsHaveBeenRemoved = threadIds.every(id => !threadIdsInList.has(id))
      if (threadsHaveBeenRemoved) {
        const actionTimeMs = NylasEnv.timer.stop(timerId, updatedAt)
        MetricsReporter.reportEvent({
          action,
          source,
          nylasId,
          accountId,
          actionTimeMs,
          targetCategory,
          threadCount: threadIds.length,
        })
        this._timers.delete(timerId)
      }
    }
  }

  _setNewTimer({threads, threadIds, source, action, targetCategory = 'unknown'} = {}) {
    if (!threads && !threadIds) {<commit_msg>[client-app] Report thread-list action perf metrics to Mixpanel<commit_after>import NylasStore from 'nylas-store'
import Actions from '../actions'
import Utils from '../models/utils'
import TaskFactory from '../tasks/task-factory'
import AccountStore from '../stores/account-store'
import IdentityStore from '../stores/identity-store'
import FocusedPerspectiveStore from '../stores/focused-perspective-store'


class ThreadListActionsStore extends NylasStore {

  constructor() {
    super()
    this._timers = new Map()
  }

  activate() {
    if (!NylasEnv.isMainWindow()) { return }
    this.listenTo(Actions.archiveThreads, this._onArchiveThreads)
    this.listenTo(Actions.trashThreads, this._onTrashThreads)
    this.listenTo(Actions.markAsSpamThreads, this._onMarkAsSpamThreads)
    this.listenTo(Actions.toggleStarredThreads, this._onToggleStarredThreads)
    this.listenTo(Actions.toggleUnreadThreads, this._onToggleUnreadThreads)
    this.listenTo(Actions.setUnreadThreads, this._onSetUnreadThreads)
    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)
  }

  deactivate() {
    this.stopListeningToAll()
  }

  _onThreadListDidUpdate = (threads) => {
    const updatedAt = Date.now()
    const identity = IdentityStore.identity()
    if (!identity) { return }

    // accountId is irrelevant for metrics reporting but we need to include
    // one in order to make a NylasAPIRequest to our /ingest-metrics endpoint
    const accountId = AccountStore.accounts()[0]

    const nylasId = identity.id
    const threadIdsInList = new Set(threads.map(t => t.id))

    for (const [timerId, timerData] of this._timers.entries()) {
      const {threadIds, source, action, targetCategory} = timerData
      const threadsHaveBeenRemoved = threadIds.every(id => !threadIdsInList.has(id))
      if (threadsHaveBeenRemoved) {
        const actionTimeMs = NylasEnv.timer.stop(timerId, updatedAt)
        Actions.recordPerfMetric({
          action,
          source,
          nylasId,
          accountId,
          actionTimeMs,
          targetCategory,
          threadCount: threadIds.length,
        })
        this._timers.delete(timerId)
      }
    }
  }

  _setNewTimer({threads, threadIds, source, action, targetCategory = 'unknown'} = {}) {
    if (!threads && !threadIds) {
{'fraction_non_alphanumeric': 0.10088964603445012, 'fraction_numerical': 0.0003785727806170736, 'mean_word_length': 3.8880666049953745, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1218387', 'n_tokens_mistral': 1585, 'n_tokens_neox': 1561, 'n_words': 311}