mirror of
https://github.com/desktop/desktop
synced 2024-09-13 21:31:32 +00:00
Merge branch 'development' into releases/3.0.5
This commit is contained in:
commit
43e37eec00
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -28,11 +28,11 @@ jobs:
|
||||||
# Needed for macOS arm64 until hosted macos-11.0 runners become available
|
# Needed for macOS arm64 until hosted macos-11.0 runners become available
|
||||||
SDKROOT: /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk
|
SDKROOT: /Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Use Node.js ${{ matrix.node }}
|
- name: Use Node.js ${{ matrix.node }}
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ jobs:
|
||||||
id: yarn-cache-dir-path
|
id: yarn-cache-dir-path
|
||||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v3
|
||||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
|
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
|
@ -18,11 +18,11 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ jobs:
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below).
|
# If this step fails, then you should remove it and run the build manually (see below).
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
|
@ -46,4 +46,4 @@ jobs:
|
||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|
2
.github/workflows/release-pr.yml
vendored
2
.github/workflows/release-pr.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
if: |
|
if: |
|
||||||
startsWith(github.ref, 'refs/heads/releases/') && !contains(github.ref, 'test')
|
startsWith(github.ref, 'refs/heads/releases/') && !contains(github.ref, 'test')
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# [GitHub Desktop](https://desktop.github.com)
|
# [GitHub Desktop](https://desktop.github.com)
|
||||||
|
|
||||||
[GitHub Desktop](https://desktop.github.com/) is an open source [Electron](https://www.electronjs.org/)-based
|
[GitHub Desktop](https://desktop.github.com/) is an open source [Electron](https://www.electronjs.org/)-based
|
||||||
GitHub app. It is written in [TypeScript](http://www.typescriptlang.org) and
|
GitHub app. It is written in [TypeScript](https://www.typescriptlang.org) and
|
||||||
uses [React](https://reactjs.org/).
|
uses [React](https://reactjs.org/).
|
||||||
|
|
||||||
![GitHub Desktop screenshot - Windows](https://cloud.githubusercontent.com/assets/359239/26094502/a1f56d02-3a5d-11e7-8799-23c7ba5e5106.png)
|
![GitHub Desktop screenshot - Windows](https://cloud.githubusercontent.com/assets/359239/26094502/a1f56d02-3a5d-11e7-8799-23c7ba5e5106.png)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
runtime = electron
|
runtime = electron
|
||||||
disturl = https://electronjs.org/headers
|
disturl = https://electronjs.org/headers
|
||||||
target = 17.0.1
|
target = 19.0.0
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"codemirror-mode-elixir": "^1.1.2",
|
"codemirror-mode-elixir": "^1.1.2",
|
||||||
"compare-versions": "^3.6.0",
|
"compare-versions": "^3.6.0",
|
||||||
"deep-equal": "^1.0.1",
|
"deep-equal": "^1.0.1",
|
||||||
"desktop-notifications": "^0.2.2",
|
"desktop-notifications": "^0.2.4",
|
||||||
"desktop-trampoline": "desktop/desktop-trampoline#v0.9.8",
|
"desktop-trampoline": "desktop/desktop-trampoline#v0.9.8",
|
||||||
"dexie": "^3.2.2",
|
"dexie": "^3.2.2",
|
||||||
"dompurify": "^2.3.3",
|
"dompurify": "^2.3.3",
|
||||||
|
|
|
@ -553,6 +553,25 @@ export interface ICommitSelection {
|
||||||
/** The commits currently selected in the app */
|
/** The commits currently selected in the app */
|
||||||
readonly shas: ReadonlyArray<string>
|
readonly shas: ReadonlyArray<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When multiple commits are selected, the diff is created using the rev range
|
||||||
|
* of firstSha^..lastSha in the selected shas. Thus comparing the trees of the
|
||||||
|
* the lastSha and the first parent of the first sha. However, our history
|
||||||
|
* list shows commits in chronological order. Thus, when a branch is merged,
|
||||||
|
* the commits from that branch are injected in their chronological order into
|
||||||
|
* the history list. Therefore, given a branch history of A, B, C, D,
|
||||||
|
* MergeCommit where B and C are from the merged branch, diffing on the
|
||||||
|
* selection of A through D would not have the changes from B an C.
|
||||||
|
*
|
||||||
|
* This is a list of the shas that are reachable by following the parent links
|
||||||
|
* (aka the graph) from the lastSha to the firstSha^ in the selection.
|
||||||
|
*
|
||||||
|
* Other notes: Given a selection A through D, executing `git diff A..D` would
|
||||||
|
* give us the changes since A but not including A; since the user will have
|
||||||
|
* selected A, we do `git diff A^..D` so that we include the changes of A.
|
||||||
|
* */
|
||||||
|
readonly shasInDiff: ReadonlyArray<string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the a selection of commits are group of adjacent to each other.
|
* Whether the a selection of commits are group of adjacent to each other.
|
||||||
* Example: Given these are indexes of sha's in history, 3, 4, 5, 6 is contiguous as
|
* Example: Given these are indexes of sha's in history, 3, 4, 5, 6 is contiguous as
|
||||||
|
@ -717,6 +736,9 @@ export interface ICompareState {
|
||||||
/** The SHAs of commits to render in the compare list */
|
/** The SHAs of commits to render in the compare list */
|
||||||
readonly commitSHAs: ReadonlyArray<string>
|
readonly commitSHAs: ReadonlyArray<string>
|
||||||
|
|
||||||
|
/** The SHAs of commits to highlight in the compare list */
|
||||||
|
readonly shasToHighlight: ReadonlyArray<string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of branches (remote and local) except the current branch, and
|
* A list of branches (remote and local) except the current branch, and
|
||||||
* Desktop fork remote branches (see `Branch.isDesktopForkRemoteBranch`)
|
* Desktop fork remote branches (see `Branch.isDesktopForkRemoteBranch`)
|
||||||
|
|
|
@ -3,7 +3,10 @@ import { UpstreamRemoteName } from './stores'
|
||||||
import {
|
import {
|
||||||
RepositoryWithGitHubRepository,
|
RepositoryWithGitHubRepository,
|
||||||
getNonForkGitHubRepository,
|
getNonForkGitHubRepository,
|
||||||
|
isRepositoryWithGitHubRepository,
|
||||||
|
Repository,
|
||||||
} from '../models/repository'
|
} from '../models/repository'
|
||||||
|
import { IBranchesState } from './app-state'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the default branch of the upstream repository of the passed repository.
|
* Finds the default branch of the upstream repository of the passed repository.
|
||||||
|
@ -41,3 +44,23 @@ export function findDefaultUpstreamBranch(
|
||||||
|
|
||||||
return foundBranch !== undefined ? foundBranch : null
|
return foundBranch !== undefined ? foundBranch : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param repository The repository to use.
|
||||||
|
* @param branchesState The branches state of the repository.
|
||||||
|
* @returns The default branch of the user's contribution target, or null if it's not known.
|
||||||
|
*
|
||||||
|
* This method will return the fork's upstream default branch, if the user
|
||||||
|
* is contributing to the parent repository.
|
||||||
|
*
|
||||||
|
* Otherwise, this method will return the default branch of the passed in repository.
|
||||||
|
*/
|
||||||
|
export function findContributionTargetDefaultBranch(
|
||||||
|
repository: Repository,
|
||||||
|
{ allBranches, defaultBranch }: IBranchesState
|
||||||
|
): Branch | null {
|
||||||
|
return isRepositoryWithGitHubRepository(repository)
|
||||||
|
? findDefaultUpstreamBranch(repository, allBranches) ?? defaultBranch
|
||||||
|
: defaultBranch
|
||||||
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ const allMenuIds: ReadonlyArray<MenuIDs> = [
|
||||||
'discard-all-changes',
|
'discard-all-changes',
|
||||||
'stash-all-changes',
|
'stash-all-changes',
|
||||||
'preferences',
|
'preferences',
|
||||||
'update-branch',
|
'update-branch-with-contribution-target-branch',
|
||||||
'compare-to-branch',
|
'compare-to-branch',
|
||||||
'merge-branch',
|
'merge-branch',
|
||||||
'rebase-branch',
|
'rebase-branch',
|
||||||
|
@ -261,7 +261,7 @@ function getRepositoryMenuBuilder(state: IAppState): MenuStateBuilder {
|
||||||
onNonDefaultBranch && !branchIsUnborn && !onDetachedHead
|
onNonDefaultBranch && !branchIsUnborn && !onDetachedHead
|
||||||
)
|
)
|
||||||
menuStateBuilder.setEnabled(
|
menuStateBuilder.setEnabled(
|
||||||
'update-branch',
|
'update-branch-with-contribution-target-branch',
|
||||||
onNonDefaultBranch && hasDefaultBranch && !onDetachedHead
|
onNonDefaultBranch && hasDefaultBranch && !onDetachedHead
|
||||||
)
|
)
|
||||||
menuStateBuilder.setEnabled('merge-branch', onBranch)
|
menuStateBuilder.setEnabled('merge-branch', onBranch)
|
||||||
|
@ -343,7 +343,7 @@ function getRepositoryMenuBuilder(state: IAppState): MenuStateBuilder {
|
||||||
menuStateBuilder.disable('delete-branch')
|
menuStateBuilder.disable('delete-branch')
|
||||||
menuStateBuilder.disable('discard-all-changes')
|
menuStateBuilder.disable('discard-all-changes')
|
||||||
menuStateBuilder.disable('stash-all-changes')
|
menuStateBuilder.disable('stash-all-changes')
|
||||||
menuStateBuilder.disable('update-branch')
|
menuStateBuilder.disable('update-branch-with-contribution-target-branch')
|
||||||
menuStateBuilder.disable('merge-branch')
|
menuStateBuilder.disable('merge-branch')
|
||||||
if (enableSquashMerging()) {
|
if (enableSquashMerging()) {
|
||||||
menuStateBuilder.disable('squash-and-merge-branch')
|
menuStateBuilder.disable('squash-and-merge-branch')
|
||||||
|
|
|
@ -12,6 +12,7 @@ export enum Shell {
|
||||||
Kitty = 'Kitty',
|
Kitty = 'Kitty',
|
||||||
Alacritty = 'Alacritty',
|
Alacritty = 'Alacritty',
|
||||||
WezTerm = 'WezTerm',
|
WezTerm = 'WezTerm',
|
||||||
|
Warp = 'Warp',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Default = Shell.Terminal
|
export const Default = Shell.Terminal
|
||||||
|
@ -36,6 +37,8 @@ function getBundleID(shell: Shell): string {
|
||||||
return 'io.alacritty'
|
return 'io.alacritty'
|
||||||
case Shell.WezTerm:
|
case Shell.WezTerm:
|
||||||
return 'com.github.wez.wezterm'
|
return 'com.github.wez.wezterm'
|
||||||
|
case Shell.Warp:
|
||||||
|
return 'dev.warp.Warp-Stable'
|
||||||
default:
|
default:
|
||||||
return assertNever(shell, `Unknown shell: ${shell}`)
|
return assertNever(shell, `Unknown shell: ${shell}`)
|
||||||
}
|
}
|
||||||
|
@ -62,6 +65,7 @@ export async function getAvailableShells(): Promise<
|
||||||
kittyPath,
|
kittyPath,
|
||||||
alacrittyPath,
|
alacrittyPath,
|
||||||
wezTermPath,
|
wezTermPath,
|
||||||
|
warpPath,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
getShellPath(Shell.Terminal),
|
getShellPath(Shell.Terminal),
|
||||||
getShellPath(Shell.Hyper),
|
getShellPath(Shell.Hyper),
|
||||||
|
@ -70,6 +74,7 @@ export async function getAvailableShells(): Promise<
|
||||||
getShellPath(Shell.Kitty),
|
getShellPath(Shell.Kitty),
|
||||||
getShellPath(Shell.Alacritty),
|
getShellPath(Shell.Alacritty),
|
||||||
getShellPath(Shell.WezTerm),
|
getShellPath(Shell.WezTerm),
|
||||||
|
getShellPath(Shell.Warp),
|
||||||
])
|
])
|
||||||
|
|
||||||
const shells: Array<IFoundShell<Shell>> = []
|
const shells: Array<IFoundShell<Shell>> = []
|
||||||
|
@ -104,6 +109,11 @@ export async function getAvailableShells(): Promise<
|
||||||
shells.push({ shell: Shell.WezTerm, path: wezTermExecutable })
|
shells.push({ shell: Shell.WezTerm, path: wezTermExecutable })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (warpPath) {
|
||||||
|
const warpExecutable = `${warpPath}/Contents/MacOS/stable`
|
||||||
|
shells.push({ shell: Shell.Warp, path: warpExecutable })
|
||||||
|
}
|
||||||
|
|
||||||
return shells
|
return shells
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,7 @@ import {
|
||||||
import * as ipcRenderer from '../ipc-renderer'
|
import * as ipcRenderer from '../ipc-renderer'
|
||||||
import { pathExists } from '../../ui/lib/path-exists'
|
import { pathExists } from '../../ui/lib/path-exists'
|
||||||
import { offsetFromNow } from '../offset-from'
|
import { offsetFromNow } from '../offset-from'
|
||||||
|
import { findContributionTargetDefaultBranch } from '../branch'
|
||||||
import { ValidNotificationPullRequestReview } from '../valid-notification-pull-request-review'
|
import { ValidNotificationPullRequestReview } from '../valid-notification-pull-request-review'
|
||||||
import { determineMergeability } from '../git/merge-tree'
|
import { determineMergeability } from '../git/merge-tree'
|
||||||
|
|
||||||
|
@ -1109,12 +1110,13 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This shouldn't be called directly. See `Dispatcher`. */
|
/** This shouldn't be called directly. See `Dispatcher`. */
|
||||||
public async _changeCommitSelection(
|
public _changeCommitSelection(
|
||||||
repository: Repository,
|
repository: Repository,
|
||||||
shas: ReadonlyArray<string>,
|
shas: ReadonlyArray<string>,
|
||||||
isContiguous: boolean
|
isContiguous: boolean
|
||||||
): Promise<void> {
|
): void {
|
||||||
const { commitSelection } = this.repositoryStateCache.get(repository)
|
const { commitSelection, commitLookup } =
|
||||||
|
this.repositoryStateCache.get(repository)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
commitSelection.shas.length === shas.length &&
|
commitSelection.shas.length === shas.length &&
|
||||||
|
@ -1123,8 +1125,11 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shasInDiff = this.getShasInDiff(shas, isContiguous, commitLookup)
|
||||||
|
|
||||||
this.repositoryStateCache.updateCommitSelection(repository, () => ({
|
this.repositoryStateCache.updateCommitSelection(repository, () => ({
|
||||||
shas,
|
shas,
|
||||||
|
shasInDiff,
|
||||||
isContiguous,
|
isContiguous,
|
||||||
file: null,
|
file: null,
|
||||||
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
||||||
|
@ -1134,6 +1139,65 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
||||||
this.emitUpdate()
|
this.emitUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** This shouldn't be called directly. See `Dispatcher`. */
|
||||||
|
public async _updateShasToHighlight(
|
||||||
|
repository: Repository,
|
||||||
|
shasToHighlight: ReadonlyArray<string>
|
||||||
|
) {
|
||||||
|
this.repositoryStateCache.updateCompareState(repository, () => ({
|
||||||
|
shasToHighlight,
|
||||||
|
}))
|
||||||
|
this.emitUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When multiple commits are selected, the diff is created using the rev range
|
||||||
|
* of firstSha^..lastSha in the selected shas. Thus comparing the trees of the
|
||||||
|
* the lastSha and the first parent of the first sha. However, our history
|
||||||
|
* list shows commits in chronological order. Thus, when a branch is merged,
|
||||||
|
* the commits from that branch are injected in their chronological order into
|
||||||
|
* the history list. Therefore, given a branch history of A, B, C, D,
|
||||||
|
* MergeCommit where B and C are from the merged branch, diffing on the
|
||||||
|
* selection of A through D would not have the changes from B an C.
|
||||||
|
*
|
||||||
|
* This method traverses the ancestral path from the last commit in the
|
||||||
|
* selection back to the first commit via checking the parents. The
|
||||||
|
* commits on this path are the commits whose changes will be seen in the
|
||||||
|
* diff. This is equivalent to doing `git rev-list firstSha^..lastSha`.
|
||||||
|
*/
|
||||||
|
private getShasInDiff(
|
||||||
|
selectedShas: ReadonlyArray<string>,
|
||||||
|
isContiguous: boolean,
|
||||||
|
commitLookup: Map<string, Commit>
|
||||||
|
) {
|
||||||
|
const shasInDiff = new Array<string>()
|
||||||
|
|
||||||
|
if (selectedShas.length <= 1 || !isContiguous) {
|
||||||
|
return selectedShas
|
||||||
|
}
|
||||||
|
|
||||||
|
const shasToTraverse = [selectedShas.at(-1)]
|
||||||
|
do {
|
||||||
|
const currentSha = shasToTraverse.pop()
|
||||||
|
if (currentSha === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
shasInDiff.push(currentSha)
|
||||||
|
|
||||||
|
// shas are selection of history -> should be in lookup -> `|| []` is for typing sake
|
||||||
|
const parentSHAs = commitLookup.get(currentSha)?.parentSHAs || []
|
||||||
|
|
||||||
|
const parentsInSelection = parentSHAs.filter(parentSha =>
|
||||||
|
selectedShas.includes(parentSha)
|
||||||
|
)
|
||||||
|
|
||||||
|
shasToTraverse.push(...parentsInSelection)
|
||||||
|
} while (shasToTraverse.length > 0)
|
||||||
|
|
||||||
|
return shasInDiff
|
||||||
|
}
|
||||||
|
|
||||||
private updateOrSelectFirstCommit(
|
private updateOrSelectFirstCommit(
|
||||||
repository: Repository,
|
repository: Repository,
|
||||||
commitSHAs: ReadonlyArray<string>
|
commitSHAs: ReadonlyArray<string>
|
||||||
|
@ -2036,6 +2100,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
||||||
private updateMenuItemLabels(state: IRepositoryState | null) {
|
private updateMenuItemLabels(state: IRepositoryState | null) {
|
||||||
const {
|
const {
|
||||||
selectedShell,
|
selectedShell,
|
||||||
|
selectedRepository,
|
||||||
selectedExternalEditor,
|
selectedExternalEditor,
|
||||||
askForConfirmationOnRepositoryRemoval,
|
askForConfirmationOnRepositoryRemoval,
|
||||||
askForConfirmationOnForcePush,
|
askForConfirmationOnForcePush,
|
||||||
|
@ -2054,12 +2119,14 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { changesState, branchesState, aheadBehind } = state
|
const { changesState, branchesState, aheadBehind } = state
|
||||||
const { defaultBranch, currentPullRequest } = branchesState
|
const { currentPullRequest } = branchesState
|
||||||
|
|
||||||
const defaultBranchName =
|
let contributionTargetDefaultBranch: string | undefined
|
||||||
defaultBranch === null || defaultBranch.upstreamWithoutRemote === null
|
if (selectedRepository instanceof Repository) {
|
||||||
? undefined
|
contributionTargetDefaultBranch =
|
||||||
: defaultBranch.upstreamWithoutRemote
|
findContributionTargetDefaultBranch(selectedRepository, branchesState)
|
||||||
|
?.name ?? undefined
|
||||||
|
}
|
||||||
|
|
||||||
const isForcePushForCurrentRepository = isCurrentBranchForcePush(
|
const isForcePushForCurrentRepository = isCurrentBranchForcePush(
|
||||||
branchesState,
|
branchesState,
|
||||||
|
@ -2074,7 +2141,7 @@ export class AppStore extends TypedBaseStore<IAppState> {
|
||||||
|
|
||||||
updatePreferredAppMenuItemLabels({
|
updatePreferredAppMenuItemLabels({
|
||||||
...labels,
|
...labels,
|
||||||
defaultBranchName,
|
contributionTargetDefaultBranch,
|
||||||
isForcePushForCurrentRepository,
|
isForcePushForCurrentRepository,
|
||||||
isStashedChangesVisible,
|
isStashedChangesVisible,
|
||||||
hasCurrentPullRequest: currentPullRequest !== null,
|
hasCurrentPullRequest: currentPullRequest !== null,
|
||||||
|
|
|
@ -178,6 +178,7 @@ function getInitialRepositoryState(): IRepositoryState {
|
||||||
return {
|
return {
|
||||||
commitSelection: {
|
commitSelection: {
|
||||||
shas: [],
|
shas: [],
|
||||||
|
shasInDiff: [],
|
||||||
isContiguous: true,
|
isContiguous: true,
|
||||||
file: null,
|
file: null,
|
||||||
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
changesetData: { files: [], linesAdded: 0, linesDeleted: 0 },
|
||||||
|
@ -219,6 +220,7 @@ function getInitialRepositoryState(): IRepositoryState {
|
||||||
showBranchList: false,
|
showBranchList: false,
|
||||||
filterText: '',
|
filterText: '',
|
||||||
commitSHAs: [],
|
commitSHAs: [],
|
||||||
|
shasToHighlight: [],
|
||||||
branches: new Array<Branch>(),
|
branches: new Array<Branch>(),
|
||||||
recentBranches: new Array<Branch>(),
|
recentBranches: new Array<Branch>(),
|
||||||
defaultBranch: null,
|
defaultBranch: null,
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {
|
||||||
installNotificationCallback,
|
installNotificationCallback,
|
||||||
terminateDesktopNotifications,
|
terminateDesktopNotifications,
|
||||||
} from './notifications'
|
} from './notifications'
|
||||||
|
import { addTrustedIPCSender } from './trusted-ipc-sender'
|
||||||
|
|
||||||
export class AppWindow {
|
export class AppWindow {
|
||||||
private window: Electron.BrowserWindow
|
private window: Electron.BrowserWindow
|
||||||
|
@ -77,6 +78,7 @@ export class AppWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.window = new BrowserWindow(windowOptions)
|
this.window = new BrowserWindow(windowOptions)
|
||||||
|
addTrustedIPCSender(this.window.webContents)
|
||||||
|
|
||||||
installNotificationCallback(this.window)
|
installNotificationCallback(this.window)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { ICrashDetails, ErrorType } from '../crash/shared'
|
||||||
import { registerWindowStateChangedEvents } from '../lib/window-state'
|
import { registerWindowStateChangedEvents } from '../lib/window-state'
|
||||||
import * as ipcMain from './ipc-main'
|
import * as ipcMain from './ipc-main'
|
||||||
import * as ipcWebContents from './ipc-webcontents'
|
import * as ipcWebContents from './ipc-webcontents'
|
||||||
|
import { addTrustedIPCSender } from './trusted-ipc-sender'
|
||||||
|
|
||||||
const minWidth = 600
|
const minWidth = 600
|
||||||
const minHeight = 500
|
const minHeight = 500
|
||||||
|
@ -51,6 +52,7 @@ export class CrashWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.window = new BrowserWindow(windowOptions)
|
this.window = new BrowserWindow(windowOptions)
|
||||||
|
addTrustedIPCSender(this.window.webContents)
|
||||||
|
|
||||||
this.error = error
|
this.error = error
|
||||||
this.errorType = errorType
|
this.errorType = errorType
|
||||||
|
|
|
@ -2,6 +2,17 @@ import { RequestChannels, RequestResponseChannels } from '../lib/ipc-shared'
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
import { ipcMain } from 'electron'
|
import { ipcMain } from 'electron'
|
||||||
import { IpcMainEvent, IpcMainInvokeEvent } from 'electron/main'
|
import { IpcMainEvent, IpcMainInvokeEvent } from 'electron/main'
|
||||||
|
import { isTrustedIPCSender } from './trusted-ipc-sender'
|
||||||
|
|
||||||
|
type RequestChannelListener<T extends keyof RequestChannels> = (
|
||||||
|
event: IpcMainEvent,
|
||||||
|
...args: Parameters<RequestChannels[T]>
|
||||||
|
) => void
|
||||||
|
|
||||||
|
type RequestResponseChannelListener<T extends keyof RequestResponseChannels> = (
|
||||||
|
event: IpcMainInvokeEvent,
|
||||||
|
...args: Parameters<RequestResponseChannels[T]>
|
||||||
|
) => ReturnType<RequestResponseChannels[T]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to the specified IPC channel and provides strong typing of
|
* Subscribes to the specified IPC channel and provides strong typing of
|
||||||
|
@ -10,12 +21,9 @@ import { IpcMainEvent, IpcMainInvokeEvent } from 'electron/main'
|
||||||
*/
|
*/
|
||||||
export function on<T extends keyof RequestChannels>(
|
export function on<T extends keyof RequestChannels>(
|
||||||
channel: T,
|
channel: T,
|
||||||
listener: (
|
listener: RequestChannelListener<T>
|
||||||
event: IpcMainEvent,
|
|
||||||
...args: Parameters<RequestChannels[T]>
|
|
||||||
) => void
|
|
||||||
) {
|
) {
|
||||||
ipcMain.on(channel, (event, ...args) => listener(event, ...(args as any)))
|
ipcMain.on(channel, safeListener(listener))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,12 +33,9 @@ export function on<T extends keyof RequestChannels>(
|
||||||
*/
|
*/
|
||||||
export function once<T extends keyof RequestChannels>(
|
export function once<T extends keyof RequestChannels>(
|
||||||
channel: T,
|
channel: T,
|
||||||
listener: (
|
listener: RequestChannelListener<T>
|
||||||
event: IpcMainEvent,
|
|
||||||
...args: Parameters<RequestChannels[T]>
|
|
||||||
) => void
|
|
||||||
) {
|
) {
|
||||||
ipcMain.once(channel, (event, ...args) => listener(event, ...(args as any)))
|
ipcMain.once(channel, safeListener(listener))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,10 +45,22 @@ export function once<T extends keyof RequestChannels>(
|
||||||
*/
|
*/
|
||||||
export function handle<T extends keyof RequestResponseChannels>(
|
export function handle<T extends keyof RequestResponseChannels>(
|
||||||
channel: T,
|
channel: T,
|
||||||
listener: (
|
listener: RequestResponseChannelListener<T>
|
||||||
event: IpcMainInvokeEvent,
|
|
||||||
...args: Parameters<RequestResponseChannels[T]>
|
|
||||||
) => ReturnType<RequestResponseChannels[T]>
|
|
||||||
) {
|
) {
|
||||||
ipcMain.handle(channel, (event, ...args) => listener(event, ...(args as any)))
|
ipcMain.handle(channel, safeListener(listener))
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeListener<E extends IpcMainEvent | IpcMainInvokeEvent, R>(
|
||||||
|
listener: (event: E, ...a: any) => R
|
||||||
|
) {
|
||||||
|
return (event: E, ...args: any) => {
|
||||||
|
if (!isTrustedIPCSender(event.sender)) {
|
||||||
|
log.error(
|
||||||
|
`IPC message received from invalid sender: ${event.senderFrame.url}`
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return listener(event, ...args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,12 +38,15 @@ export function buildDefaultMenu({
|
||||||
askForConfirmationOnForcePush,
|
askForConfirmationOnForcePush,
|
||||||
askForConfirmationOnRepositoryRemoval,
|
askForConfirmationOnRepositoryRemoval,
|
||||||
hasCurrentPullRequest = false,
|
hasCurrentPullRequest = false,
|
||||||
defaultBranchName = defaultBranchNameValue,
|
contributionTargetDefaultBranch = defaultBranchNameValue,
|
||||||
isForcePushForCurrentRepository = false,
|
isForcePushForCurrentRepository = false,
|
||||||
isStashedChangesVisible = false,
|
isStashedChangesVisible = false,
|
||||||
askForConfirmationWhenStashingAllChanges = true,
|
askForConfirmationWhenStashingAllChanges = true,
|
||||||
}: MenuLabelsEvent): Electron.Menu {
|
}: MenuLabelsEvent): Electron.Menu {
|
||||||
defaultBranchName = truncateWithEllipsis(defaultBranchName, 25)
|
contributionTargetDefaultBranch = truncateWithEllipsis(
|
||||||
|
contributionTargetDefaultBranch,
|
||||||
|
25
|
||||||
|
)
|
||||||
|
|
||||||
const removeRepoLabel = askForConfirmationOnRepositoryRemoval
|
const removeRepoLabel = askForConfirmationOnRepositoryRemoval
|
||||||
? confirmRepositoryRemovalLabel
|
? confirmRepositoryRemovalLabel
|
||||||
|
@ -376,11 +379,11 @@ export function buildDefaultMenu({
|
||||||
separator,
|
separator,
|
||||||
{
|
{
|
||||||
label: __DARWIN__
|
label: __DARWIN__
|
||||||
? `Update from ${defaultBranchName}`
|
? `Update from ${contributionTargetDefaultBranch}`
|
||||||
: `&Update from ${defaultBranchName}`,
|
: `&Update from ${contributionTargetDefaultBranch}`,
|
||||||
id: 'update-branch',
|
id: 'update-branch-with-contribution-target-branch',
|
||||||
accelerator: 'CmdOrCtrl+Shift+U',
|
accelerator: 'CmdOrCtrl+Shift+U',
|
||||||
click: emit('update-branch'),
|
click: emit('update-branch-with-contribution-target-branch'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __DARWIN__ ? 'Compare to Branch' : '&Compare to branch',
|
label: __DARWIN__ ? 'Compare to Branch' : '&Compare to branch',
|
||||||
|
|
|
@ -16,7 +16,7 @@ export type MenuEvent =
|
||||||
| 'show-preferences'
|
| 'show-preferences'
|
||||||
| 'choose-repository'
|
| 'choose-repository'
|
||||||
| 'open-working-directory'
|
| 'open-working-directory'
|
||||||
| 'update-branch'
|
| 'update-branch-with-contribution-target-branch'
|
||||||
| 'compare-to-branch'
|
| 'compare-to-branch'
|
||||||
| 'merge-branch'
|
| 'merge-branch'
|
||||||
| 'squash-and-merge-branch'
|
| 'squash-and-merge-branch'
|
||||||
|
|
|
@ -11,6 +11,11 @@ import * as ipcWebContents from './ipc-webcontents'
|
||||||
let windowsToastActivatorClsid: string | undefined = undefined
|
let windowsToastActivatorClsid: string | undefined = undefined
|
||||||
|
|
||||||
export function initializeDesktopNotifications() {
|
export function initializeDesktopNotifications() {
|
||||||
|
if (__LINUX__) {
|
||||||
|
// notifications not currently supported
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (__DARWIN__) {
|
if (__DARWIN__) {
|
||||||
initializeNotifications({})
|
initializeNotifications({})
|
||||||
return
|
return
|
||||||
|
@ -24,7 +29,7 @@ export function initializeDesktopNotifications() {
|
||||||
|
|
||||||
if (windowsToastActivatorClsid === undefined) {
|
if (windowsToastActivatorClsid === undefined) {
|
||||||
log.error(
|
log.error(
|
||||||
'Toast activator CLSID not found in any of the shortucts. Falling back to known CLSIDs.'
|
'Toast activator CLSID not found in any of the shortcuts. Falling back to known CLSIDs.'
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is generated by Squirrel.Windows here:
|
// This is generated by Squirrel.Windows here:
|
||||||
|
|
|
@ -17,16 +17,13 @@ export function showUncaughtException(isLaunchError: boolean, error: Error) {
|
||||||
|
|
||||||
setCrashMenu()
|
setCrashMenu()
|
||||||
|
|
||||||
const crashWindow = new CrashWindow(
|
const window = new CrashWindow(isLaunchError ? 'launch' : 'generic', error)
|
||||||
isLaunchError ? 'launch' : 'generic',
|
|
||||||
error
|
|
||||||
)
|
|
||||||
|
|
||||||
crashWindow.onDidLoad(() => {
|
window.onDidLoad(() => {
|
||||||
crashWindow.show()
|
window.show()
|
||||||
})
|
})
|
||||||
|
|
||||||
crashWindow.onFailedToLoad(async () => {
|
window.onFailedToLoad(async () => {
|
||||||
await dialog.showMessageBox({
|
await dialog.showMessageBox({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: __DARWIN__ ? `Unrecoverable Error` : 'Unrecoverable error',
|
title: __DARWIN__ ? `Unrecoverable Error` : 'Unrecoverable error',
|
||||||
|
@ -44,12 +41,12 @@ export function showUncaughtException(isLaunchError: boolean, error: Error) {
|
||||||
app.quit()
|
app.quit()
|
||||||
})
|
})
|
||||||
|
|
||||||
crashWindow.onClose(() => {
|
window.onClose(() => {
|
||||||
if (!__DEV__) {
|
if (!__DEV__) {
|
||||||
app.relaunch()
|
app.relaunch()
|
||||||
}
|
}
|
||||||
app.quit()
|
app.quit()
|
||||||
})
|
})
|
||||||
|
|
||||||
crashWindow.load()
|
window.load()
|
||||||
}
|
}
|
||||||
|
|
16
app/src/main-process/trusted-ipc-sender.ts
Normal file
16
app/src/main-process/trusted-ipc-sender.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { WebContents } from 'electron'
|
||||||
|
|
||||||
|
// WebContents id of trusted senders of IPC messages. This is used to verify
|
||||||
|
// that only IPC messages sent from trusted senders are handled, as recommended
|
||||||
|
// by the Electron security documentation:
|
||||||
|
// https://github.com/electron/electron/blob/main/docs/tutorial/security.md#17-validate-the-sender-of-all-ipc-messages
|
||||||
|
const trustedSenders = new Set<number>()
|
||||||
|
|
||||||
|
/** Adds a WebContents instance to the set of trusted IPC senders. */
|
||||||
|
export const addTrustedIPCSender = (wc: WebContents) => {
|
||||||
|
trustedSenders.add(wc.id)
|
||||||
|
wc.on('destroyed', () => trustedSenders.delete(wc.id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the given WebContents is a trusted sender of IPC messages. */
|
||||||
|
export const isTrustedIPCSender = (wc: WebContents) => trustedSenders.has(wc.id)
|
|
@ -5,7 +5,7 @@ export type MenuIDs =
|
||||||
| 'discard-all-changes'
|
| 'discard-all-changes'
|
||||||
| 'stash-all-changes'
|
| 'stash-all-changes'
|
||||||
| 'preferences'
|
| 'preferences'
|
||||||
| 'update-branch'
|
| 'update-branch-with-contribution-target-branch'
|
||||||
| 'merge-branch'
|
| 'merge-branch'
|
||||||
| 'squash-and-merge-branch'
|
| 'squash-and-merge-branch'
|
||||||
| 'rebase-branch'
|
| 'rebase-branch'
|
||||||
|
|
|
@ -28,11 +28,16 @@ export type MenuLabelsEvent = {
|
||||||
readonly askForConfirmationOnRepositoryRemoval: boolean
|
readonly askForConfirmationOnRepositoryRemoval: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify the default branch associated with the current repository.
|
* Specify the default branch of the user's contribution target.
|
||||||
|
*
|
||||||
|
* This value should be the fork's upstream default branch, if the user
|
||||||
|
* is contributing to the parent repository.
|
||||||
|
*
|
||||||
|
* Otherwise, this value should be the default branch of the repository.
|
||||||
*
|
*
|
||||||
* Omit this value to indicate that the default branch is unknown.
|
* Omit this value to indicate that the default branch is unknown.
|
||||||
*/
|
*/
|
||||||
readonly defaultBranchName?: string
|
readonly contributionTargetDefaultBranch?: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the current branch in a state where it can be force pushed to the remote?
|
* Is the current branch in a state where it can be force pushed to the remote?
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { IAuthor } from './author'
|
||||||
import { IRefCheck } from '../lib/ci-checks/ci-checks'
|
import { IRefCheck } from '../lib/ci-checks/ci-checks'
|
||||||
import { GitHubRepository } from './github-repository'
|
import { GitHubRepository } from './github-repository'
|
||||||
import { ValidNotificationPullRequestReview } from '../lib/valid-notification-pull-request-review'
|
import { ValidNotificationPullRequestReview } from '../lib/valid-notification-pull-request-review'
|
||||||
|
import { UnreachableCommitsTab } from '../ui/history/unreachable-commits-dialog'
|
||||||
|
|
||||||
export enum PopupType {
|
export enum PopupType {
|
||||||
RenameBranch = 1,
|
RenameBranch = 1,
|
||||||
|
@ -84,6 +85,7 @@ export enum PopupType {
|
||||||
WarnForcePush,
|
WarnForcePush,
|
||||||
DiscardChangesRetry,
|
DiscardChangesRetry,
|
||||||
PullRequestReview,
|
PullRequestReview,
|
||||||
|
UnreachableCommits,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Popup =
|
export type Popup =
|
||||||
|
@ -353,3 +355,7 @@ export type Popup =
|
||||||
shouldCheckoutBranch: boolean
|
shouldCheckoutBranch: boolean
|
||||||
shouldChangeRepository: boolean
|
shouldChangeRepository: boolean
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: PopupType.UnreachableCommits
|
||||||
|
selectedTab: UnreachableCommitsTab
|
||||||
|
}
|
||||||
|
|
|
@ -104,7 +104,10 @@ import { TutorialStep, isValidTutorialStep } from '../models/tutorial-step'
|
||||||
import { WorkflowPushRejectedDialog } from './workflow-push-rejected/workflow-push-rejected'
|
import { WorkflowPushRejectedDialog } from './workflow-push-rejected/workflow-push-rejected'
|
||||||
import { SAMLReauthRequiredDialog } from './saml-reauth-required/saml-reauth-required'
|
import { SAMLReauthRequiredDialog } from './saml-reauth-required/saml-reauth-required'
|
||||||
import { CreateForkDialog } from './forks/create-fork-dialog'
|
import { CreateForkDialog } from './forks/create-fork-dialog'
|
||||||
import { findDefaultUpstreamBranch } from '../lib/branch'
|
import {
|
||||||
|
findContributionTargetDefaultBranch,
|
||||||
|
findDefaultUpstreamBranch,
|
||||||
|
} from '../lib/branch'
|
||||||
import {
|
import {
|
||||||
GitHubRepository,
|
GitHubRepository,
|
||||||
hasWritePermission,
|
hasWritePermission,
|
||||||
|
@ -147,6 +150,7 @@ import { PullRequestChecksFailed } from './notifications/pull-request-checks-fai
|
||||||
import { CICheckRunRerunDialog } from './check-runs/ci-check-run-rerun-dialog'
|
import { CICheckRunRerunDialog } from './check-runs/ci-check-run-rerun-dialog'
|
||||||
import { WarnForcePushDialog } from './multi-commit-operation/dialog/warn-force-push-dialog'
|
import { WarnForcePushDialog } from './multi-commit-operation/dialog/warn-force-push-dialog'
|
||||||
import { clamp } from '../lib/clamp'
|
import { clamp } from '../lib/clamp'
|
||||||
|
import { generateRepositoryListContextMenu } from './repositories-list/repository-list-item-context-menu'
|
||||||
import * as ipcRenderer from '../lib/ipc-renderer'
|
import * as ipcRenderer from '../lib/ipc-renderer'
|
||||||
import { showNotification } from '../lib/notifications/show-notification'
|
import { showNotification } from '../lib/notifications/show-notification'
|
||||||
import { DiscardChangesRetryDialog } from './discard-changes/discard-changes-retry-dialog'
|
import { DiscardChangesRetryDialog } from './discard-changes/discard-changes-retry-dialog'
|
||||||
|
@ -155,6 +159,8 @@ import { PullRequestReview } from './notifications/pull-request-review'
|
||||||
import { getPullRequestCommitRef } from '../models/pull-request'
|
import { getPullRequestCommitRef } from '../models/pull-request'
|
||||||
import { getRepositoryType } from '../lib/git'
|
import { getRepositoryType } from '../lib/git'
|
||||||
import { SSHUserPassword } from './ssh/ssh-user-password'
|
import { SSHUserPassword } from './ssh/ssh-user-password'
|
||||||
|
import { showContextualMenu } from '../lib/menu-item'
|
||||||
|
import { UnreachableCommitsDialog } from './history/unreachable-commits-dialog'
|
||||||
|
|
||||||
const MinuteInMilliseconds = 1000 * 60
|
const MinuteInMilliseconds = 1000 * 60
|
||||||
const HourInMilliseconds = MinuteInMilliseconds * 60
|
const HourInMilliseconds = MinuteInMilliseconds * 60
|
||||||
|
@ -382,9 +388,9 @@ export class App extends React.Component<IAppProps, IAppState> {
|
||||||
return this.props.dispatcher.showPopup({ type: PopupType.Preferences })
|
return this.props.dispatcher.showPopup({ type: PopupType.Preferences })
|
||||||
case 'open-working-directory':
|
case 'open-working-directory':
|
||||||
return this.openCurrentRepositoryWorkingDirectory()
|
return this.openCurrentRepositoryWorkingDirectory()
|
||||||
case 'update-branch':
|
case 'update-branch-with-contribution-target-branch':
|
||||||
this.props.dispatcher.recordMenuInitiatedUpdate()
|
this.props.dispatcher.recordMenuInitiatedUpdate()
|
||||||
return this.updateBranch()
|
return this.updateBranchWithContributionTargetBranch()
|
||||||
case 'compare-to-branch':
|
case 'compare-to-branch':
|
||||||
return this.showHistory(true)
|
return this.showHistory(true)
|
||||||
case 'merge-branch':
|
case 'merge-branch':
|
||||||
|
@ -635,7 +641,7 @@ export class App extends React.Component<IAppProps, IAppState> {
|
||||||
return enterpriseAccount || null
|
return enterpriseAccount || null
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateBranch() {
|
private updateBranchWithContributionTargetBranch() {
|
||||||
const { selectedState } = this.state
|
const { selectedState } = this.state
|
||||||
if (
|
if (
|
||||||
selectedState == null ||
|
selectedState == null ||
|
||||||
|
@ -645,19 +651,27 @@ export class App extends React.Component<IAppProps, IAppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { state, repository } = selectedState
|
const { state, repository } = selectedState
|
||||||
const defaultBranch = state.branchesState.defaultBranch
|
|
||||||
if (!defaultBranch) {
|
const contributionTargetDefaultBranch = findContributionTargetDefaultBranch(
|
||||||
|
repository,
|
||||||
|
state.branchesState
|
||||||
|
)
|
||||||
|
if (!contributionTargetDefaultBranch) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatcher.initializeMergeOperation(
|
this.props.dispatcher.initializeMergeOperation(
|
||||||
repository,
|
repository,
|
||||||
false,
|
false,
|
||||||
defaultBranch
|
contributionTargetDefaultBranch
|
||||||
)
|
)
|
||||||
|
|
||||||
const { mergeStatus } = state.compareState
|
const { mergeStatus } = state.compareState
|
||||||
this.props.dispatcher.mergeBranch(repository, defaultBranch, mergeStatus)
|
this.props.dispatcher.mergeBranch(
|
||||||
|
repository,
|
||||||
|
contributionTargetDefaultBranch,
|
||||||
|
mergeStatus
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private mergeBranch(isSquash: boolean = false) {
|
private mergeBranch(isSquash: boolean = false) {
|
||||||
|
@ -2201,6 +2215,31 @@ export class App extends React.Component<IAppProps, IAppState> {
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
case PopupType.UnreachableCommits: {
|
||||||
|
const { selectedState, emoji } = this.state
|
||||||
|
if (
|
||||||
|
selectedState == null ||
|
||||||
|
selectedState.type !== SelectionType.Repository
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
commitLookup,
|
||||||
|
commitSelection: { shas, shasInDiff },
|
||||||
|
} = selectedState.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UnreachableCommitsDialog
|
||||||
|
selectedShas={shas}
|
||||||
|
shasInDiff={shasInDiff}
|
||||||
|
commitLookup={commitLookup}
|
||||||
|
selectedTab={popup.selectedTab}
|
||||||
|
emoji={emoji}
|
||||||
|
onDismissed={onPopupDismissedFn}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return assertNever(popup, `Unknown popup type: ${popup}`)
|
return assertNever(popup, `Unknown popup type: ${popup}`)
|
||||||
}
|
}
|
||||||
|
@ -2555,6 +2594,7 @@ export class App extends React.Component<IAppProps, IAppState> {
|
||||||
description={__DARWIN__ ? 'Current Repository' : 'Current repository'}
|
description={__DARWIN__ ? 'Current Repository' : 'Current repository'}
|
||||||
tooltip={tooltip}
|
tooltip={tooltip}
|
||||||
foldoutStyle={foldoutStyle}
|
foldoutStyle={foldoutStyle}
|
||||||
|
onContextMenu={this.onRepositoryToolbarButtonContextMenu}
|
||||||
onDropdownStateChanged={this.onRepositoryDropdownStateChanged}
|
onDropdownStateChanged={this.onRepositoryDropdownStateChanged}
|
||||||
dropdownContentRenderer={this.renderRepositoryList}
|
dropdownContentRenderer={this.renderRepositoryList}
|
||||||
dropdownState={currentState}
|
dropdownState={currentState}
|
||||||
|
@ -2562,6 +2602,43 @@ export class App extends React.Component<IAppProps, IAppState> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onRepositoryToolbarButtonContextMenu = () => {
|
||||||
|
const repository = this.state.selectedState?.repository
|
||||||
|
if (repository === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const externalEditorLabel = this.state.selectedExternalEditor ?? undefined
|
||||||
|
|
||||||
|
const onChangeRepositoryAlias = (repository: Repository) => {
|
||||||
|
this.props.dispatcher.showPopup({
|
||||||
|
type: PopupType.ChangeRepositoryAlias,
|
||||||
|
repository,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onRemoveRepositoryAlias = (repository: Repository) => {
|
||||||
|
this.props.dispatcher.changeRepositoryAlias(repository, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = generateRepositoryListContextMenu({
|
||||||
|
onRemoveRepository: this.removeRepository,
|
||||||
|
onShowRepository: this.showRepository,
|
||||||
|
onOpenInShell: this.openInShell,
|
||||||
|
onOpenInExternalEditor: this.openInExternalEditor,
|
||||||
|
askForConfirmationOnRemoveRepository:
|
||||||
|
this.state.askForConfirmationOnRepositoryRemoval,
|
||||||
|
externalEditorLabel: externalEditorLabel,
|
||||||
|
onChangeRepositoryAlias: onChangeRepositoryAlias,
|
||||||
|
onRemoveRepositoryAlias: onRemoveRepositoryAlias,
|
||||||
|
onViewOnGitHub: this.viewOnGitHub,
|
||||||
|
repository: repository,
|
||||||
|
shellLabel: this.state.selectedShell,
|
||||||
|
})
|
||||||
|
|
||||||
|
showContextualMenu(items)
|
||||||
|
}
|
||||||
|
|
||||||
private renderPushPullToolbarButton() {
|
private renderPushPullToolbarButton() {
|
||||||
const selection = this.state.selectedState
|
const selection = this.state.selectedState
|
||||||
if (!selection || selection.type !== SelectionType.Repository) {
|
if (!selection || selection.type !== SelectionType.Repository) {
|
||||||
|
|
40
app/src/ui/branches/branch-list-item-context-menu.tsx
Normal file
40
app/src/ui/branches/branch-list-item-context-menu.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { IMenuItem } from '../../lib/menu-item'
|
||||||
|
import { clipboard } from 'electron'
|
||||||
|
|
||||||
|
interface IBranchContextMenuConfig {
|
||||||
|
name: string
|
||||||
|
isLocal: boolean
|
||||||
|
onRenameBranch?: (branchName: string) => void
|
||||||
|
onDeleteBranch?: (branchName: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateBranchContextMenuItems(
|
||||||
|
config: IBranchContextMenuConfig
|
||||||
|
): IMenuItem[] {
|
||||||
|
const { name, isLocal, onRenameBranch, onDeleteBranch } = config
|
||||||
|
const items = new Array<IMenuItem>()
|
||||||
|
|
||||||
|
if (onRenameBranch !== undefined) {
|
||||||
|
items.push({
|
||||||
|
label: 'Rename…',
|
||||||
|
action: () => onRenameBranch(name),
|
||||||
|
enabled: isLocal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
label: __DARWIN__ ? 'Copy Branch Name' : 'Copy branch name',
|
||||||
|
action: () => clipboard.writeText(name),
|
||||||
|
})
|
||||||
|
|
||||||
|
items.push({ type: 'separator' })
|
||||||
|
|
||||||
|
if (onDeleteBranch !== undefined) {
|
||||||
|
items.push({
|
||||||
|
label: 'Delete…',
|
||||||
|
action: () => onDeleteBranch(name),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
import { clipboard } from 'electron'
|
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
import { IMatches } from '../../lib/fuzzy-find'
|
import { IMatches } from '../../lib/fuzzy-find'
|
||||||
|
@ -7,12 +6,12 @@ import { Octicon } from '../octicons'
|
||||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||||
import { HighlightText } from '../lib/highlight-text'
|
import { HighlightText } from '../lib/highlight-text'
|
||||||
import { showContextualMenu } from '../../lib/menu-item'
|
import { showContextualMenu } from '../../lib/menu-item'
|
||||||
import { IMenuItem } from '../../lib/menu-item'
|
|
||||||
import { dragAndDropManager } from '../../lib/drag-and-drop-manager'
|
import { dragAndDropManager } from '../../lib/drag-and-drop-manager'
|
||||||
import { DragType, DropTargetType } from '../../models/drag-drop'
|
import { DragType, DropTargetType } from '../../models/drag-drop'
|
||||||
import { TooltippedContent } from '../lib/tooltipped-content'
|
import { TooltippedContent } from '../lib/tooltipped-content'
|
||||||
import { RelativeTime } from '../relative-time'
|
import { RelativeTime } from '../relative-time'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import { generateBranchContextMenuItems } from './branch-list-item-context-menu'
|
||||||
|
|
||||||
interface IBranchListItemProps {
|
interface IBranchListItemProps {
|
||||||
/** The name of the branch */
|
/** The name of the branch */
|
||||||
|
@ -74,29 +73,12 @@ export class BranchListItem extends React.Component<
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const items: Array<IMenuItem> = []
|
const items = generateBranchContextMenuItems({
|
||||||
|
name,
|
||||||
if (onRenameBranch !== undefined) {
|
isLocal,
|
||||||
items.push({
|
onRenameBranch,
|
||||||
label: 'Rename…',
|
onDeleteBranch,
|
||||||
action: () => onRenameBranch(name),
|
|
||||||
enabled: isLocal,
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
items.push({
|
|
||||||
label: __DARWIN__ ? 'Copy Branch Name' : 'Copy branch name',
|
|
||||||
action: () => clipboard.writeText(name),
|
|
||||||
})
|
|
||||||
|
|
||||||
items.push({ type: 'separator' })
|
|
||||||
|
|
||||||
if (onDeleteBranch !== undefined) {
|
|
||||||
items.push({
|
|
||||||
label: 'Delete…',
|
|
||||||
action: () => onDeleteBranch(name),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
showContextualMenu(items)
|
showContextualMenu(items)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
Repository,
|
Repository,
|
||||||
isRepositoryWithGitHubRepository,
|
isRepositoryWithGitHubRepository,
|
||||||
} from '../../models/repository'
|
} from '../../models/repository'
|
||||||
import { Branch, BranchType } from '../../models/branch'
|
import { Branch } from '../../models/branch'
|
||||||
import { BranchesTab } from '../../models/branches-tab'
|
import { BranchesTab } from '../../models/branches-tab'
|
||||||
import { PopupType } from '../../models/popup'
|
import { PopupType } from '../../models/popup'
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ interface IBranchesContainerProps {
|
||||||
readonly currentBranch: Branch | null
|
readonly currentBranch: Branch | null
|
||||||
readonly recentBranches: ReadonlyArray<Branch>
|
readonly recentBranches: ReadonlyArray<Branch>
|
||||||
readonly pullRequests: ReadonlyArray<PullRequest>
|
readonly pullRequests: ReadonlyArray<PullRequest>
|
||||||
|
readonly onRenameBranch: (branchName: string) => void
|
||||||
|
readonly onDeleteBranch: (branchName: string) => void
|
||||||
|
|
||||||
/** The pull request associated with the current branch. */
|
/** The pull request associated with the current branch. */
|
||||||
readonly currentPullRequest: PullRequest | null
|
readonly currentPullRequest: PullRequest | null
|
||||||
|
@ -204,8 +206,8 @@ export class BranchesContainer extends React.Component<
|
||||||
item,
|
item,
|
||||||
matches,
|
matches,
|
||||||
this.props.currentBranch,
|
this.props.currentBranch,
|
||||||
this.onRenameBranch,
|
this.props.onRenameBranch,
|
||||||
this.onDeleteBranch,
|
this.props.onDeleteBranch,
|
||||||
this.onDropOntoBranch,
|
this.onDropOntoBranch,
|
||||||
this.onDropOntoCurrentBranch
|
this.onDropOntoCurrentBranch
|
||||||
)
|
)
|
||||||
|
@ -401,52 +403,6 @@ export class BranchesContainer extends React.Component<
|
||||||
this.setState({ selectedPullRequest })
|
this.setState({ selectedPullRequest })
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBranchWithName(branchName: string): Branch | undefined {
|
|
||||||
return this.props.allBranches.find(branch => branch.name === branchName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private onRenameBranch = (branchName: string) => {
|
|
||||||
const branch = this.getBranchWithName(branchName)
|
|
||||||
|
|
||||||
if (branch === undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.dispatcher.showPopup({
|
|
||||||
type: PopupType.RenameBranch,
|
|
||||||
repository: this.props.repository,
|
|
||||||
branch: branch,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private onDeleteBranch = async (branchName: string) => {
|
|
||||||
const branch = this.getBranchWithName(branchName)
|
|
||||||
|
|
||||||
if (branch === undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (branch.type === BranchType.Remote) {
|
|
||||||
this.props.dispatcher.showPopup({
|
|
||||||
type: PopupType.DeleteRemoteBranch,
|
|
||||||
repository: this.props.repository,
|
|
||||||
branch,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const aheadBehind = await this.props.dispatcher.getBranchAheadBehind(
|
|
||||||
this.props.repository,
|
|
||||||
branch
|
|
||||||
)
|
|
||||||
this.props.dispatcher.showPopup({
|
|
||||||
type: PopupType.DeleteBranch,
|
|
||||||
repository: this.props.repository,
|
|
||||||
branch,
|
|
||||||
existsOnRemote: aheadBehind !== null,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method is to handle when something is dragged and dropped onto a branch
|
* Method is to handle when something is dragged and dropped onto a branch
|
||||||
* in the branch dropdown.
|
* in the branch dropdown.
|
||||||
|
|
|
@ -187,6 +187,10 @@ export class CloneRepository extends React.Component<
|
||||||
if (prevProps.selectedTab !== this.props.selectedTab) {
|
if (prevProps.selectedTab !== this.props.selectedTab) {
|
||||||
this.validatePath()
|
this.validatePath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prevProps.initialURL !== this.props.initialURL) {
|
||||||
|
this.updateUrl(this.props.initialURL || '')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
|
|
|
@ -237,10 +237,18 @@ export class Dispatcher {
|
||||||
repository: Repository,
|
repository: Repository,
|
||||||
shas: ReadonlyArray<string>,
|
shas: ReadonlyArray<string>,
|
||||||
isContiguous: boolean
|
isContiguous: boolean
|
||||||
): Promise<void> {
|
): void {
|
||||||
return this.appStore._changeCommitSelection(repository, shas, isContiguous)
|
return this.appStore._changeCommitSelection(repository, shas, isContiguous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Update the shas that should be highlighted */
|
||||||
|
public updateShasToHighlight(
|
||||||
|
repository: Repository,
|
||||||
|
shasToHighlight: ReadonlyArray<string>
|
||||||
|
) {
|
||||||
|
this.appStore._updateShasToHighlight(repository, shasToHighlight)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the selected changed file in the history view.
|
* Change the selected changed file in the history view.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { CommitListItem } from './commit-list-item'
|
||||||
import { List } from '../lib/list'
|
import { List } from '../lib/list'
|
||||||
import { arrayEquals } from '../../lib/equality'
|
import { arrayEquals } from '../../lib/equality'
|
||||||
import { DragData, DragType } from '../../models/drag-drop'
|
import { DragData, DragType } from '../../models/drag-drop'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
const RowHeight = 50
|
const RowHeight = 50
|
||||||
|
|
||||||
|
@ -23,13 +24,13 @@ interface ICommitListProps {
|
||||||
readonly selectedSHAs: ReadonlyArray<string>
|
readonly selectedSHAs: ReadonlyArray<string>
|
||||||
|
|
||||||
/** Whether or not commits in this list can be undone. */
|
/** Whether or not commits in this list can be undone. */
|
||||||
readonly canUndoCommits: boolean
|
readonly canUndoCommits?: boolean
|
||||||
|
|
||||||
/** Whether or not commits in this list can be amended. */
|
/** Whether or not commits in this list can be amended. */
|
||||||
readonly canAmendCommits: boolean
|
readonly canAmendCommits?: boolean
|
||||||
|
|
||||||
/** Whether or the user can reset to commits in this list. */
|
/** Whether or the user can reset to commits in this list. */
|
||||||
readonly canResetToCommits: boolean
|
readonly canResetToCommits?: boolean
|
||||||
|
|
||||||
/** The emoji lookup to render images inline */
|
/** The emoji lookup to render images inline */
|
||||||
readonly emoji: Map<string, string>
|
readonly emoji: Map<string, string>
|
||||||
|
@ -38,42 +39,42 @@ interface ICommitListProps {
|
||||||
readonly localCommitSHAs: ReadonlyArray<string>
|
readonly localCommitSHAs: ReadonlyArray<string>
|
||||||
|
|
||||||
/** The message to display inside the list when no results are displayed */
|
/** The message to display inside the list when no results are displayed */
|
||||||
readonly emptyListMessage: JSX.Element | string
|
readonly emptyListMessage?: JSX.Element | string
|
||||||
|
|
||||||
/** Callback which fires when a commit has been selected in the list */
|
/** Callback which fires when a commit has been selected in the list */
|
||||||
readonly onCommitsSelected: (
|
readonly onCommitsSelected?: (
|
||||||
commits: ReadonlyArray<Commit>,
|
commits: ReadonlyArray<Commit>,
|
||||||
isContiguous: boolean
|
isContiguous: boolean
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
/** Callback that fires when a scroll event has occurred */
|
/** Callback that fires when a scroll event has occurred */
|
||||||
readonly onScroll: (start: number, end: number) => void
|
readonly onScroll?: (start: number, end: number) => void
|
||||||
|
|
||||||
/** Callback to fire to undo a given commit in the current repository */
|
/** Callback to fire to undo a given commit in the current repository */
|
||||||
readonly onUndoCommit: ((commit: Commit) => void) | undefined
|
readonly onUndoCommit?: (commit: Commit) => void
|
||||||
|
|
||||||
/** Callback to fire to reset to a given commit in the current repository */
|
/** Callback to fire to reset to a given commit in the current repository */
|
||||||
readonly onResetToCommit: (commit: Commit) => void
|
readonly onResetToCommit?: (commit: Commit) => void
|
||||||
|
|
||||||
/** Callback to fire to revert a given commit in the current repository */
|
/** Callback to fire to revert a given commit in the current repository */
|
||||||
readonly onRevertCommit: ((commit: Commit) => void) | undefined
|
readonly onRevertCommit?: (commit: Commit) => void
|
||||||
|
|
||||||
readonly onAmendCommit?: (commit: Commit, isLocalCommit: boolean) => void
|
readonly onAmendCommit?: (commit: Commit, isLocalCommit: boolean) => void
|
||||||
|
|
||||||
/** Callback to fire to open a given commit on GitHub */
|
/** Callback to fire to open a given commit on GitHub */
|
||||||
readonly onViewCommitOnGitHub: (sha: string) => void
|
readonly onViewCommitOnGitHub?: (sha: string) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to fire to create a branch from a given commit in the current
|
* Callback to fire to create a branch from a given commit in the current
|
||||||
* repository
|
* repository
|
||||||
*/
|
*/
|
||||||
readonly onCreateBranch: (commit: CommitOneLine) => void
|
readonly onCreateBranch?: (commit: CommitOneLine) => void
|
||||||
|
|
||||||
/** Callback to fire to open the dialog to create a new tag on the given commit */
|
/** Callback to fire to open the dialog to create a new tag on the given commit */
|
||||||
readonly onCreateTag: (targetCommitSha: string) => void
|
readonly onCreateTag?: (targetCommitSha: string) => void
|
||||||
|
|
||||||
/** Callback to fire to delete an unpushed tag */
|
/** Callback to fire to delete an unpushed tag */
|
||||||
readonly onDeleteTag: (tagName: string) => void
|
readonly onDeleteTag?: (tagName: string) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handler called whenever the user drops commits on the list to be inserted.
|
* A handler called whenever the user drops commits on the list to be inserted.
|
||||||
|
@ -90,10 +91,10 @@ interface ICommitListProps {
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
/** Callback to fire to cherry picking the commit */
|
/** Callback to fire to cherry picking the commit */
|
||||||
readonly onCherryPick: (commits: ReadonlyArray<CommitOneLine>) => void
|
readonly onCherryPick?: (commits: ReadonlyArray<CommitOneLine>) => void
|
||||||
|
|
||||||
/** Callback to fire to squashing commits */
|
/** Callback to fire to squashing commits */
|
||||||
readonly onSquash: (
|
readonly onSquash?: (
|
||||||
toSquash: ReadonlyArray<Commit>,
|
toSquash: ReadonlyArray<Commit>,
|
||||||
squashOnto: Commit,
|
squashOnto: Commit,
|
||||||
lastRetainedCommitRef: string | null,
|
lastRetainedCommitRef: string | null,
|
||||||
|
@ -113,25 +114,28 @@ interface ICommitListProps {
|
||||||
readonly isLocalRepository: boolean
|
readonly isLocalRepository: boolean
|
||||||
|
|
||||||
/* Tags that haven't been pushed yet. This is used to show the unpushed indicator */
|
/* Tags that haven't been pushed yet. This is used to show the unpushed indicator */
|
||||||
readonly tagsToPush: ReadonlyArray<string> | null
|
readonly tagsToPush?: ReadonlyArray<string>
|
||||||
|
|
||||||
/** Whether or not commits in this list can be reordered. */
|
/** Whether or not commits in this list can be reordered. */
|
||||||
readonly reorderingEnabled: boolean
|
readonly reorderingEnabled?: boolean
|
||||||
|
|
||||||
/** Whether a cherry pick is progress */
|
/** Whether a cherry pick is progress */
|
||||||
readonly isCherryPickInProgress: boolean
|
readonly isCherryPickInProgress?: boolean
|
||||||
|
|
||||||
/** Callback to render commit drag element */
|
/** Callback to render commit drag element */
|
||||||
readonly onRenderCommitDragElement: (
|
readonly onRenderCommitDragElement?: (
|
||||||
commit: Commit,
|
commit: Commit,
|
||||||
selectedCommits: ReadonlyArray<Commit>
|
selectedCommits: ReadonlyArray<Commit>
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
/** Callback to remove commit drag element */
|
/** Callback to remove commit drag element */
|
||||||
readonly onRemoveCommitDragElement: () => void
|
readonly onRemoveCommitDragElement?: () => void
|
||||||
|
|
||||||
/** Whether squashing should be enabled on the commit list */
|
/** Whether squashing should be enabled on the commit list */
|
||||||
readonly disableSquashing?: boolean
|
readonly disableSquashing?: boolean
|
||||||
|
|
||||||
|
/** Shas that should be highlighted */
|
||||||
|
readonly shasToHighlight?: ReadonlyArray<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A component which displays the list of commits. */
|
/** A component which displays the list of commits. */
|
||||||
|
@ -163,7 +167,7 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsToPushSet = new Set(this.props.tagsToPush || [])
|
const tagsToPushSet = new Set(this.props.tagsToPush ?? [])
|
||||||
|
|
||||||
const isLocal = this.props.localCommitSHAs.includes(commit.sha)
|
const isLocal = this.props.localCommitSHAs.includes(commit.sha)
|
||||||
const unpushedTags = commit.tags.filter(tagName =>
|
const unpushedTags = commit.tags.filter(tagName =>
|
||||||
|
@ -185,9 +189,11 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
key={commit.sha}
|
key={commit.sha}
|
||||||
gitHubRepository={this.props.gitHubRepository}
|
gitHubRepository={this.props.gitHubRepository}
|
||||||
isLocal={isLocal}
|
isLocal={isLocal}
|
||||||
canBeUndone={this.props.canUndoCommits && isLocal && row === 0}
|
canBeUndone={this.props.canUndoCommits === true && isLocal && row === 0}
|
||||||
canBeAmended={this.props.canAmendCommits && row === 0}
|
canBeAmended={this.props.canAmendCommits === true && row === 0}
|
||||||
canBeResetTo={this.props.canResetToCommits && isResettableCommit}
|
canBeResetTo={
|
||||||
|
this.props.canResetToCommits === true && isResettableCommit
|
||||||
|
}
|
||||||
showUnpushedIndicator={showUnpushedIndicator}
|
showUnpushedIndicator={showUnpushedIndicator}
|
||||||
unpushedIndicatorTitle={this.getUnpushedIndicatorTitle(
|
unpushedIndicatorTitle={this.getUnpushedIndicatorTitle(
|
||||||
isLocal,
|
isLocal,
|
||||||
|
@ -233,7 +239,7 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
const indexes = [...toSquash, squashOnto].map(v =>
|
const indexes = [...toSquash, squashOnto].map(v =>
|
||||||
this.props.commitSHAs.findIndex(sha => sha === v.sha)
|
this.props.commitSHAs.findIndex(sha => sha === v.sha)
|
||||||
)
|
)
|
||||||
this.props.onSquash(
|
this.props.onSquash?.(
|
||||||
toSquash,
|
toSquash,
|
||||||
squashOnto,
|
squashOnto,
|
||||||
this.getLastRetainedCommitRef(indexes),
|
this.getLastRetainedCommitRef(indexes),
|
||||||
|
@ -242,7 +248,7 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRenderCommitDragElement = (commit: Commit) => {
|
private onRenderCommitDragElement = (commit: Commit) => {
|
||||||
this.props.onRenderCommitDragElement(
|
this.props.onRenderCommitDragElement?.(
|
||||||
commit,
|
commit,
|
||||||
this.lookupCommits(this.props.selectedSHAs)
|
this.lookupCommits(this.props.selectedSHAs)
|
||||||
)
|
)
|
||||||
|
@ -274,7 +280,7 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
const sorted = [...rows].sort((a, b) => b - a)
|
const sorted = [...rows].sort((a, b) => b - a)
|
||||||
const selectedShas = sorted.map(r => this.props.commitSHAs[r])
|
const selectedShas = sorted.map(r => this.props.commitSHAs[r])
|
||||||
const selectedCommits = this.lookupCommits(selectedShas)
|
const selectedCommits = this.lookupCommits(selectedShas)
|
||||||
this.props.onCommitsSelected(selectedCommits, this.isContiguous(sorted))
|
this.props.onCommitsSelected?.(selectedCommits, this.isContiguous(sorted))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -308,7 +314,7 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
const sha = this.props.commitSHAs[row]
|
const sha = this.props.commitSHAs[row]
|
||||||
const commit = this.props.commitLookup.get(sha)
|
const commit = this.props.commitLookup.get(sha)
|
||||||
if (commit) {
|
if (commit) {
|
||||||
this.props.onCommitsSelected([commit], true)
|
this.props.onCommitsSelected?.([commit], true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,12 +339,10 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
const numberOfRows = Math.ceil(clientHeight / RowHeight)
|
const numberOfRows = Math.ceil(clientHeight / RowHeight)
|
||||||
const top = Math.floor(scrollTop / RowHeight)
|
const top = Math.floor(scrollTop / RowHeight)
|
||||||
const bottom = top + numberOfRows
|
const bottom = top + numberOfRows
|
||||||
this.props.onScroll(top, bottom)
|
this.props.onScroll?.(top, bottom)
|
||||||
|
|
||||||
// Pass new scroll value so the scroll position will be remembered (if the callback has been supplied).
|
// Pass new scroll value so the scroll position will be remembered (if the callback has been supplied).
|
||||||
if (this.props.onCompareListScrolled != null) {
|
this.props.onCompareListScrolled?.(scrollTop)
|
||||||
this.props.onCompareListScrolled(scrollTop)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private rowForSHA(sha_: string | null): number {
|
private rowForSHA(sha_: string | null): number {
|
||||||
|
@ -350,19 +354,47 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
return this.props.commitSHAs.findIndex(s => s === sha)
|
return this.props.commitSHAs.findIndex(s => s === sha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getRowCustomClassMap = () => {
|
||||||
|
const { commitSHAs, shasToHighlight } = this.props
|
||||||
|
if (shasToHighlight === undefined || shasToHighlight.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowsForShasNotInDiff = commitSHAs
|
||||||
|
.filter(sha => shasToHighlight.includes(sha))
|
||||||
|
.map(sha => this.rowForSHA(sha))
|
||||||
|
|
||||||
|
if (rowsForShasNotInDiff.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowClassMap = new Map<string, ReadonlyArray<number>>()
|
||||||
|
rowClassMap.set('highlighted', rowsForShasNotInDiff)
|
||||||
|
return rowClassMap
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
if (this.props.commitSHAs.length === 0) {
|
const { commitSHAs, selectedSHAs, shasToHighlight, emptyListMessage } =
|
||||||
|
this.props
|
||||||
|
if (commitSHAs.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="panel blankslate">{this.props.emptyListMessage}</div>
|
<div className="panel blankslate">
|
||||||
|
{emptyListMessage ?? 'No commits to list'}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const classes = classNames({
|
||||||
|
'has-highlighted-commits':
|
||||||
|
shasToHighlight !== undefined && shasToHighlight.length > 0,
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="commit-list">
|
<div id="commit-list" className={classes}>
|
||||||
<List
|
<List
|
||||||
rowCount={this.props.commitSHAs.length}
|
rowCount={commitSHAs.length}
|
||||||
rowHeight={RowHeight}
|
rowHeight={RowHeight}
|
||||||
selectedRows={this.props.selectedSHAs.map(sha => this.rowForSHA(sha))}
|
selectedRows={selectedSHAs.map(sha => this.rowForSHA(sha))}
|
||||||
rowRenderer={this.renderCommit}
|
rowRenderer={this.renderCommit}
|
||||||
onDropDataInsertion={this.onDropDataInsertion}
|
onDropDataInsertion={this.onDropDataInsertion}
|
||||||
onSelectionChanged={this.onSelectionChanged}
|
onSelectionChanged={this.onSelectionChanged}
|
||||||
|
@ -370,15 +402,17 @@ export class CommitList extends React.Component<ICommitListProps, {}> {
|
||||||
selectionMode="multi"
|
selectionMode="multi"
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
insertionDragType={
|
insertionDragType={
|
||||||
this.props.reorderingEnabled ? DragType.Commit : undefined
|
this.props.reorderingEnabled === true ? DragType.Commit : undefined
|
||||||
}
|
}
|
||||||
invalidationProps={{
|
invalidationProps={{
|
||||||
commits: this.props.commitSHAs,
|
commits: this.props.commitSHAs,
|
||||||
localCommitSHAs: this.props.localCommitSHAs,
|
localCommitSHAs: this.props.localCommitSHAs,
|
||||||
commitLookupHash: this.commitsHash(this.getVisibleCommits()),
|
commitLookupHash: this.commitsHash(this.getVisibleCommits()),
|
||||||
tagsToPush: this.props.tagsToPush,
|
tagsToPush: this.props.tagsToPush,
|
||||||
|
shasToHighlight: this.props.shasToHighlight,
|
||||||
}}
|
}}
|
||||||
setScrollTop={this.props.compareListScrollTop}
|
setScrollTop={this.props.compareListScrollTop}
|
||||||
|
rowCustomClassNameMap={this.getRowCustomClassMap()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,10 +19,13 @@ import { clipboard } from 'electron'
|
||||||
import { TooltipDirection } from '../lib/tooltip'
|
import { TooltipDirection } from '../lib/tooltip'
|
||||||
import { AppFileStatusKind } from '../../models/status'
|
import { AppFileStatusKind } from '../../models/status'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import { LinkButton } from '../lib/link-button'
|
||||||
|
import { UnreachableCommitsTab } from './unreachable-commits-dialog'
|
||||||
|
|
||||||
interface ICommitSummaryProps {
|
interface ICommitSummaryProps {
|
||||||
readonly repository: Repository
|
readonly repository: Repository
|
||||||
readonly commits: ReadonlyArray<Commit>
|
readonly selectedCommits: ReadonlyArray<Commit>
|
||||||
|
readonly shasInDiff: ReadonlyArray<string>
|
||||||
readonly changesetData: IChangesetData
|
readonly changesetData: IChangesetData
|
||||||
readonly emoji: Map<string, string>
|
readonly emoji: Map<string, string>
|
||||||
|
|
||||||
|
@ -52,6 +55,12 @@ interface ICommitSummaryProps {
|
||||||
|
|
||||||
/** Called when the user opens the diff options popover */
|
/** Called when the user opens the diff options popover */
|
||||||
readonly onDiffOptionsOpened: () => void
|
readonly onDiffOptionsOpened: () => void
|
||||||
|
|
||||||
|
/** Called to highlight certain shas in the history */
|
||||||
|
readonly onHighlightShas: (shasToHighlight: ReadonlyArray<string>) => void
|
||||||
|
|
||||||
|
/** Called to show unreachable commits dialog */
|
||||||
|
readonly showUnreachableCommits: (tab: UnreachableCommitsTab) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICommitSummaryState {
|
interface ICommitSummaryState {
|
||||||
|
@ -62,6 +71,11 @@ interface ICommitSummaryState {
|
||||||
*/
|
*/
|
||||||
readonly summary: ReadonlyArray<TokenResult>
|
readonly summary: ReadonlyArray<TokenResult>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the commit summary was empty.
|
||||||
|
*/
|
||||||
|
readonly hasEmptySummary: boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The commit message body, i.e. anything after the first line of text in the
|
* The commit message body, i.e. anything after the first line of text in the
|
||||||
* commit message. Note that this may differ from the body property in the
|
* commit message. Note that this may differ from the body property in the
|
||||||
|
@ -99,36 +113,49 @@ function createState(
|
||||||
isOverflowed: boolean,
|
isOverflowed: boolean,
|
||||||
props: ICommitSummaryProps
|
props: ICommitSummaryProps
|
||||||
): ICommitSummaryState {
|
): ICommitSummaryState {
|
||||||
const { emoji, repository, commits } = props
|
const { emoji, repository, selectedCommits } = props
|
||||||
const tokenizer = new Tokenizer(emoji, repository)
|
const tokenizer = new Tokenizer(emoji, repository)
|
||||||
|
|
||||||
const plainTextBody =
|
|
||||||
commits.length > 1
|
|
||||||
? commits
|
|
||||||
.map(
|
|
||||||
c =>
|
|
||||||
`${c.shortSha} - ${c.summary}${
|
|
||||||
c.body.trim() !== '' ? `\n${c.body}` : ''
|
|
||||||
}`
|
|
||||||
)
|
|
||||||
.join('\n\n')
|
|
||||||
: commits[0].body
|
|
||||||
|
|
||||||
const { summary, body } = wrapRichTextCommitMessage(
|
const { summary, body } = wrapRichTextCommitMessage(
|
||||||
commits[0].summary,
|
getCommitSummary(selectedCommits),
|
||||||
plainTextBody,
|
selectedCommits[0].body,
|
||||||
tokenizer
|
tokenizer
|
||||||
)
|
)
|
||||||
|
|
||||||
const allAvatarUsers = commits.flatMap(c =>
|
const hasEmptySummary =
|
||||||
|
selectedCommits.length === 1 && selectedCommits[0].summary.length === 0
|
||||||
|
|
||||||
|
const allAvatarUsers = selectedCommits.flatMap(c =>
|
||||||
getAvatarUsersForCommit(repository.gitHubRepository, c)
|
getAvatarUsersForCommit(repository.gitHubRepository, c)
|
||||||
)
|
)
|
||||||
|
|
||||||
const avatarUsers = _.uniqWith(
|
const avatarUsers = _.uniqWith(
|
||||||
allAvatarUsers,
|
allAvatarUsers,
|
||||||
(a, b) => a.email === b.email && a.name === b.name
|
(a, b) => a.email === b.email && a.name === b.name
|
||||||
)
|
)
|
||||||
|
|
||||||
return { isOverflowed, summary, body, avatarUsers }
|
return { isOverflowed, summary, body, avatarUsers, hasEmptySummary }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCommitSummary(selectedCommits: ReadonlyArray<Commit>) {
|
||||||
|
return selectedCommits[0].summary.length === 0
|
||||||
|
? 'Empty commit message'
|
||||||
|
: selectedCommits[0].summary
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCountCommitsNotInDiff(
|
||||||
|
selectedCommits: ReadonlyArray<Commit>,
|
||||||
|
shasInDiff: ReadonlyArray<string>
|
||||||
|
) {
|
||||||
|
if (selectedCommits.length === 1) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const excludedCommits = selectedCommits.filter(
|
||||||
|
({ sha }) => !shasInDiff.includes(sha)
|
||||||
|
)
|
||||||
|
|
||||||
|
return excludedCommits.length
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -260,9 +287,9 @@ export class CommitSummary extends React.Component<
|
||||||
|
|
||||||
public componentWillUpdate(nextProps: ICommitSummaryProps) {
|
public componentWillUpdate(nextProps: ICommitSummaryProps) {
|
||||||
if (
|
if (
|
||||||
nextProps.commits.length !== this.props.commits.length ||
|
nextProps.selectedCommits.length !== this.props.selectedCommits.length ||
|
||||||
!nextProps.commits.every((nextCommit, i) =>
|
!nextProps.selectedCommits.every((nextCommit, i) =>
|
||||||
messageEquals(nextCommit, this.props.commits[i])
|
messageEquals(nextCommit, this.props.selectedCommits[i])
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.setState(createState(false, nextProps))
|
this.setState(createState(false, nextProps))
|
||||||
|
@ -316,60 +343,93 @@ export class CommitSummary extends React.Component<
|
||||||
}
|
}
|
||||||
|
|
||||||
private getShaRef = (useShortSha?: boolean) => {
|
private getShaRef = (useShortSha?: boolean) => {
|
||||||
const { commits } = this.props
|
const { selectedCommits } = this.props
|
||||||
const oldest = useShortSha ? commits[0].shortSha : commits[0].sha
|
return useShortSha ? selectedCommits[0].shortSha : selectedCommits[0].sha
|
||||||
|
|
||||||
if (commits.length === 1) {
|
|
||||||
return oldest
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const latestCommit = commits.at(-1)
|
private onHighlightShasInDiff = () => {
|
||||||
const latest = useShortSha ? latestCommit?.shortSha : latestCommit?.sha
|
this.props.onHighlightShas(this.props.shasInDiff)
|
||||||
|
|
||||||
return `${oldest}^..${latest}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
private onHighlightShasNotInDiff = () => {
|
||||||
const className = classNames({
|
const { onHighlightShas, selectedCommits, shasInDiff } = this.props
|
||||||
expanded: this.props.isExpanded,
|
onHighlightShas(
|
||||||
collapsed: !this.props.isExpanded,
|
selectedCommits.filter(c => !shasInDiff.includes(c.sha)).map(c => c.sha)
|
||||||
'has-expander': this.props.isExpanded || this.state.isOverflowed,
|
)
|
||||||
'hide-description-border': this.props.hideDescriptionBorder,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const hasEmptySummary = this.state.summary.length === 0
|
private onRemoveHighlightOfShas = () => {
|
||||||
const commitSummary = hasEmptySummary
|
this.props.onHighlightShas([])
|
||||||
? 'Empty commit message'
|
}
|
||||||
: this.props.commits.length > 1
|
|
||||||
? `Viewing the diff of ${this.props.commits.length} commits`
|
|
||||||
: this.state.summary
|
|
||||||
|
|
||||||
const summaryClassNames = classNames('commit-summary-title', {
|
private showUnreachableCommits = () => {
|
||||||
'empty-summary': hasEmptySummary,
|
this.props.showUnreachableCommits(UnreachableCommitsTab.Unreachable)
|
||||||
})
|
}
|
||||||
|
|
||||||
|
private showReachableCommits = () => {
|
||||||
|
this.props.showUnreachableCommits(UnreachableCommitsTab.Reachable)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderCommitsNotReachable = () => {
|
||||||
|
const { selectedCommits, shasInDiff } = this.props
|
||||||
|
if (selectedCommits.length === 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const excludedCommitsCount = getCountCommitsNotInDiff(
|
||||||
|
selectedCommits,
|
||||||
|
shasInDiff
|
||||||
|
)
|
||||||
|
|
||||||
|
if (excludedCommitsCount === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const commitsPluralized = excludedCommitsCount > 1 ? 'commits' : 'commit'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="commit-summary" className={className}>
|
<div
|
||||||
<div className="commit-summary-header">
|
className="commit-unreachable-info"
|
||||||
<RichText
|
onMouseOver={this.onHighlightShasNotInDiff}
|
||||||
className={summaryClassNames}
|
onMouseOut={this.onRemoveHighlightOfShas}
|
||||||
emoji={this.props.emoji}
|
>
|
||||||
repository={this.props.repository}
|
<Octicon symbol={OcticonSymbol.info} />
|
||||||
text={commitSummary}
|
<LinkButton onClick={this.showUnreachableCommits}>
|
||||||
/>
|
{excludedCommitsCount} unreachable {commitsPluralized}
|
||||||
|
</LinkButton>{' '}
|
||||||
|
not included.
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
<ul className="commit-summary-meta">
|
private renderAuthors = () => {
|
||||||
|
const { selectedCommits, repository } = this.props
|
||||||
|
const { avatarUsers } = this.state
|
||||||
|
if (selectedCommits.length > 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<li
|
<li
|
||||||
className="commit-summary-meta-item without-truncation"
|
className="commit-summary-meta-item without-truncation"
|
||||||
aria-label="Author"
|
aria-label="Author"
|
||||||
>
|
>
|
||||||
<AvatarStack users={this.state.avatarUsers} />
|
<AvatarStack users={avatarUsers} />
|
||||||
<CommitAttribution
|
<CommitAttribution
|
||||||
gitHubRepository={this.props.repository.gitHubRepository}
|
gitHubRepository={repository.gitHubRepository}
|
||||||
commits={this.props.commits}
|
commits={selectedCommits}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderCommitRef = () => {
|
||||||
|
const { selectedCommits } = this.props
|
||||||
|
if (selectedCommits.length > 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<li
|
<li
|
||||||
className="commit-summary-meta-item without-truncation"
|
className="commit-summary-meta-item without-truncation"
|
||||||
aria-label="SHA"
|
aria-label="SHA"
|
||||||
|
@ -385,7 +445,69 @@ export class CommitSummary extends React.Component<
|
||||||
{this.getShaRef(true)}
|
{this.getShaRef(true)}
|
||||||
</TooltippedContent>
|
</TooltippedContent>
|
||||||
</li>
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderSummary = () => {
|
||||||
|
const { selectedCommits, shasInDiff } = this.props
|
||||||
|
const { summary, hasEmptySummary } = this.state
|
||||||
|
const summaryClassNames = classNames('commit-summary-title', {
|
||||||
|
'empty-summary': hasEmptySummary,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (selectedCommits.length === 1) {
|
||||||
|
return (
|
||||||
|
<RichText
|
||||||
|
className={summaryClassNames}
|
||||||
|
emoji={this.props.emoji}
|
||||||
|
repository={this.props.repository}
|
||||||
|
text={summary}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const commitsNotInDiff = getCountCommitsNotInDiff(
|
||||||
|
selectedCommits,
|
||||||
|
shasInDiff
|
||||||
|
)
|
||||||
|
const numInDiff = selectedCommits.length - commitsNotInDiff
|
||||||
|
const commitsPluralized = numInDiff > 1 ? 'commits' : 'commit'
|
||||||
|
return (
|
||||||
|
<div className={summaryClassNames}>
|
||||||
|
Showing changes from{' '}
|
||||||
|
{commitsNotInDiff > 0 ? (
|
||||||
|
<LinkButton
|
||||||
|
onMouseOver={this.onHighlightShasInDiff}
|
||||||
|
onMouseOut={this.onRemoveHighlightOfShas}
|
||||||
|
onClick={this.showReachableCommits}
|
||||||
|
>
|
||||||
|
{numInDiff} {commitsPluralized}
|
||||||
|
</LinkButton>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
{numInDiff} {commitsPluralized}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const className = classNames({
|
||||||
|
expanded: this.props.isExpanded,
|
||||||
|
collapsed: !this.props.isExpanded,
|
||||||
|
'has-expander': this.props.isExpanded || this.state.isOverflowed,
|
||||||
|
'hide-description-border': this.props.hideDescriptionBorder,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="commit-summary" className={className}>
|
||||||
|
<div className="commit-summary-header">
|
||||||
|
{this.renderSummary()}
|
||||||
|
<ul className="commit-summary-meta">
|
||||||
|
{this.renderAuthors()}
|
||||||
|
{this.renderCommitRef()}
|
||||||
{this.renderChangedFilesDescription()}
|
{this.renderChangedFilesDescription()}
|
||||||
{this.renderLinesChanged()}
|
{this.renderLinesChanged()}
|
||||||
{this.renderTags()}
|
{this.renderTags()}
|
||||||
|
@ -411,6 +533,7 @@ export class CommitSummary extends React.Component<
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{this.renderDescription()}
|
{this.renderDescription()}
|
||||||
|
{this.renderCommitsNotReachable()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -528,10 +651,15 @@ export class CommitSummary extends React.Component<
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderTags() {
|
private renderTags() {
|
||||||
const tags = this.props.commits.flatMap(c => c.tags) || []
|
const { selectedCommits } = this.props
|
||||||
|
if (selectedCommits.length > 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = selectedCommits[0].tags
|
||||||
|
|
||||||
if (tags.length === 0) {
|
if (tags.length === 0) {
|
||||||
return null
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -55,6 +55,7 @@ interface ICompareSidebarProps {
|
||||||
readonly tagsToPush: ReadonlyArray<string> | null
|
readonly tagsToPush: ReadonlyArray<string> | null
|
||||||
readonly aheadBehindStore: AheadBehindStore
|
readonly aheadBehindStore: AheadBehindStore
|
||||||
readonly isCherryPickInProgress: boolean
|
readonly isCherryPickInProgress: boolean
|
||||||
|
readonly shasToHighlight: ReadonlyArray<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ICompareSidebarState {
|
interface ICompareSidebarState {
|
||||||
|
@ -230,6 +231,7 @@ export class CompareSidebar extends React.Component<
|
||||||
commitLookup={this.props.commitLookup}
|
commitLookup={this.props.commitLookup}
|
||||||
commitSHAs={commitSHAs}
|
commitSHAs={commitSHAs}
|
||||||
selectedSHAs={this.props.selectedCommitShas}
|
selectedSHAs={this.props.selectedCommitShas}
|
||||||
|
shasToHighlight={this.props.shasToHighlight}
|
||||||
localCommitSHAs={this.props.localCommitSHAs}
|
localCommitSHAs={this.props.localCommitSHAs}
|
||||||
canResetToCommits={formState.kind === HistoryTabMode.History}
|
canResetToCommits={formState.kind === HistoryTabMode.History}
|
||||||
canUndoCommits={formState.kind === HistoryTabMode.History}
|
canUndoCommits={formState.kind === HistoryTabMode.History}
|
||||||
|
@ -258,7 +260,7 @@ export class CompareSidebar extends React.Component<
|
||||||
emptyListMessage={emptyListMessage}
|
emptyListMessage={emptyListMessage}
|
||||||
onCompareListScrolled={this.props.onCompareListScrolled}
|
onCompareListScrolled={this.props.onCompareListScrolled}
|
||||||
compareListScrollTop={this.props.compareListScrollTop}
|
compareListScrollTop={this.props.compareListScrollTop}
|
||||||
tagsToPush={this.props.tagsToPush}
|
tagsToPush={this.props.tagsToPush ?? []}
|
||||||
isCherryPickInProgress={this.props.isCherryPickInProgress}
|
isCherryPickInProgress={this.props.isCherryPickInProgress}
|
||||||
onRenderCommitDragElement={this.onRenderCommitDragElement}
|
onRenderCommitDragElement={this.onRenderCommitDragElement}
|
||||||
onRemoveCommitDragElement={this.onRemoveCommitDragElement}
|
onRemoveCommitDragElement={this.onRemoveCommitDragElement}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { SelectedCommits } from './selected-commit'
|
export { SelectedCommits } from './selected-commits'
|
||||||
export { CompareSidebar } from './compare'
|
export { CompareSidebar } from './compare'
|
||||||
|
|
|
@ -35,6 +35,8 @@ import { IConstrainedValue } from '../../lib/app-state'
|
||||||
import { clamp } from '../../lib/clamp'
|
import { clamp } from '../../lib/clamp'
|
||||||
import { pathExists } from '../lib/path-exists'
|
import { pathExists } from '../lib/path-exists'
|
||||||
import { enableMultiCommitDiffs } from '../../lib/feature-flag'
|
import { enableMultiCommitDiffs } from '../../lib/feature-flag'
|
||||||
|
import { PopupType } from '../../models/popup'
|
||||||
|
import { UnreachableCommitsTab } from './unreachable-commits-dialog'
|
||||||
|
|
||||||
interface ISelectedCommitsProps {
|
interface ISelectedCommitsProps {
|
||||||
readonly repository: Repository
|
readonly repository: Repository
|
||||||
|
@ -42,6 +44,7 @@ interface ISelectedCommitsProps {
|
||||||
readonly dispatcher: Dispatcher
|
readonly dispatcher: Dispatcher
|
||||||
readonly emoji: Map<string, string>
|
readonly emoji: Map<string, string>
|
||||||
readonly selectedCommits: ReadonlyArray<Commit>
|
readonly selectedCommits: ReadonlyArray<Commit>
|
||||||
|
readonly shasInDiff: ReadonlyArray<string>
|
||||||
readonly localCommitSHAs: ReadonlyArray<string>
|
readonly localCommitSHAs: ReadonlyArray<string>
|
||||||
readonly changesetData: IChangesetData
|
readonly changesetData: IChangesetData
|
||||||
readonly selectedFile: CommittedFileChange | null
|
readonly selectedFile: CommittedFileChange | null
|
||||||
|
@ -166,7 +169,8 @@ export class SelectedCommits extends React.Component<
|
||||||
private renderCommitSummary(commits: ReadonlyArray<Commit>) {
|
private renderCommitSummary(commits: ReadonlyArray<Commit>) {
|
||||||
return (
|
return (
|
||||||
<CommitSummary
|
<CommitSummary
|
||||||
commits={commits}
|
selectedCommits={commits}
|
||||||
|
shasInDiff={this.props.shasInDiff}
|
||||||
changesetData={this.props.changesetData}
|
changesetData={this.props.changesetData}
|
||||||
emoji={this.props.emoji}
|
emoji={this.props.emoji}
|
||||||
repository={this.props.repository}
|
repository={this.props.repository}
|
||||||
|
@ -179,10 +183,26 @@ export class SelectedCommits extends React.Component<
|
||||||
onHideWhitespaceInDiffChanged={this.onHideWhitespaceInDiffChanged}
|
onHideWhitespaceInDiffChanged={this.onHideWhitespaceInDiffChanged}
|
||||||
onShowSideBySideDiffChanged={this.onShowSideBySideDiffChanged}
|
onShowSideBySideDiffChanged={this.onShowSideBySideDiffChanged}
|
||||||
onDiffOptionsOpened={this.props.onDiffOptionsOpened}
|
onDiffOptionsOpened={this.props.onDiffOptionsOpened}
|
||||||
|
onHighlightShas={this.onHighlightShas}
|
||||||
|
showUnreachableCommits={this.showUnreachableCommits}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showUnreachableCommits = (selectedTab: UnreachableCommitsTab) => {
|
||||||
|
this.props.dispatcher.showPopup({
|
||||||
|
type: PopupType.UnreachableCommits,
|
||||||
|
selectedTab,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private onHighlightShas = (shasToHighlight: ReadonlyArray<string>) => {
|
||||||
|
this.props.dispatcher.updateShasToHighlight(
|
||||||
|
this.props.repository,
|
||||||
|
shasToHighlight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private onExpandChanged = (isExpanded: boolean) => {
|
private onExpandChanged = (isExpanded: boolean) => {
|
||||||
this.setState({ isExpanded })
|
this.setState({ isExpanded })
|
||||||
}
|
}
|
149
app/src/ui/history/unreachable-commits-dialog.tsx
Normal file
149
app/src/ui/history/unreachable-commits-dialog.tsx
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import * as React from 'react'
|
||||||
|
import { Dialog, DialogFooter } from '../dialog'
|
||||||
|
import { TabBar } from '../tab-bar'
|
||||||
|
import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group'
|
||||||
|
import { Commit } from '../../models/commit'
|
||||||
|
import { CommitList } from './commit-list'
|
||||||
|
|
||||||
|
export enum UnreachableCommitsTab {
|
||||||
|
Unreachable,
|
||||||
|
Reachable,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUnreachableCommitsDialogProps {
|
||||||
|
/** The shas of the currently selected commits */
|
||||||
|
readonly selectedShas: ReadonlyArray<string>
|
||||||
|
|
||||||
|
/** The shas of the commits showed in the diff */
|
||||||
|
readonly shasInDiff: ReadonlyArray<string>
|
||||||
|
|
||||||
|
/** The commits loaded, keyed by their full SHA. */
|
||||||
|
readonly commitLookup: Map<string, Commit>
|
||||||
|
|
||||||
|
/** Used to set the selected tab. */
|
||||||
|
readonly selectedTab: UnreachableCommitsTab
|
||||||
|
|
||||||
|
/** The emoji lookup to render images inline */
|
||||||
|
readonly emoji: Map<string, string>
|
||||||
|
|
||||||
|
/** Called to dismiss the */
|
||||||
|
readonly onDismissed: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IUnreachableCommitsDialogState {
|
||||||
|
/** The currently select tab. */
|
||||||
|
readonly selectedTab: UnreachableCommitsTab
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The component for for viewing the unreachable commits in the current diff a repository. */
|
||||||
|
export class UnreachableCommitsDialog extends React.Component<
|
||||||
|
IUnreachableCommitsDialogProps,
|
||||||
|
IUnreachableCommitsDialogState
|
||||||
|
> {
|
||||||
|
public constructor(props: IUnreachableCommitsDialogProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
selectedTab: props.selectedTab,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUpdate(nextProps: IUnreachableCommitsDialogProps) {
|
||||||
|
const currentSelectedTab = this.props.selectedTab
|
||||||
|
const selectedTab = nextProps.selectedTab
|
||||||
|
|
||||||
|
if (currentSelectedTab !== selectedTab) {
|
||||||
|
this.setState({ selectedTab })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onTabClicked = (selectedTab: UnreachableCommitsTab) => {
|
||||||
|
this.setState({ selectedTab })
|
||||||
|
}
|
||||||
|
|
||||||
|
private getShasToDisplay = () => {
|
||||||
|
const { selectedTab } = this.state
|
||||||
|
const { shasInDiff, selectedShas } = this.props
|
||||||
|
if (selectedTab === UnreachableCommitsTab.Reachable) {
|
||||||
|
return shasInDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedShas.filter(sha => !shasInDiff.includes(sha))
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderTabs() {
|
||||||
|
return (
|
||||||
|
<TabBar
|
||||||
|
onTabClicked={this.onTabClicked}
|
||||||
|
selectedIndex={this.state.selectedTab}
|
||||||
|
>
|
||||||
|
<span>Unreachable</span>
|
||||||
|
<span>Reachable</span>
|
||||||
|
</TabBar>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderActiveTab() {
|
||||||
|
const { commitLookup, emoji } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{this.renderUnreachableCommitsMessage()}
|
||||||
|
<div className="unreachable-commit-list">
|
||||||
|
<CommitList
|
||||||
|
gitHubRepository={null}
|
||||||
|
isLocalRepository={true}
|
||||||
|
commitLookup={commitLookup}
|
||||||
|
commitSHAs={this.getShasToDisplay()}
|
||||||
|
selectedSHAs={[]}
|
||||||
|
localCommitSHAs={[]}
|
||||||
|
emoji={emoji}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderFooter() {
|
||||||
|
return (
|
||||||
|
<DialogFooter>
|
||||||
|
<OkCancelButtonGroup cancelButtonVisible={false} />
|
||||||
|
</DialogFooter>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderUnreachableCommitsMessage = () => {
|
||||||
|
const count = this.getShasToDisplay().length
|
||||||
|
const commitsPluralized = count > 1 ? 'commits' : 'commit'
|
||||||
|
const pronounPluralized = count > 1 ? `they're` : `it's`
|
||||||
|
return (
|
||||||
|
<div className="message">
|
||||||
|
You will{' '}
|
||||||
|
{this.state.selectedTab === UnreachableCommitsTab.Unreachable
|
||||||
|
? 'not'
|
||||||
|
: ''}{' '}
|
||||||
|
see changes from the following {commitsPluralized} because{' '}
|
||||||
|
{pronounPluralized}{' '}
|
||||||
|
{this.state.selectedTab === UnreachableCommitsTab.Unreachable
|
||||||
|
? 'not'
|
||||||
|
: ''}{' '}
|
||||||
|
in the ancestry path of the most recent commit in your selection.
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
className="unreachable-commits"
|
||||||
|
title={__DARWIN__ ? 'Commit Reachability' : 'Commit reachability'}
|
||||||
|
onSubmit={this.props.onDismissed}
|
||||||
|
onDismissed={this.props.onDismissed}
|
||||||
|
>
|
||||||
|
{this.renderTabs()}
|
||||||
|
{this.renderActiveTab()}
|
||||||
|
{this.renderFooter()}
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -202,6 +202,13 @@ process.on(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HACK: this is a workaround for a known crash in the Dev Tools on Electron 19
|
||||||
|
// See https://github.com/electron/electron/issues/34350
|
||||||
|
if (__DEV__) {
|
||||||
|
window.onerror = e =>
|
||||||
|
e === 'Uncaught EvalError: Possible side-effect in debug-evaluate'
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chromium won't crash on an unhandled rejection (similar to how it won't crash
|
* Chromium won't crash on an unhandled rejection (similar to how it won't crash
|
||||||
* on an unhandled error). We've taken the approach that unhandled errors should
|
* on an unhandled error). We've taken the approach that unhandled errors should
|
||||||
|
|
|
@ -8,10 +8,18 @@ export interface IButtonProps {
|
||||||
* A callback which is invoked when the button is clicked
|
* A callback which is invoked when the button is clicked
|
||||||
* using a pointer device or keyboard. The source event is
|
* using a pointer device or keyboard. The source event is
|
||||||
* passed along and can be used to prevent the default action
|
* passed along and can be used to prevent the default action
|
||||||
* or stop the even from bubbling.
|
* or stop the event from bubbling.
|
||||||
*/
|
*/
|
||||||
readonly onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
readonly onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback which is invoked when the button's context menu
|
||||||
|
* is activated using a pointer device or keyboard. The source
|
||||||
|
* event is passed along and can be used to prevent the default
|
||||||
|
* action or stop the event from bubbling.
|
||||||
|
*/
|
||||||
|
readonly onContextMenu?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that's called when the user moves over the button with
|
* A function that's called when the user moves over the button with
|
||||||
* a pointer device.
|
* a pointer device.
|
||||||
|
@ -118,6 +126,7 @@ export class Button extends React.Component<IButtonProps, {}> {
|
||||||
<button
|
<button
|
||||||
className={className}
|
className={className}
|
||||||
onClick={disabled ? preventDefault : this.onClick}
|
onClick={disabled ? preventDefault : this.onClick}
|
||||||
|
onContextMenu={disabled ? preventDefault : this.onContextMenu}
|
||||||
type={this.props.type || 'button'}
|
type={this.props.type || 'button'}
|
||||||
ref={this.innerButtonRef}
|
ref={this.innerButtonRef}
|
||||||
tabIndex={this.props.tabIndex}
|
tabIndex={this.props.tabIndex}
|
||||||
|
@ -151,6 +160,14 @@ export class Button extends React.Component<IButtonProps, {}> {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onContextMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
this.props.onContextMenu?.(event)
|
||||||
|
|
||||||
|
if (this.props.type === undefined) {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const preventDefault = (e: Event | React.SyntheticEvent) => e.preventDefault()
|
const preventDefault = (e: Event | React.SyntheticEvent) => e.preventDefault()
|
||||||
|
|
|
@ -11,6 +11,12 @@ interface ILinkButtonProps {
|
||||||
/** A function to call on click. */
|
/** A function to call on click. */
|
||||||
readonly onClick?: () => void
|
readonly onClick?: () => void
|
||||||
|
|
||||||
|
/** A function to call when mouse is hovered over */
|
||||||
|
readonly onMouseOver?: () => void
|
||||||
|
|
||||||
|
/** A function to call when mouse is moved off */
|
||||||
|
readonly onMouseOut?: () => void
|
||||||
|
|
||||||
/** CSS classes attached to the component */
|
/** CSS classes attached to the component */
|
||||||
readonly className?: string
|
readonly className?: string
|
||||||
|
|
||||||
|
@ -42,6 +48,8 @@ export class LinkButton extends React.Component<ILinkButtonProps, {}> {
|
||||||
ref={this.anchorRef}
|
ref={this.anchorRef}
|
||||||
className={className}
|
className={className}
|
||||||
href={href}
|
href={href}
|
||||||
|
onMouseOver={this.props.onMouseOver}
|
||||||
|
onMouseOut={this.props.onMouseOut}
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
tabIndex={this.props.tabIndex}
|
tabIndex={this.props.tabIndex}
|
||||||
>
|
>
|
||||||
|
|
|
@ -77,6 +77,11 @@ interface IListProps {
|
||||||
*/
|
*/
|
||||||
readonly selectedRows: ReadonlyArray<number>
|
readonly selectedRows: ReadonlyArray<number>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to attach special classes to specific rows
|
||||||
|
*/
|
||||||
|
readonly rowCustomClassNameMap?: Map<string, ReadonlyArray<number>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function will be called when a pointer device is pressed and then
|
* This function will be called when a pointer device is pressed and then
|
||||||
* released on a selectable row. Note that this follows the conventions
|
* released on a selectable row. Note that this follows the conventions
|
||||||
|
@ -791,10 +796,30 @@ export class List extends React.Component<IListProps, IListState> {
|
||||||
this.focusRow = -1
|
this.focusRow = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getCustomRowClassNames = (rowIndex: number) => {
|
||||||
|
const { rowCustomClassNameMap } = this.props
|
||||||
|
if (rowCustomClassNameMap === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const customClasses = new Array<string>()
|
||||||
|
rowCustomClassNameMap.forEach(
|
||||||
|
(rows: ReadonlyArray<number>, className: string) => {
|
||||||
|
if (rows.includes(rowIndex)) {
|
||||||
|
customClasses.push(className)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return customClasses.length === 0 ? undefined : customClasses.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
private renderRow = (params: IRowRendererParams) => {
|
private renderRow = (params: IRowRendererParams) => {
|
||||||
const rowIndex = params.rowIndex
|
const rowIndex = params.rowIndex
|
||||||
const selectable = this.canSelectRow(rowIndex)
|
const selectable = this.canSelectRow(rowIndex)
|
||||||
const selected = this.props.selectedRows.indexOf(rowIndex) !== -1
|
const selected = this.props.selectedRows.indexOf(rowIndex) !== -1
|
||||||
|
const customClasses = this.getCustomRowClassNames(rowIndex)
|
||||||
|
|
||||||
const focused = rowIndex === this.focusRow
|
const focused = rowIndex === this.focusRow
|
||||||
|
|
||||||
// An unselectable row shouldn't be focusable
|
// An unselectable row shouldn't be focusable
|
||||||
|
@ -843,13 +868,13 @@ export class List extends React.Component<IListProps, IListState> {
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
children={element}
|
children={element}
|
||||||
selectable={selectable}
|
selectable={selectable}
|
||||||
|
className={customClasses}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
let content: JSX.Element[] | JSX.Element | null
|
let content: JSX.Element[] | JSX.Element | null
|
||||||
|
|
||||||
if (this.resizeObserver) {
|
if (this.resizeObserver) {
|
||||||
content = this.renderContents(
|
content = this.renderContents(
|
||||||
this.state.width ?? 0,
|
this.state.width ?? 0,
|
||||||
|
@ -932,7 +957,6 @@ export class List extends React.Component<IListProps, IListState> {
|
||||||
// it with keyboard navigation and select an item.
|
// it with keyboard navigation and select an item.
|
||||||
const tabIndex =
|
const tabIndex =
|
||||||
this.props.selectedRows.length < 1 && this.props.rowCount > 0 ? 0 : -1
|
this.props.selectedRows.length < 1 && this.props.rowCount > 0 ? 0 : -1
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusContainer
|
<FocusContainer
|
||||||
className="list-focus-container"
|
className="list-focus-container"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { createUniqueId, releaseUniqueId } from './id-pool'
|
import { createUniqueId, releaseUniqueId } from './id-pool'
|
||||||
import { LinkButton } from './link-button'
|
|
||||||
import { showContextualMenu } from '../../lib/menu-item'
|
import { showContextualMenu } from '../../lib/menu-item'
|
||||||
|
|
||||||
export interface ITextBoxProps {
|
export interface ITextBoxProps {
|
||||||
|
@ -47,34 +46,6 @@ export interface ITextBoxProps {
|
||||||
/** The type of the input. Defaults to `text`. */
|
/** The type of the input. Defaults to `text`. */
|
||||||
readonly type?: 'text' | 'search' | 'password' | 'email'
|
readonly type?: 'text' | 'search' | 'password' | 'email'
|
||||||
|
|
||||||
/**
|
|
||||||
* An optional text for a link label element. A link label is, for the purposes
|
|
||||||
* of this control an anchor element that's rendered alongside (ie on the same)
|
|
||||||
* row as the the label element.
|
|
||||||
*
|
|
||||||
* Note that the link label will only be rendered if the textbox has a
|
|
||||||
* label text (specified through the label prop). A link label is used for
|
|
||||||
* presenting the user with a contextual link related to a specific text
|
|
||||||
* input such as a password recovery link for a password text box.
|
|
||||||
*/
|
|
||||||
readonly labelLinkText?: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An optional URL to be opened when the label link (if present, see the
|
|
||||||
* labelLinkText prop for more details) is clicked. The link will be opened using the
|
|
||||||
* standard semantics of a LinkButton, i.e. in the configured system browser.
|
|
||||||
*
|
|
||||||
* If not specified consumers need to subscribe to the onLabelLinkClick event.
|
|
||||||
*/
|
|
||||||
readonly labelLinkUri?: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An optional event handler which is invoked when the label link (if present,
|
|
||||||
* see the labelLinkText prop for more details) is clicked. See the onClick
|
|
||||||
* event on the LinkButton component for more details.
|
|
||||||
*/
|
|
||||||
readonly onLabelLinkClick?: () => void
|
|
||||||
|
|
||||||
/** The tab index of the input element. */
|
/** The tab index of the input element. */
|
||||||
readonly tabIndex?: number
|
readonly tabIndex?: number
|
||||||
|
|
||||||
|
@ -213,35 +184,6 @@ export class TextBox extends React.Component<ITextBoxProps, ITextBoxState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderLabelLink() {
|
|
||||||
if (!this.props.labelLinkText) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LinkButton
|
|
||||||
uri={this.props.labelLinkUri}
|
|
||||||
onClick={this.props.onLabelLinkClick}
|
|
||||||
className="link-label"
|
|
||||||
>
|
|
||||||
{this.props.labelLinkText}
|
|
||||||
</LinkButton>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderLabel() {
|
|
||||||
if (!this.props.label) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="label-container">
|
|
||||||
<label htmlFor={this.state.inputId}>{this.props.label}</label>
|
|
||||||
{this.renderLabelLink()}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private onContextMenu = (event: React.MouseEvent<any>) => {
|
private onContextMenu = (event: React.MouseEvent<any>) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
showContextualMenu([{ role: 'editMenu' }])
|
showContextualMenu([{ role: 'editMenu' }])
|
||||||
|
@ -290,12 +232,12 @@ export class TextBox extends React.Component<ITextBoxProps, ITextBoxState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const className = classNames('text-box-component', this.props.className)
|
const { label, className } = this.props
|
||||||
const inputId = this.props.label ? this.state.inputId : undefined
|
const inputId = label ? this.state.inputId : undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={classNames('text-box-component', className)}>
|
||||||
{this.renderLabel()}
|
{label && <label htmlFor={inputId}>{label}</label>}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
id={inputId}
|
id={inputId}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { Repository } from '../../models/repository'
|
||||||
|
import { IMenuItem } from '../../lib/menu-item'
|
||||||
|
import { enableRepositoryAliases } from '../../lib/feature-flag'
|
||||||
|
import { Repositoryish } from './group-repositories'
|
||||||
|
import { clipboard } from 'electron'
|
||||||
|
import {
|
||||||
|
RevealInFileManagerLabel,
|
||||||
|
DefaultEditorLabel,
|
||||||
|
} from '../lib/context-menu'
|
||||||
|
|
||||||
|
interface IRepositoryListItemContextMenuConfig {
|
||||||
|
repository: Repositoryish
|
||||||
|
shellLabel: string
|
||||||
|
externalEditorLabel: string | undefined
|
||||||
|
askForConfirmationOnRemoveRepository: boolean
|
||||||
|
onViewOnGitHub: (repository: Repositoryish) => void
|
||||||
|
onOpenInShell: (repository: Repositoryish) => void
|
||||||
|
onShowRepository: (repository: Repositoryish) => void
|
||||||
|
onOpenInExternalEditor: (repository: Repositoryish) => void
|
||||||
|
onRemoveRepository: (repository: Repositoryish) => void
|
||||||
|
onChangeRepositoryAlias: (repository: Repository) => void
|
||||||
|
onRemoveRepositoryAlias: (repository: Repository) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateRepositoryListContextMenu = (
|
||||||
|
config: IRepositoryListItemContextMenuConfig
|
||||||
|
) => {
|
||||||
|
const { repository } = config
|
||||||
|
const missing = repository instanceof Repository && repository.missing
|
||||||
|
const github =
|
||||||
|
repository instanceof Repository && repository.gitHubRepository != null
|
||||||
|
const openInExternalEditor = config.externalEditorLabel
|
||||||
|
? `Open in ${config.externalEditorLabel}`
|
||||||
|
: DefaultEditorLabel
|
||||||
|
|
||||||
|
const items: ReadonlyArray<IMenuItem> = [
|
||||||
|
...buildAliasMenuItems(config),
|
||||||
|
{
|
||||||
|
label: __DARWIN__ ? 'Copy Repo Name' : 'Copy repo name',
|
||||||
|
action: () => clipboard.writeText(repository.name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: __DARWIN__ ? 'Copy Repo Path' : 'Copy repo path',
|
||||||
|
action: () => clipboard.writeText(repository.path),
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: 'View on GitHub',
|
||||||
|
action: () => config.onViewOnGitHub(repository),
|
||||||
|
enabled: github,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: `Open in ${config.shellLabel}`,
|
||||||
|
action: () => config.onOpenInShell(repository),
|
||||||
|
enabled: !missing,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: RevealInFileManagerLabel,
|
||||||
|
action: () => config.onShowRepository(repository),
|
||||||
|
enabled: !missing,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: openInExternalEditor,
|
||||||
|
action: () => config.onOpenInExternalEditor(repository),
|
||||||
|
enabled: !missing,
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: config.askForConfirmationOnRemoveRepository ? 'Remove…' : 'Remove',
|
||||||
|
action: () => config.onRemoveRepository(repository),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildAliasMenuItems = (
|
||||||
|
config: IRepositoryListItemContextMenuConfig
|
||||||
|
): ReadonlyArray<IMenuItem> => {
|
||||||
|
const { repository } = config
|
||||||
|
|
||||||
|
if (!(repository instanceof Repository) || !enableRepositoryAliases()) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const verb = repository.alias == null ? 'Create' : 'Change'
|
||||||
|
const items: Array<IMenuItem> = [
|
||||||
|
{
|
||||||
|
label: __DARWIN__ ? `${verb} Alias` : `${verb} alias`,
|
||||||
|
action: () => config.onChangeRepositoryAlias(repository),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if (repository.alias !== null) {
|
||||||
|
items.push({
|
||||||
|
label: __DARWIN__ ? 'Remove Alias' : 'Remove alias',
|
||||||
|
action: () => config.onRemoveRepositoryAlias(repository),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
|
@ -1,24 +1,18 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { clipboard } from 'electron'
|
|
||||||
|
|
||||||
import { Repository } from '../../models/repository'
|
import { Repository } from '../../models/repository'
|
||||||
import { Octicon, iconForRepository } from '../octicons'
|
import { Octicon, iconForRepository } from '../octicons'
|
||||||
import * as OcticonSymbol from '../octicons/octicons.generated'
|
import * as OcticonSymbol from '../octicons/octicons.generated'
|
||||||
import { showContextualMenu } from '../../lib/menu-item'
|
import { showContextualMenu } from '../../lib/menu-item'
|
||||||
import { Repositoryish } from './group-repositories'
|
import { Repositoryish } from './group-repositories'
|
||||||
import { IMenuItem } from '../../lib/menu-item'
|
|
||||||
import { HighlightText } from '../lib/highlight-text'
|
import { HighlightText } from '../lib/highlight-text'
|
||||||
import { IMatches } from '../../lib/fuzzy-find'
|
import { IMatches } from '../../lib/fuzzy-find'
|
||||||
import { IAheadBehind } from '../../models/branch'
|
import { IAheadBehind } from '../../models/branch'
|
||||||
import {
|
|
||||||
RevealInFileManagerLabel,
|
|
||||||
DefaultEditorLabel,
|
|
||||||
} from '../lib/context-menu'
|
|
||||||
import { enableRepositoryAliases } from '../../lib/feature-flag'
|
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { createObservableRef } from '../lib/observable-ref'
|
import { createObservableRef } from '../lib/observable-ref'
|
||||||
import { Tooltip } from '../lib/tooltip'
|
import { Tooltip } from '../lib/tooltip'
|
||||||
import { TooltippedContent } from '../lib/tooltipped-content'
|
import { TooltippedContent } from '../lib/tooltipped-content'
|
||||||
|
import { generateRepositoryListContextMenu } from './repository-list-item-context-menu'
|
||||||
|
|
||||||
interface IRepositoryListItemProps {
|
interface IRepositoryListItemProps {
|
||||||
readonly repository: Repositoryish
|
readonly repository: Repositoryish
|
||||||
|
@ -154,121 +148,23 @@ export class RepositoryListItem extends React.Component<
|
||||||
private onContextMenu = (event: React.MouseEvent<any>) => {
|
private onContextMenu = (event: React.MouseEvent<any>) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
const repository = this.props.repository
|
const items = generateRepositoryListContextMenu({
|
||||||
const missing = repository instanceof Repository && repository.missing
|
onRemoveRepository: this.props.onRemoveRepository,
|
||||||
const github =
|
onShowRepository: this.props.onShowRepository,
|
||||||
repository instanceof Repository && repository.gitHubRepository != null
|
onOpenInShell: this.props.onOpenInShell,
|
||||||
const openInExternalEditor = this.props.externalEditorLabel
|
onOpenInExternalEditor: this.props.onOpenInExternalEditor,
|
||||||
? `Open in ${this.props.externalEditorLabel}`
|
askForConfirmationOnRemoveRepository:
|
||||||
: DefaultEditorLabel
|
this.props.askForConfirmationOnRemoveRepository,
|
||||||
|
externalEditorLabel: this.props.externalEditorLabel,
|
||||||
const items: ReadonlyArray<IMenuItem> = [
|
onChangeRepositoryAlias: this.props.onChangeRepositoryAlias,
|
||||||
...this.buildAliasMenuItems(),
|
onRemoveRepositoryAlias: this.props.onRemoveRepositoryAlias,
|
||||||
{
|
onViewOnGitHub: this.props.onViewOnGitHub,
|
||||||
label: __DARWIN__ ? 'Copy Repo Name' : 'Copy repo name',
|
repository: this.props.repository,
|
||||||
action: this.copyNameToClipboard,
|
shellLabel: this.props.shellLabel,
|
||||||
},
|
})
|
||||||
{
|
|
||||||
label: __DARWIN__ ? 'Copy Repo Path' : 'Copy repo path',
|
|
||||||
action: this.copyPathToClipboard,
|
|
||||||
},
|
|
||||||
{ type: 'separator' },
|
|
||||||
{
|
|
||||||
label: 'View on GitHub',
|
|
||||||
action: this.viewOnGitHub,
|
|
||||||
enabled: github,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: `Open in ${this.props.shellLabel}`,
|
|
||||||
action: this.openInShell,
|
|
||||||
enabled: !missing,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: RevealInFileManagerLabel,
|
|
||||||
action: this.showRepository,
|
|
||||||
enabled: !missing,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: openInExternalEditor,
|
|
||||||
action: this.openInExternalEditor,
|
|
||||||
enabled: !missing,
|
|
||||||
},
|
|
||||||
{ type: 'separator' },
|
|
||||||
{
|
|
||||||
label: this.props.askForConfirmationOnRemoveRepository
|
|
||||||
? 'Remove…'
|
|
||||||
: 'Remove',
|
|
||||||
action: this.removeRepository,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
showContextualMenu(items)
|
showContextualMenu(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildAliasMenuItems(): ReadonlyArray<IMenuItem> {
|
|
||||||
const repository = this.props.repository
|
|
||||||
|
|
||||||
if (!(repository instanceof Repository) || !enableRepositoryAliases()) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const verb = repository.alias == null ? 'Create' : 'Change'
|
|
||||||
const items: Array<IMenuItem> = [
|
|
||||||
{
|
|
||||||
label: __DARWIN__ ? `${verb} Alias` : `${verb} alias`,
|
|
||||||
action: this.changeAlias,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
if (repository.alias !== null) {
|
|
||||||
items.push({
|
|
||||||
label: __DARWIN__ ? 'Remove Alias' : 'Remove alias',
|
|
||||||
action: this.removeAlias,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeRepository = () => {
|
|
||||||
this.props.onRemoveRepository(this.props.repository)
|
|
||||||
}
|
|
||||||
|
|
||||||
private showRepository = () => {
|
|
||||||
this.props.onShowRepository(this.props.repository)
|
|
||||||
}
|
|
||||||
|
|
||||||
private viewOnGitHub = () => {
|
|
||||||
this.props.onViewOnGitHub(this.props.repository)
|
|
||||||
}
|
|
||||||
|
|
||||||
private openInShell = () => {
|
|
||||||
this.props.onOpenInShell(this.props.repository)
|
|
||||||
}
|
|
||||||
|
|
||||||
private openInExternalEditor = () => {
|
|
||||||
this.props.onOpenInExternalEditor(this.props.repository)
|
|
||||||
}
|
|
||||||
|
|
||||||
private changeAlias = () => {
|
|
||||||
if (this.props.repository instanceof Repository) {
|
|
||||||
this.props.onChangeRepositoryAlias(this.props.repository)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeAlias = () => {
|
|
||||||
if (this.props.repository instanceof Repository) {
|
|
||||||
this.props.onRemoveRepositoryAlias(this.props.repository)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private copyNameToClipboard = () => {
|
|
||||||
clipboard.writeText(this.props.repository.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
private copyPathToClipboard = () => {
|
|
||||||
clipboard.writeText(this.props.repository.path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderRepoIndicators: React.FunctionComponent<{
|
const renderRepoIndicators: React.FunctionComponent<{
|
||||||
|
|
|
@ -265,6 +265,7 @@ export class RepositoryView extends React.Component<
|
||||||
isLocalRepository={remote === null}
|
isLocalRepository={remote === null}
|
||||||
compareState={compareState}
|
compareState={compareState}
|
||||||
selectedCommitShas={shas}
|
selectedCommitShas={shas}
|
||||||
|
shasToHighlight={compareState.shasToHighlight}
|
||||||
currentBranch={currentBranch}
|
currentBranch={currentBranch}
|
||||||
emoji={emoji}
|
emoji={emoji}
|
||||||
commitLookup={commitLookup}
|
commitLookup={commitLookup}
|
||||||
|
@ -373,7 +374,8 @@ export class RepositoryView extends React.Component<
|
||||||
|
|
||||||
private renderContentForHistory(): JSX.Element {
|
private renderContentForHistory(): JSX.Element {
|
||||||
const { commitSelection, commitLookup, localCommitSHAs } = this.props.state
|
const { commitSelection, commitLookup, localCommitSHAs } = this.props.state
|
||||||
const { changesetData, file, diff, shas, isContiguous } = commitSelection
|
const { changesetData, file, diff, shas, shasInDiff, isContiguous } =
|
||||||
|
commitSelection
|
||||||
|
|
||||||
const selectedCommits = []
|
const selectedCommits = []
|
||||||
for (const sha of shas) {
|
for (const sha of shas) {
|
||||||
|
@ -393,6 +395,7 @@ export class RepositoryView extends React.Component<
|
||||||
isLocalRepository={this.props.state.remote === null}
|
isLocalRepository={this.props.state.remote === null}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
selectedCommits={selectedCommits}
|
selectedCommits={selectedCommits}
|
||||||
|
shasInDiff={shasInDiff}
|
||||||
isContiguous={isContiguous}
|
isContiguous={isContiguous}
|
||||||
localCommitSHAs={localCommitSHAs}
|
localCommitSHAs={localCommitSHAs}
|
||||||
changesetData={changesetData}
|
changesetData={changesetData}
|
||||||
|
|
|
@ -265,8 +265,6 @@ export class SignIn extends React.Component<ISignInProps, ISignInState> {
|
||||||
label="Authentication code"
|
label="Authentication code"
|
||||||
value={this.state.otpToken}
|
value={this.state.otpToken}
|
||||||
onValueChanged={this.onOTPTokenChanged}
|
onValueChanged={this.onOTPTokenChanged}
|
||||||
labelLinkText={`What's this?`}
|
|
||||||
labelLinkUri="https://help.github.com/articles/providing-your-2fa-authentication-code/"
|
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
@ -19,6 +19,10 @@ import { dragAndDropManager } from '../../lib/drag-and-drop-manager'
|
||||||
import { DragType } from '../../models/drag-drop'
|
import { DragType } from '../../models/drag-drop'
|
||||||
import { CICheckRunPopover } from '../check-runs/ci-check-run-popover'
|
import { CICheckRunPopover } from '../check-runs/ci-check-run-popover'
|
||||||
import { TooltipTarget } from '../lib/tooltip'
|
import { TooltipTarget } from '../lib/tooltip'
|
||||||
|
import { BranchType, Branch } from '../../models/branch'
|
||||||
|
import { PopupType } from '../../models/popup'
|
||||||
|
import { generateBranchContextMenuItems } from '../branches/branch-list-item-context-menu'
|
||||||
|
import { showContextualMenu } from '../../lib/menu-item'
|
||||||
|
|
||||||
interface IBranchDropdownProps {
|
interface IBranchDropdownProps {
|
||||||
readonly dispatcher: Dispatcher
|
readonly dispatcher: Dispatcher
|
||||||
|
@ -84,7 +88,6 @@ export class BranchDropdown extends React.Component<
|
||||||
|
|
||||||
const tip = repositoryState.branchesState.tip
|
const tip = repositoryState.branchesState.tip
|
||||||
const currentBranch = tip.kind === TipState.Valid ? tip.branch : null
|
const currentBranch = tip.kind === TipState.Valid ? tip.branch : null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BranchesContainer
|
<BranchesContainer
|
||||||
allBranches={branchesState.allBranches}
|
allBranches={branchesState.allBranches}
|
||||||
|
@ -98,6 +101,8 @@ export class BranchDropdown extends React.Component<
|
||||||
currentPullRequest={this.props.currentPullRequest}
|
currentPullRequest={this.props.currentPullRequest}
|
||||||
isLoadingPullRequests={this.props.isLoadingPullRequests}
|
isLoadingPullRequests={this.props.isLoadingPullRequests}
|
||||||
emoji={this.props.emoji}
|
emoji={this.props.emoji}
|
||||||
|
onDeleteBranch={this.onDeleteBranch}
|
||||||
|
onRenameBranch={this.onRenameBranch}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -190,6 +195,7 @@ export class BranchDropdown extends React.Component<
|
||||||
iconClassName={iconClassName}
|
iconClassName={iconClassName}
|
||||||
title={title}
|
title={title}
|
||||||
description={description}
|
description={description}
|
||||||
|
onContextMenu={this.onBranchToolbarButtonContextMenu}
|
||||||
tooltip={isOpen ? undefined : tooltip}
|
tooltip={isOpen ? undefined : tooltip}
|
||||||
onDropdownStateChanged={this.onDropDownStateChanged}
|
onDropdownStateChanged={this.onDropDownStateChanged}
|
||||||
dropdownContentRenderer={this.renderBranchFoldout}
|
dropdownContentRenderer={this.renderBranchFoldout}
|
||||||
|
@ -222,6 +228,76 @@ export class BranchDropdown extends React.Component<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onBranchToolbarButtonContextMenu = (
|
||||||
|
event: React.MouseEvent<HTMLButtonElement>
|
||||||
|
): void => {
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
const { tip } = this.props.repositoryState.branchesState
|
||||||
|
|
||||||
|
if (tip.kind !== TipState.Valid) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = generateBranchContextMenuItems({
|
||||||
|
name: tip.branch.name,
|
||||||
|
isLocal: tip.branch.type === BranchType.Local,
|
||||||
|
onRenameBranch: this.onRenameBranch,
|
||||||
|
onDeleteBranch: this.onDeleteBranch,
|
||||||
|
})
|
||||||
|
|
||||||
|
showContextualMenu(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBranchWithName(branchName: string): Branch | undefined {
|
||||||
|
return this.props.repositoryState.branchesState.allBranches.find(
|
||||||
|
branch => branch.name === branchName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private onRenameBranch = (branchName: string) => {
|
||||||
|
const branch = this.getBranchWithName(branchName)
|
||||||
|
|
||||||
|
if (branch === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.dispatcher.showPopup({
|
||||||
|
type: PopupType.RenameBranch,
|
||||||
|
repository: this.props.repository,
|
||||||
|
branch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private onDeleteBranch = async (branchName: string) => {
|
||||||
|
const branch = this.getBranchWithName(branchName)
|
||||||
|
const { dispatcher, repository } = this.props
|
||||||
|
|
||||||
|
if (branch === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (branch.type === BranchType.Remote) {
|
||||||
|
dispatcher.showPopup({
|
||||||
|
type: PopupType.DeleteRemoteBranch,
|
||||||
|
repository,
|
||||||
|
branch,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const aheadBehind = await dispatcher.getBranchAheadBehind(
|
||||||
|
repository,
|
||||||
|
branch
|
||||||
|
)
|
||||||
|
dispatcher.showPopup({
|
||||||
|
type: PopupType.DeleteBranch,
|
||||||
|
repository,
|
||||||
|
branch,
|
||||||
|
existsOnRemote: aheadBehind !== null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private onBadgeClick = () => {
|
private onBadgeClick = () => {
|
||||||
// The badge can't be clicked while the CI status popover is shown, because
|
// The badge can't be clicked while the CI status popover is shown, because
|
||||||
// in that case the Popover component will recognize the "click outside"
|
// in that case the Popover component will recognize the "click outside"
|
||||||
|
|
|
@ -38,6 +38,13 @@ export interface IToolbarButtonProps {
|
||||||
*/
|
*/
|
||||||
readonly onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
readonly onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional event handler for when the button's context menu
|
||||||
|
* is activated by a pointer event or by hitting the menu key
|
||||||
|
* while focused.
|
||||||
|
*/
|
||||||
|
readonly onContextMenu?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that's called when the user hovers over the button with
|
* A function that's called when the user hovers over the button with
|
||||||
* a pointer device.
|
* a pointer device.
|
||||||
|
@ -206,6 +213,7 @@ export class ToolbarButton extends React.Component<IToolbarButtonProps, {}> {
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
|
onContextMenu={this.props.onContextMenu}
|
||||||
ref={this.onButtonRef}
|
ref={this.onButtonRef}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
onMouseEnter={this.props.onMouseEnter}
|
onMouseEnter={this.props.onMouseEnter}
|
||||||
|
|
|
@ -65,6 +65,13 @@ export interface IToolbarDropdownProps {
|
||||||
*/
|
*/
|
||||||
readonly dropdownContentRenderer: () => JSX.Element | null
|
readonly dropdownContentRenderer: () => JSX.Element | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback which is invoked when the button's context menu
|
||||||
|
* is activated. The source event is passed along and can be
|
||||||
|
* used to prevent the default action or stop the event from bubbling.
|
||||||
|
*/
|
||||||
|
readonly onContextMenu?: (event: React.MouseEvent<HTMLButtonElement>) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that's called whenever something is dragged over the
|
* A function that's called whenever something is dragged over the
|
||||||
* dropdown.
|
* dropdown.
|
||||||
|
@ -238,6 +245,10 @@ export class ToolbarDropdown extends React.Component<
|
||||||
this.props.onDropdownStateChanged(newState, source)
|
this.props.onDropdownStateChanged(newState, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onContextMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
this.props.onContextMenu?.(event)
|
||||||
|
}
|
||||||
|
|
||||||
private updateClientRectIfNecessary() {
|
private updateClientRectIfNecessary() {
|
||||||
if (this.props.dropdownState === 'open' && this.innerButton) {
|
if (this.props.dropdownState === 'open' && this.innerButton) {
|
||||||
const newRect = this.innerButton.getButtonBoundingClientRect()
|
const newRect = this.innerButton.getButtonBoundingClientRect()
|
||||||
|
@ -380,6 +391,7 @@ export class ToolbarDropdown extends React.Component<
|
||||||
description={this.props.description}
|
description={this.props.description}
|
||||||
tooltip={this.props.tooltip}
|
tooltip={this.props.tooltip}
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
|
onContextMenu={this.onContextMenu}
|
||||||
onMouseEnter={this.props.onMouseEnter}
|
onMouseEnter={this.props.onMouseEnter}
|
||||||
style={this.props.style}
|
style={this.props.style}
|
||||||
iconClassName={this.props.iconClassName}
|
iconClassName={this.props.iconClassName}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
@import 'dialogs/commit-message';
|
@import 'dialogs/commit-message';
|
||||||
@import 'dialogs/choose-branch';
|
@import 'dialogs/choose-branch';
|
||||||
@import 'dialogs/ci-check-run-rerun';
|
@import 'dialogs/ci-check-run-rerun';
|
||||||
|
@import 'dialogs/unreachable-commits';
|
||||||
|
|
||||||
// The styles herein attempt to follow a flow where margins are only applied
|
// The styles herein attempt to follow a flow where margins are only applied
|
||||||
// to the bottom of elements (with the exception of the last child). This to
|
// to the bottom of elements (with the exception of the last child). This to
|
||||||
|
|
|
@ -5,22 +5,8 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
.label-container {
|
& > label {
|
||||||
display: flex;
|
overflow-wrap: anywhere;
|
||||||
|
|
||||||
label {
|
|
||||||
@include ellipsis;
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-label {
|
|
||||||
@include ellipsis;
|
|
||||||
|
|
||||||
justify-content: flex-end;
|
|
||||||
flex-shrink: 0;
|
|
||||||
flex-grow: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
margin-bottom: var(--spacing-third);
|
margin-bottom: var(--spacing-third);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
app/styles/ui/dialogs/_unreachable-commits.scss
Normal file
15
app/styles/ui/dialogs/_unreachable-commits.scss
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.unreachable-commits {
|
||||||
|
max-width: 400px;
|
||||||
|
|
||||||
|
.unreachable-commit-list {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
padding: var(--spacing);
|
||||||
|
border-bottom: var(--base-border);
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,6 +52,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.has-highlighted-commits {
|
||||||
|
.list-item {
|
||||||
|
transition: opacity 0.5s;
|
||||||
|
|
||||||
|
&:not(.highlighted) {
|
||||||
|
opacity: 30%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.has-highlighted-commits) {
|
||||||
|
.list-item {
|
||||||
|
transition: opacity 0.25s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.focus-within {
|
.focus-within {
|
||||||
.list-item.selected {
|
.list-item.selected {
|
||||||
.commit {
|
.commit {
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
.commit-summary-description-scroll-view {
|
.commit-summary-description-scroll-view {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
display: revert;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: none;
|
content: none;
|
||||||
|
@ -60,6 +61,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commit-unreachable-info {
|
||||||
|
padding: var(--spacing-half) var(--spacing);
|
||||||
|
border-bottom: var(--base-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.octicon {
|
||||||
|
margin-right: var(--spacing-half);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-button-component {
|
||||||
|
margin-right: var(--spacing-half);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This isn't a real class, it's an SCSS hack to allow us to only write
|
// NOTE: This isn't a real class, it's an SCSS hack to allow us to only write
|
||||||
|
@ -103,9 +119,11 @@
|
||||||
|
|
||||||
&-description-scroll-view {
|
&-description-scroll-view {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
// The extra pixel makes the space align up with the commit list.
|
|
||||||
max-height: 69px;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
// Maximum amount of commit description lines to show before collapsing
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable text selection inside the title and description elements.
|
// Enable text selection inside the title and description elements.
|
||||||
|
|
|
@ -363,10 +363,10 @@ delegates@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||||
|
|
||||||
desktop-notifications@^0.2.2:
|
desktop-notifications@^0.2.4:
|
||||||
version "0.2.2"
|
version "0.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/desktop-notifications/-/desktop-notifications-0.2.2.tgz#197a32ee504a894ad074793dab285681c533e5ac"
|
resolved "https://registry.yarnpkg.com/desktop-notifications/-/desktop-notifications-0.2.4.tgz#d51db18be583784a296748efd361fe3a5aefea70"
|
||||||
integrity sha512-XMnxdWV6ZfiCzLZNC00n6h30Jt3z8yv21FAPBt/kK6hANI0PaoYWsRKEYya0zMUAX/9lrh429R5OtRGOKWZQSw==
|
integrity sha512-Au0CbBE4TQ09vsC4/L15FhDsCr/daIyYUY3vkx4S3Y0Sp9EPpbXxBdmz0ry1cOnQ8A47K45zTYsuKP7a+xHm7Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
node-addon-api "^5.0.0"
|
node-addon-api "^5.0.0"
|
||||||
prebuild-install "^7.0.1"
|
prebuild-install "^7.0.1"
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
"3.0.5": [
|
"3.0.5": [
|
||||||
"[Fixed] Surface again Git's warning about unsafe directories and provide a way to trust repositories not owned by the current user"
|
"[Fixed] Surface again Git's warning about unsafe directories and provide a way to trust repositories not owned by the current user"
|
||||||
],
|
],
|
||||||
|
"3.0.5-beta1": [
|
||||||
|
"[Fixed] Surface again Git's warning about unsafe directories and provide a way to trust repositories not owned by the current user"
|
||||||
|
],
|
||||||
"3.0.4": ["[Improved] Upgrade embedded Git to 2.35.4"],
|
"3.0.4": ["[Improved] Upgrade embedded Git to 2.35.4"],
|
||||||
|
"3.0.4-beta1": ["[Improved] Upgrade embedded Git to 2.35.4"],
|
||||||
"3.0.3": [
|
"3.0.3": [
|
||||||
"[Added] Add Aptana Studio support - #14669. Thanks @tsvetilian-ty!",
|
"[Added] Add Aptana Studio support - #14669. Thanks @tsvetilian-ty!",
|
||||||
"[Fixed] Fix crash when user's locale is unsupported by the spellchecker - #14817. Thanks @tsvetilian-ty!",
|
"[Fixed] Fix crash when user's locale is unsupported by the spellchecker - #14817. Thanks @tsvetilian-ty!",
|
||||||
|
|
|
@ -54,17 +54,15 @@ $ set GITHUB_ACCESS_TOKEN={your token here}
|
||||||
$ $env:GITHUB_ACCESS_TOKEN="{your token here}"
|
$ $env:GITHUB_ACCESS_TOKEN="{your token here}"
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Create Release Branch
|
### 2. Switch to the Commit of the Release
|
||||||
|
|
||||||
Create a new branch to represent the work that will be released to users:
|
You have to switch to the commit that represents the work that will be released to users:
|
||||||
|
|
||||||
- for `beta` releases, branch from `development` to ensure the latest changes are published
|
- for `beta` releases, switch to `development` to ensure the latest changes are published
|
||||||
- for `production` releases, branch from the latest beta tag
|
- for `production` releases, check out the latest beta tag
|
||||||
- to find this tag: `git tag | grep 'beta' | sort -r | head -n 1`
|
- to find this tag: `git tag | grep 'beta' | sort -r | head -n 1`
|
||||||
|
|
||||||
When naming the branch, ensure you use the `releases/[version]` pattern to ensure all CI platforms are aware of the branch and will build any PRs that target the branch.
|
### 3. Create Draft Release and Release Branch
|
||||||
|
|
||||||
### 3. Create Draft Release
|
|
||||||
|
|
||||||
Run the script below (which relies on the your personal access token being set), which will determine the next version from what was previously published, based on the desired channel.
|
Run the script below (which relies on the your personal access token being set), which will determine the next version from what was previously published, based on the desired channel.
|
||||||
|
|
||||||
|
@ -78,12 +76,11 @@ If you are creating a new beta release, the `yarn draft-release beta` command wi
|
||||||
|
|
||||||
If you are create a new `production` release, you should just combine and sort the previous `beta` changelog entries.
|
If you are create a new `production` release, you should just combine and sort the previous `beta` changelog entries.
|
||||||
|
|
||||||
|
The script will output a draft changelog, which covers everything that's been merged, and probably needs some love. It will also create the release branch for you. If that fails for whatever reason and you must create the branch manually, ensure you use the `releases/[version]` pattern for its name to ensure all CI platforms are aware of the branch and will build any PRs that target the branch.
|
||||||
The script will output a draft changelog, which covers everything that's been merged, and probably needs some love.
|
|
||||||
The output will then explain the next steps:
|
|
||||||
|
|
||||||
If you have pretext release note drafted in `app/static/common/pretext-draft.md`, you can add the `--pretext` flag to generate a pretext change log entry it. Example: `yarn draft-release test --pretext`
|
If you have pretext release note drafted in `app/static/common/pretext-draft.md`, you can add the `--pretext` flag to generate a pretext change log entry it. Example: `yarn draft-release test --pretext`
|
||||||
|
|
||||||
|
The output will then explain the next steps:
|
||||||
```shellsession
|
```shellsession
|
||||||
Here's what you should do next:
|
Here's what you should do next:
|
||||||
|
|
||||||
|
@ -135,6 +132,8 @@ Add your new changelog entries to `changelog.json`, update the version in `app/p
|
||||||
|
|
||||||
If a maintainer would like to backport a pull request to the next release, it is their responsibility to co-ordinate with the release owner and ensure they are fine with accepting this work.
|
If a maintainer would like to backport a pull request to the next release, it is their responsibility to co-ordinate with the release owner and ensure they are fine with accepting this work.
|
||||||
|
|
||||||
|
After pushing the branch, a [GitHub Action](https://github.com/desktop/desktop/blob/development/.github/workflows/release-pr.yml) will create a release Pull Request for it. If that action fails for whatever reason, you can fall back to using the `yarn draft-release:pr` command, or create it manually.
|
||||||
|
|
||||||
Once your release branch is ready to review and ship, ask the other maintainers to review and approve the changes!
|
Once your release branch is ready to review and ship, ask the other maintainers to review and approve the changes!
|
||||||
|
|
||||||
IMPORTANT NOTE: Do NOT "Update branch" and merge development into the release branch. This might be tempting if the "branch is out-of-date with the base branch" dotcom feature is enabled. However, doing so would inadvertently release everything on development to production or beta 🙀
|
IMPORTANT NOTE: Do NOT "Update branch" and merge development into the release branch. This might be tempting if the "branch is out-of-date with the base branch" dotcom feature is enabled. However, doing so would inadvertently release everything on development to production or beta 🙀
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
The following are the larger areas of upcoming work the GitHub Desktop team intends to explore. This is not inclusive of everything we're working on, and it's not written in stone. We'll continue to update it as our priorities evolve.
|
The following are the larger areas of upcoming work the GitHub Desktop team intends to explore and has recently shipped. This is not inclusive of everything we're working on (see existing open pull requests for that), and it's not written in stone. We'll attempt to update this intermittently as priorities evolve, but can't guarantee that it stays up to date over time.
|
||||||
|
|
||||||
#### Native arm64 support for macOS and Windows
|
## Major features shipped in previous releases
|
||||||
|
|
||||||
- Provide support for arm64 Windows machines: [#9691](https://github.com/desktop/desktop/pull/9691)
|
#### High signal notifications (2.9.10 and 3.0.0)
|
||||||
|
|
||||||
## Shipped in previous releases
|
- Receive a notification when checks fail: [#13655](https://github.com/desktop/desktop/pull/14175)
|
||||||
|
- Receive a notification when your pull request is reviewed: [#14175](https://github.com/desktop/desktop/pull/14175)
|
||||||
|
|
||||||
#### Native support for Apple Silicon (M1)
|
#### Improved commit history: reorder commits, squash commits, amend commits, and create a branch from previous commit (2.9.0)
|
||||||
|
|
||||||
|
- Reorder commits via drag/drop: [#12384](https://github.com/desktop/desktop/pull/12384)
|
||||||
|
- Squash commits via drag/drop: [#12235](https://github.com/desktop/desktop/pull/12235)
|
||||||
|
- Amend last commit: [#12353](https://github.com/desktop/desktop/pull/12353)
|
||||||
|
- Create a branch from a previous commit: [#12160](https://github.com/desktop/desktop/pull/12160)
|
||||||
|
|
||||||
|
#### Native support for Apple Silicon (M1) machines (2.8.2)
|
||||||
|
|
||||||
- Provide support for Apple Silicon (M1) machines: [#9691](https://github.com/desktop/desktop/pull/9691)
|
- Provide support for Apple Silicon (M1) machines: [#9691](https://github.com/desktop/desktop/pull/9691)
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,7 @@
|
||||||
"@types/webpack-hot-middleware": "^2.25.6",
|
"@types/webpack-hot-middleware": "^2.25.6",
|
||||||
"@types/webpack-merge": "^5.0.0",
|
"@types/webpack-merge": "^5.0.0",
|
||||||
"@types/xml2js": "^0.4.0",
|
"@types/xml2js": "^0.4.0",
|
||||||
"electron": "17.0.1",
|
"electron": "19.0.0",
|
||||||
"electron-builder": "^22.7.0",
|
"electron-builder": "^22.7.0",
|
||||||
"electron-packager": "^15.1.0",
|
"electron-packager": "^15.1.0",
|
||||||
"electron-winstaller": "^5.0.0",
|
"electron-winstaller": "^5.0.0",
|
||||||
|
|
|
@ -48,12 +48,21 @@ function capitalized(str: string): string {
|
||||||
*/
|
*/
|
||||||
export function findReleaseNote(body: string): string | null | undefined {
|
export function findReleaseNote(body: string): string | null | undefined {
|
||||||
const re = /^Notes: (.+)$/gm
|
const re = /^Notes: (.+)$/gm
|
||||||
const matches = re.exec(body)
|
let lastMatches = null
|
||||||
if (!matches || matches.length < 2) {
|
|
||||||
|
// There might be multiple lines starting with "Notes: ", but we're only
|
||||||
|
// interested in the last one.
|
||||||
|
let matches = re.exec(body)
|
||||||
|
while (matches) {
|
||||||
|
lastMatches = matches
|
||||||
|
matches = re.exec(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lastMatches || lastMatches.length < 2) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = matches[1].replace(/\.$/, '')
|
const note = lastMatches[1].replace(/\.$/, '')
|
||||||
return note === 'no-notes' ? null : note
|
return note === 'no-notes' ? null : note
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,19 @@ Notes: [Fixed] Fix lorem impsum dolor sit amet.
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('looks for the last Notes entry if there are several', () => {
|
||||||
|
const body = `
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sollicitudin turpis
|
||||||
|
tempor euismod fermentum. Nullam hendrerit neque eget risus faucibus volutpat. Donec
|
||||||
|
ultrices, orci quis auctor ultrices, nulla lacus gravida lectus, non rutrum dolor
|
||||||
|
quam vel augue.
|
||||||
|
Notes: ignore this notes
|
||||||
|
|
||||||
|
Notes: These are valid notes
|
||||||
|
`
|
||||||
|
expect(findReleaseNote(body)).toBe('These are valid notes')
|
||||||
|
})
|
||||||
|
|
||||||
it('detected no release notes wanted for the PR', () => {
|
it('detected no release notes wanted for the PR', () => {
|
||||||
const body = `
|
const body = `
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sollicitudin turpis
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sollicitudin turpis
|
||||||
|
|
466
yarn.lock
466
yarn.lock
|
@ -506,10 +506,10 @@
|
||||||
ajv "^6.12.0"
|
ajv "^6.12.0"
|
||||||
ajv-keywords "^3.4.1"
|
ajv-keywords "^3.4.1"
|
||||||
|
|
||||||
"@electron/get@^1.13.0":
|
"@electron/get@^1.14.1":
|
||||||
version "1.13.1"
|
version "1.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.13.1.tgz#42a0aa62fd1189638bd966e23effaebb16108368"
|
resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.14.1.tgz#16ba75f02dffb74c23965e72d617adc721d27f40"
|
||||||
integrity sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==
|
integrity sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "^4.1.1"
|
debug "^4.1.1"
|
||||||
env-paths "^2.2.0"
|
env-paths "^2.2.0"
|
||||||
|
@ -838,6 +838,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
defer-to-connect "^1.0.1"
|
defer-to-connect "^1.0.1"
|
||||||
|
|
||||||
|
"@tootallnate/once@1":
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
|
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||||
|
|
||||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
||||||
version "7.1.12"
|
version "7.1.12"
|
||||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d"
|
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d"
|
||||||
|
@ -1158,10 +1163,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234"
|
||||||
integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==
|
integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw==
|
||||||
|
|
||||||
"@types/node@^14.6.2":
|
"@types/node@^16.11.26":
|
||||||
version "14.17.5"
|
version "16.11.40"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.5.tgz#b59daf6a7ffa461b5648456ca59050ba8e40ed54"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.40.tgz#bcf85f3febe74436107aeb2d3fb5fd0d30818600"
|
||||||
integrity sha512-bjqH2cX/O33jXT/UmReo2pM7DIJREPMnarixbQ57DOOzzFaI6D2+IcwaJQaJpv0M1E9TIhPCYVxrkcityLjlqA==
|
integrity sha512-7bOWglXUO6f21NG3YDI7hIpeMX3M59GG+DzZuzX2EkFKYUnRoxq3EOg4R0KNv2hxryY9M3UUqG5akwwsifrukw==
|
||||||
|
|
||||||
"@types/normalize-package-data@^2.4.0":
|
"@types/normalize-package-data@^2.4.0":
|
||||||
version "2.4.0"
|
version "2.4.0"
|
||||||
|
@ -1659,10 +1664,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
|
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
|
||||||
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
|
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
|
||||||
|
|
||||||
abab@^2.0.3:
|
abab@^2.0.3, abab@^2.0.5:
|
||||||
version "2.0.5"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
|
||||||
integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
|
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
|
||||||
|
|
||||||
accepts@~1.3.7:
|
accepts@~1.3.7:
|
||||||
version "1.3.7"
|
version "1.3.7"
|
||||||
|
@ -1700,20 +1705,22 @@ acorn-walk@^8.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
||||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
||||||
|
|
||||||
acorn@^7.1.1:
|
acorn@^7.1.1, acorn@^7.3.1:
|
||||||
version "7.3.1"
|
version "7.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||||
integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==
|
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||||
|
|
||||||
acorn@^7.3.1:
|
acorn@^8.0.4, acorn@^8.2.4, acorn@^8.4.1:
|
||||||
version "7.4.0"
|
version "8.7.1"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||||
integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==
|
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||||
|
|
||||||
acorn@^8.0.4, acorn@^8.4.1:
|
agent-base@6:
|
||||||
version "8.7.0"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
|
||||||
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
|
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
|
||||||
|
dependencies:
|
||||||
|
debug "4"
|
||||||
|
|
||||||
airbnb-browser-shims@^3.0.0:
|
airbnb-browser-shims@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
@ -1785,16 +1792,6 @@ ajv@^4.9.2:
|
||||||
co "^4.6.0"
|
co "^4.6.0"
|
||||||
json-stable-stringify "^1.0.1"
|
json-stable-stringify "^1.0.1"
|
||||||
|
|
||||||
ajv@^5.1.0:
|
|
||||||
version "5.3.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda"
|
|
||||||
integrity sha1-RBT/dKUIecII7l/cgm4ywwNUnto=
|
|
||||||
dependencies:
|
|
||||||
co "^4.6.0"
|
|
||||||
fast-deep-equal "^1.0.0"
|
|
||||||
fast-json-stable-stringify "^2.0.0"
|
|
||||||
json-schema-traverse "^0.3.0"
|
|
||||||
|
|
||||||
ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.5, ajv@^6.9.1:
|
ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.5, ajv@^6.9.1:
|
||||||
version "6.12.6"
|
version "6.12.6"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||||
|
@ -2103,7 +2100,7 @@ async@^3.2.3:
|
||||||
asynckit@^0.4.0:
|
asynckit@^0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||||
|
|
||||||
at-least-node@^1.0.0:
|
at-least-node@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
|
@ -2132,11 +2129,6 @@ aws-sign2@~0.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||||
|
|
||||||
aws4@^1.6.0:
|
|
||||||
version "1.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
|
|
||||||
integrity sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=
|
|
||||||
|
|
||||||
aws4@^1.8.0:
|
aws4@^1.8.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||||
|
@ -2320,20 +2312,6 @@ boolean@^3.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.2.tgz#df1baa18b6a2b0e70840475e1d93ec8fe75b2570"
|
resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.0.2.tgz#df1baa18b6a2b0e70840475e1d93ec8fe75b2570"
|
||||||
integrity sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==
|
integrity sha512-RwywHlpCRc3/Wh81MiCKun4ydaIFyW5Ea6JbL6sRCVx5q5irDw7pMXBUFYF/jArQ6YrG36q0kpovc9P/Kd3I4g==
|
||||||
|
|
||||||
boom@4.x.x:
|
|
||||||
version "4.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31"
|
|
||||||
integrity sha1-T4owBctKfjiJ90kDD9JbluAdLjE=
|
|
||||||
dependencies:
|
|
||||||
hoek "4.x.x"
|
|
||||||
|
|
||||||
boom@5.x.x:
|
|
||||||
version "5.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02"
|
|
||||||
integrity sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==
|
|
||||||
dependencies:
|
|
||||||
hoek "4.x.x"
|
|
||||||
|
|
||||||
boxen@^4.2.0:
|
boxen@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
|
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
|
||||||
|
@ -2748,10 +2726,10 @@ combined-stream@1.0.6, combined-stream@~1.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream "~1.0.0"
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
combined-stream@^1.0.5, combined-stream@~1.0.5:
|
combined-stream@^1.0.8:
|
||||||
version "1.0.5"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
integrity sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream "~1.0.0"
|
delayed-stream "~1.0.0"
|
||||||
|
|
||||||
|
@ -2921,13 +2899,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
cryptiles@3.x.x:
|
|
||||||
version "3.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
|
|
||||||
integrity sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=
|
|
||||||
dependencies:
|
|
||||||
boom "5.x.x"
|
|
||||||
|
|
||||||
crypto-random-string@^2.0.0:
|
crypto-random-string@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
|
||||||
|
@ -2978,7 +2949,7 @@ cssom@~0.3.6:
|
||||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
|
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
|
||||||
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
|
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
|
||||||
|
|
||||||
cssstyle@^2.2.0:
|
cssstyle@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
|
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
|
||||||
integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
|
integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
|
||||||
|
@ -3018,6 +2989,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
ms "2.0.0"
|
||||||
|
|
||||||
|
debug@4:
|
||||||
|
version "4.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
|
dependencies:
|
||||||
|
ms "2.1.2"
|
||||||
|
|
||||||
debug@^3.1.0:
|
debug@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||||
|
@ -3063,10 +3041,10 @@ decamelize@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||||
|
|
||||||
decimal.js@^10.2.0:
|
decimal.js@^10.2.1:
|
||||||
version "10.2.1"
|
version "10.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3"
|
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
|
||||||
integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==
|
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
||||||
|
|
||||||
decode-uri-component@^0.2.0:
|
decode-uri-component@^0.2.0:
|
||||||
version "0.2.0"
|
version "0.2.0"
|
||||||
|
@ -3085,11 +3063,16 @@ deep-extend@^0.6.0:
|
||||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||||
|
|
||||||
deep-is@^0.1.3, deep-is@~0.1.3:
|
deep-is@^0.1.3:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||||
|
|
||||||
|
deep-is@~0.1.3:
|
||||||
|
version "0.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||||
|
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
||||||
|
|
||||||
deepmerge@^4.2.2:
|
deepmerge@^4.2.2:
|
||||||
version "4.2.2"
|
version "4.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||||
|
@ -3132,7 +3115,7 @@ define-property@^2.0.2:
|
||||||
delayed-stream@~1.0.0:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||||
|
|
||||||
depd@~1.1.2:
|
depd@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
|
@ -3419,13 +3402,13 @@ electron-winstaller@*, electron-winstaller@^5.0.0:
|
||||||
lodash.template "^4.2.2"
|
lodash.template "^4.2.2"
|
||||||
temp "^0.9.0"
|
temp "^0.9.0"
|
||||||
|
|
||||||
electron@17.0.1:
|
electron@19.0.0:
|
||||||
version "17.0.1"
|
version "19.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-17.0.1.tgz#e6c7ad2be26e7be8a5a9bac16b21920ad2671224"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-19.0.0.tgz#f6b742b708ec118676ba3b38d0f3712d8f0311cf"
|
||||||
integrity sha512-CBReR/QEOpgwMdt59lWCtj9wC8oHB6aAjMF1lhXcGew132xtp+C5N6EaXb/fmDceVYLouziYjbNcpeXsWrqdpA==
|
integrity sha512-VXwqLQxuIUr0SI8vOYDj5OLPwtKa/trn5DVKd/BFGT/U/IerfVoSZuydGLOjSL5yJlckfmKQpiq+8PW4gI8hXA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^1.13.0"
|
"@electron/get" "^1.14.1"
|
||||||
"@types/node" "^14.6.2"
|
"@types/node" "^16.11.26"
|
||||||
extract-zip "^1.0.3"
|
extract-zip "^1.0.3"
|
||||||
|
|
||||||
element-closest@^2.0.2:
|
element-closest@^2.0.2:
|
||||||
|
@ -3632,13 +3615,13 @@ escape-string-regexp@^4.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||||
|
|
||||||
escodegen@^1.14.1:
|
escodegen@^2.0.0:
|
||||||
version "1.14.3"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
|
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
|
||||||
integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
|
integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
|
||||||
dependencies:
|
dependencies:
|
||||||
esprima "^4.0.1"
|
esprima "^4.0.1"
|
||||||
estraverse "^4.2.0"
|
estraverse "^5.2.0"
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
optionator "^0.8.1"
|
optionator "^0.8.1"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
@ -3835,7 +3818,7 @@ esrecurse@^4.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
estraverse "^5.2.0"
|
estraverse "^5.2.0"
|
||||||
|
|
||||||
estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
|
estraverse@^4.1.0, estraverse@^4.1.1:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
|
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
|
||||||
integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
|
integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
|
||||||
|
@ -3851,9 +3834,9 @@ estraverse@^5.2.0:
|
||||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||||
|
|
||||||
esutils@^2.0.2:
|
esutils@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||||
integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
|
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||||
|
|
||||||
etag@~1.8.1:
|
etag@~1.8.1:
|
||||||
version "1.8.1"
|
version "1.8.1"
|
||||||
|
@ -3996,7 +3979,7 @@ extend-shallow@^3.0.2:
|
||||||
assign-symbols "^1.0.0"
|
assign-symbols "^1.0.0"
|
||||||
is-extendable "^1.0.1"
|
is-extendable "^1.0.1"
|
||||||
|
|
||||||
extend@^3.0.2, extend@~3.0.1, extend@~3.0.2:
|
extend@^3.0.2, extend@~3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||||
|
@ -4050,11 +4033,6 @@ fake-indexeddb@^2.0.4:
|
||||||
realistic-structured-clone "^2.0.1"
|
realistic-structured-clone "^2.0.1"
|
||||||
setimmediate "^1.0.5"
|
setimmediate "^1.0.5"
|
||||||
|
|
||||||
fast-deep-equal@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
|
|
||||||
integrity sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=
|
|
||||||
|
|
||||||
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||||
version "3.1.3"
|
version "3.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||||
|
@ -4081,7 +4059,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||||
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
|
||||||
|
|
||||||
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.4:
|
fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
|
||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
@ -4220,13 +4198,13 @@ forever-agent@~0.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||||
|
|
||||||
form-data@~2.3.1:
|
form-data@^3.0.0:
|
||||||
version "2.3.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf"
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||||
integrity sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=
|
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
asynckit "^0.4.0"
|
asynckit "^0.4.0"
|
||||||
combined-stream "^1.0.5"
|
combined-stream "^1.0.8"
|
||||||
mime-types "^2.1.12"
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
form-data@~2.3.2:
|
form-data@~2.3.2:
|
||||||
|
@ -4595,14 +4573,6 @@ har-schema@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||||
|
|
||||||
har-validator@~5.0.3:
|
|
||||||
version "5.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
|
|
||||||
integrity sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=
|
|
||||||
dependencies:
|
|
||||||
ajv "^5.1.0"
|
|
||||||
har-schema "^2.0.0"
|
|
||||||
|
|
||||||
har-validator@~5.1.3:
|
har-validator@~5.1.3:
|
||||||
version "5.1.5"
|
version "5.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
|
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
|
||||||
|
@ -4718,26 +4688,11 @@ hash-base@^3.0.0:
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
hawk@~6.0.2:
|
|
||||||
version "6.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038"
|
|
||||||
integrity sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==
|
|
||||||
dependencies:
|
|
||||||
boom "4.x.x"
|
|
||||||
cryptiles "3.x.x"
|
|
||||||
hoek "4.x.x"
|
|
||||||
sntp "2.x.x"
|
|
||||||
|
|
||||||
he@^1.2.0:
|
he@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||||
|
|
||||||
hoek@4.x.x:
|
|
||||||
version "4.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
|
|
||||||
integrity sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==
|
|
||||||
|
|
||||||
hosted-git-info@^2.1.4:
|
hosted-git-info@^2.1.4:
|
||||||
version "2.8.9"
|
version "2.8.9"
|
||||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
|
||||||
|
@ -4817,6 +4772,15 @@ http-errors@1.7.2, http-errors@~1.7.2:
|
||||||
statuses ">= 1.5.0 < 2"
|
statuses ">= 1.5.0 < 2"
|
||||||
toidentifier "1.0.0"
|
toidentifier "1.0.0"
|
||||||
|
|
||||||
|
http-proxy-agent@^4.0.1:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
|
||||||
|
integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
|
||||||
|
dependencies:
|
||||||
|
"@tootallnate/once" "1"
|
||||||
|
agent-base "6"
|
||||||
|
debug "4"
|
||||||
|
|
||||||
http-signature@~1.2.0:
|
http-signature@~1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||||
|
@ -4826,6 +4790,14 @@ http-signature@~1.2.0:
|
||||||
jsprim "^1.2.2"
|
jsprim "^1.2.2"
|
||||||
sshpk "^1.7.0"
|
sshpk "^1.7.0"
|
||||||
|
|
||||||
|
https-proxy-agent@^5.0.0:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
|
||||||
|
integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
|
||||||
|
dependencies:
|
||||||
|
agent-base "6"
|
||||||
|
debug "4"
|
||||||
|
|
||||||
human-signals@^1.1.1:
|
human-signals@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||||
|
@ -4938,11 +4910,6 @@ interpret@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0"
|
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0"
|
||||||
integrity sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=
|
integrity sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=
|
||||||
|
|
||||||
ip-regex@^2.1.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
|
||||||
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
|
|
||||||
|
|
||||||
ipaddr.js@1.9.0:
|
ipaddr.js@1.9.0:
|
||||||
version "1.9.0"
|
version "1.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
|
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
|
||||||
|
@ -5193,10 +5160,10 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
isobject "^3.0.1"
|
isobject "^3.0.1"
|
||||||
|
|
||||||
is-potential-custom-element-name@^1.0.0:
|
is-potential-custom-element-name@^1.0.1:
|
||||||
version "1.0.0"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
|
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
|
||||||
integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
|
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
|
||||||
|
|
||||||
is-regex@^1.0.4:
|
is-regex@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
|
@ -5902,35 +5869,36 @@ jsdoc-type-pratt-parser@~2.2.2:
|
||||||
integrity sha512-zRokSWcPLSWkoNzsWn9pq7YYSwDhKyEe+cJYT2qaPqLOOJb5sFSi46BPj81vP+e8chvCNdQL9RG86Bi9EI6MDw==
|
integrity sha512-zRokSWcPLSWkoNzsWn9pq7YYSwDhKyEe+cJYT2qaPqLOOJb5sFSi46BPj81vP+e8chvCNdQL9RG86Bi9EI6MDw==
|
||||||
|
|
||||||
jsdom@^16.4.0:
|
jsdom@^16.4.0:
|
||||||
version "16.4.0"
|
version "16.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
|
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710"
|
||||||
integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
|
integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==
|
||||||
dependencies:
|
dependencies:
|
||||||
abab "^2.0.3"
|
abab "^2.0.5"
|
||||||
acorn "^7.1.1"
|
acorn "^8.2.4"
|
||||||
acorn-globals "^6.0.0"
|
acorn-globals "^6.0.0"
|
||||||
cssom "^0.4.4"
|
cssom "^0.4.4"
|
||||||
cssstyle "^2.2.0"
|
cssstyle "^2.3.0"
|
||||||
data-urls "^2.0.0"
|
data-urls "^2.0.0"
|
||||||
decimal.js "^10.2.0"
|
decimal.js "^10.2.1"
|
||||||
domexception "^2.0.1"
|
domexception "^2.0.1"
|
||||||
escodegen "^1.14.1"
|
escodegen "^2.0.0"
|
||||||
|
form-data "^3.0.0"
|
||||||
html-encoding-sniffer "^2.0.1"
|
html-encoding-sniffer "^2.0.1"
|
||||||
is-potential-custom-element-name "^1.0.0"
|
http-proxy-agent "^4.0.1"
|
||||||
|
https-proxy-agent "^5.0.0"
|
||||||
|
is-potential-custom-element-name "^1.0.1"
|
||||||
nwsapi "^2.2.0"
|
nwsapi "^2.2.0"
|
||||||
parse5 "5.1.1"
|
parse5 "6.0.1"
|
||||||
request "^2.88.2"
|
saxes "^5.0.1"
|
||||||
request-promise-native "^1.0.8"
|
|
||||||
saxes "^5.0.0"
|
|
||||||
symbol-tree "^3.2.4"
|
symbol-tree "^3.2.4"
|
||||||
tough-cookie "^3.0.1"
|
tough-cookie "^4.0.0"
|
||||||
w3c-hr-time "^1.0.2"
|
w3c-hr-time "^1.0.2"
|
||||||
w3c-xmlserializer "^2.0.0"
|
w3c-xmlserializer "^2.0.0"
|
||||||
webidl-conversions "^6.1.0"
|
webidl-conversions "^6.1.0"
|
||||||
whatwg-encoding "^1.0.5"
|
whatwg-encoding "^1.0.5"
|
||||||
whatwg-mimetype "^2.3.0"
|
whatwg-mimetype "^2.3.0"
|
||||||
whatwg-url "^8.0.0"
|
whatwg-url "^8.5.0"
|
||||||
ws "^7.2.3"
|
ws "^7.4.6"
|
||||||
xml-name-validator "^3.0.0"
|
xml-name-validator "^3.0.0"
|
||||||
|
|
||||||
jsesc@^2.5.1:
|
jsesc@^2.5.1:
|
||||||
|
@ -5960,11 +5928,6 @@ json-parse-even-better-errors@^2.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||||
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
|
||||||
|
|
||||||
json-schema-traverse@^0.3.0:
|
|
||||||
version "0.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
|
||||||
integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
|
|
||||||
|
|
||||||
json-schema-traverse@^0.4.1:
|
json-schema-traverse@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||||
|
@ -6171,7 +6134,7 @@ levn@^0.4.1:
|
||||||
levn@~0.3.0:
|
levn@~0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
|
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
|
||||||
integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
|
integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
|
||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
type-check "~0.3.2"
|
type-check "~0.3.2"
|
||||||
|
@ -6286,7 +6249,7 @@ lodash.templatesettings@^4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash._reinterpolate "~3.0.0"
|
lodash._reinterpolate "~3.0.0"
|
||||||
|
|
||||||
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21:
|
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
|
@ -6470,22 +6433,22 @@ mime-db@1.51.0:
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
|
||||||
integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==
|
integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==
|
||||||
|
|
||||||
mime-db@~1.30.0:
|
mime-db@1.52.0:
|
||||||
version "1.30.0"
|
version "1.52.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||||
integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=
|
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||||
|
|
||||||
mime-db@~1.36.0:
|
mime-db@~1.36.0:
|
||||||
version "1.36.0"
|
version "1.36.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397"
|
||||||
integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==
|
integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==
|
||||||
|
|
||||||
mime-types@^2.1.12, mime-types@~2.1.17:
|
mime-types@^2.1.12:
|
||||||
version "2.1.17"
|
version "2.1.35"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||||
integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=
|
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db "~1.30.0"
|
mime-db "1.52.0"
|
||||||
|
|
||||||
mime-types@^2.1.27, mime-types@^2.1.31:
|
mime-types@^2.1.27, mime-types@^2.1.31:
|
||||||
version "2.1.34"
|
version "2.1.34"
|
||||||
|
@ -6774,11 +6737,6 @@ nwsapi@^2.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
||||||
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
|
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
|
||||||
|
|
||||||
oauth-sign@~0.8.2:
|
|
||||||
version "0.8.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
|
||||||
integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=
|
|
||||||
|
|
||||||
oauth-sign@~0.9.0:
|
oauth-sign@~0.9.0:
|
||||||
version "0.9.0"
|
version "0.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||||
|
@ -6942,16 +6900,16 @@ opener@^1.5.2:
|
||||||
integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
|
integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
|
||||||
|
|
||||||
optionator@^0.8.1:
|
optionator@^0.8.1:
|
||||||
version "0.8.2"
|
version "0.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
|
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
|
||||||
integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
|
integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-is "~0.1.3"
|
deep-is "~0.1.3"
|
||||||
fast-levenshtein "~2.0.4"
|
fast-levenshtein "~2.0.6"
|
||||||
levn "~0.3.0"
|
levn "~0.3.0"
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
type-check "~0.3.2"
|
type-check "~0.3.2"
|
||||||
wordwrap "~1.0.0"
|
word-wrap "~1.2.3"
|
||||||
|
|
||||||
optionator@^0.9.1:
|
optionator@^0.9.1:
|
||||||
version "0.9.1"
|
version "0.9.1"
|
||||||
|
@ -7088,10 +7046,10 @@ parse-json@^5.0.0:
|
||||||
json-parse-even-better-errors "^2.3.0"
|
json-parse-even-better-errors "^2.3.0"
|
||||||
lines-and-columns "^1.1.6"
|
lines-and-columns "^1.1.6"
|
||||||
|
|
||||||
parse5@5.1.1:
|
parse5@6.0.1:
|
||||||
version "5.1.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
|
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||||
integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
|
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||||
|
|
||||||
parseurl@~1.3.3:
|
parseurl@~1.3.3:
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
|
@ -7284,7 +7242,7 @@ prelude-ls@^1.2.1:
|
||||||
prelude-ls@~1.1.2:
|
prelude-ls@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
|
||||||
|
|
||||||
prepend-http@^2.0.0:
|
prepend-http@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
@ -7418,7 +7376,7 @@ pseudomap@^1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||||
|
|
||||||
psl@^1.1.28:
|
psl@^1.1.28, psl@^1.1.33:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
||||||
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
|
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
|
||||||
|
@ -7431,11 +7389,6 @@ pump@^3.0.0:
|
||||||
end-of-stream "^1.1.0"
|
end-of-stream "^1.1.0"
|
||||||
once "^1.3.1"
|
once "^1.3.1"
|
||||||
|
|
||||||
punycode@^1.4.1:
|
|
||||||
version "1.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
|
||||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
|
||||||
|
|
||||||
punycode@^2.1.0:
|
punycode@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
|
||||||
|
@ -7458,11 +7411,6 @@ qs@6.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||||
|
|
||||||
qs@~6.5.1:
|
|
||||||
version "6.5.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
|
||||||
integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==
|
|
||||||
|
|
||||||
qs@~6.5.2:
|
qs@~6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||||
|
@ -7761,51 +7709,7 @@ repeat-string@^1.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
||||||
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
|
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
|
||||||
|
|
||||||
request-promise-core@1.1.4:
|
request@^2.72.0, request@^2.86.0:
|
||||||
version "1.1.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
|
|
||||||
integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.19"
|
|
||||||
|
|
||||||
request-promise-native@^1.0.8:
|
|
||||||
version "1.0.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28"
|
|
||||||
integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==
|
|
||||||
dependencies:
|
|
||||||
request-promise-core "1.1.4"
|
|
||||||
stealthy-require "^1.1.1"
|
|
||||||
tough-cookie "^2.3.3"
|
|
||||||
|
|
||||||
request@^2.72.0:
|
|
||||||
version "2.83.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
|
|
||||||
integrity sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==
|
|
||||||
dependencies:
|
|
||||||
aws-sign2 "~0.7.0"
|
|
||||||
aws4 "^1.6.0"
|
|
||||||
caseless "~0.12.0"
|
|
||||||
combined-stream "~1.0.5"
|
|
||||||
extend "~3.0.1"
|
|
||||||
forever-agent "~0.6.1"
|
|
||||||
form-data "~2.3.1"
|
|
||||||
har-validator "~5.0.3"
|
|
||||||
hawk "~6.0.2"
|
|
||||||
http-signature "~1.2.0"
|
|
||||||
is-typedarray "~1.0.0"
|
|
||||||
isstream "~0.1.2"
|
|
||||||
json-stringify-safe "~5.0.1"
|
|
||||||
mime-types "~2.1.17"
|
|
||||||
oauth-sign "~0.8.2"
|
|
||||||
performance-now "^2.1.0"
|
|
||||||
qs "~6.5.1"
|
|
||||||
safe-buffer "^5.1.1"
|
|
||||||
stringstream "~0.0.5"
|
|
||||||
tough-cookie "~2.3.3"
|
|
||||||
tunnel-agent "^0.6.0"
|
|
||||||
uuid "^3.1.0"
|
|
||||||
|
|
||||||
request@^2.86.0, request@^2.88.2:
|
|
||||||
version "2.88.2"
|
version "2.88.2"
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||||
|
@ -7975,7 +7879,7 @@ safe-buffer@5.1.2, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||||
|
|
||||||
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1:
|
safe-buffer@^5.0.1, safe-buffer@^5.1.0:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||||
integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==
|
integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==
|
||||||
|
@ -8047,7 +7951,7 @@ sax@>=0.6.0, sax@^1.2.4:
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||||
|
|
||||||
saxes@^5.0.0:
|
saxes@^5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
|
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
|
||||||
integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
|
integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
|
||||||
|
@ -8336,13 +8240,6 @@ snapdragon@^0.8.1:
|
||||||
source-map-resolve "^0.5.0"
|
source-map-resolve "^0.5.0"
|
||||||
use "^2.0.0"
|
use "^2.0.0"
|
||||||
|
|
||||||
sntp@2.x.x:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8"
|
|
||||||
integrity sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==
|
|
||||||
dependencies:
|
|
||||||
hoek "4.x.x"
|
|
||||||
|
|
||||||
source-map-js@^1.0.2:
|
source-map-js@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||||
|
@ -8507,11 +8404,6 @@ static-extend@^0.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
|
||||||
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
|
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
|
||||||
|
|
||||||
stealthy-require@^1.1.1:
|
|
||||||
version "1.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
|
||||||
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
|
||||||
|
|
||||||
string-length@^4.0.1:
|
string-length@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1"
|
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1"
|
||||||
|
@ -8616,11 +8508,6 @@ string_decoder@~1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "~5.1.0"
|
safe-buffer "~5.1.0"
|
||||||
|
|
||||||
stringstream@~0.0.5:
|
|
||||||
version "0.0.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
|
|
||||||
integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=
|
|
||||||
|
|
||||||
strip-ansi@^3.0.0:
|
strip-ansi@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||||
|
@ -8933,7 +8820,16 @@ totalist@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
||||||
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
|
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
|
||||||
|
|
||||||
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
tough-cookie@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
|
||||||
|
integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
|
||||||
|
dependencies:
|
||||||
|
psl "^1.1.33"
|
||||||
|
punycode "^2.1.1"
|
||||||
|
universalify "^0.1.2"
|
||||||
|
|
||||||
|
tough-cookie@~2.5.0:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||||
|
@ -8941,22 +8837,6 @@ tough-cookie@^2.3.3, tough-cookie@~2.5.0:
|
||||||
psl "^1.1.28"
|
psl "^1.1.28"
|
||||||
punycode "^2.1.1"
|
punycode "^2.1.1"
|
||||||
|
|
||||||
tough-cookie@^3.0.1:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2"
|
|
||||||
integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==
|
|
||||||
dependencies:
|
|
||||||
ip-regex "^2.1.0"
|
|
||||||
psl "^1.1.28"
|
|
||||||
punycode "^2.1.1"
|
|
||||||
|
|
||||||
tough-cookie@~2.3.3:
|
|
||||||
version "2.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
|
|
||||||
integrity sha1-C2GKVWW23qkL80JdBNVe3EdadWE=
|
|
||||||
dependencies:
|
|
||||||
punycode "^1.4.1"
|
|
||||||
|
|
||||||
tr46@^1.0.0:
|
tr46@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||||
|
@ -8964,10 +8844,10 @@ tr46@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
tr46@^2.0.2:
|
tr46@^2.1.0:
|
||||||
version "2.0.2"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
|
||||||
integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==
|
integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.1"
|
punycode "^2.1.1"
|
||||||
|
|
||||||
|
@ -9085,7 +8965,7 @@ type-check@^0.4.0, type-check@~0.4.0:
|
||||||
type-check@~0.3.2:
|
type-check@~0.3.2:
|
||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
|
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
|
||||||
integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
|
integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
|
||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
|
|
||||||
|
@ -9191,7 +9071,7 @@ unique-string@^2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
crypto-random-string "^2.0.0"
|
crypto-random-string "^2.0.0"
|
||||||
|
|
||||||
universalify@^0.1.0:
|
universalify@^0.1.0, universalify@^0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||||
|
@ -9296,7 +9176,7 @@ uuid@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||||
|
|
||||||
uuid@^3.1.0, uuid@^3.3.2:
|
uuid@^3.3.2:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||||
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
||||||
|
@ -9527,13 +9407,13 @@ whatwg-url@6.4.0:
|
||||||
tr46 "^1.0.0"
|
tr46 "^1.0.0"
|
||||||
webidl-conversions "^4.0.1"
|
webidl-conversions "^4.0.1"
|
||||||
|
|
||||||
whatwg-url@^8.0.0:
|
whatwg-url@^8.0.0, whatwg-url@^8.5.0:
|
||||||
version "8.4.0"
|
version "8.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837"
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
|
||||||
integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==
|
integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash.sortby "^4.7.0"
|
lodash "^4.7.0"
|
||||||
tr46 "^2.0.2"
|
tr46 "^2.1.0"
|
||||||
webidl-conversions "^6.1.0"
|
webidl-conversions "^6.1.0"
|
||||||
|
|
||||||
which-boxed-primitive@^1.0.2:
|
which-boxed-primitive@^1.0.2:
|
||||||
|
@ -9583,16 +9463,11 @@ window-location-origin@^0.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/window-location-origin/-/window-location-origin-0.1.0.tgz#e0a0b3cbe8802c4966b358f859315355d3a15e04"
|
resolved "https://registry.yarnpkg.com/window-location-origin/-/window-location-origin-0.1.0.tgz#e0a0b3cbe8802c4966b358f859315355d3a15e04"
|
||||||
integrity sha1-4KCzy+iALElms1j4WTFTVdOhXgQ=
|
integrity sha1-4KCzy+iALElms1j4WTFTVdOhXgQ=
|
||||||
|
|
||||||
word-wrap@^1.2.3:
|
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||||
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
|
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
|
||||||
|
|
||||||
wordwrap@~1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
|
|
||||||
integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
|
|
||||||
|
|
||||||
worker-farm@^1.3.1:
|
worker-farm@^1.3.1:
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.1.tgz#8e9f4a7da4f3c595aa600903051b969390423fa1"
|
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.1.tgz#8e9f4a7da4f3c595aa600903051b969390423fa1"
|
||||||
|
@ -9632,15 +9507,10 @@ write@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
|
|
||||||
ws@^7.2.3:
|
ws@^7.3.1, ws@^7.4.6:
|
||||||
version "7.3.1"
|
version "7.5.8"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a"
|
||||||
integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==
|
integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==
|
||||||
|
|
||||||
ws@^7.3.1:
|
|
||||||
version "7.5.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67"
|
|
||||||
integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==
|
|
||||||
|
|
||||||
xdg-basedir@^4.0.0:
|
xdg-basedir@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
|
|
Loading…
Reference in a new issue