<commit_before>import * as React from 'react'

import { Branch } from '../../models/branch'
import { Repository } from '../../models/repository'
import { RebasePreview } from '../../models/rebase'
import { ComputedAction } from '../../models/computed-action'

import { IMatches } from '../../lib/fuzzy-find'
import { truncateWithEllipsis } from '../../lib/truncate-with-ellipsis'
import { getCommitsInRange, getMergeBase } from '../../lib/git'

import { Button } from '../lib/button'
import { ButtonGroup } from '../lib/button-group'
import { ActionStatusIcon } from '../lib/action-status-icon'

import { Dialog, DialogContent, DialogFooter } from '../dialog'
import { BranchList, IBranchListItem, renderDefaultBranch } from '../branches'
import { Dispatcher } from '../dispatcher'

interface IChooseBranchDialogProps {
  readonly dispatcher: Dispatcher

  readonly repository: Repository

  /**
   * See IBranchesState.defaultBranch
   */
  readonly defaultBranch: Branch | null

  /**
   * The currently checked out branch
   */
  readonly currentBranch: Branch

  /**
   * See IBranchesState.allBranches
   */
  readonly allBranches: ReadonlyArray<Branch>

  /**
   * See IBranchesState.recentBranches
   */
  readonly recentBranches: ReadonlyArray<Branch>

  /**
   * The branch to select when the rebase dialog is opened
   */
  readonly initialBranch?: Branch

  /**
   * A function that's called when the dialog is dismissed by the user in the
   * ways described in the Dialog component's dismissable prop.
   */
  readonly onDismissed: () => void
}

interface IChooseBranchDialogState {
  /** The currently selected branch. */
  readonly selectedBranch: Branch | null

  /**
   * A preview of the rebase, using the selected base branch to test whether the
   * current branch will be cleanly applied.
   */
  readonly rebasePreview: RebasePreview | null

  /** The filter text to use in the branch selector */
  readonly filterText: string
}

/** A component for initating a rebase of the current branch. */
export class ChooseBranchDialog extends React.Component<
  IChooseBranchDialogProps,
  IChooseBranchDialogState
