mirror of
https://github.com/desktop/desktop
synced 2024-09-12 21:01:16 +00:00
Merge branch 'development' into high-contrast
This commit is contained in:
commit
027efae770
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: "⭐ Submit a feature request"
|
||||
about: 'Feature requests are considered based on team''s capacity '
|
||||
about: 'Feature requests are considered based on the team''s capacity. '
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
@ -9,12 +9,12 @@ assignees: ''
|
|||
|
||||
### Describe the feature or problem you’d like to solve
|
||||
|
||||
A clear and concise description of what the feature or problem is. If this is a bug report, please use the bug report template instead.
|
||||
Write a clear and concise description of what the feature or problem is. If this is a bug report, please use the bug report template instead.
|
||||
|
||||
### Proposed solution
|
||||
|
||||
How will it benefit Desktop and its users?
|
||||
Please share how this will it benefit Desktop and its users?
|
||||
|
||||
### Additional context
|
||||
|
||||
Add any other context like screenshots or mockups are helpful, if applicable.
|
||||
Please include any other context, like screenshots or mockups, if applicable.
|
||||
|
|
11
.github/ISSUE_TEMPLATE/bug_report.md
vendored
11
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: "\U0001F41B Bug report"
|
||||
about: Report a bug while using GitHub Desktop (full template required)
|
||||
about: Report a bug while using GitHub Desktop. The full template is required.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
@ -8,12 +8,11 @@ assignees: ''
|
|||
---
|
||||
|
||||
### Describe the bug
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
Write a clear and concise description of what the bug is.
|
||||
|
||||
### Version & OS
|
||||
|
||||
Open 'About GitHub Desktop' menu to see the Desktop version. Also include what operating system you are using.
|
||||
Open the 'About GitHub Desktop' menu to see the GitHub Desktop version. Also include what operating system you are using.
|
||||
|
||||
### Steps to reproduce the behavior
|
||||
|
||||
|
@ -24,11 +23,11 @@ Open 'About GitHub Desktop' menu to see the Desktop version. Also include what o
|
|||
|
||||
### Expected behavior
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
Write a clear and concise description of what you expected to happen.
|
||||
|
||||
### Actual behavior
|
||||
|
||||
A clear and concise description of what actually happened.
|
||||
Write a clear and concise description of what actually happened.
|
||||
|
||||
### Screenshots
|
||||
|
||||
|
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -101,3 +101,7 @@ jobs:
|
|||
S3_KEY: ${{ secrets.S3_KEY }}
|
||||
S3_SECRET: ${{ secrets.S3_SECRET }}
|
||||
S3_BUCKET: github-desktop
|
||||
AZURE_STORAGE_ACCOUNT: ${{ secrets.AZURE_STORAGE_ACCOUNT }}
|
||||
AZURE_STORAGE_ACCESS_KEY: ${{ secrets.AZURE_STORAGE_ACCESS_KEY }}
|
||||
AZURE_BLOB_CONTAINER: ${{ secrets.AZURE_BLOB_CONTAINER }}
|
||||
AZURE_STORAGE_URL: ${{ secrets.AZURE_STORAGE_URL }}
|
||||
|
|
|
@ -8,7 +8,8 @@ import {
|
|||
getWindowState,
|
||||
windowStateChannelName,
|
||||
} from '../lib/window-state'
|
||||
import { Octicon, OcticonSymbol } from '../ui/octicons'
|
||||
import { Octicon } from '../ui/octicons'
|
||||
import * as OcticonSymbol from '../ui/octicons/octicons.generated'
|
||||
import { Button } from '../ui/lib/button'
|
||||
import { LinkButton } from '../ui/lib/link-button'
|
||||
import { getVersion } from '../ui/lib/app-proxy'
|
||||
|
|
|
@ -13,6 +13,7 @@ import { AuthenticationMode } from './2fa'
|
|||
import { uuid } from './uuid'
|
||||
import username from 'username'
|
||||
import { GitProtocol } from './remote-parsing'
|
||||
import { Emitter } from 'event-kit'
|
||||
|
||||
const envEndpoint = process.env['DESKTOP_GITHUB_DOTCOM_API_ENDPOINT']
|
||||
const envHTMLURL = process.env['DESKTOP_GITHUB_DOTCOM_HTML_URL']
|
||||
|
@ -576,6 +577,18 @@ function toGitHubIsoDateString(date: Date) {
|
|||
* An object for making authenticated requests to the GitHub API
|
||||
*/
|
||||
export class API {
|
||||
private static readonly TOKEN_INVALIDATED_EVENT = 'token-invalidated'
|
||||
|
||||
private static readonly emitter = new Emitter()
|
||||
|
||||
public static onTokenInvalidated(callback: (endpoint: string) => void) {
|
||||
API.emitter.on(API.TOKEN_INVALIDATED_EVENT, callback)
|
||||
}
|
||||
|
||||
private static emitTokenInvalidated(endpoint: string) {
|
||||
API.emitter.emit(API.TOKEN_INVALIDATED_EVENT, endpoint)
|
||||
}
|
||||
|
||||
/** Create a new API client from the given account. */
|
||||
public static fromAccount(account: Account): API {
|
||||
return new API(account.endpoint, account.token)
|
||||
|
@ -633,10 +646,11 @@ export class API {
|
|||
name: string,
|
||||
protocol: GitProtocol | undefined
|
||||
): Promise<IAPIRepositoryCloneInfo | null> {
|
||||
const response = await this.requestReloadCache(
|
||||
'GET',
|
||||
`repos/${owner}/${name}`
|
||||
)
|
||||
const response = await this.request('GET', `repos/${owner}/${name}`, {
|
||||
// Make sure we don't run into cache issues when fetching the repositories,
|
||||
// specially after repositories have been renamed.
|
||||
reloadCache: true,
|
||||
})
|
||||
|
||||
if (response.status === HttpStatusCode.NotFound) {
|
||||
return null
|
||||
|
@ -715,9 +729,11 @@ export class API {
|
|||
try {
|
||||
const apiPath = org ? `orgs/${org.login}/repos` : 'user/repos'
|
||||
const response = await this.request('POST', apiPath, {
|
||||
name,
|
||||
description,
|
||||
private: private_,
|
||||
body: {
|
||||
name,
|
||||
description,
|
||||
private: private_,
|
||||
},
|
||||
})
|
||||
|
||||
return await parsedResponse<IAPIFullRepository>(response)
|
||||
|
@ -918,7 +934,7 @@ export class API {
|
|||
Accept: 'application/vnd.github.antiope-preview+json',
|
||||
}
|
||||
|
||||
const response = await this.request('GET', path, undefined, headers)
|
||||
const response = await this.request('GET', path, { customHeaders: headers })
|
||||
|
||||
try {
|
||||
return await parsedResponse<IAPIRefCheckRuns>(response)
|
||||
|
@ -950,7 +966,9 @@ export class API {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await this.request('GET', path, undefined, headers)
|
||||
const response = await this.request('GET', path, {
|
||||
customHeaders: headers,
|
||||
})
|
||||
return await parsedResponse<IAPIPushControl>(response)
|
||||
} catch (err) {
|
||||
log.info(
|
||||
|
@ -1021,32 +1039,30 @@ export class API {
|
|||
}
|
||||
|
||||
/** Make an authenticated request to the client's endpoint with its token. */
|
||||
private request(
|
||||
private async request(
|
||||
method: HTTPMethod,
|
||||
path: string,
|
||||
body?: Object,
|
||||
customHeaders?: Object
|
||||
options: {
|
||||
body?: Object
|
||||
customHeaders?: Object
|
||||
reloadCache?: boolean
|
||||
} = {}
|
||||
): Promise<Response> {
|
||||
return request(this.endpoint, this.token, method, path, body, customHeaders)
|
||||
}
|
||||
|
||||
/** Make an authenticated request to the client's endpoint with its token but
|
||||
* skip checking cache while also updating cache. */
|
||||
private requestReloadCache(
|
||||
method: HTTPMethod,
|
||||
path: string,
|
||||
body?: Object,
|
||||
customHeaders?: Object
|
||||
): Promise<Response> {
|
||||
return request(
|
||||
const response = await request(
|
||||
this.endpoint,
|
||||
this.token,
|
||||
method,
|
||||
path,
|
||||
body,
|
||||
customHeaders,
|
||||
true
|
||||
options.body,
|
||||
options.customHeaders,
|
||||
options.reloadCache
|
||||
)
|
||||
|
||||
if (response.status === 401) {
|
||||
API.emitTokenInvalidated(this.endpoint)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1089,7 +1105,9 @@ export class API {
|
|||
|
||||
try {
|
||||
const path = `repos/${owner}/${name}/mentionables/users`
|
||||
const response = await this.request('GET', path, undefined, headers)
|
||||
const response = await this.request('GET', path, {
|
||||
customHeaders: headers,
|
||||
})
|
||||
|
||||
if (response.status === HttpStatusCode.NotFound) {
|
||||
log.warn(`fetchMentionables: '${path}' returned a 404`)
|
||||
|
|
|
@ -50,6 +50,7 @@ import {
|
|||
MultiCommitOperationStep,
|
||||
} from '../models/multi-commit-operation'
|
||||
import { DragAndDropIntroType } from '../ui/history/drag-and-drop-intro'
|
||||
import { IChangesetData } from './git'
|
||||
|
||||
export enum SelectionType {
|
||||
Repository,
|
||||
|
@ -580,8 +581,8 @@ export interface ICommitSelection {
|
|||
/** The commits currently selected in the app */
|
||||
readonly shas: ReadonlyArray<string>
|
||||
|
||||
/** The list of files associated with the current commit */
|
||||
readonly changedFiles: ReadonlyArray<CommittedFileChange>
|
||||
/** The changeset data associated with the selected commit */
|
||||
readonly changesetData: IChangesetData
|
||||
|
||||
/** The selected file inside the selected commit */
|
||||
readonly file: CommittedFileChange | null
|
||||
|
|
|
@ -123,6 +123,11 @@ export function enableResetToCommit(): boolean {
|
|||
return enableDevelopmentFeatures()
|
||||
}
|
||||
|
||||
/** Should we show line changes (added/deleted) in commits? */
|
||||
export function enableLineChangesInCommit(): boolean {
|
||||
return enableBetaFeatures()
|
||||
}
|
||||
|
||||
/** Should we allow high contrast theme option */
|
||||
export function enableHighContrastTheme(): boolean {
|
||||
return enableDevelopmentFeatures()
|
||||
|
|
|
@ -302,7 +302,8 @@ function getDescriptionForError(error: DugiteError): string | null {
|
|||
- You may need to log out and log back in to refresh your token.
|
||||
- You do not have permission to access this repository.
|
||||
- The repository is archived on GitHub. Check the repository settings to confirm you are still permitted to push commits.
|
||||
- If you use SSH authentication, check that your key is added to the ssh-agent and associated with your account.`
|
||||
- If you use SSH authentication, check that your key is added to the ssh-agent and associated with your account.
|
||||
- If you used username / password authentication, you might need to use a Personal Access Token instead of your account password. Check the documentation of your repository hosting service.`
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
import { getCaptures } from '../helpers/regex'
|
||||
import { createLogParser } from './git-delimiter-parser'
|
||||
import { revRange } from '.'
|
||||
import { enableLineChangesInCommit } from '../feature-flag'
|
||||
|
||||
/**
|
||||
* Map the raw status text from Git to an app-friendly value
|
||||
|
@ -66,6 +67,7 @@ export async function getCommits(
|
|||
repository: Repository,
|
||||
revisionRange?: string,
|
||||
limit?: number,
|
||||
skip?: number,
|
||||
additionalArgs: ReadonlyArray<string> = []
|
||||
): Promise<ReadonlyArray<Commit>> {
|
||||
const { formatArgs, parse } = createLogParser({
|
||||
|
@ -95,6 +97,10 @@ export async function getCommits(
|
|||
args.push(`--max-count=${limit}`)
|
||||
}
|
||||
|
||||
if (skip !== undefined) {
|
||||
args.push(`--skip=${skip}`)
|
||||
}
|
||||
|
||||
args.push(
|
||||
...formatArgs,
|
||||
'--no-show-signature',
|
||||
|
@ -133,15 +139,27 @@ export async function getCommits(
|
|||
})
|
||||
}
|
||||
|
||||
/** This interface contains information of a changeset. */
|
||||
export interface IChangesetData {
|
||||
/** Files changed in the changeset. */
|
||||
readonly files: ReadonlyArray<CommittedFileChange>
|
||||
|
||||
/** Number of lines added in the changeset. */
|
||||
readonly linesAdded: number
|
||||
|
||||
/** Number of lines deleted in the changeset. */
|
||||
readonly linesDeleted: number
|
||||
}
|
||||
|
||||
/** Get the files that were changed in the given commit. */
|
||||
export async function getChangedFiles(
|
||||
repository: Repository,
|
||||
sha: string
|
||||
): Promise<ReadonlyArray<CommittedFileChange>> {
|
||||
): Promise<IChangesetData> {
|
||||
// opt-in for rename detection (-M) and copies detection (-C)
|
||||
// this is equivalent to the user configuring 'diff.renames' to 'copies'
|
||||
// NOTE: order here matters - doing -M before -C means copies aren't detected
|
||||
const args = [
|
||||
const baseArgs = [
|
||||
'log',
|
||||
sha,
|
||||
'-C',
|
||||
|
@ -150,14 +168,63 @@ export async function getChangedFiles(
|
|||
'-1',
|
||||
'--no-show-signature',
|
||||
'--first-parent',
|
||||
'--name-status',
|
||||
'--format=format:',
|
||||
'-z',
|
||||
'--',
|
||||
]
|
||||
const result = await git(args, repository.path, 'getChangedFiles')
|
||||
|
||||
return parseChangedFiles(result.stdout, sha)
|
||||
// Run `git log` to obtain the file names and their state
|
||||
const resultNameStatus = await git(
|
||||
[...baseArgs, '--name-status', '--'],
|
||||
repository.path,
|
||||
'getChangedFilesNameStatus'
|
||||
)
|
||||
|
||||
const files = parseChangedFiles(resultNameStatus.stdout, sha)
|
||||
|
||||
if (!enableLineChangesInCommit()) {
|
||||
return { files, linesAdded: 0, linesDeleted: 0 }
|
||||
}
|
||||
|
||||
// Run `git log` again, but this time to get the number of lines added/deleted
|
||||
// per file
|
||||
const resultNumStat = await git(
|
||||
[...baseArgs, '--numstat', '--'],
|
||||
repository.path,
|
||||
'getChangedFilesNumStats'
|
||||
)
|
||||
|
||||
const linesChanged = parseChangedFilesNumStat(resultNumStat.stdout)
|
||||
|
||||
return {
|
||||
files,
|
||||
...linesChanged,
|
||||
}
|
||||
}
|
||||
|
||||
function parseChangedFilesNumStat(
|
||||
stdout: string
|
||||
): { linesAdded: number; linesDeleted: number } {
|
||||
const lines = stdout.split('\0')
|
||||
let totalLinesAdded = 0
|
||||
let totalLinesDeleted = 0
|
||||
|
||||
for (const line of lines) {
|
||||
const parts = line.split('\t')
|
||||
if (parts.length !== 3) {
|
||||
continue
|
||||
}
|
||||
|
||||
const [added, deleted] = parts
|
||||
|
||||
if (added === '-' || deleted === '-') {
|
||||
continue
|
||||
}
|
||||
|
||||
totalLinesAdded += parseInt(added, 10)
|
||||
totalLinesDeleted += parseInt(deleted, 10)
|
||||
}
|
||||
|
||||
return { linesAdded: totalLinesAdded, linesDeleted: totalLinesDeleted }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -221,9 +288,13 @@ export async function doMergeCommitsExistAfterCommit(
|
|||
const commitRevRange =
|
||||
commitRef === null ? undefined : revRange(commitRef, 'HEAD')
|
||||
|
||||
const mergeCommits = await getCommits(repository, commitRevRange, undefined, [
|
||||
'--merges',
|
||||
])
|
||||
const mergeCommits = await getCommits(
|
||||
repository,
|
||||
commitRevRange,
|
||||
undefined,
|
||||
undefined,
|
||||
['--merges']
|
||||
)
|
||||
|
||||
return mergeCommits.length > 0
|
||||
}
|
||||
|
|
|
@ -527,6 +527,31 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
this.repositoryIndicatorUpdater.start()
|
||||
}
|
||||
}, InitialRepositoryIndicatorTimeout)
|
||||
|
||||
API.onTokenInvalidated(this.onTokenInvalidated)
|
||||
}
|
||||
|
||||
private onTokenInvalidated = (endpoint: string) => {
|
||||
const account = getAccountForEndpoint(this.accounts, endpoint)
|
||||
|
||||
if (account === null) {
|
||||
return
|
||||
}
|
||||
|
||||
// If there is a currently open popup, don't do anything here. Since the
|
||||
// app can only show one popup at a time, we don't want to close the current
|
||||
// one in favor of the error we're about to show.
|
||||
if (this.currentPopup !== null) {
|
||||
return
|
||||
}
|
||||
|
||||
// If the token was invalidated for an account, sign out from that account
|
||||
this._removeAccount(account)
|
||||
|
||||
this._showPopup({
|
||||
type: PopupType.InvalidatedToken,
|
||||
account,
|
||||
})
|
||||
}
|
||||
|
||||
/** Figure out what step of the tutorial the user needs to do next */
|
||||
|
@ -993,7 +1018,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
this.repositoryStateCache.updateCommitSelection(repository, () => ({
|
||||
shas: [],
|
||||
file: null,
|
||||
changedFiles: [],
|
||||
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
||||
diff: null,
|
||||
}))
|
||||
}
|
||||
|
@ -1015,7 +1040,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
this.repositoryStateCache.updateCommitSelection(repository, () => ({
|
||||
shas,
|
||||
file: null,
|
||||
changedFiles: [],
|
||||
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
||||
diff: null,
|
||||
}))
|
||||
|
||||
|
@ -1127,7 +1152,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
}
|
||||
|
||||
// load initial group of commits for current branch
|
||||
const commits = await gitStore.loadCommitBatch('HEAD')
|
||||
const commits = await gitStore.loadCommitBatch('HEAD', 0)
|
||||
|
||||
if (commits === null) {
|
||||
return
|
||||
|
@ -1278,9 +1303,8 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
const { formState } = state.compareState
|
||||
if (formState.kind === HistoryTabMode.History) {
|
||||
const commits = state.compareState.commitSHAs
|
||||
const lastCommitSha = commits[commits.length - 1]
|
||||
|
||||
const newCommits = await gitStore.loadCommitBatch(`${lastCommitSha}^`)
|
||||
const newCommits = await gitStore.loadCommitBatch('HEAD', commits.length)
|
||||
if (newCommits == null) {
|
||||
return
|
||||
}
|
||||
|
@ -1305,10 +1329,10 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
}
|
||||
|
||||
const gitStore = this.gitStoreCache.get(repository)
|
||||
const changedFiles = await gitStore.performFailableOperation(() =>
|
||||
const changesetData = await gitStore.performFailableOperation(() =>
|
||||
getChangedFiles(repository, currentSHAs[0])
|
||||
)
|
||||
if (!changedFiles) {
|
||||
if (!changesetData) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1328,13 +1352,13 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
|||
const noFileSelected = commitSelection.file === null
|
||||
|
||||
const firstFileOrDefault =
|
||||
noFileSelected && changedFiles.length
|
||||
? changedFiles[0]
|
||||
noFileSelected && changesetData.files.length
|
||||
? changesetData.files[0]
|
||||
: commitSelection.file
|
||||
|
||||
this.repositoryStateCache.updateCommitSelection(repository, () => ({
|
||||
file: firstFileOrDefault,
|
||||
changedFiles,
|
||||
changesetData,
|
||||
diff: null,
|
||||
}))
|
||||
|
||||
|
|
|
@ -201,44 +201,13 @@ export class GitStore extends BaseStore {
|
|||
this.emitUpdate()
|
||||
}
|
||||
|
||||
/** Load the next batch of history, starting from the last loaded commit. */
|
||||
public async loadNextHistoryBatch() {
|
||||
if (this.requestsInFight.has(LoadingHistoryRequestKey)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.history.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const lastSHA = this.history[this.history.length - 1]
|
||||
const requestKey = `history/${lastSHA}`
|
||||
if (this.requestsInFight.has(requestKey)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.requestsInFight.add(requestKey)
|
||||
|
||||
const commits = await this.performFailableOperation(() =>
|
||||
getCommits(this.repository, `${lastSHA}^`, CommitBatchSize)
|
||||
)
|
||||
if (!commits) {
|
||||
return
|
||||
}
|
||||
|
||||
this._history = this._history.concat(commits.map(c => c.sha))
|
||||
this.storeCommits(commits)
|
||||
this.requestsInFight.delete(requestKey)
|
||||
this.emitUpdate()
|
||||
}
|
||||
|
||||
/** Load a batch of commits from the repository, using a given commitish object as the starting point */
|
||||
public async loadCommitBatch(commitish: string) {
|
||||
public async loadCommitBatch(commitish: string, skip: number) {
|
||||
if (this.requestsInFight.has(LoadingHistoryRequestKey)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const requestKey = `history/compare/${commitish}`
|
||||
const requestKey = `history/compare/${commitish}/skip/${skip}`
|
||||
if (this.requestsInFight.has(requestKey)) {
|
||||
return null
|
||||
}
|
||||
|
@ -246,7 +215,7 @@ export class GitStore extends BaseStore {
|
|||
this.requestsInFight.add(requestKey)
|
||||
|
||||
const commits = await this.performFailableOperation(() =>
|
||||
getCommits(this.repository, commitish, CommitBatchSize)
|
||||
getCommits(this.repository, commitish, CommitBatchSize, skip)
|
||||
)
|
||||
|
||||
this.requestsInFight.delete(requestKey)
|
||||
|
@ -647,7 +616,7 @@ export class GitStore extends BaseStore {
|
|||
)
|
||||
} else {
|
||||
localCommits = await this.performFailableOperation(() =>
|
||||
getCommits(this.repository, 'HEAD', CommitBatchSize, [
|
||||
getCommits(this.repository, 'HEAD', CommitBatchSize, undefined, [
|
||||
'--not',
|
||||
'--remotes',
|
||||
])
|
||||
|
|
|
@ -3,7 +3,6 @@ import { Commit } from '../../models/commit'
|
|||
import { PullRequest } from '../../models/pull-request'
|
||||
import { Repository } from '../../models/repository'
|
||||
import {
|
||||
CommittedFileChange,
|
||||
WorkingDirectoryFileChange,
|
||||
WorkingDirectoryStatus,
|
||||
} from '../../models/status'
|
||||
|
@ -195,7 +194,7 @@ function getInitialRepositoryState(): IRepositoryState {
|
|||
commitSelection: {
|
||||
shas: [],
|
||||
file: null,
|
||||
changedFiles: new Array<CommittedFileChange>(),
|
||||
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
||||
diff: null,
|
||||
},
|
||||
changesState: {
|
||||
|
|
|
@ -74,6 +74,7 @@ export enum PopupType {
|
|||
MultiCommitOperation,
|
||||
WarnLocalChangesBeforeUndo,
|
||||
WarningBeforeReset,
|
||||
InvalidatedToken,
|
||||
}
|
||||
|
||||
export type Popup =
|
||||
|
@ -298,3 +299,7 @@ export type Popup =
|
|||
repository: Repository
|
||||
commit: Commit
|
||||
}
|
||||
| {
|
||||
type: PopupType.InvalidatedToken
|
||||
account: Account
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ import { Button } from '../lib/button'
|
|||
import { TextBox } from '../lib/text-box'
|
||||
import { Row } from '../lib/row'
|
||||
import { Dialog, DialogContent, DialogFooter } from '../dialog'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { PopupType } from '../../models/popup'
|
||||
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||
|
|
|
@ -24,7 +24,8 @@ import { ILicense, getLicenses, writeLicense } from './licenses'
|
|||
import { writeGitAttributes } from './git-attributes'
|
||||
import { getDefaultDir, setDefaultDir } from '../lib/default-dir'
|
||||
import { Dialog, DialogContent, DialogFooter, DialogError } from '../dialog'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { PopupType } from '../../models/popup'
|
||||
import { Ref } from '../lib/ref'
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as React from 'react'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { MenuItem } from '../../models/app-menu'
|
||||
import { AccessText } from '../lib/access-text'
|
||||
import { getPlatformSpecificNameOrSymbolForModifier } from '../../lib/menu-item'
|
||||
|
|
|
@ -55,7 +55,8 @@ import {
|
|||
BranchDropdown,
|
||||
RevertProgress,
|
||||
} from './toolbar'
|
||||
import { OcticonSymbol, iconForRepository } from './octicons'
|
||||
import { iconForRepository, OcticonSymbolType } from './octicons'
|
||||
import * as OcticonSymbol from './octicons/octicons.generated'
|
||||
import { showCertificateTrustDialog, sendReady } from './main-process-proxy'
|
||||
import { DiscardChanges } from './discard-changes'
|
||||
import { Welcome } from './welcome'
|
||||
|
@ -147,6 +148,7 @@ import { dragAndDropManager } from '../lib/drag-and-drop-manager'
|
|||
import { MultiCommitOperation } from './multi-commit-operation/multi-commit-operation'
|
||||
import { WarnLocalChangesBeforeUndo } from './undo/warn-local-changes-before-undo'
|
||||
import { WarningBeforeReset } from './reset/warning-before-reset'
|
||||
import { InvalidatedToken } from './invalidated-token/invalidated-token'
|
||||
|
||||
const MinuteInMilliseconds = 1000 * 60
|
||||
const HourInMilliseconds = MinuteInMilliseconds * 60
|
||||
|
@ -2116,6 +2118,16 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
/>
|
||||
)
|
||||
}
|
||||
case PopupType.InvalidatedToken: {
|
||||
return (
|
||||
<InvalidatedToken
|
||||
key="invalidated-token"
|
||||
dispatcher={this.props.dispatcher}
|
||||
account={popup.account}
|
||||
onDismissed={onPopupDismissedFn}
|
||||
/>
|
||||
)
|
||||
}
|
||||
default:
|
||||
return assertNever(popup, `Unknown popup type: ${popup}`)
|
||||
}
|
||||
|
@ -2441,7 +2453,7 @@ export class App extends React.Component<IAppProps, IAppState> {
|
|||
|
||||
const repository = selection ? selection.repository : null
|
||||
|
||||
let icon: OcticonSymbol
|
||||
let icon: OcticonSymbolType
|
||||
let title: string
|
||||
if (repository) {
|
||||
const alias = repository instanceof Repository ? repository.alias : null
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
interface IBannerProps {
|
||||
readonly id?: string
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Banner } from './banner'
|
||||
|
||||
export function BranchAlreadyUpToDate({
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Banner } from './banner'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Banner } from './banner'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Banner } from './banner'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Popup } from '../../models/popup'
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Banner } from './banner'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Banner } from './banner'
|
||||
|
||||
interface ISuccessBannerProps {
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
import { Dispatcher } from '../dispatcher/index'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { updateStore } from '../lib/update-store'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { PopupType } from '../../models/popup'
|
||||
import { shell } from '../../lib/app-shell'
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ import moment from 'moment'
|
|||
|
||||
import { IMatches } from '../../lib/fuzzy-find'
|
||||
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { HighlightText } from '../lib/highlight-text'
|
||||
import { showContextualMenu } from '../main-process-proxy'
|
||||
import { IMenuItem } from '../../lib/menu-item'
|
||||
import { String } from 'aws-sdk/clients/apigateway'
|
||||
import { dragAndDropManager } from '../../lib/drag-and-drop-manager'
|
||||
import { DragType, DropTargetType } from '../../models/drag-drop'
|
||||
|
||||
|
@ -33,7 +33,7 @@ interface IBranchListItemProps {
|
|||
readonly onDeleteBranch?: (branchName: string) => void
|
||||
|
||||
/** When a drag element has landed on a branch that is not current */
|
||||
readonly onDropOntoBranch?: (branchName: String) => void
|
||||
readonly onDropOntoBranch?: (branchName: string) => void
|
||||
|
||||
/** When a drag element has landed on the current branch */
|
||||
readonly onDropOntoCurrentBranch?: () => void
|
||||
|
|
|
@ -16,7 +16,8 @@ import { assertNever } from '../../lib/fatal-error'
|
|||
import { TabBar } from '../tab-bar'
|
||||
|
||||
import { Row } from '../lib/row'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Button } from '../lib/button'
|
||||
|
||||
import { BranchList } from './branch-list'
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, OcticonSymbolType } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import classNames from 'classnames'
|
||||
import { GitHubRepository } from '../../models/github-repository'
|
||||
import { IDisposable } from 'event-kit'
|
||||
|
@ -109,7 +110,7 @@ export class CIStatus extends React.PureComponent<
|
|||
}
|
||||
}
|
||||
|
||||
function getSymbolForCheck(check: ICombinedRefCheck): OcticonSymbol {
|
||||
function getSymbolForCheck(check: ICombinedRefCheck): OcticonSymbolType {
|
||||
switch (check.conclusion) {
|
||||
case 'timed_out':
|
||||
return OcticonSymbol.x
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as React from 'react'
|
||||
import moment from 'moment'
|
||||
import classNames from 'classnames'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { CIStatus } from './ci-status'
|
||||
import { HighlightText } from '../lib/highlight-text'
|
||||
import { IMatches } from '../../lib/fuzzy-find'
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
import { PathLabel } from '../lib/path-label'
|
||||
import { AppFileStatus } from '../../models/status'
|
||||
import { IDiff, DiffType } from '../../models/diff'
|
||||
import { Octicon, OcticonSymbol, iconForStatus } from '../octicons'
|
||||
import { Octicon, iconForStatus } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { mapStatus } from '../../lib/status'
|
||||
import { DiffOptions } from '../diff/diff-options'
|
||||
import { RepositorySectionTab } from '../../lib/app-state'
|
||||
|
|
|
@ -34,17 +34,19 @@ import { basename } from 'path'
|
|||
import { Commit, ICommitContext } from '../../models/commit'
|
||||
import { RebaseConflictState, ConflictState } from '../../lib/app-state'
|
||||
import { ContinueRebase } from './continue-rebase'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { IStashEntry } from '../../models/stash-entry'
|
||||
import classNames from 'classnames'
|
||||
import { hasWritePermission } from '../../models/github-repository'
|
||||
import { hasConflictedFiles } from '../../lib/status'
|
||||
|
||||
const RowHeight = 29
|
||||
const StashIcon = new OcticonSymbol(
|
||||
16,
|
||||
16,
|
||||
'M10.5 1.286h-9a.214.214 0 0 0-.214.214v9a.214.214 0 0 0 .214.214h9a.214.214 0 0 0 ' +
|
||||
const StashIcon: OcticonSymbol.OcticonSymbolType = {
|
||||
w: 16,
|
||||
h: 16,
|
||||
d:
|
||||
'M10.5 1.286h-9a.214.214 0 0 0-.214.214v9a.214.214 0 0 0 .214.214h9a.214.214 0 0 0 ' +
|
||||
'.214-.214v-9a.214.214 0 0 0-.214-.214zM1.5 0h9A1.5 1.5 0 0 1 12 1.5v9a1.5 1.5 0 0 1-1.5 ' +
|
||||
'1.5h-9A1.5 1.5 0 0 1 0 10.5v-9A1.5 1.5 0 0 1 1.5 0zm5.712 7.212a1.714 1.714 0 1 ' +
|
||||
'1-2.424-2.424 1.714 1.714 0 0 1 2.424 2.424zM2.015 12.71c.102.729.728 1.29 1.485 ' +
|
||||
|
@ -52,8 +54,8 @@ const StashIcon = new OcticonSymbol(
|
|||
'.004.043v9a.214.214 0 0 1-.214.214h-9a.216.216 0 0 1-.043-.004H2.015zm2 2c.102.729.728 ' +
|
||||
'1.29 1.485 1.29h9a1.5 1.5 0 0 0 1.5-1.5v-9a1.5 1.5 0 0 0-1.29-1.485v1.442a.216.216 0 0 1 ' +
|
||||
'.004.043v9a.214.214 0 0 1-.214.214h-9a.216.216 0 0 1-.043-.004H4.015z',
|
||||
'evenodd'
|
||||
)
|
||||
fr: 'evenodd',
|
||||
}
|
||||
|
||||
const GitIgnoreFileName = '.gitignore'
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import { Row } from '../lib/row'
|
|||
import { Popover, PopoverCaretPosition } from '../lib/popover'
|
||||
import { IAvatarUser } from '../../models/avatar'
|
||||
import { Avatar } from '../lib/avatar'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
|
||||
interface ICommitMessageAvatarState {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { Button } from '../lib/button'
|
|||
import { Loading } from '../lib/loading'
|
||||
import { AuthorInput } from '../lib/author-input'
|
||||
import { FocusContainer } from '../lib/focus-container'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import { IAuthor } from '../../models/author'
|
||||
import { IMenuItem } from '../../lib/menu-item'
|
||||
import { Commit, ICommitContext } from '../../models/commit'
|
||||
|
@ -36,16 +36,17 @@ import { PopupType } from '../../models/popup'
|
|||
import { RepositorySettingsTab } from '../repository-settings/repository-settings'
|
||||
import { isAccountEmail } from '../../lib/is-account-email'
|
||||
|
||||
const addAuthorIcon = new OcticonSymbol(
|
||||
18,
|
||||
13,
|
||||
'M14 6V4.25a.75.75 0 0 1 1.5 0V6h1.75a.75.75 0 1 1 0 1.5H15.5v1.75a.75.75 0 0 ' +
|
||||
const addAuthorIcon = {
|
||||
w: 18,
|
||||
h: 13,
|
||||
d:
|
||||
'M14 6V4.25a.75.75 0 0 1 1.5 0V6h1.75a.75.75 0 1 1 0 1.5H15.5v1.75a.75.75 0 0 ' +
|
||||
'1-1.5 0V7.5h-1.75a.75.75 0 1 1 0-1.5H14zM8.5 4a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 ' +
|
||||
'0zm.063 3.064a3.995 3.995 0 0 0 1.2-4.429A3.996 3.996 0 0 0 8.298.725a4.01 4.01 0 0 ' +
|
||||
'0-6.064 1.91 3.987 3.987 0 0 0 1.2 4.43A5.988 5.988 0 0 0 0 12.2a.748.748 0 0 0 ' +
|
||||
'.716.766.751.751 0 0 0 .784-.697 4.49 4.49 0 0 1 1.39-3.04 4.51 4.51 0 0 1 6.218 ' +
|
||||
'0 4.49 4.49 0 0 1 1.39 3.04.748.748 0 0 0 .786.73.75.75 0 0 0 .714-.8 5.989 5.989 0 0 0-3.435-5.136z'
|
||||
)
|
||||
'0 4.49 4.49 0 0 1 1.39 3.04.748.748 0 0 0 .786.73.75.75 0 0 0 .714-.8 5.989 5.989 0 0 0-3.435-5.136z',
|
||||
}
|
||||
|
||||
interface ICommitMessageProps {
|
||||
readonly onCreateCommit: (context: ICommitContext) => Promise<boolean>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import { assertNever } from '../../lib/fatal-error'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
export enum CommitWarningIcon {
|
||||
Warning,
|
||||
|
|
|
@ -18,7 +18,6 @@ import { WorkingDirectoryStatus } from '../../models/status'
|
|||
import { getResolvedFiles } from '../../lib/status'
|
||||
import { ConfirmCherryPickAbortDialog } from './confirm-cherry-pick-abort-dialog'
|
||||
import { CreateBranch } from '../create-branch'
|
||||
import { String } from 'aws-sdk/clients/acm'
|
||||
import { ConflictsDialog } from '../multi-commit-operation/conflicts-dialog'
|
||||
|
||||
interface ICherryPickFlowProps {
|
||||
|
@ -161,7 +160,7 @@ export class CherryPickFlow extends React.Component<ICherryPickFlowProps> {
|
|||
})
|
||||
}
|
||||
|
||||
private onCreateNewBranch = (targetBranchName: String) => {
|
||||
private onCreateNewBranch = (targetBranchName: string) => {
|
||||
const { dispatcher, repository } = this.props
|
||||
dispatcher.setCherryPickCreateBranchFlowStep(repository, targetBranchName)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as React from 'react'
|
||||
import { RichText } from '../lib/rich-text'
|
||||
import { Dialog, DialogContent } from '../dialog'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { ICherryPickProgress } from '../../models/progress'
|
||||
|
||||
interface ICherryPickProgressDialogProps {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { IAPIRepository } from '../../lib/api'
|
||||
import { IFilterListGroup, IFilterListItem } from '../lib/filter-list'
|
||||
import { caseInsensitiveCompare } from '../../lib/compare'
|
||||
import { OcticonSymbol } from '../octicons'
|
||||
import { OcticonSymbolType } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
/** The identifier for the "Your Repositories" grouping. */
|
||||
export const YourRepositoriesIdentifier = 'your-repositories'
|
||||
|
@ -17,13 +18,13 @@ export interface ICloneableRepositoryListItem extends IFilterListItem {
|
|||
readonly name: string
|
||||
|
||||
/** The icon for the repo. */
|
||||
readonly icon: OcticonSymbol
|
||||
readonly icon: OcticonSymbolType
|
||||
|
||||
/** The clone URL. */
|
||||
readonly url: string
|
||||
}
|
||||
|
||||
function getIcon(gitHubRepo: IAPIRepository): OcticonSymbol {
|
||||
function getIcon(gitHubRepo: IAPIRepository): OcticonSymbolType {
|
||||
if (gitHubRepo.private) {
|
||||
return OcticonSymbol.lock
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
|
||||
import { CloningRepository } from '../models/cloning-repository'
|
||||
import { ICloneProgress } from '../models/progress'
|
||||
import { Octicon, OcticonSymbol } from './octicons'
|
||||
import { Octicon } from './octicons'
|
||||
import * as OcticonSymbol from './octicons/octicons.generated'
|
||||
import { UiView } from './ui-view'
|
||||
|
||||
interface ICloningRepositoryProps {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
/**
|
||||
* A component used for displaying short error messages inline
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol, syncClockwise } from '../octicons'
|
||||
import { Octicon, syncClockwise } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
interface IDialogHeaderProps {
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import { Checkbox, CheckboxValue } from '../lib/checkbox'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { RadioButton } from '../lib/radio-button'
|
||||
import { getBoolean, setBoolean } from '../../lib/local-storage'
|
||||
import { Popover, PopoverCaretPosition } from '../lib/popover'
|
||||
|
|
|
@ -9,7 +9,8 @@ import {
|
|||
} from './diff-helpers'
|
||||
import { ILineTokens } from '../../lib/highlighter/types'
|
||||
import classNames from 'classnames'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { narrowNoNewlineSymbol } from './text-diff'
|
||||
import { shallowEquals, structuralEquals } from '../../lib/equality'
|
||||
import { DiffHunkExpansionType } from '../../models/diff'
|
||||
|
|
|
@ -15,8 +15,6 @@ import {
|
|||
CommittedFileChange,
|
||||
} from '../../models/status'
|
||||
|
||||
import { OcticonSymbol } from '../octicons'
|
||||
|
||||
import { IEditorConfigurationExtra } from './editor-configuration-extra'
|
||||
import { DiffSyntaxMode, IDiffSyntaxModeSpec } from './diff-syntax-mode'
|
||||
import { CodeMirrorHost } from './code-mirror-host'
|
||||
|
@ -56,6 +54,7 @@ import {
|
|||
expandWholeTextDiff,
|
||||
} from './text-diff-expansion'
|
||||
import { createOcticonElement } from '../octicons/octicon'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { HideWhitespaceWarning } from './hide-whitespace-warning'
|
||||
|
||||
/** The longest line for which we'd try to calculate a line diff. */
|
||||
|
@ -63,11 +62,12 @@ const MaxIntraLineDiffStringLength = 4096
|
|||
|
||||
// This is a custom version of the no-newline octicon that's exactly as
|
||||
// tall as it needs to be (8px) which helps with aligning it on the line.
|
||||
export const narrowNoNewlineSymbol = new OcticonSymbol(
|
||||
16,
|
||||
8,
|
||||
'm 16,1 0,3 c 0,0.55 -0.45,1 -1,1 l -3,0 0,2 -3,-3 3,-3 0,2 2,0 0,-2 2,0 z M 8,4 C 8,6.2 6.2,8 4,8 1.8,8 0,6.2 0,4 0,1.8 1.8,0 4,0 6.2,0 8,1.8 8,4 Z M 1.5,5.66 5.66,1.5 C 5.18,1.19 4.61,1 4,1 2.34,1 1,2.34 1,4 1,4.61 1.19,5.17 1.5,5.66 Z M 7,4 C 7,3.39 6.81,2.83 6.5,2.34 L 2.34,6.5 C 2.82,6.81 3.39,7 4,7 5.66,7 7,5.66 7,4 Z'
|
||||
)
|
||||
export const narrowNoNewlineSymbol = {
|
||||
w: 16,
|
||||
h: 8,
|
||||
d:
|
||||
'm 16,1 0,3 c 0,0.55 -0.45,1 -1,1 l -3,0 0,2 -3,-3 3,-3 0,2 2,0 0,-2 2,0 z M 8,4 C 8,6.2 6.2,8 4,8 1.8,8 0,6.2 0,4 0,1.8 1.8,0 4,0 6.2,0 8,1.8 8,4 Z M 1.5,5.66 5.66,1.5 C 5.18,1.19 4.61,1 4,1 2.34,1 1,2.34 1,4 1,4.61 1.19,5.17 1.5,5.66 Z M 7,4 C 7,3.39 6.81,2.83 6.5,2.34 L 2.34,6.5 C 2.82,6.81 3.39,7 4,7 5.66,7 7,5.66 7,4 Z',
|
||||
}
|
||||
|
||||
type ChangedFile = WorkingDirectoryFileChange | CommittedFileChange
|
||||
|
||||
|
|
|
@ -1524,9 +1524,15 @@ export class Dispatcher {
|
|||
/**
|
||||
* Launch a sign in dialog for authenticating a user with
|
||||
* a GitHub Enterprise instance.
|
||||
* Optionally, you can provide an endpoint URL.
|
||||
*/
|
||||
public async showEnterpriseSignInDialog(): Promise<void> {
|
||||
public async showEnterpriseSignInDialog(endpoint?: string): Promise<void> {
|
||||
await this.appStore._beginEnterpriseSignIn()
|
||||
|
||||
if (endpoint !== undefined) {
|
||||
await this.appStore._setSignInEndpoint(endpoint)
|
||||
}
|
||||
|
||||
await this.appStore._showPopup({ type: PopupType.SignIn })
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ import { Commit } from '../../models/commit'
|
|||
import { DragType, DropTarget, DropTargetType } from '../../models/drag-drop'
|
||||
import { GitHubRepository } from '../../models/github-repository'
|
||||
import { CommitListItem } from '../history/commit-list-item'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
interface ICommitDragElementProps {
|
||||
readonly commit: Commit
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
import { Button } from './lib/button'
|
||||
import { Octicon, OcticonSymbol } from './octicons'
|
||||
import { Octicon } from './octicons'
|
||||
import * as OcticonSymbol from './octicons/octicons.generated'
|
||||
|
||||
export interface IDropdownSelectButtonOption {
|
||||
/** The select option header label. */
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Dialog, DialogContent, DialogFooter } from '../dialog'
|
|||
import { RetryAction } from '../../models/retry-actions'
|
||||
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||
import { Ref } from '../lib/ref'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
|
||||
interface IGenericGitAuthenticationProps {
|
||||
/** The hostname with which the user tried to authenticate. */
|
||||
|
@ -74,6 +75,18 @@ export class GenericGitAuthentication extends React.Component<
|
|||
onValueChanged={this.onPasswordChange}
|
||||
/>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<div>
|
||||
Depending on your repository's hosting service, you might need to
|
||||
use a Personal Access Token (PAT) as your password. Learn more
|
||||
about creating a PAT in our{' '}
|
||||
<LinkButton uri="https://github.com/desktop/desktop/tree/development/docs/integrations">
|
||||
integration docs
|
||||
</LinkButton>
|
||||
.
|
||||
</div>
|
||||
</Row>
|
||||
</DialogContent>
|
||||
|
||||
<DialogFooter>
|
||||
|
|
|
@ -10,7 +10,8 @@ import { showContextualMenu } from '../main-process-proxy'
|
|||
import { CommitAttribution } from '../lib/commit-attribution'
|
||||
import { AvatarStack } from '../lib/avatar-stack'
|
||||
import { IMenuItem } from '../../lib/menu-item'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Draggable } from '../lib/draggable'
|
||||
import {
|
||||
enableAmendingCommits,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as React from 'react'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { FileChange } from '../../models/status'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { RichText } from '../lib/rich-text'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { Commit } from '../../models/commit'
|
||||
|
@ -13,11 +13,12 @@ import { Tokenizer, TokenResult } from '../../lib/text-token-parser'
|
|||
import { wrapRichTextCommitMessage } from '../../lib/wrap-rich-text-commit-message'
|
||||
import { DiffOptions } from '../diff/diff-options'
|
||||
import { RepositorySectionTab } from '../../lib/app-state'
|
||||
import { IChangesetData } from '../../lib/git'
|
||||
|
||||
interface ICommitSummaryProps {
|
||||
readonly repository: Repository
|
||||
readonly commit: Commit
|
||||
readonly files: ReadonlyArray<FileChange>
|
||||
readonly changesetData: IChangesetData
|
||||
readonly emoji: Map<string, string>
|
||||
|
||||
/**
|
||||
|
@ -289,7 +290,7 @@ export class CommitSummary extends React.Component<
|
|||
}
|
||||
|
||||
public render() {
|
||||
const fileCount = this.props.files.length
|
||||
const fileCount = this.props.changesetData.files.length
|
||||
const filesPlural = fileCount === 1 ? 'file' : 'files'
|
||||
const filesDescription = `${fileCount} changed ${filesPlural}`
|
||||
const shortSHA = this.props.commit.shortSha
|
||||
|
@ -352,6 +353,7 @@ export class CommitSummary extends React.Component<
|
|||
|
||||
{filesDescription}
|
||||
</li>
|
||||
{this.renderLinesChanged()}
|
||||
{this.renderTags()}
|
||||
|
||||
<li
|
||||
|
@ -379,6 +381,36 @@ export class CommitSummary extends React.Component<
|
|||
)
|
||||
}
|
||||
|
||||
private renderLinesChanged() {
|
||||
const linesAdded = this.props.changesetData.linesAdded
|
||||
const linesDeleted = this.props.changesetData.linesDeleted
|
||||
if (linesAdded + linesDeleted === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const linesAddedPlural = linesAdded === 1 ? 'line' : 'lines'
|
||||
const linesDeletedPlural = linesDeleted === 1 ? 'line' : 'lines'
|
||||
const linesAddedTitle = `${linesAdded} ${linesAddedPlural} added`
|
||||
const linesDeletedTitle = `${linesDeleted} ${linesDeletedPlural} deleted`
|
||||
|
||||
return (
|
||||
<>
|
||||
<li
|
||||
className="commit-summary-meta-item without-truncation lines-added"
|
||||
title={linesAddedTitle}
|
||||
>
|
||||
+{linesAdded}
|
||||
</li>
|
||||
<li
|
||||
className="commit-summary-meta-item without-truncation lines-deleted"
|
||||
title={linesDeletedTitle}
|
||||
>
|
||||
-{linesDeleted}
|
||||
</li>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private renderTags() {
|
||||
const tags = this.props.commit.tags || []
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { HighlightText } from '../lib/highlight-text'
|
||||
import { Branch, IAheadBehind } from '../../models/branch'
|
||||
import { IMatches } from '../../lib/fuzzy-find'
|
||||
|
|
|
@ -19,7 +19,7 @@ import { IBranchListItem } from '../branches/group-branches'
|
|||
import { TabBar } from '../tab-bar'
|
||||
import { CompareBranchListItem } from './compare-branch-list-item'
|
||||
import { FancyTextBox } from '../lib/fancy-text-box'
|
||||
import { OcticonSymbol } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { SelectionSource } from '../lib/filter-list'
|
||||
import { IMatches } from '../../lib/fuzzy-find'
|
||||
import { Ref } from '../lib/ref'
|
||||
|
@ -498,7 +498,7 @@ export class CompareSidebar extends React.Component<
|
|||
if (commits.length - end <= CloseToBottomThreshold) {
|
||||
if (this.loadingMoreCommitsPromise != null) {
|
||||
// as this callback fires for any scroll event we need to guard
|
||||
// against re-entrant calls to loadNextHistoryBatch
|
||||
// against re-entrant calls to loadCommitBatch
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,14 @@ import { showContextualMenu } from '../main-process-proxy'
|
|||
import { CommitSummary } from './commit-summary'
|
||||
import { FileList } from './file-list'
|
||||
import { SeamlessDiffSwitcher } from '../diff/seamless-diff-switcher'
|
||||
import { IChangesetData } from '../../lib/git'
|
||||
|
||||
interface ISelectedCommitProps {
|
||||
readonly repository: Repository
|
||||
readonly dispatcher: Dispatcher
|
||||
readonly emoji: Map<string, string>
|
||||
readonly selectedCommit: Commit | null
|
||||
readonly changedFiles: ReadonlyArray<CommittedFileChange>
|
||||
readonly changesetData: IChangesetData
|
||||
readonly selectedFile: CommittedFileChange | null
|
||||
readonly currentDiff: IDiff | null
|
||||
readonly commitSummaryWidth: number
|
||||
|
@ -132,7 +133,7 @@ export class SelectedCommit extends React.Component<
|
|||
if (file == null) {
|
||||
// don't show both 'empty' messages
|
||||
const message =
|
||||
this.props.changedFiles.length === 0 ? '' : 'No file selected'
|
||||
this.props.changesetData.files.length === 0 ? '' : 'No file selected'
|
||||
|
||||
return (
|
||||
<div className="panel blankslate" id="diff">
|
||||
|
@ -160,7 +161,7 @@ export class SelectedCommit extends React.Component<
|
|||
return (
|
||||
<CommitSummary
|
||||
commit={commit}
|
||||
files={this.props.changedFiles}
|
||||
changesetData={this.props.changesetData}
|
||||
emoji={this.props.emoji}
|
||||
repository={this.props.repository}
|
||||
onExpandChanged={this.onExpandChanged}
|
||||
|
@ -210,7 +211,7 @@ export class SelectedCommit extends React.Component<
|
|||
}
|
||||
|
||||
private renderFileList() {
|
||||
const files = this.props.changedFiles
|
||||
const files = this.props.changesetData.files
|
||||
if (files.length === 0) {
|
||||
return <div className="fill-window">No files in commit</div>
|
||||
}
|
||||
|
|
62
app/src/ui/invalidated-token/invalidated-token.tsx
Normal file
62
app/src/ui/invalidated-token/invalidated-token.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import * as React from 'react'
|
||||
import { Dialog, DialogContent, DialogFooter } from '../dialog'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Row } from '../lib/row'
|
||||
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||
import { Account } from '../../models/account'
|
||||
import { getDotComAPIEndpoint } from '../../lib/api'
|
||||
|
||||
interface IInvalidatedTokenResetProps {
|
||||
readonly dispatcher: Dispatcher
|
||||
readonly account: Account
|
||||
readonly onDismissed: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog that alerts user that their GitHub (Enterprise) account token is not
|
||||
* valid and they need to sign in again.
|
||||
*/
|
||||
export class InvalidatedToken extends React.Component<
|
||||
IInvalidatedTokenResetProps
|
||||
> {
|
||||
public render() {
|
||||
const accountTypeSuffix = this.isEnterpriseAccount ? ' Enterprise' : ''
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
id="invalidated-token"
|
||||
type="warning"
|
||||
title="Warning"
|
||||
onSubmit={this.onSubmit}
|
||||
onDismissed={this.props.onDismissed}
|
||||
>
|
||||
<DialogContent>
|
||||
<Row>
|
||||
Your account token has been invalidated and you have been signed out
|
||||
from your GitHub{accountTypeSuffix} account. Do you want to sign in
|
||||
again?
|
||||
</Row>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<OkCancelButtonGroup okButtonText="Yes" cancelButtonText="No" />
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
private get isEnterpriseAccount() {
|
||||
return this.props.account.endpoint !== getDotComAPIEndpoint()
|
||||
}
|
||||
|
||||
private onSubmit = () => {
|
||||
const { dispatcher, onDismissed } = this.props
|
||||
|
||||
onDismissed()
|
||||
|
||||
if (this.isEnterpriseAccount) {
|
||||
dispatcher.showEnterpriseSignInDialog(this.props.account.endpoint)
|
||||
} else {
|
||||
dispatcher.showDotComSignInDialog()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,8 @@ import classNames from 'classnames'
|
|||
import { ComputedAction } from '../../models/computed-action'
|
||||
import { assertNever } from '../../lib/fatal-error'
|
||||
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, OcticonSymbolType } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
|
||||
interface IActionStatusIconProps {
|
||||
/** The status to display to the user */
|
||||
|
@ -51,7 +52,7 @@ export class ActionStatusIcon extends React.Component<IActionStatusIconProps> {
|
|||
}
|
||||
}
|
||||
|
||||
function getSymbolForState(status: ComputedAction): OcticonSymbol {
|
||||
function getSymbolForState(status: ComputedAction): OcticonSymbolType {
|
||||
switch (status) {
|
||||
case ComputedAction.Loading:
|
||||
return OcticonSymbol.dotFill
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Loading } from './loading'
|
||||
import { Form } from './form'
|
||||
import { Button } from './button'
|
||||
|
|
|
@ -10,7 +10,8 @@ import classNames from 'classnames'
|
|||
import { UserAutocompletionProvider, IUserHit } from '../autocompletion'
|
||||
import { compare } from '../../lib/compare'
|
||||
import { arrayEquals } from '../../lib/equality'
|
||||
import { OcticonSymbol, syncClockwise } from '../octicons'
|
||||
import { syncClockwise } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { IAuthor } from '../../models/author'
|
||||
import { showContextualMenu } from '../main-process-proxy'
|
||||
import { IMenuItem } from '../../lib/menu-item'
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from 'react'
|
|||
import { IAvatarUser } from '../../models/avatar'
|
||||
import { shallowEquals } from '../../lib/equality'
|
||||
import { generateGravatarUrl } from '../../lib/gravatar'
|
||||
import { OcticonSymbol, Octicon } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import { getDotComAPIEndpoint } from '../../lib/api'
|
||||
|
||||
interface IAvatarProps {
|
||||
|
@ -35,11 +35,12 @@ const avatarEndpoint = 'https://avatars.githubusercontent.com'
|
|||
* The octicon has been tweaked to add some padding and so that it scales nicely in
|
||||
* a square aspect ratio.
|
||||
*/
|
||||
const DefaultAvatarSymbol = new OcticonSymbol(
|
||||
16,
|
||||
16,
|
||||
'M13 13.145a.844.844 0 0 1-.832.855H3.834A.846.846 0 0 1 3 13.142v-.856c0-2.257 3.333-3.429 3.333-3.429s.191-.35 0-.857c-.7-.531-.786-1.363-.833-3.429C5.644 2.503 7.056 2 8 2s2.356.502 2.5 2.571C10.453 6.637 10.367 7.47 9.667 8c-.191.506 0 .857 0 .857S13 10.03 13 12.286v.859z'
|
||||
)
|
||||
const DefaultAvatarSymbol = {
|
||||
w: 16,
|
||||
h: 16,
|
||||
d:
|
||||
'M13 13.145a.844.844 0 0 1-.832.855H3.834A.846.846 0 0 1 3 13.142v-.856c0-2.257 3.333-3.429 3.333-3.429s.191-.35 0-.857c-.7-.531-.786-1.363-.833-3.429C5.644 2.503 7.056 2 8 2s2.356.502 2.5 2.571C10.453 6.637 10.367 7.47 9.667 8c-.191.506 0 .857 0 .857S13 10.03 13 12.286v.859z',
|
||||
}
|
||||
|
||||
/**
|
||||
* A regular expression meant to match both the legacy format GitHub.com
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
import { Branch, BranchType } from '../../models/branch'
|
||||
|
||||
import { Row } from './row'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Ref } from './ref'
|
||||
import { IStashEntry } from '../../models/stash-entry'
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../../octicons'
|
||||
import { Octicon } from '../../octicons'
|
||||
import * as OcticonSymbol from '../../octicons/octicons.generated'
|
||||
import { LinkButton } from '../link-button'
|
||||
|
||||
export function renderUnmergedFilesSummary(conflictedFilesCount: number) {
|
||||
|
|
|
@ -11,7 +11,8 @@ import { join } from 'path'
|
|||
import { Repository } from '../../../models/repository'
|
||||
import { Dispatcher } from '../../dispatcher'
|
||||
import { showContextualMenu } from '../../main-process-proxy'
|
||||
import { Octicon, OcticonSymbol } from '../../octicons'
|
||||
import { Octicon } from '../../octicons'
|
||||
import * as OcticonSymbol from '../../octicons/octicons.generated'
|
||||
import { PathText } from '../path-text'
|
||||
import { ManualConflictResolution } from '../../../models/manual-conflict-resolution'
|
||||
import {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, OcticonSymbolType } from '../octicons'
|
||||
import { TextBox, ITextBoxProps } from './text-box'
|
||||
import classNames from 'classnames'
|
||||
|
||||
interface IFancyTextBoxProps extends ITextBoxProps {
|
||||
/** Icon to render */
|
||||
readonly symbol: OcticonSymbol
|
||||
readonly symbol: OcticonSymbolType
|
||||
|
||||
/** Callback used to get a reference to internal TextBox */
|
||||
readonly onRef: (textbox: TextBox) => void
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as React from 'react'
|
||||
|
||||
import { AppFileStatus, AppFileStatusKind } from '../../models/status'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { PathText } from './path-text'
|
||||
|
||||
interface IPathLabelProps {
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
|
||||
import { sanitizedRefName } from '../../lib/sanitize-ref-name'
|
||||
import { TextBox } from './text-box'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Ref } from './ref'
|
||||
|
||||
interface IRefNameProps {
|
||||
|
|
|
@ -35,6 +35,12 @@ interface ISegmentedItemProps<T> {
|
|||
* a pointer device.
|
||||
*/
|
||||
readonly onClick: (value: T) => void
|
||||
|
||||
/**
|
||||
* A function that's called when a user double-clicks on the item
|
||||
* using a pointer device.
|
||||
*/
|
||||
readonly onDoubleClick: (value: T) => void
|
||||
}
|
||||
|
||||
export class SegmentedItem<T> extends React.Component<
|
||||
|
@ -45,6 +51,10 @@ export class SegmentedItem<T> extends React.Component<
|
|||
this.props.onClick(this.props.value)
|
||||
}
|
||||
|
||||
private onDoubleClick = () => {
|
||||
this.props.onDoubleClick(this.props.value)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const description = this.props.description ? (
|
||||
<p>{this.props.description}</p>
|
||||
|
@ -57,6 +67,7 @@ export class SegmentedItem<T> extends React.Component<
|
|||
<li
|
||||
className={className}
|
||||
onClick={this.onClick}
|
||||
onDoubleClick={this.onDoubleClick}
|
||||
role="radio"
|
||||
id={this.props.id}
|
||||
aria-checked={isSelected ? 'true' : 'false'}
|
||||
|
|
|
@ -116,12 +116,27 @@ export class VerticalSegmentedControl<T extends Key> extends React.Component<
|
|||
}
|
||||
}
|
||||
|
||||
private submitForm() {
|
||||
const form = this.formRef
|
||||
if (form) {
|
||||
// NB: In order to play nicely with React's custom event dispatching,
|
||||
// we dispatch an event instead of calling `submit` directly on the
|
||||
// form.
|
||||
form.dispatchEvent(new Event('submit'))
|
||||
}
|
||||
}
|
||||
|
||||
private onItemClick = (key: T) => {
|
||||
if (key !== this.props.selectedKey) {
|
||||
this.props.onSelectionChanged(key)
|
||||
}
|
||||
}
|
||||
|
||||
private onItemDoubleClick = (key: T) => {
|
||||
this.onItemClick(key)
|
||||
this.submitForm()
|
||||
}
|
||||
|
||||
private getListItemId(index: number) {
|
||||
return `${this.state.listId}_Item_${index}`
|
||||
}
|
||||
|
@ -136,6 +151,7 @@ export class VerticalSegmentedControl<T extends Key> extends React.Component<
|
|||
isSelected={item.key === this.props.selectedKey}
|
||||
value={item.key}
|
||||
onClick={this.onItemClick}
|
||||
onDoubleClick={this.onItemDoubleClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -154,13 +170,7 @@ export class VerticalSegmentedControl<T extends Key> extends React.Component<
|
|||
}
|
||||
event.preventDefault()
|
||||
} else if (event.key === 'Enter') {
|
||||
const form = this.formRef
|
||||
if (form) {
|
||||
// NB: In order to play nicely with React's custom event dispatching,
|
||||
// we dispatch an event instead of calling `submit` directly on the
|
||||
// form.
|
||||
form.dispatchEvent(new Event('submit'))
|
||||
}
|
||||
this.submitForm()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
import { formatRebaseValue } from '../../lib/rebase'
|
||||
import { RichText } from '../lib/rich-text'
|
||||
import { Dialog, DialogContent } from '../dialog'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { IMultiCommitOperationProgress } from '../../models/progress'
|
||||
|
||||
interface IProgressDialogProps {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as React from 'react'
|
||||
import { UiView } from '../ui-view'
|
||||
import { Button } from '../lib/button'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, OcticonSymbolType } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import {
|
||||
WelcomeLeftTopImageUri,
|
||||
WelcomeLeftBottomImageUri,
|
||||
|
@ -340,7 +341,7 @@ export class NoRepositoriesView extends React.Component<
|
|||
private onShowClone = () => this.props.onClone()
|
||||
|
||||
private renderButtonGroupButton(
|
||||
symbol: OcticonSymbol,
|
||||
symbol: OcticonSymbolType,
|
||||
title: string,
|
||||
onClick: () => void,
|
||||
type?: 'submit'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
export { OcticonSymbolType } from './octicons.generated'
|
||||
export { Octicon } from './octicon'
|
||||
export { OcticonSymbol } from './octicons.generated'
|
||||
export { iconForRepository } from './repository'
|
||||
export { iconForStatus } from './status'
|
||||
export { syncClockwise } from './sync-clockwise'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react'
|
||||
import { OcticonSymbol } from './octicons.generated'
|
||||
import { OcticonSymbolType } from './octicons.generated'
|
||||
import classNames from 'classnames'
|
||||
import { createUniqueId, releaseUniqueId } from '../lib/id-pool'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
@ -10,7 +10,7 @@ interface IOcticonProps {
|
|||
* type. Supports custom paths as well as those provided
|
||||
* through the static properties of the OcticonSymbol class.
|
||||
*/
|
||||
readonly symbol: OcticonSymbol
|
||||
readonly symbol: OcticonSymbolType
|
||||
|
||||
/**
|
||||
* An optional classname that will be appended to the default
|
||||
|
@ -86,7 +86,7 @@ export class Octicon extends React.Component<IOcticonProps, {}> {
|
|||
* @param id Optional identifier to set to the wrapper element.
|
||||
*/
|
||||
export function createOcticonElement(
|
||||
symbol: OcticonSymbol,
|
||||
symbol: OcticonSymbolType,
|
||||
className?: string,
|
||||
id?: string
|
||||
) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
import { OcticonSymbol } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { CloningRepository } from '../../models/cloning-repository'
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@ import {
|
|||
AppFileStatus,
|
||||
isConflictWithMarkers,
|
||||
} from '../../models/status'
|
||||
import { OcticonSymbol } from './octicons.generated'
|
||||
import * as OcticonSymbol from './octicons.generated'
|
||||
import { OcticonSymbolType } from '../octicons'
|
||||
import { assertNever } from '../../lib/fatal-error'
|
||||
|
||||
/**
|
||||
|
@ -12,7 +13,7 @@ import { assertNever } from '../../lib/fatal-error'
|
|||
*
|
||||
* Used in file lists.
|
||||
*/
|
||||
export function iconForStatus(status: AppFileStatus): OcticonSymbol {
|
||||
export function iconForStatus(status: AppFileStatus): OcticonSymbolType {
|
||||
switch (status.kind) {
|
||||
case AppFileStatusKind.New:
|
||||
case AppFileStatusKind.Untracked:
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import { OcticonSymbol } from './octicons.generated'
|
||||
import { OcticonSymbolType } from './octicons.generated'
|
||||
|
||||
/**
|
||||
* An horizontally flipped (i.e `scaleX(-1)`) but otherwise unmodified version of
|
||||
* the `sync` octicon.
|
||||
*/
|
||||
export const syncClockwise = new OcticonSymbol(
|
||||
16,
|
||||
16,
|
||||
'M8 2.5c1.645 0 3.123.722 4.131 1.869l-1.204 1.204a.25.25 0 0 0 .177.427h3.646a.25.25 ' +
|
||||
export const syncClockwise: OcticonSymbolType = {
|
||||
w: 16,
|
||||
h: 16,
|
||||
d:
|
||||
'M8 2.5c1.645 0 3.123.722 4.131 1.869l-1.204 1.204a.25.25 0 0 0 .177.427h3.646a.25.25 ' +
|
||||
'0 0 0 .25-.25V2.104a.25.25 0 0 0-.427-.177l-1.38 1.38A7.001 7.001 0 0 0 1.05 7.16a.75.75 ' +
|
||||
'0 1 0 1.49.178A5.501 5.501 0 0 1 8 2.5zm6.294 5.505a.75.75 0 0 0-.833.656 5.501 5.501 ' +
|
||||
'0 0 1-9.592 2.97l1.204-1.204A.25.25 0 0 0 4.896 10H1.25a.25.25 0 0 0-.25.25v3.646c0 ' +
|
||||
'.223.27.335.427.177l1.38-1.38A7.001 7.001 0 0 0 14.95 8.84a.75.75 0 0 0-.657-.834z',
|
||||
'evenodd'
|
||||
)
|
||||
fr: 'evenodd',
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ import {
|
|||
UncommittedChangesStrategy,
|
||||
defaultUncommittedChangesStrategy,
|
||||
} from '../../models/uncommitted-changes-strategy'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import {
|
||||
isConfigFileLockError,
|
||||
parseConfigLockFilePathFromError,
|
||||
|
|
|
@ -8,7 +8,8 @@ import { Row } from '../lib/row'
|
|||
import { merge } from '../../lib/merge'
|
||||
import { caseInsensitiveCompare } from '../../lib/compare'
|
||||
import { sanitizedRepositoryName } from '../add-repository/sanitized-repository-name'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { RepositoryPublicationSettings } from '../../models/publish-settings'
|
||||
|
||||
interface IPublishRepositoryProps {
|
||||
|
|
|
@ -5,7 +5,8 @@ import { formatRebaseValue } from '../../lib/rebase'
|
|||
import { RichText } from '../lib/rich-text'
|
||||
|
||||
import { Dialog, DialogContent } from '../dialog'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { IMultiCommitOperationProgress } from '../../models/progress'
|
||||
|
||||
interface IRebaseProgressDialogProps {
|
||||
|
|
|
@ -14,7 +14,8 @@ import { IMatches } from '../../lib/fuzzy-find'
|
|||
import { ILocalRepositoryState, Repository } from '../../models/repository'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Button } from '../lib/button'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { showContextualMenu } from '../main-process-proxy'
|
||||
import { IMenuItem } from '../../lib/menu-item'
|
||||
import { PopupType } from '../../models/popup'
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
import { clipboard } from 'electron'
|
||||
|
||||
import { Repository } from '../../models/repository'
|
||||
import { Octicon, iconForRepository, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, iconForRepository } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { showContextualMenu } from '../main-process-proxy'
|
||||
import { Repositoryish } from './group-repositories'
|
||||
import { IMenuItem } from '../../lib/menu-item'
|
||||
|
|
|
@ -377,7 +377,7 @@ export class RepositoryView extends React.Component<
|
|||
const selectedCommit =
|
||||
sha != null ? this.props.state.commitLookup.get(sha) || null : null
|
||||
|
||||
const { changedFiles, file, diff } = commitSelection
|
||||
const { changesetData, file, diff } = commitSelection
|
||||
|
||||
const showDragOverlay = dragAndDropManager.isDragOfTypeInProgress(
|
||||
DragType.Commit
|
||||
|
@ -388,7 +388,7 @@ export class RepositoryView extends React.Component<
|
|||
repository={this.props.repository}
|
||||
dispatcher={this.props.dispatcher}
|
||||
selectedCommit={selectedCommit}
|
||||
changedFiles={changedFiles}
|
||||
changesetData={changesetData}
|
||||
selectedFile={file}
|
||||
currentDiff={diff}
|
||||
emoji={this.props.emoji}
|
||||
|
|
|
@ -9,7 +9,8 @@ import {
|
|||
} from '../../lib/stores'
|
||||
import { assertNever } from '../../lib/fatal-error'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Row } from '../lib/row'
|
||||
import { TextBox } from '../lib/text-box'
|
||||
import { Dialog, DialogError, DialogContent, DialogFooter } from '../dialog'
|
||||
|
|
|
@ -6,7 +6,8 @@ import { VerticalSegmentedControl } from '../lib/vertical-segmented-control'
|
|||
import { Row } from '../lib/row'
|
||||
import { Branch } from '../../models/branch'
|
||||
import { UncommittedChangesStrategy } from '../../models/uncommitted-changes-strategy'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { PopupType } from '../../models/popup'
|
||||
import { startTimer } from '../lib/timing'
|
||||
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||
|
|
|
@ -3,7 +3,8 @@ import { IStashEntry } from '../../models/stash-entry'
|
|||
import { Dispatcher } from '../dispatcher'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { PopupType } from '../../models/popup'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||
|
||||
interface IStashDiffHeaderProps {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as React from 'react'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { OcticonSymbol, syncClockwise } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { syncClockwise } from '../octicons'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { TipState } from '../../models/tip'
|
||||
import { ToolbarDropdown, DropdownState } from './dropdown'
|
||||
|
@ -97,7 +98,7 @@ export class BranchDropdown extends React.Component<IBranchDropdownProps> {
|
|||
|
||||
const tipKind = tip.kind
|
||||
|
||||
let icon = OcticonSymbol.gitBranch
|
||||
let icon: OcticonSymbol.OcticonSymbolType = OcticonSymbol.gitBranch
|
||||
let iconClassName: string | undefined = undefined
|
||||
let title: string
|
||||
let description = __DARWIN__ ? 'Current Branch' : 'Current branch'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, OcticonSymbolType } from '../octicons'
|
||||
import classNames from 'classnames'
|
||||
import { assertNever } from '../../lib/fatal-error'
|
||||
import { Button } from '../lib/button'
|
||||
|
@ -25,7 +25,7 @@ export interface IToolbarButtonProps {
|
|||
readonly tooltip?: string
|
||||
|
||||
/** An optional symbol to be displayed next to the button text */
|
||||
readonly icon?: OcticonSymbol
|
||||
readonly icon?: OcticonSymbolType
|
||||
|
||||
/** The class name for the icon element. */
|
||||
readonly iconClassName?: string
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as React from 'react'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon, OcticonSymbolType } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { assertNever } from '../../lib/fatal-error'
|
||||
import { ToolbarButton, ToolbarButtonStyle } from './button'
|
||||
import { rectEquals } from '../lib/rect'
|
||||
|
@ -20,7 +21,7 @@ export interface IToolbarDropdownProps {
|
|||
readonly tooltip?: string
|
||||
|
||||
/** An optional symbol to be displayed next to the button text */
|
||||
readonly icon?: OcticonSymbol
|
||||
readonly icon?: OcticonSymbolType
|
||||
|
||||
/**
|
||||
* The state for of the drop down button.
|
||||
|
@ -173,7 +174,7 @@ export class ToolbarDropdown extends React.Component<
|
|||
return this.props.dropdownState === 'open'
|
||||
}
|
||||
|
||||
private dropdownIcon(state: DropdownState): OcticonSymbol {
|
||||
private dropdownIcon(state: DropdownState): OcticonSymbolType {
|
||||
// @TODO: Remake triangle octicon in a 12px version,
|
||||
// right now it's scaled badly on normal dpi monitors.
|
||||
if (state === 'open') {
|
||||
|
|
|
@ -7,7 +7,8 @@ import { TipState } from '../../models/tip'
|
|||
import { FetchType } from '../../models/fetch'
|
||||
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Octicon, OcticonSymbol, syncClockwise } from '../octicons'
|
||||
import { Octicon, syncClockwise } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { RelativeTime } from '../relative-time'
|
||||
|
||||
import { ToolbarButton, ToolbarButtonStyle } from './button'
|
||||
|
@ -261,15 +262,16 @@ function pushButton(
|
|||
* This represents the "double arrow" icon used to show a force-push, and is a
|
||||
* less complicated icon than the generated Octicon from the `octicons` package.
|
||||
*/
|
||||
const forcePushIcon = new OcticonSymbol(
|
||||
10,
|
||||
16,
|
||||
'M0 6a.75.75 0 0 0 .974.714L4.469 3.22a.75.75 0 0 1 1.06 0l3.478 3.478a.75.75 ' +
|
||||
const forcePushIcon: OcticonSymbol.OcticonSymbolType = {
|
||||
w: 10,
|
||||
h: 16,
|
||||
d:
|
||||
'M0 6a.75.75 0 0 0 .974.714L4.469 3.22a.75.75 0 0 1 1.06 0l3.478 3.478a.75.75 ' +
|
||||
'0 0 0 .772-1.228L5.53 1.22a.75.75 0 0 0-1.06 0L.22 5.47A.75.75 0 0 0 0 6zm0 ' +
|
||||
'3a.75.75 0 0 0 1.28.53l2.97-2.97V14a.75.75 0 1 0 1.5 0V6.56l2.97 2.97a.75.75 ' +
|
||||
'0 0 0 1.06-1.06L5.53 4.22a.75.75 0 0 0-1.06 0L.22 8.47A.75.75 0 0 0 0 9z',
|
||||
'evenodd'
|
||||
)
|
||||
fr: 'evenodd',
|
||||
}
|
||||
|
||||
function forcePushButton(
|
||||
remoteName: string,
|
||||
|
|
|
@ -4,7 +4,8 @@ import { encodePathAsUrl } from '../../lib/path'
|
|||
import { Dispatcher } from '../dispatcher'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { PopupType } from '../../models/popup'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { SuggestedAction } from '../suggested-actions'
|
||||
import { SuggestedActionGroup } from '../suggested-actions'
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import { LinkButton } from '../lib/link-button'
|
|||
import { Button } from '../lib/button'
|
||||
import { Repository } from '../../models/repository'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import {
|
||||
ValidTutorialStep,
|
||||
TutorialStep,
|
||||
|
|
|
@ -2,7 +2,8 @@ import * as React from 'react'
|
|||
import { WelcomeStep } from './welcome'
|
||||
import { LinkButton } from '../lib/link-button'
|
||||
import { Dispatcher } from '../dispatcher'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { Button } from '../lib/button'
|
||||
import { Loading } from '../lib/loading'
|
||||
import { BrowserRedirectMessage } from '../lib/authentication-form'
|
||||
|
|
|
@ -3,7 +3,8 @@ import memoizeOne from 'memoize-one'
|
|||
import { remote } from 'electron'
|
||||
import { WindowState } from '../../lib/window-state'
|
||||
import { WindowControls } from './window-controls'
|
||||
import { Octicon, OcticonSymbol } from '../octicons'
|
||||
import { Octicon } from '../octicons/octicon'
|
||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||
import { isMacOSBigSurOrLater } from '../../lib/get-os'
|
||||
|
||||
/** Get the height (in pixels) of the title bar depending on the platform */
|
||||
|
|
|
@ -180,6 +180,13 @@ $overlay-background-color: rgba(0, 0, 0, 0.4);
|
|||
--co-author-tag-background-color: #{$blue-000};
|
||||
--co-author-tag-border-color: #{$blue-200};
|
||||
|
||||
/**
|
||||
* Author input (co-authors)
|
||||
*/
|
||||
--commit-warning-badge-background-color: #{$gray-000};
|
||||
--commit-warning-badge-border-color: #{$gray-300};
|
||||
--commit-warning-badge-icon-color: #{$gray-900};
|
||||
|
||||
/**
|
||||
* The height of the title bar area on Win32 platforms
|
||||
* If changed, update titleBarHeight in 'app/src/ui/dialog/dialog.tsx'
|
||||
|
|
|
@ -3,16 +3,17 @@
|
|||
position: relative;
|
||||
|
||||
.warning-badge {
|
||||
background-color: #f6f8fa;
|
||||
background-color: var(--commit-warning-badge-background-color);
|
||||
border: var(--commit-warning-badge-border-color) 1px solid;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
position: absolute;
|
||||
margin-top: -6px;
|
||||
margin-left: -7px;
|
||||
border-radius: 9px;
|
||||
border: #d1d5da 1px solid;
|
||||
|
||||
> svg {
|
||||
color: var(--commit-warning-badge-icon-color);
|
||||
height: 10px;
|
||||
// With width=100%, the icon will be centered horizontally
|
||||
width: 100%;
|
||||
|
|
|
@ -31,6 +31,7 @@ dialog#multi-commit-progress {
|
|||
height: 22px;
|
||||
width: 22px;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,14 @@
|
|||
&-title,
|
||||
&-meta {
|
||||
padding: var(--spacing);
|
||||
|
||||
.lines-added {
|
||||
color: var(--color-new);
|
||||
}
|
||||
|
||||
.lines-deleted {
|
||||
color: var(--color-deleted);
|
||||
}
|
||||
}
|
||||
|
||||
&-title {
|
||||
|
|
|
@ -39,7 +39,7 @@ describe('GitStore', () => {
|
|||
const repo = new Repository(path, -1, null, false)
|
||||
const gitStore = new GitStore(repo, shell, statsStore)
|
||||
|
||||
const commits = await gitStore.loadCommitBatch('HEAD')
|
||||
const commits = await gitStore.loadCommitBatch('HEAD', 0)
|
||||
|
||||
expect(commits).not.toBeNull()
|
||||
expect(commits).toHaveLength(100)
|
||||
|
|
|
@ -187,9 +187,9 @@ describe('git/commit', () => {
|
|||
expect(newTip.shortSha).toEqual(sha)
|
||||
|
||||
// verify that the contents of this new commit are just the new file
|
||||
const changedFiles = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changedFiles.length).toEqual(1)
|
||||
expect(changedFiles[0].path).toEqual(newFileName)
|
||||
const changesetData = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changesetData.files.length).toEqual(1)
|
||||
expect(changesetData.files[0].path).toEqual(newFileName)
|
||||
|
||||
// verify that changes remain for this new file
|
||||
const status = await getStatusOrThrow(repository)
|
||||
|
@ -239,9 +239,9 @@ describe('git/commit', () => {
|
|||
expect(newTip.summary).toEqual('title')
|
||||
|
||||
// verify that the contents of this new commit are just the modified file
|
||||
const changedFiles = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changedFiles.length).toEqual(1)
|
||||
expect(changedFiles[0].path).toEqual(modifiedFile)
|
||||
const changesetData = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changesetData.files.length).toEqual(1)
|
||||
expect(changesetData.files[0].path).toEqual(modifiedFile)
|
||||
|
||||
// verify that changes remain for this modified file
|
||||
const status = await getStatusOrThrow(repository)
|
||||
|
@ -294,9 +294,9 @@ describe('git/commit', () => {
|
|||
expect(newTip.shortSha).toEqual(sha)
|
||||
|
||||
// verify that the contents of this new commit are just the modified file
|
||||
const changedFiles = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changedFiles.length).toEqual(1)
|
||||
expect(changedFiles[0].path).toEqual(fileName)
|
||||
const changesetData = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changesetData.files.length).toEqual(1)
|
||||
expect(changesetData.files[0].path).toEqual(fileName)
|
||||
})
|
||||
|
||||
it('can commit multiple hunks from modified file', async () => {
|
||||
|
@ -340,9 +340,9 @@ describe('git/commit', () => {
|
|||
expect(newTip.shortSha).toEqual(sha)
|
||||
|
||||
// verify that the contents of this new commit are just the modified file
|
||||
const changedFiles = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changedFiles.length).toEqual(1)
|
||||
expect(changedFiles[0].path).toEqual(modifiedFile)
|
||||
const changesetData = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changesetData.files.length).toEqual(1)
|
||||
expect(changesetData.files[0].path).toEqual(modifiedFile)
|
||||
|
||||
// verify that changes remain for this modified file
|
||||
const status = await getStatusOrThrow(repository)
|
||||
|
@ -382,9 +382,9 @@ describe('git/commit', () => {
|
|||
expect(newTip.sha.substring(0, 7)).toEqual(sha)
|
||||
|
||||
// verify that the contents of this new commit are just the new file
|
||||
const changedFiles = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changedFiles.length).toEqual(1)
|
||||
expect(changedFiles[0].path).toEqual(deletedFile)
|
||||
const changesetData = await getChangedFiles(repository, newTip.sha)
|
||||
expect(changesetData.files.length).toEqual(1)
|
||||
expect(changesetData.files[0].path).toEqual(deletedFile)
|
||||
|
||||
// verify that changes remain for this new file
|
||||
const status = await getStatusOrThrow(repository)
|
||||
|
@ -838,10 +838,12 @@ describe('git/commit', () => {
|
|||
expect(beforeCommit.currentTip).not.toBe(afterCommit.currentTip)
|
||||
|
||||
// Verify the file was delete in repo
|
||||
const changedFiles = await getChangedFiles(repo, afterCommit.currentTip!)
|
||||
expect(changedFiles.length).toBe(2)
|
||||
expect(changedFiles[0].status.kind).toBe(AppFileStatusKind.Modified)
|
||||
expect(changedFiles[1].status.kind).toBe(AppFileStatusKind.Deleted)
|
||||
const changesetData = await getChangedFiles(repo, afterCommit.currentTip!)
|
||||
expect(changesetData.files.length).toBe(2)
|
||||
expect(changesetData.files[0].status.kind).toBe(
|
||||
AppFileStatusKind.Modified
|
||||
)
|
||||
expect(changesetData.files[1].status.kind).toBe(AppFileStatusKind.Deleted)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -61,13 +61,13 @@ describe('git/log', () => {
|
|||
|
||||
describe('getChangedFiles', () => {
|
||||
it('loads the files changed in the commit', async () => {
|
||||
const files = await getChangedFiles(
|
||||
const changesetData = await getChangedFiles(
|
||||
repository,
|
||||
'7cd6640e5b6ca8dbfd0b33d0281ebe702127079c'
|
||||
)
|
||||
expect(files).toHaveLength(1)
|
||||
expect(files[0].path).toBe('README.md')
|
||||
expect(files[0].status.kind).toBe(AppFileStatusKind.New)
|
||||
expect(changesetData.files).toHaveLength(1)
|
||||
expect(changesetData.files[0].path).toBe('README.md')
|
||||
expect(changesetData.files[0].status.kind).toBe(AppFileStatusKind.New)
|
||||
})
|
||||
|
||||
it('detects renames', async () => {
|
||||
|
@ -77,19 +77,19 @@ describe('git/log', () => {
|
|||
repository = new Repository(testRepoPath, -1, null, false)
|
||||
|
||||
const first = await getChangedFiles(repository, '55bdecb')
|
||||
expect(first).toHaveLength(1)
|
||||
expect(first.files).toHaveLength(1)
|
||||
|
||||
expect(first[0].path).toBe('NEWER.md')
|
||||
expect(first[0].status).toEqual({
|
||||
expect(first.files[0].path).toBe('NEWER.md')
|
||||
expect(first.files[0].status).toEqual({
|
||||
kind: AppFileStatusKind.Renamed,
|
||||
oldPath: 'NEW.md',
|
||||
})
|
||||
|
||||
const second = await getChangedFiles(repository, 'c898ca8')
|
||||
expect(second).toHaveLength(1)
|
||||
expect(second.files).toHaveLength(1)
|
||||
|
||||
expect(second[0].path).toBe('NEW.md')
|
||||
expect(second[0].status).toEqual({
|
||||
expect(second.files[0].path).toBe('NEW.md')
|
||||
expect(second.files[0].status).toEqual({
|
||||
kind: AppFileStatusKind.Renamed,
|
||||
oldPath: 'OLD.md',
|
||||
})
|
||||
|
@ -104,27 +104,29 @@ describe('git/log', () => {
|
|||
// ensure the test repository is configured to detect copies
|
||||
await setupLocalConfig(repository, [['diff.renames', 'copies']])
|
||||
|
||||
const files = await getChangedFiles(repository, 'a500bf415')
|
||||
expect(files).toHaveLength(2)
|
||||
const changesetData = await getChangedFiles(repository, 'a500bf415')
|
||||
expect(changesetData.files).toHaveLength(2)
|
||||
|
||||
expect(files[0].path).toBe('duplicate-with-edits.md')
|
||||
expect(files[0].status).toEqual({
|
||||
expect(changesetData.files[0].path).toBe('duplicate-with-edits.md')
|
||||
expect(changesetData.files[0].status).toEqual({
|
||||
kind: AppFileStatusKind.Copied,
|
||||
oldPath: 'initial.md',
|
||||
})
|
||||
|
||||
expect(files[1].path).toBe('duplicate.md')
|
||||
expect(files[1].status).toEqual({
|
||||
expect(changesetData.files[1].path).toBe('duplicate.md')
|
||||
expect(changesetData.files[1].status).toEqual({
|
||||
kind: AppFileStatusKind.Copied,
|
||||
oldPath: 'initial.md',
|
||||
})
|
||||
})
|
||||
|
||||
it('handles commit when HEAD exists on disk', async () => {
|
||||
const files = await getChangedFiles(repository, 'HEAD')
|
||||
expect(files).toHaveLength(1)
|
||||
expect(files[0].path).toBe('README.md')
|
||||
expect(files[0].status.kind).toBe(AppFileStatusKind.Modified)
|
||||
const changesetData = await getChangedFiles(repository, 'HEAD')
|
||||
expect(changesetData.files).toHaveLength(1)
|
||||
expect(changesetData.files[0].path).toBe('README.md')
|
||||
expect(changesetData.files[0].status.kind).toBe(
|
||||
AppFileStatusKind.Modified
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -290,10 +290,12 @@ describe('git/rebase', () => {
|
|||
|
||||
status = await getStatusOrThrow(repository)
|
||||
|
||||
filesInRebasedCommit = await getChangedFiles(
|
||||
const changesetData = await getChangedFiles(
|
||||
repository,
|
||||
status.currentTip!
|
||||
)
|
||||
|
||||
filesInRebasedCommit = changesetData.files
|
||||
})
|
||||
|
||||
it('returns success', () => {
|
||||
|
|
|
@ -47,8 +47,13 @@ describe('git/cherry-pick', () => {
|
|||
expect(log.length).toBe(2)
|
||||
|
||||
// verify squashed commit contains changes from squashed commits
|
||||
const squashedFiles = await getChangedFiles(repository, squashed.sha)
|
||||
const squashedFilePaths = squashedFiles.map(f => f.path).join(' ')
|
||||
const squashedChangesetData = await getChangedFiles(
|
||||
repository,
|
||||
squashed.sha
|
||||
)
|
||||
const squashedFilePaths = squashedChangesetData.files
|
||||
.map(f => f.path)
|
||||
.join(' ')
|
||||
expect(squashedFilePaths).toContain('first.md')
|
||||
expect(squashedFilePaths).toContain('second.md')
|
||||
})
|
||||
|
@ -91,8 +96,13 @@ describe('git/cherry-pick', () => {
|
|||
expect(log.length).toBe(2)
|
||||
|
||||
// verify squashed commit contains changes from squashed commits
|
||||
const squashedFiles = await getChangedFiles(repository, squashed.sha)
|
||||
const squashedFilePaths = squashedFiles.map(f => f.path).join(' ')
|
||||
const squashedChangesetData = await getChangedFiles(
|
||||
repository,
|
||||
squashed.sha
|
||||
)
|
||||
const squashedFilePaths = squashedChangesetData.files
|
||||
.map(f => f.path)
|
||||
.join(' ')
|
||||
expect(squashedFilePaths).toContain('first.md')
|
||||
expect(squashedFilePaths).toContain('second.md')
|
||||
expect(squashedFilePaths).toContain('third.md')
|
||||
|
@ -123,8 +133,13 @@ describe('git/cherry-pick', () => {
|
|||
expect(log.length).toBe(1)
|
||||
|
||||
// verify squashed commit contains changes from squashed commits
|
||||
const squashedFiles = await getChangedFiles(repository, squashed.sha)
|
||||
const squashedFilePaths = squashedFiles.map(f => f.path).join(' ')
|
||||
const squashedChangesetData = await getChangedFiles(
|
||||
repository,
|
||||
squashed.sha
|
||||
)
|
||||
const squashedFilePaths = squashedChangesetData.files
|
||||
.map(f => f.path)
|
||||
.join(' ')
|
||||
expect(squashedFilePaths).toContain('initialize')
|
||||
expect(squashedFilePaths).toContain('first.md')
|
||||
expect(squashedFilePaths).toContain('second.md')
|
||||
|
@ -169,8 +184,13 @@ describe('git/cherry-pick', () => {
|
|||
expect(log.length).toBe(4)
|
||||
|
||||
// verify squashed commit contains changes from squashed commits
|
||||
const squashedFiles = await getChangedFiles(repository, squashed.sha)
|
||||
const squashedFilePaths = squashedFiles.map(f => f.path).join(' ')
|
||||
const squashedChangesetData = await getChangedFiles(
|
||||
repository,
|
||||
squashed.sha
|
||||
)
|
||||
const squashedFilePaths = squashedChangesetData.files
|
||||
.map(f => f.path)
|
||||
.join(' ')
|
||||
expect(squashedFilePaths).toContain('first.md')
|
||||
expect(squashedFilePaths).toContain('third.md')
|
||||
expect(squashedFilePaths).toContain('fifth.md')
|
||||
|
@ -257,8 +277,13 @@ describe('git/cherry-pick', () => {
|
|||
expect(squashed.body).toBe('Test Body\n')
|
||||
|
||||
// verify squashed commit contains changes from squashed commits
|
||||
const squashedFiles = await getChangedFiles(repository, squashed.sha)
|
||||
const squashedFilePaths = squashedFiles.map(f => f.path).join(' ')
|
||||
const squashedChangesetData = await getChangedFiles(
|
||||
repository,
|
||||
squashed.sha
|
||||
)
|
||||
const squashedFilePaths = squashedChangesetData.files
|
||||
.map(f => f.path)
|
||||
.join(' ')
|
||||
expect(squashedFilePaths).toContain('first.md')
|
||||
expect(squashedFilePaths).toContain('second.md')
|
||||
})
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { OcticonSymbol, iconForRepository } from '../../src/ui/octicons'
|
||||
import { iconForRepository } from '../../src/ui/octicons'
|
||||
import * as OcticonSymbol from '../../src/ui/octicons/octicons.generated'
|
||||
import { CloningRepository } from '../../src/models/cloning-repository'
|
||||
import { Repository } from '../../src/models/repository'
|
||||
import { gitHubRepoFixture } from '../helpers/github-repo-builder'
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue