mirror of
https://github.com/desktop/desktop
synced 2024-09-19 08:02:22 +00:00
Merge branch 'development' into update-eslint-dependencies
This commit is contained in:
commit
dc5bb72afa
|
@ -3,7 +3,7 @@
|
|||
"productName": "GitHub Desktop",
|
||||
"bundleID": "com.github.GitHubClient",
|
||||
"companyName": "GitHub, Inc.",
|
||||
"version": "1.7.1-beta1",
|
||||
"version": "2.0.4-beta0",
|
||||
"main": "./main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -91,5 +91,5 @@ export function enableStashing(): boolean {
|
|||
* protected branch?
|
||||
*/
|
||||
export function enableBranchProtectionWarning(): boolean {
|
||||
return enableBetaFeatures()
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -69,10 +69,10 @@ export async function getRecentBranches(
|
|||
* Returns a map keyed on branch names
|
||||
*
|
||||
* @param repository the repository who's reflog you want to check
|
||||
* @param afterDate the minimum date a checkout has to occur
|
||||
* @param afterDate filters checkouts so that only those occuring on or after this date are returned
|
||||
* @returns map of branch name -> checkout date
|
||||
*/
|
||||
export async function getCheckoutsAfterDate(
|
||||
export async function getBranchCheckouts(
|
||||
repository: Repository,
|
||||
afterDate: Date
|
||||
): Promise<Map<string, Date>> {
|
||||
|
|
|
@ -75,7 +75,7 @@ export class AccountsStore extends TypedBaseStore<ReadonlyArray<Account>> {
|
|||
/**
|
||||
* Add the account to the store.
|
||||
*/
|
||||
public async addAccount(account: Account): Promise<void> {
|
||||
public async addAccount(account: Account): Promise<Account | null> {
|
||||
await this.loadingPromise
|
||||
|
||||
let updated = account
|
||||
|
@ -103,12 +103,13 @@ export class AccountsStore extends TypedBaseStore<ReadonlyArray<Account>> {
|
|||
} else {
|
||||
this.emitError(e)
|
||||
}
|
||||
return
|
||||
return null
|
||||
}
|
||||
|
||||
this.accounts = [...this.accounts, updated]
|
||||
|
||||
this.save()
|
||||
return updated
|
||||
}
|
||||
|
||||
/** Refresh all accounts by fetching their latest info from the API. */
|
||||
|
|
|
@ -171,15 +171,16 @@ export class ApiRepositoriesStore extends BaseStore {
|
|||
* the provided account has explicit permissions to access.
|
||||
*/
|
||||
public async loadRepositories(account: Account) {
|
||||
const existingRepositories = this.accountState.get(account)
|
||||
const existingAccount = resolveAccount(account, this.accountState)
|
||||
const existingRepositories = this.accountState.get(existingAccount)
|
||||
|
||||
if (existingRepositories !== undefined && existingRepositories.loading) {
|
||||
return
|
||||
}
|
||||
|
||||
this.updateAccount(account, { loading: true })
|
||||
this.updateAccount(existingAccount, { loading: true })
|
||||
|
||||
const api = API.fromAccount(account)
|
||||
const api = API.fromAccount(existingAccount)
|
||||
const repositories = await api.fetchRepositories()
|
||||
|
||||
if (repositories === null) {
|
||||
|
|
|
@ -4449,7 +4449,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
log.info(
|
||||
`[AppStore] adding account ${account.login} (${account.name}) to store`
|
||||
)
|
||||
await this.accountsStore.addAccount(account)
|
||||
const storedAccount = await this.accountsStore.addAccount(account)
|
||||
const selectedState = this.getState().selectedState
|
||||
|
||||
if (selectedState && selectedState.type === SelectionType.Repository) {
|
||||
|
@ -4466,8 +4466,8 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
// a refresh of the repositories available for cloning straight away
|
||||
// in order to have the list of repositories ready for them when they
|
||||
// get to the blankslate.
|
||||
if (this.showWelcomeFlow) {
|
||||
this.apiRepositoriesStore.loadRepositories(account)
|
||||
if (this.showWelcomeFlow && storedAccount !== null) {
|
||||
this.apiRepositoriesStore.loadRepositories(storedAccount)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5228,6 +5228,14 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
public async _testPruneBranches() {
|
||||
if (this.currentBranchPruner === null) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.currentBranchPruner.testPrune()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Branch } from '../../../models/branch'
|
|||
import { GitStoreCache } from '../git-store-cache'
|
||||
import {
|
||||
getMergedBranches,
|
||||
getCheckoutsAfterDate,
|
||||
getBranchCheckouts,
|
||||
getSymbolicRef,
|
||||
IMergedBranch,
|
||||
formatAsLocalRef,
|
||||
|
@ -28,6 +28,31 @@ const ReservedRefs = [
|
|||
'refs/heads/release',
|
||||
]
|
||||
|
||||
/**
|
||||
* Behavior flags for the branch prune execution, to aid with testing and
|
||||
* verifying locally.
|
||||
*/
|
||||
type PruneRuntimeOptions = {
|
||||
/**
|
||||
* By default the branch pruner will only run every 24 hours
|
||||
*
|
||||
* Set this flag to `false` to ignore this check.
|
||||
*/
|
||||
readonly enforcePruneThreshold: boolean
|
||||
/**
|
||||
* By default the branch pruner will also delete the branches it believes can
|
||||
* be pruned safely.
|
||||
*
|
||||
* Set this to `false` to keep these in your repository.
|
||||
*/
|
||||
readonly deleteBranch: boolean
|
||||
}
|
||||
|
||||
const DefaultPruneOptions: PruneRuntimeOptions = {
|
||||
enforcePruneThreshold: true,
|
||||
deleteBranch: true,
|
||||
}
|
||||
|
||||
export class BranchPruner {
|
||||
private timer: number | null = null
|
||||
|
||||
|
@ -48,9 +73,9 @@ export class BranchPruner {
|
|||
)
|
||||
}
|
||||
|
||||
await this.pruneLocalBranches()
|
||||
await this.pruneLocalBranches(DefaultPruneOptions)
|
||||
this.timer = window.setInterval(
|
||||
() => this.pruneLocalBranches(),
|
||||
() => this.pruneLocalBranches(DefaultPruneOptions),
|
||||
BackgroundPruneMinimumInterval
|
||||
)
|
||||
}
|
||||
|
@ -64,6 +89,13 @@ export class BranchPruner {
|
|||
this.timer = null
|
||||
}
|
||||
|
||||
public async testPrune(): Promise<void> {
|
||||
return this.pruneLocalBranches({
|
||||
enforcePruneThreshold: false,
|
||||
deleteBranch: false,
|
||||
})
|
||||
}
|
||||
|
||||
private async findBranchesMergedIntoDefaultBranch(
|
||||
repository: Repository,
|
||||
defaultBranch: Branch
|
||||
|
@ -87,7 +119,14 @@ export class BranchPruner {
|
|||
)
|
||||
}
|
||||
|
||||
private async pruneLocalBranches(): Promise<void> {
|
||||
/**
|
||||
* Prune the local branches for the repository
|
||||
*
|
||||
* @param options configure the behaviour of the branch pruning process
|
||||
*/
|
||||
private async pruneLocalBranches(
|
||||
options: PruneRuntimeOptions
|
||||
): Promise<void> {
|
||||
if (this.repository.gitHubRepository === null) {
|
||||
return
|
||||
}
|
||||
|
@ -103,9 +142,13 @@ export class BranchPruner {
|
|||
|
||||
// Using type coelescing behavior to deal with Dexie returning `undefined`
|
||||
// for records that haven't been updated with the new field yet
|
||||
if (lastPruneDate != null && threshold.isBefore(lastPruneDate)) {
|
||||
if (
|
||||
options.enforcePruneThreshold &&
|
||||
lastPruneDate != null &&
|
||||
threshold.isBefore(lastPruneDate)
|
||||
) {
|
||||
log.info(
|
||||
`Last prune took place ${moment(lastPruneDate).from(
|
||||
`[BranchPruner] Last prune took place ${moment(lastPruneDate).from(
|
||||
dateNow
|
||||
)} - skipping`
|
||||
)
|
||||
|
@ -126,7 +169,7 @@ export class BranchPruner {
|
|||
)
|
||||
|
||||
if (mergedBranches.length === 0) {
|
||||
log.info('No branches to prune.')
|
||||
log.info('[BranchPruner] No branches to prune.')
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -134,7 +177,7 @@ export class BranchPruner {
|
|||
const twoWeeksAgo = moment()
|
||||
.subtract(2, 'weeks')
|
||||
.toDate()
|
||||
const recentlyCheckedOutBranches = await getCheckoutsAfterDate(
|
||||
const recentlyCheckedOutBranches = await getBranchCheckouts(
|
||||
this.repository,
|
||||
twoWeeksAgo
|
||||
)
|
||||
|
@ -152,7 +195,7 @@ export class BranchPruner {
|
|||
)
|
||||
|
||||
log.info(
|
||||
`Pruning ${
|
||||
`[BranchPruner] Pruning ${
|
||||
branchesReadyForPruning.length
|
||||
} branches that have been merged into the default branch, ${
|
||||
defaultBranch.name
|
||||
|
@ -169,12 +212,18 @@ export class BranchPruner {
|
|||
|
||||
const branchName = branch.canonicalRef.substr(branchRefPrefix.length)
|
||||
|
||||
if (options.deleteBranch) {
|
||||
const isDeleted = await gitStore.performFailableOperation(() =>
|
||||
deleteLocalBranch(this.repository, branchName)
|
||||
)
|
||||
|
||||
if (isDeleted) {
|
||||
log.info(`Pruned branch ${branchName} (was ${branch.sha})`)
|
||||
log.info(
|
||||
`[BranchPruner] Pruned branch ${branchName} (was ${branch.sha})`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
log.info(`[BranchPruner] Branch '${branchName}' marked for deletion`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
import { GitHubRepository } from '../../models/github-repository'
|
||||
import { Account } from '../../models/account'
|
||||
import { API, IAPIPullRequest, MaxResultsError } from '../api'
|
||||
import { fatalError, forceUnwrap } from '../fatal-error'
|
||||
import { fatalError } from '../fatal-error'
|
||||
import { RepositoriesStore } from './repositories-store'
|
||||
import { PullRequest, PullRequestRef } from '../../models/pull-request'
|
||||
import { structuralEquals } from '../equality'
|
||||
|
@ -69,7 +69,16 @@ export class PullRequestStore {
|
|||
|
||||
/** Loads all pull requests against the given repository. */
|
||||
public refreshPullRequests(repo: GitHubRepository, account: Account) {
|
||||
const dbId = forceUnwrap("Can't refresh PRs, no dbId", repo.dbID)
|
||||
const dbId = repo.dbID
|
||||
|
||||
if (dbId === null) {
|
||||
// This can happen when the `repositoryWithRefreshedGitHubRepository`
|
||||
// method in AppStore fails to retrieve API information about the current
|
||||
// repository either due to the user being signed out or the API failing
|
||||
// to provide a response. There's nothing for us to do when that happens
|
||||
// so instead of crashing we'll bail here.
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
const currentOp = this.currentRefreshOperations.get(dbId)
|
||||
|
||||
|
@ -182,8 +191,13 @@ export class PullRequestStore {
|
|||
|
||||
/** Gets all stored pull requests for the given repository. */
|
||||
public async getAll(repository: GitHubRepository) {
|
||||
if (repository.dbID == null) {
|
||||
return fatalError("Can't fetch PRs for repository, no dbId")
|
||||
if (repository.dbID === null) {
|
||||
// This can happen when the `repositoryWithRefreshedGitHubRepository`
|
||||
// method in AppStore fails to retrieve API information about the current
|
||||
// repository either due to the user being signed out or the API failing
|
||||
// to provide a response. There's nothing for us to do when that happens
|
||||
// so instead of crashing we'll bail here.
|
||||
return []
|
||||
}
|
||||
|
||||
const records = await this.db.getAllPullRequestsInRepository(repository)
|
||||
|
|
|
@ -58,10 +58,23 @@ function handleUncaughtException(error: Error) {
|
|||
showUncaughtException(isLaunchError, error)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of seconds the app has been running
|
||||
*/
|
||||
function getUptimeInSeconds() {
|
||||
return (now() - launchTime) / 1000
|
||||
}
|
||||
|
||||
function getExtraErrorContext(): Record<string, string> {
|
||||
return {
|
||||
uptime: getUptimeInSeconds().toFixed(3),
|
||||
time: new Date().toString(),
|
||||
}
|
||||
}
|
||||
|
||||
process.on('uncaughtException', (error: Error) => {
|
||||
error = withSourceMappedStack(error)
|
||||
|
||||
reportError(error)
|
||||
reportError(error, getExtraErrorContext())
|
||||
handleUncaughtException(error)
|
||||
})
|
||||
|
||||
|
@ -447,7 +460,10 @@ app.on('ready', () => {
|
|||
event: Electron.IpcMessageEvent,
|
||||
{ error, extra }: { error: Error; extra: { [key: string]: string } }
|
||||
) => {
|
||||
reportError(error, extra)
|
||||
reportError(error, {
|
||||
...getExtraErrorContext(),
|
||||
...extra,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -9,10 +9,8 @@ import { log } from '../log'
|
|||
import { openDirectorySafe } from '../shell'
|
||||
import { enableRebaseDialog, enableStashing } from '../../lib/feature-flag'
|
||||
import { MenuLabelsEvent } from '../../models/menu-labels'
|
||||
import { DefaultEditorLabel } from '../../ui/lib/context-menu'
|
||||
|
||||
const defaultEditorLabel = __DARWIN__
|
||||
? 'Open in External Editor'
|
||||
: 'Open in external editor'
|
||||
const defaultShellLabel = __DARWIN__
|
||||
? 'Open in Terminal'
|
||||
: 'Open in Command Prompt'
|
||||
|
@ -57,7 +55,7 @@ export function buildDefaultMenu({
|
|||
|
||||
const editorLabel =
|
||||
selectedExternalEditor === null
|
||||
? defaultEditorLabel
|
||||
? DefaultEditorLabel
|
||||
: `Open in ${selectedExternalEditor}`
|
||||
|
||||
const template = new Array<Electron.MenuItemConstructorOptions>()
|
||||
|
@ -286,7 +284,7 @@ export function buildDefaultMenu({
|
|||
{
|
||||
label: removeRepoLabel,
|
||||
id: 'remove-repository',
|
||||
accelerator: 'CmdOrCtrl+Delete',
|
||||
accelerator: 'CmdOrCtrl+Backspace',
|
||||
click: emit('remove-repository'),
|
||||
},
|
||||
separator,
|
||||
|
@ -353,6 +351,7 @@ export function buildDefaultMenu({
|
|||
{
|
||||
label: __DARWIN__ ? 'Discard All Changes…' : 'Discard all changes…',
|
||||
id: 'discard-all-changes',
|
||||
accelerator: 'CmdOrCtrl+Shift+Backspace',
|
||||
click: emit('discard-all-changes'),
|
||||
},
|
||||
separator,
|
||||
|
@ -497,6 +496,10 @@ export function buildDefaultMenu({
|
|||
click: emit('show-release-notes-popup'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Prune branches',
|
||||
click: emit('test-prune-branches'),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -34,3 +34,4 @@ export type MenuEvent =
|
|||
| 'show-release-notes-popup'
|
||||
| 'show-stashed-changes'
|
||||
| 'hide-stashed-changes'
|
||||
| 'test-prune-branches'
|
||||
|
|
|
@ -365,6 +365,8 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
return this.showStashedChanges()
|
||||
case 'hide-stashed-changes':
|
||||
return this.hideStashedChanges()
|
||||
case 'test-prune-branches':
|
||||
return this.testPruneBranches()
|
||||
}
|
||||
|
||||
return assertNever(name, `Unknown menu event name: ${name}`)
|
||||
|
@ -425,6 +427,14 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
}
|
||||
}
|
||||
|
||||
private testPruneBranches() {
|
||||
if (!__DEV__) {
|
||||
return
|
||||
}
|
||||
|
||||
this.props.appStore._testPruneBranches()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the 'select-all' menu event, dispatches
|
||||
* a custom DOM event originating from the element which
|
||||
|
@ -473,18 +483,14 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
}
|
||||
|
||||
private getDotComAccount(): Account | null {
|
||||
const state = this.props.appStore.getState()
|
||||
const accounts = state.accounts
|
||||
const dotComAccount = accounts.find(
|
||||
const dotComAccount = this.state.accounts.find(
|
||||
a => a.endpoint === getDotComAPIEndpoint()
|
||||
)
|
||||
return dotComAccount || null
|
||||
}
|
||||
|
||||
private getEnterpriseAccount(): Account | null {
|
||||
const state = this.props.appStore.getState()
|
||||
const accounts = state.accounts
|
||||
const enterpriseAccount = accounts.find(
|
||||
const enterpriseAccount = this.state.accounts.find(
|
||||
a => a.endpoint !== getDotComAPIEndpoint()
|
||||
)
|
||||
return enterpriseAccount || null
|
||||
|
|
|
@ -142,15 +142,24 @@ export class BlankSlateView extends React.Component<
|
|||
this.ensureRepositoriesForAccount(this.getSelectedAccount())
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IBlankSlateProps) {
|
||||
public componentDidUpdate(
|
||||
prevProps: IBlankSlateProps,
|
||||
prevState: IBlankSlateState
|
||||
) {
|
||||
if (
|
||||
prevProps.dotComAccount !== this.props.dotComAccount ||
|
||||
prevProps.enterpriseAccount !== this.props.enterpriseAccount ||
|
||||
prevState.selectedTab !== this.state.selectedTab
|
||||
) {
|
||||
this.ensureRepositoriesForAccount(this.getSelectedAccount())
|
||||
}
|
||||
}
|
||||
|
||||
private ensureRepositoriesForAccount(account: Account | null) {
|
||||
if (account !== null) {
|
||||
const accountState = this.props.apiRepositories.get(account)
|
||||
|
||||
if (accountState === undefined || accountState.repositories === null) {
|
||||
if (accountState === undefined) {
|
||||
this.props.onRefreshRepositories(account)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import {
|
|||
} from '../lib/stores'
|
||||
import { GitHubUserDatabase } from '../lib/databases'
|
||||
import { URLActionType } from '../lib/parse-app-url'
|
||||
import { SelectionType } from '../lib/app-state'
|
||||
import { SelectionType, IAppState } from '../lib/app-state'
|
||||
import { StatsDatabase, StatsStore } from '../lib/stats'
|
||||
import {
|
||||
IssuesDatabase,
|
||||
|
@ -89,6 +89,10 @@ if (!process.env.TEST_ENV) {
|
|||
require('../../styles/desktop.scss')
|
||||
}
|
||||
|
||||
let currentState: IAppState | null = null
|
||||
let lastUnhandledRejection: string | null = null
|
||||
let lastUnhandledRejectionTime: Date | null = null
|
||||
|
||||
process.once('uncaughtException', (error: Error) => {
|
||||
error = withSourceMappedStack(error)
|
||||
|
||||
|
@ -99,15 +103,100 @@ process.once('uncaughtException', (error: Error) => {
|
|||
`An uncaught exception was thrown. If this were a production build it would be reported to Central. Instead, maybe give it a lil lookyloo.`
|
||||
)
|
||||
} else {
|
||||
sendErrorReport(error, {
|
||||
const extra: Record<string, string> = {
|
||||
osVersion: getOS(),
|
||||
guid: getGUID(),
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
if (currentState) {
|
||||
if (currentState.currentBanner !== null) {
|
||||
extra.currentBanner = currentState.currentBanner.type
|
||||
}
|
||||
|
||||
if (currentState.currentPopup !== null) {
|
||||
extra.currentPopup = `${currentState.currentPopup.type}`
|
||||
}
|
||||
|
||||
if (currentState.selectedState !== null) {
|
||||
extra.selectedState = `${currentState.selectedState.type}`
|
||||
|
||||
if (currentState.selectedState.type === SelectionType.Repository) {
|
||||
extra.selectedRepositorySection = `${
|
||||
currentState.selectedState.state.selectedSection
|
||||
}`
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState.currentFoldout !== null) {
|
||||
extra.currentFoldout = `${currentState.currentFoldout.type}`
|
||||
}
|
||||
|
||||
if (currentState.showWelcomeFlow) {
|
||||
extra.inWelcomeFlow = 'true'
|
||||
}
|
||||
|
||||
if (currentState.windowZoomFactor !== 1) {
|
||||
extra.windowZoomFactor = `${currentState.windowZoomFactor}`
|
||||
}
|
||||
|
||||
if (currentState.errors.length > 0) {
|
||||
extra.activeAppErrors = `${currentState.errors.length}`
|
||||
}
|
||||
|
||||
if (
|
||||
lastUnhandledRejection !== null &&
|
||||
lastUnhandledRejectionTime !== null
|
||||
) {
|
||||
extra.lastUnhandledRejection = lastUnhandledRejection
|
||||
extra.lastUnhandledRejectionTime = lastUnhandledRejectionTime.toString()
|
||||
}
|
||||
|
||||
extra.repositoryCount = `${currentState.repositories.length}`
|
||||
extra.windowState = currentState.windowState
|
||||
extra.accounts = `${currentState.accounts.length}`
|
||||
|
||||
if (__DARWIN__) {
|
||||
extra.automaticallySwitchTheme = `${
|
||||
currentState.automaticallySwitchTheme
|
||||
}`
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
/* ignore */
|
||||
}
|
||||
|
||||
sendErrorReport(error, extra)
|
||||
}
|
||||
|
||||
reportUncaughtException(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* Chromium won't crash on an unhandled rejection (similar to how
|
||||
* it won't crash on an unhandled error). We've taken the approach
|
||||
* that unhandled errors should crash the app and very likely we
|
||||
* should do the same thing for unhandled promise rejections but
|
||||
* that's a bit too risky to do until we've established some sense
|
||||
* of how often it happens. For now this simply stores the last
|
||||
* rejection so that we can pass it along with the crash report
|
||||
* if the app does crash. Note that this does not prevent the
|
||||
* default browser behavior of logging since we're not calling
|
||||
* `preventDefault` on the event.
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event
|
||||
*/
|
||||
window.addEventListener('unhandledrejection', ev => {
|
||||
if (ev.reason !== null && ev.reason !== undefined) {
|
||||
try {
|
||||
lastUnhandledRejection = `${ev.reason}`
|
||||
lastUnhandledRejectionTime = new Date()
|
||||
} catch (err) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const gitHubUserStore = new GitHubUserStore(
|
||||
new GitHubUserDatabase('GitHubUserDatabase')
|
||||
)
|
||||
|
@ -150,6 +239,10 @@ const appStore = new AppStore(
|
|||
apiRepositoriesStore
|
||||
)
|
||||
|
||||
appStore.onDidUpdate(state => {
|
||||
currentState = state
|
||||
})
|
||||
|
||||
const dispatcher = new Dispatcher(
|
||||
appStore,
|
||||
repositoryStateManager,
|
||||
|
|
|
@ -7,13 +7,12 @@ import { IMenuItem } from '../../lib/menu-item'
|
|||
import { HighlightText } from '../lib/highlight-text'
|
||||
import { IMatches } from '../../lib/fuzzy-find'
|
||||
import { IAheadBehind } from '../../models/branch'
|
||||
import { RevealInFileManagerLabel } from '../lib/context-menu'
|
||||
import {
|
||||
RevealInFileManagerLabel,
|
||||
DefaultEditorLabel,
|
||||
} from '../lib/context-menu'
|
||||
import { enableGroupRepositoriesByOwner } from '../../lib/feature-flag'
|
||||
|
||||
const defaultEditorLabel = __DARWIN__
|
||||
? 'Open in External Editor'
|
||||
: 'Open in external editor'
|
||||
|
||||
interface IRepositoryListItemProps {
|
||||
readonly repository: Repositoryish
|
||||
|
||||
|
@ -137,7 +136,7 @@ export class RepositoryListItem extends React.Component<
|
|||
const missing = repository instanceof Repository && repository.missing
|
||||
const openInExternalEditor = this.props.externalEditorLabel
|
||||
? `Open in ${this.props.externalEditorLabel}`
|
||||
: defaultEditorLabel
|
||||
: DefaultEditorLabel
|
||||
|
||||
const items: ReadonlyArray<IMenuItem> = [
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
createBranch,
|
||||
checkoutBranch,
|
||||
renameBranch,
|
||||
getCheckoutsAfterDate,
|
||||
getBranchCheckouts,
|
||||
} from '../../../src/lib/git'
|
||||
import { setupFixtureRepository } from '../../helpers/repositories'
|
||||
import * as moment from 'moment'
|
||||
|
@ -75,7 +75,7 @@ describe('git/reflog', () => {
|
|||
await createAndCheckout(repository, 'branch-1')
|
||||
await createAndCheckout(repository, 'branch-2')
|
||||
|
||||
const branches = await getCheckoutsAfterDate(
|
||||
const branches = await getBranchCheckouts(
|
||||
repository,
|
||||
moment()
|
||||
.add(1, 'day')
|
||||
|
@ -89,7 +89,7 @@ describe('git/reflog', () => {
|
|||
await createAndCheckout(repository, 'branch-1')
|
||||
await createAndCheckout(repository, 'branch-2')
|
||||
|
||||
const branches = await getCheckoutsAfterDate(
|
||||
const branches = await getBranchCheckouts(
|
||||
repository,
|
||||
moment()
|
||||
.subtract(1, 'hour')
|
||||
|
|
|
@ -1,5 +1,64 @@
|
|||
{
|
||||
"releases": {
|
||||
"2.0.4-beta0": [
|
||||
"[Added] Extend crash reports with more information about application state for troubleshooting - #7693",
|
||||
"[Fixed] Crash when attempting to update pull requests with partially updated repository information - #7688",
|
||||
"[Fixed] Crash when loading repositories after signing in through the welcome flow - #7699"
|
||||
],
|
||||
"2.0.3": [
|
||||
"[Fixed] Crash when loading repositories after signing in through the welcome flow - #7699"
|
||||
],
|
||||
"2.0.2": [
|
||||
"[Added] Extend crash reports with more information about application state for troubleshooting - #7693"
|
||||
],
|
||||
"2.0.1": [
|
||||
"[Fixed] Crash when attempting to update pull requests with partially updated repository information - #7688"
|
||||
],
|
||||
"2.0.0": [
|
||||
"[New] You can now choose to bring your changes with you to a new branch or stash them on the current branch when switching branches - #6107",
|
||||
"[New] Rebase your current branch onto another branch using a guided flow - #5953",
|
||||
"[New] Repositories grouped by owner, and recent repositories listed at top - #6923 #7132",
|
||||
"[New] Suggested next steps now includes suggestion to create a pull request after publishing a branch - #7505",
|
||||
"[Added] .resx syntax highlighting - #7235. Thanks @say25!",
|
||||
"[Added] \"Exit\" menu item now has accelerator and access key - #6507. Thanks @AndreiMaga!",
|
||||
"[Added] Help menu entry to view documentation about keyboard shortcuts - #7184",
|
||||
"[Added] \"Discard all changes\" action under Branch menu - #7394. Thanks @ahuth!",
|
||||
"[Fixed] \"Esc\" key does not close Repository or Branch list - #7177. Thanks @roottool!",
|
||||
"[Fixed] Attempting to revert commits not on current branch results in an error - #6300. Thanks @msftrncs!",
|
||||
"[Fixed] Emoji rendering in app when account name has special characters - #6909",
|
||||
"[Fixed] Files staged outside Desktop for deletion are incorrectly marked as modified after committing - #4133",
|
||||
"[Fixed] Horizontal scroll bar appears unnecessarily when switching branches - #7212",
|
||||
"[Fixed] Icon accessibility labels fail when multiple icons are visible at the same time - #7174",
|
||||
"[Fixed] Incorrectly encoding URLs affects issue filtering - #7506",
|
||||
"[Fixed] License templates do not end with newline character - #6999",
|
||||
"[Fixed] Conflicts banners do not hide after aborting operation outside Desktop - #7046",
|
||||
"[Fixed] Missing tooltips for change indicators in the sidebar - #7174",
|
||||
"[Fixed] Mistaken classification of all crashes being related to launch - #7126",
|
||||
"[Fixed] Unable to switch keyboard layout and retain keyboard focus while using commit form - #6366. Thanks @AndreiMaga!",
|
||||
"[Fixed] Prevent console errors due to underlying component unmounts - #6970",
|
||||
"[Fixed] Menus disabled by activity in inactive repositories - #6313",
|
||||
"[Fixed] Race condition with Git remote lookup may cause push to incorrect remote - #6986",
|
||||
"[Fixed] Restore GitHub Desktop to main screen if external monitor removed - #7418 #2107. Thanks @say25!",
|
||||
"[Fixed] Tab Bar focus ring outlines clip into other elements - #5802. Thanks @Daniel-McCarthy!",
|
||||
"[Improved] \"Automatically Switch Theme\" on macOS checks theme on launch - #7116. Thanks @say25!",
|
||||
"[Improved] \"Add\" button in repository list should always be visible - #6646",
|
||||
"[Improved] Pull Requests list loads and updates pull requests from GitHub more quickly - #7501 #7163",
|
||||
"[Improved] Indicator hidden in Pull Requests list when there are no open pull requests - #7258",
|
||||
"[Improved] Manually refresh pull requests instead of having to wait for a fetch - #7027",
|
||||
"[Improved] Accessibility attributes for dialog - #6496. Thanks @HirdayGupta!",
|
||||
"[Improved] Alignment of icons in repository list - #7133",
|
||||
"[Improved] Command line interface warning when using \"github open\" with a remote URL - #7452. Thanks @msztech!",
|
||||
"[Improved] Error message when unable to publish private repository to an organization - #7472",
|
||||
"[Improved] Initiate cloning by pressing \"Enter\" when a repository is selected - #6570. Thanks @Daniel-McCarthy!",
|
||||
"[Improved] Lowercase pronoun in \"Revert this commit\" menu item - #7534",
|
||||
"[Improved] Styles for manual resolution button in \"Resolve Conflicts\" dialog - #7302",
|
||||
"[Improved] Onboarding language for blank slate components - #6638. Thanks @jamesgeorge007!",
|
||||
"[Improved] Explanation for manually conflicted text files in diff viewer - #7611",
|
||||
"[Improved] Visual progress on \"Remove Repository\" and \"Discard Changes\" dialogs - #7015. Thanks @HashimotoYT!",
|
||||
"[Improved] Menu items now aware of force push state and preference to confirm repository removal - #4976 #7138",
|
||||
"[Removed] Branch and pull request filter text persistence - #7437",
|
||||
"[Removed] \"Discard all changes\" context menu item from Changes list - #7394. Thanks @ahuth!"
|
||||
],
|
||||
"1.7.1-beta1": [
|
||||
"[Fixed] Tab Bar focus ring outlines clip into other elements - #5802. Thanks @Daniel-McCarthy!",
|
||||
"[Improved] Show explanation for manually conflicted text files in diff viewer - #7611",
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
### Download Desktop
|
||||
- [ ] User can download latest (Mac & Windows) Desktop from https://desktop.github.com/
|
||||
- [ ] Mac: https://central.github.com/deployments/desktop/desktop/latest/darwin
|
||||
- [ ] [User can download latest (Mac & Windows) Desktop](https://desktop.github.com/)
|
||||
- [ ] [Mac](https://central.github.com/deployments/desktop/desktop/latest/darwin)
|
||||
- [ ] Homebrew package manager: `brew cask install github-desktop`
|
||||
- [ ] Windows: https://central.github.com/deployments/desktop/desktop/latest/win32
|
||||
- [ ] [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32)
|
||||
- [ ] Chocolatey package manager: `choco install github-desktop`
|
||||
- [ ] 64-bit and up
|
||||
- [ ] Data is retained if you download and open a fresh copy
|
||||
- [ ] Release notes page is up-to-date in app and here https://desktop.github.com/release-notes/
|
||||
- [ ] Help page is accessible https://help.github.com/desktop/
|
||||
- [ ] Release notes page is up-to-date in app and can be accessed from [here](https://desktop.github.com/release-notes/)
|
||||
- [ ] [Help page](https://help.github.com/desktop/) is accessible
|
||||
- [ ] 'Please update' notification shown in Classic apps
|
||||
|
||||
### Welcome Flow
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8.11 < 12.0.0",
|
||||
"node": ">= 8.11",
|
||||
"yarn": ">= 1.9"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -91,7 +91,7 @@
|
|||
"klaw-sync": "^3.0.0",
|
||||
"legal-eagle": "0.16.0",
|
||||
"mini-css-extract-plugin": "^0.4.0",
|
||||
"node-sass": "^4.11.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"octicons": "^8.2.0",
|
||||
"parallel-webpack": "^2.3.0",
|
||||
"prettier": "1.16.0",
|
||||
|
|
34
yarn.lock
34
yarn.lock
|
@ -6310,16 +6310,11 @@ lodash._reinterpolate@~3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
|
||||
|
||||
lodash.assign@^4.0.8, lodash.assign@^4.2.0:
|
||||
lodash.assign@^4.0.8:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
|
||||
integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
|
||||
|
||||
lodash.clonedeep@^4.3.2:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.endswith@^4.0.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09"
|
||||
|
@ -6340,11 +6335,6 @@ lodash.isplainobject@^4.0.6:
|
|||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
|
||||
|
||||
lodash.mergewith@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55"
|
||||
integrity sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=
|
||||
|
||||
lodash.some@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
|
||||
|
@ -6826,10 +6816,10 @@ mute-stream@0.0.7:
|
|||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
|
||||
|
||||
nan@^2.10.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099"
|
||||
integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw==
|
||||
nan@^2.13.2:
|
||||
version "2.14.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||
|
||||
nan@^2.9.2:
|
||||
version "2.10.0"
|
||||
|
@ -7009,10 +6999,10 @@ node-pre-gyp@^0.9.0:
|
|||
semver "^5.3.0"
|
||||
tar "^4"
|
||||
|
||||
node-sass@^4.11.0:
|
||||
version "4.11.0"
|
||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a"
|
||||
integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==
|
||||
node-sass@^4.12.0:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
|
||||
integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
|
||||
dependencies:
|
||||
async-foreach "^0.1.3"
|
||||
chalk "^1.1.1"
|
||||
|
@ -7021,12 +7011,10 @@ node-sass@^4.11.0:
|
|||
get-stdin "^4.0.1"
|
||||
glob "^7.0.3"
|
||||
in-publish "^2.0.0"
|
||||
lodash.assign "^4.2.0"
|
||||
lodash.clonedeep "^4.3.2"
|
||||
lodash.mergewith "^4.6.0"
|
||||
lodash "^4.17.11"
|
||||
meow "^3.7.0"
|
||||
mkdirp "^0.5.1"
|
||||
nan "^2.10.0"
|
||||
nan "^2.13.2"
|
||||
node-gyp "^3.8.0"
|
||||
npmlog "^4.0.0"
|
||||
request "^2.88.0"
|
||||
|
|
Loading…
Reference in a new issue