> {
  public constructor(props: IChooseBranchDialogProps) {
    super(props)

    const { initialBranch, currentBranch, defaultBranch } = props

    const selectedBranch = resolveSelectedBranch(
      currentBranch,
      defaultBranch,
      initialBranch
    )

    if (selectedBranch !== null) {
      this.onBranchChanged(selectedBranch)
    }

    this.state = {
      selectedBranch,
      rebasePreview: null,
      filterText: '',
    }
  }

  private onFilterTextChanged = (filterText: string) => {
    this.setState({ filterText })
  }

  private onBranchChanged = async (selectedBranch: Branch) => {
    const { currentBranch } = this.props

    await this.updateRebaseStatus(selectedBranch, currentBranch)
  }

  private async updateRebaseStatus(baseBranch: Branch, targetBranch: Branch) {
    const { repository } = this.props
    this.setState({
      rebasePreview: {
        kind: ComputedAction.Loading,
      },
    })

    const commits = await getCommitsInRange(
      this.props.repository,
      baseBranch.tip.sha,
      targetBranch.tip.sha
    )

    // TODO: in what situations might this not be possible to compute?

    const base = await getMergeBase(
      repository,
      baseBranch.tip.sha,
      targetBranch.tip.sha
    )

    if (base === baseBranch.tip.sha) {
      // the target branch is a direct descendant of the base branch
      // which means the target branch is already up to date
      this.setState({
        rebasePreview: {
          kind: ComputedAction.Clean,
          commits: [],
        },
      })
    } else {<commit_msg>wrap the git operations in a minimum timer<commit_after>import * as React from 'react'

import { Branch } from '../../models/branch'
import { Repository } from '../../models/repository'
import { RebasePreview } from '../../models/rebase'
import { ComputedAction } from '../../models/computed-action'

import { IMatches } from '../../lib/fuzzy-find'
import { truncateWithEllipsis } from '../../lib/truncate-with-ellipsis'
import { getCommitsInRange, getMergeBase } from '../../lib/git'

import { Button } from '../lib/button'
import { ButtonGroup } from '../lib/button-group'
import { ActionStatusIcon } from '../lib/action-status-icon'

import { Dialog, DialogContent, DialogFooter } from '../dialog'
import { BranchList, IBranchListItem, renderDefaultBranch } from '../branches'
import { Dispatcher } from '../dispatcher'
import { promiseWithMinimumTimeout } from '../../lib/promise'

interface IChooseBranchDialogProps {
  readonly dispatcher: Dispatcher

  readonly repository: Repository

  /**
   * See IBranchesState.defaultBranch
   */
  readonly defaultBranch: Branch | null

  /**
   * The currently checked out branch
   */
  readonly currentBranch: Branch

  /**
   * See IBranchesState.allBranches
   */
  readonly allBranches: ReadonlyArray<Branch>

  /**
   * See IBranchesState.recentBranches
   */
  readonly recentBranches: ReadonlyArray<Branch>

  /**
   * The branch to select when the rebase dialog is opened
   */
  readonly initialBranch?: Branch

  /**
   * A function that's called when the dialog is dismissed by the user in the
   * ways described in the Dialog component's dismissable prop.
   */
  readonly onDismissed: () => void
}

interface IChooseBranchDialogState {
  /** The currently selected branch. */
  readonly selectedBranch: Branch | null

  /**
   * A preview of the rebase, using the selected base branch to test whether the
   * current branch will be cleanly applied.
   */
  readonly rebasePreview: RebasePreview | null

  /** The filter text to use in the branch selector */
  readonly filterText: string
}

/** A component for initating a rebase of the current branch. */
export class ChooseBranchDialog extends React.Component<
  IChooseBranchDialogProps,
  IChooseBranchDialogState
> {
  public constructor(props: IChooseBranchDialogProps) {
    super(props)

    const { initialBranch, currentBranch, defaultBranch } = props

    const selectedBranch = resolveSelectedBranch(
      currentBranch,
      defaultBranch,
      initialBranch
    )

    if (selectedBranch !== null) {
      this.onBranchChanged(selectedBranch)
    }

    this.state = {
      selectedBranch,
      rebasePreview: null,
      filterText: '',
    }
  }

  private onFilterTextChanged = (filterText: string) => {
    this.setState({ filterText })
  }

  private onBranchChanged = async (selectedBranch: Branch) => {
    const { currentBranch } = this.props

    await this.updateRebaseStatus(selectedBranch, currentBranch)
  }

  private async updateRebaseStatus(baseBranch: Branch, targetBranch: Branch) {
    const { repository } = this.props
    this.setState({
      rebasePreview: {
        kind: ComputedAction.Loading,
      },
    })

    const { commits, base } = await promiseWithMinimumTimeout(async () => {
      const commits = await getCommitsInRange(
        this.props.repository,
        baseBranch.tip.sha,
        targetBranch.tip.sha
      )

      // TODO: in what situations might this not be possible to compute?

      const base = await getMergeBase(
        repository,
        baseBranch.tip.sha,
        targetBranch.tip.sha
      )

      return { commits, base }
    }, 500)

    if (base === baseBranch.tip.sha) {
      // the target branch is a direct descendant of the base branch
      // which means the target branch is already up to date
      this.setState({
        rebasePreview: {
          kind: ComputedAction.Clean,
          commits: [],
        },
      })
    } else {
{'fraction_non_alphanumeric': 0.10390798588419814, 'fraction_numerical': 0.0003921056071101817, 'mean_word_length': 2.9647668393782385, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 16, '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': '1767441', 'n_tokens_mistral': 2127, 'n_tokens_neox': 2159, 'n_words': 628}