Merge branch 'development' into refactor-remote-usage-in-app-theme-settings-to-main-process

This commit is contained in:
tidy-dev 2022-02-03 06:49:28 -05:00 committed by GitHub
commit b648099bf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 429 additions and 212 deletions

View file

@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14.15.4]
node: [14.17.0]
os: [macos-10.15, windows-2019]
arch: [x64, arm64]
include:

View file

@ -1 +1 @@
14.15.1
14.17.0

2
.nvmrc
View file

@ -1 +1 @@
v14.15.4
v14.17.0

View file

@ -1,2 +1,2 @@
python 3.9.5
nodejs 14.15.1
nodejs 14.17.0

View file

@ -3,7 +3,7 @@
"productName": "GitHub Desktop",
"bundleID": "com.github.GitHubClient",
"companyName": "GitHub, Inc.",
"version": "2.9.6",
"version": "2.9.7-beta1",
"main": "./main.js",
"repository": {
"type": "git",
@ -26,6 +26,7 @@
"codemirror-mode-elixir": "^1.1.2",
"compare-versions": "^3.6.0",
"deep-equal": "^1.0.1",
"desktop-notifications": "^0.1.4",
"desktop-trampoline": "desktop/desktop-trampoline#v0.9.8",
"detect-arm64-translation": "https://github.com/desktop/node-detect-arm64-translation#v1.0.4",
"dexie": "^2.0.0",
@ -41,7 +42,7 @@
"fs-admin": "^0.19.0",
"fs-extra": "^9.0.1",
"fuzzaldrin-plus": "^0.6.0",
"keytar": "^7.7.0",
"keytar": "^7.8.0",
"marked": "^4.0.10",
"mem": "^4.3.0",
"memoize-one": "^4.0.3",

View file

@ -165,5 +165,5 @@ export function enablePullRequestQuickView(): boolean {
/** Should we enable high-signal notifications? */
export function enableHighSignalNotifications(): boolean {
return enableDevelopmentFeatures()
return __DARWIN__ ? enableBetaFeatures() : enableDevelopmentFeatures()
}

View file

@ -0,0 +1,55 @@
import * as path from 'path'
import * as os from 'os'
import { shell } from 'electron'
/**
* Checks all Windows shortcuts created by Squirrel looking for the toast
* activator CLSID needed to handle Windows notifications from the Action Center.
*/
export function findToastActivatorClsid() {
const shortcutPaths = [
path.join(
os.homedir(),
'AppData',
'Roaming',
'Microsoft',
'Windows',
'Start Menu',
'Programs',
'GitHub, Inc',
'GitHub Desktop.lnk'
),
path.join(os.homedir(), 'Desktop', 'GitHub Desktop.lnk'),
]
for (const shortcutPath of shortcutPaths) {
const toastActivatorClsid = findToastActivatorClsidInShorcut(shortcutPath)
if (toastActivatorClsid !== undefined) {
return toastActivatorClsid
}
}
return undefined
}
function findToastActivatorClsidInShorcut(shortcutPath: string) {
try {
const shortcutDetails = shell.readShortcutLink(shortcutPath)
if (
shortcutDetails.toastActivatorClsid === undefined ||
shortcutDetails.toastActivatorClsid === ''
) {
return undefined
}
return shortcutDetails.toastActivatorClsid
} catch (error) {
log.error(
`Error looking for toast activator CLSID in shortcut ${shortcutPath}`,
error
)
return undefined
}
}

View file

@ -88,7 +88,8 @@ export type RequestResponseChannels = {
'is-running-under-rosetta-translation': () => Promise<boolean>
'move-to-trash': (path: string) => Promise<void>
'show-contextual-menu': (
items: ReadonlyArray<ISerializableMenuItem>
items: ReadonlyArray<ISerializableMenuItem>,
addSpellCheckMenu: boolean
) => Promise<ReadonlyArray<number> | null>
'is-window-focused': () => Promise<boolean>
'open-external': (path: string) => Promise<boolean>

View file

@ -1,3 +1,5 @@
import { invokeContextualMenu } from '../ui/main-process-proxy'
export interface IMenuItem {
/** The user-facing label. */
readonly label?: string
@ -72,3 +74,58 @@ export function getPlatformSpecificNameOrSymbolForModifier(
// Not a known modifier, likely a normal key
return modifier
}
/** Show the given menu items in a contextual menu. */
export async function showContextualMenu(
items: ReadonlyArray<IMenuItem>,
addSpellCheckMenu = false
) {
const indices = await invokeContextualMenu(
serializeMenuItems(items),
addSpellCheckMenu
)
if (indices !== null) {
const menuItem = findSubmenuItem(items, indices)
if (menuItem !== undefined && menuItem.action !== undefined) {
menuItem.action()
}
}
}
/**
* Remove the menu items properties that can't be serializable in
* order to pass them via IPC.
*/
function serializeMenuItems(
items: ReadonlyArray<IMenuItem>
): ReadonlyArray<ISerializableMenuItem> {
return items.map(item => ({
...item,
action: undefined,
submenu: item.submenu ? serializeMenuItems(item.submenu) : undefined,
}))
}
/**
* Traverse the submenus of the context menu until we find the appropriate index.
*/
function findSubmenuItem(
currentContextualMenuItems: ReadonlyArray<IMenuItem>,
indices: ReadonlyArray<number>
): IMenuItem | undefined {
let foundMenuItem: IMenuItem | undefined = {
submenu: currentContextualMenuItems,
}
for (const index of indices) {
if (foundMenuItem === undefined || foundMenuItem.submenu === undefined) {
return undefined
}
foundMenuItem = foundMenuItem.submenu[index]
}
return foundMenuItem
}

View file

@ -1,4 +1,32 @@
import { focusWindow } from '../../../ui/main-process-proxy'
import {
DesktopNotification,
initializeNotifications,
} from 'desktop-notifications'
import { findToastActivatorClsid } from '../../find-toast-activator-clsid'
let windowsToastActivatorClsid: string | undefined = undefined
function initializeWindowsNotifications() {
if (windowsToastActivatorClsid !== undefined) {
return
}
windowsToastActivatorClsid = findToastActivatorClsid()
if (windowsToastActivatorClsid === undefined) {
log.error(
'Toast activator CLSID not found in any of the shortucts. Falling back to known CLSIDs.'
)
// This is generated by Squirrel.Windows here:
// https://github.com/Squirrel/Squirrel.Windows/blob/7396fa50ccebf97e28c79ef519c07cb9eee121be/src/Squirrel/UpdateManager.ApplyReleases.cs#L258
windowsToastActivatorClsid = '{27D44D0C-A542-5B90-BCDB-AC3126048BA2}'
}
log.info(`Using toast activator CLSID ${windowsToastActivatorClsid}`)
initializeNotifications(windowsToastActivatorClsid)
}
/**
* Shows a notification with a title, a body, and a function to handle when the
@ -9,6 +37,18 @@ export function showNotification(
body: string,
onClick: () => void
) {
if (__WIN32__) {
initializeWindowsNotifications()
const notification = new DesktopNotification(title, body)
notification.onclick = () => {
focusWindow()
onClick()
}
notification.show()
return
}
const notification = new Notification(title, {
body,
})

View file

@ -38,6 +38,7 @@ import { installSameOriginFilter } from './same-origin-filter'
import * as ipcMain from './ipc-main'
import { getArchitecture } from '../lib/get-architecture'
import * as remoteMain from '@electron/remote/main'
import { buildSpellCheckMenu } from './menu/build-spell-check-menu'
remoteMain.initialize()
@ -452,14 +453,24 @@ app.on('ready', () => {
* Handle the action to show a contextual menu.
*
* It responds an array of indices that maps to the path to reach
* the menu (or submenu) item that was clicked or null if the menu
* was closed without clicking on any item.
* the menu (or submenu) item that was clicked or null if the menu was closed
* without clicking on any item or the item click was handled by the main
* process as opposed to the renderer.
*/
ipcMain.handle('show-contextual-menu', (event, items) => {
return new Promise(resolve => {
const menu = buildContextMenu(items, indices => resolve(indices))
ipcMain.handle('show-contextual-menu', (event, items, addSpellCheckMenu) => {
return new Promise(async resolve => {
const window = BrowserWindow.fromWebContents(event.sender) || undefined
const spellCheckMenuItems = addSpellCheckMenu
? await buildSpellCheckMenu(window)
: undefined
const menu = buildContextMenu(
items,
indices => resolve(indices),
spellCheckMenuItems
)
menu.popup({ window, callback: () => resolve(null) })
})
})

View file

@ -48,9 +48,20 @@ function getEditMenuItems(): ReadonlyArray<MenuItem> {
*/
export function buildContextMenu(
template: ReadonlyArray<ISerializableMenuItem>,
onClick: (indices: ReadonlyArray<number>) => void
onClick: (indices: ReadonlyArray<number>) => void,
spellCheckMenuItems?: ReadonlyArray<MenuItem>
): Menu {
return buildRecursiveContextMenu(template, onClick)
const menu = buildRecursiveContextMenu(template, onClick)
if (spellCheckMenuItems === undefined) {
return menu
}
for (const spellCheckMenuItem of spellCheckMenuItems) {
menu.append(spellCheckMenuItem)
}
return menu
}
function buildRecursiveContextMenu(

View file

@ -0,0 +1,111 @@
import { app, BrowserWindow, MenuItem } from 'electron'
export async function buildSpellCheckMenu(
window: BrowserWindow | undefined
): Promise<ReadonlyArray<MenuItem> | undefined> {
if (window === undefined) {
return
}
/*
When a user right clicks on a misspelled word in an input, we get event from
electron. That event comes after the context menu event that we get from the
dom.
*/
return new Promise(resolve => {
window.webContents.once('context-menu', (event, params) =>
resolve(getSpellCheckMenuItems(event, params, window.webContents))
)
})
}
function getSpellCheckMenuItems(
event: Electron.Event,
params: Electron.ContextMenuParams,
webContents: Electron.WebContents
): ReadonlyArray<MenuItem> | undefined {
const { misspelledWord, dictionarySuggestions } = params
if (!misspelledWord && dictionarySuggestions.length === 0) {
return
}
const items = new Array<MenuItem>()
items.push(
new MenuItem({
type: 'separator',
})
)
for (const suggestion of dictionarySuggestions) {
items.push(
new MenuItem({
label: suggestion,
click: () => webContents.replaceMisspelling(suggestion),
})
)
}
if (misspelledWord) {
items.push(
new MenuItem({
label: __DARWIN__ ? 'Add to Dictionary' : 'Add to dictionary',
click: () =>
webContents.session.addWordToSpellCheckerDictionary(misspelledWord),
})
)
}
if (!__DARWIN__) {
// NOTE: "On macOS as we use the native APIs there is no way to set the
// language that the spellchecker uses" -- electron docs Therefore, we are
// only allowing setting to English for non-mac machines.
const spellCheckLanguageItem = getSpellCheckLanguageMenuItem(
webContents.session
)
if (spellCheckLanguageItem !== null) {
items.push(spellCheckLanguageItem)
}
}
return items
}
/**
* Method to get a menu item to give user the option to use English or their
* system language.
*
* If system language is english, it returns null. If spellchecker is not set to
* english, it returns item that can set it to English. If spellchecker is set
* to english, it returns the item that can set it to their system language.
*/
function getSpellCheckLanguageMenuItem(
session: Electron.session
): MenuItem | null {
const userLanguageCode = app.getLocale()
const englishLanguageCode = 'en-US'
const spellcheckLanguageCodes = session.getSpellCheckerLanguages()
if (
userLanguageCode === englishLanguageCode &&
spellcheckLanguageCodes.includes(englishLanguageCode)
) {
return null
}
const languageCode =
spellcheckLanguageCodes.includes(englishLanguageCode) &&
!spellcheckLanguageCodes.includes(userLanguageCode)
? userLanguageCode
: englishLanguageCode
const label =
languageCode === englishLanguageCode
? 'Set spellcheck to English'
: 'Set spellcheck to system language'
return new MenuItem({
label,
click: () => session.setSpellCheckerLanguages([languageCode]),
})
}

View file

@ -15,7 +15,7 @@ interface IRange {
}
import getCaretCoordinates from 'textarea-caret'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
interface IAutocompletingTextInputProps<ElementType> {
/**

View file

@ -6,7 +6,7 @@ import { IMatches } from '../../lib/fuzzy-find'
import { Octicon } from '../octicons'
import * as OcticonSymbol from '../octicons/octicons.generated'
import { HighlightText } from '../lib/highlight-text'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { IMenuItem } from '../../lib/menu-item'
import { dragAndDropManager } from '../../lib/drag-and-drop-manager'
import { DragType, DropTargetType } from '../../models/drag-drop'

View file

@ -27,7 +27,7 @@ import {
import { CommitMessage } from './commit-message'
import { ChangedFile } from './changed-file'
import { IAutocompletionProvider } from '../autocompletion'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { arrayEquals } from '../../lib/equality'
import { clipboard } from 'electron'
import { basename } from 'path'

View file

@ -27,7 +27,7 @@ import { CommitWarning, CommitWarningIcon } from './commit-warning'
import { LinkButton } from '../lib/link-button'
import { FoldoutType } from '../../lib/app-state'
import { IAvatarUser, getAvatarUserFromAuthor } from '../../models/avatar'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { Account } from '../../models/account'
import { CommitMessageAvatar } from './commit-message-avatar'
import { getDotComAPIEndpoint } from '../../lib/api'

View file

@ -46,7 +46,7 @@ import {
getLineWidthFromDigitCount,
getNumberOfDigits,
} from './diff-helpers'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { getTokens } from './diff-syntax-mode'
import { DiffSearchInput } from './diff-search-input'
import { escapeRegExp } from '../../lib/helpers/regex'

View file

@ -40,7 +40,7 @@ import { structuralEquals } from '../../lib/equality'
import { assertNever } from '../../lib/fatal-error'
import { clamp } from '../../lib/clamp'
import { uuid } from '../../lib/uuid'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { IMenuItem } from '../../lib/menu-item'
import {
canSelect,

View file

@ -6,7 +6,7 @@ import { RichText } from '../lib/rich-text'
import { RelativeTime } from '../relative-time'
import { getDotComAPIEndpoint } from '../../lib/api'
import { clipboard } from 'electron'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { CommitAttribution } from '../lib/commit-attribution'
import { AvatarStack } from '../lib/avatar-stack'
import { IMenuItem } from '../../lib/menu-item'

View file

@ -23,7 +23,7 @@ import { ThrottledScheduler } from '../lib/throttled-scheduler'
import { Dispatcher } from '../dispatcher'
import { Resizable } from '../resizable'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { CommitSummary } from './commit-summary'
import { FileList } from './file-list'

View file

@ -13,7 +13,7 @@ import { arrayEquals } from '../../lib/equality'
import { syncClockwise } from '../octicons'
import * as OcticonSymbol from '../octicons/octicons.generated'
import { IAuthor } from '../../models/author'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { IMenuItem } from '../../lib/menu-item'
import { getLegacyStealthEmailForUser } from '../../lib/email'

View file

@ -10,7 +10,7 @@ import {
import { join } from 'path'
import { Repository } from '../../../models/repository'
import { Dispatcher } from '../../dispatcher'
import { showContextualMenu } from '../../main-process-proxy'
import { showContextualMenu } from '../../../lib/menu-item'
import { Octicon } from '../../octicons'
import * as OcticonSymbol from '../../octicons/octicons.generated'
import { PathText } from '../path-text'

View file

@ -1,6 +1,6 @@
import * as React from 'react'
import classNames from 'classnames'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
interface ITextAreaProps {
/** The label for the textarea field. */

View file

@ -2,7 +2,7 @@ import * as React from 'react'
import classNames from 'classnames'
import { createUniqueId, releaseUniqueId } from './id-pool'
import { LinkButton } from './link-button'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
export interface ITextBoxProps {
/** The label for the input field. */

View file

@ -1,6 +1,4 @@
import * as remote from '@electron/remote'
import { ExecutableMenuItem } from '../models/app-menu'
import { IMenuItem, ISerializableMenuItem } from '../lib/menu-item'
import { RequestResponseChannels, RequestChannels } from '../lib/ipc-shared'
import * as ipcRenderer from '../lib/ipc-renderer'
@ -221,176 +219,7 @@ export const moveToApplicationsFolder = sendProxy(
*/
export const getAppMenu = sendProxy('get-app-menu', 0)
function findSubmenuItem(
currentContextualMenuItems: ReadonlyArray<IMenuItem>,
indices: ReadonlyArray<number>
): IMenuItem | undefined {
let foundMenuItem: IMenuItem | undefined = {
submenu: currentContextualMenuItems,
}
// Traverse the submenus of the context menu until we find the appropriate index.
for (const index of indices) {
if (foundMenuItem === undefined || foundMenuItem.submenu === undefined) {
return undefined
}
foundMenuItem = foundMenuItem.submenu[index]
}
return foundMenuItem
}
let deferredContextMenuItems: ReadonlyArray<IMenuItem> | null = null
/** Takes a context menu and spelling suggestions from electron and merges them
* into one context menu. */
function mergeDeferredContextMenuItems(
event: Electron.Event,
params: Electron.ContextMenuParams
) {
if (deferredContextMenuItems === null) {
return
}
const items = [...deferredContextMenuItems]
const { misspelledWord, dictionarySuggestions } = params
if (!misspelledWord && dictionarySuggestions.length === 0) {
showContextualMenu(items, false)
return
}
items.push({ type: 'separator' })
const { webContents } = remote.getCurrentWindow()
for (const suggestion of dictionarySuggestions) {
items.push({
label: suggestion,
action: () => webContents.replaceMisspelling(suggestion),
})
}
if (misspelledWord) {
items.push({
label: __DARWIN__ ? 'Add to Dictionary' : 'Add to dictionary',
action: () =>
webContents.session.addWordToSpellCheckerDictionary(misspelledWord),
})
}
if (!__DARWIN__) {
// NOTE: "On macOS as we use the native APIs there is no way to set the
// language that the spellchecker uses" -- electron docs Therefore, we are
// only allowing setting to English for non-mac machines.
const spellCheckLanguageItem = getSpellCheckLanguageMenuItem(
webContents.session
)
if (spellCheckLanguageItem !== null) {
items.push(spellCheckLanguageItem)
}
}
showContextualMenu(items, false)
}
/**
* Method to get a menu item to give user the option to use English or their
* system language.
*
* If system language is english, it returns null. If spellchecker is not set to
* english, it returns item that can set it to English. If spellchecker is set
* to english, it returns the item that can set it to their system language.
*/
function getSpellCheckLanguageMenuItem(
session: Electron.session
): IMenuItem | null {
const userLanguageCode = remote.app.getLocale()
const englishLanguageCode = 'en-US'
const spellcheckLanguageCodes = session.getSpellCheckerLanguages()
if (
userLanguageCode === englishLanguageCode &&
spellcheckLanguageCodes.includes(englishLanguageCode)
) {
return null
}
const languageCode =
spellcheckLanguageCodes.includes(englishLanguageCode) &&
!spellcheckLanguageCodes.includes(userLanguageCode)
? userLanguageCode
: englishLanguageCode
const label =
languageCode === englishLanguageCode
? 'Set spellcheck to English'
: 'Set spellcheck to system language'
return {
label,
action: () => session.setSpellCheckerLanguages([languageCode]),
}
}
const _showContextualMenu = invokeProxy('show-contextual-menu', 1)
/** Show the given menu items in a contextual menu. */
export async function showContextualMenu(
items: ReadonlyArray<IMenuItem>,
mergeWithSpellcheckSuggestions = false
) {
/*
When a user right clicks on a misspelled word in an input, we get event from
electron. That event comes after the context menu event that we get from the
dom. In order merge the spelling suggestions from electron with the context
menu that the input wants to show, we stash the context menu items from the
input away while we wait for the event from electron.
*/
if (deferredContextMenuItems !== null) {
deferredContextMenuItems = null
remote
.getCurrentWebContents()
.off('context-menu', mergeDeferredContextMenuItems)
}
if (mergeWithSpellcheckSuggestions) {
deferredContextMenuItems = items
remote
.getCurrentWebContents()
.once('context-menu', mergeDeferredContextMenuItems)
return
}
/*
This is a regular context menu that does not need to merge with spellcheck
items. They can be shown right away.
*/
const indices = await _showContextualMenu(serializeMenuItems(items))
if (indices !== null) {
const menuItem = findSubmenuItem(items, indices)
if (menuItem !== undefined && menuItem.action !== undefined) {
menuItem.action()
}
}
}
/**
* Remove the menu items properties that can't be serializable in
* order to pass them via IPC.
*/
function serializeMenuItems(
items: ReadonlyArray<IMenuItem>
): ReadonlyArray<ISerializableMenuItem> {
return items.map(item => ({
...item,
action: undefined,
submenu: item.submenu ? serializeMenuItems(item.submenu) : undefined,
}))
}
export const invokeContextualMenu = invokeProxy('show-contextual-menu', 2)
/** Update the menu item labels with the user's preferred apps. */
export const updatePreferredAppMenuItemLabels = sendProxy(

View file

@ -16,7 +16,7 @@ import { Dispatcher } from '../dispatcher'
import { Button } from '../lib/button'
import { Octicon } from '../octicons'
import * as OcticonSymbol from '../octicons/octicons.generated'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { IMenuItem } from '../../lib/menu-item'
import { PopupType } from '../../models/popup'
import { encodePathAsUrl } from '../../lib/path'

View file

@ -4,7 +4,7 @@ import { clipboard } from 'electron'
import { Repository } from '../../models/repository'
import { Octicon, iconForRepository } from '../octicons'
import * as OcticonSymbol from '../octicons/octicons.generated'
import { showContextualMenu } from '../main-process-proxy'
import { showContextualMenu } from '../../lib/menu-item'
import { Repositoryish } from './group-repositories'
import { IMenuItem } from '../../lib/menu-item'
import { HighlightText } from '../lib/highlight-text'

View file

@ -2,7 +2,7 @@
# The least terrible way to resolve a symlink to its real path.
function realpath() {
/usr/bin/python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$0";
/usr/bin/perl -e "use Cwd;print Cwd::abs_path(@ARGV[0])" "$0";
}
CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")"

View file

@ -306,6 +306,13 @@ decompress-response@^4.2.0:
dependencies:
mimic-response "^2.0.0"
decompress-response@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
dependencies:
mimic-response "^3.1.0"
deep-equal@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@ -326,6 +333,15 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
desktop-notifications@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/desktop-notifications/-/desktop-notifications-0.1.4.tgz#698c5822fb88d7a2289f36b4f64eaac8b5bdefed"
integrity sha512-3ADhNvqL9ISbN17x/hWcYUcGHvWJxPnoxxsQbmrU26wpk2eakvDplCm0fvNIpHx/Ar5O7n1VmMOVmLr8W6B8sQ==
dependencies:
node-addon-api "^4.3.0"
prebuild-install "^7.0.1"
uuid "^8.3.2"
desktop-trampoline@desktop/desktop-trampoline#v0.9.8:
version "0.9.8"
resolved "https://codeload.github.com/desktop/desktop-trampoline/tar.gz/cbd3dbb31d0d3ea9f325067f48bfbf60b6663a57"
@ -345,6 +361,11 @@ detect-libc@^1.0.3:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
detect-libc@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.0.tgz#c528bc09bc6d1aa30149228240917c225448f204"
integrity sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw==
devtron@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/devtron/-/devtron-1.4.0.tgz#b5e748bd6e95bbe70bfcc68aae6fe696119441e1"
@ -832,13 +853,13 @@ keyboardevents-areequal@^0.2.1:
resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
keytar@^7.7.0:
version "7.7.0"
resolved "https://registry.yarnpkg.com/keytar/-/keytar-7.7.0.tgz#3002b106c01631aa79b1aa9ee0493b94179bbbd2"
integrity sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==
keytar@^7.8.0:
version "7.8.0"
resolved "https://registry.yarnpkg.com/keytar/-/keytar-7.8.0.tgz#28cf5ceeb1275350888870022869b8b4fe6a87f9"
integrity sha512-mR+BqtAOIW8j+T5FtLVyckCbvROWQD+4FzPeFMuk5njEZkXLpVPCGF26Y3mTyxMAAL1XCfswR7S6kIf+THSRFA==
dependencies:
node-addon-api "^3.0.0"
prebuild-install "^6.0.0"
node-addon-api "^4.3.0"
prebuild-install "^7.0.1"
keyv@^3.0.0:
version "3.1.0"
@ -888,6 +909,13 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
map-age-cleaner@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
@ -934,6 +962,11 @@ mimic-response@^2.0.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.0.0.tgz#996a51c60adf12cb8a87d7fb8ef24c2f3d5ebb46"
integrity sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==
mimic-response@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@ -1027,16 +1060,23 @@ node-abi@^2.7.0:
dependencies:
semver "^5.4.1"
node-addon-api@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681"
integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg==
node-abi@^3.3.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.7.0.tgz#ed980f6dbb6db9ff3b31aeb27d43cd9b096f6e9e"
integrity sha512-3J+U4CvxVNEk9+lGdJkmYbN8cIN0HMTDT9R0ezX7pmp7aD6BaKsfAHwVn3IvVg6pYIRUuQ+gHW1eawrvywnSQQ==
dependencies:
semver "^7.3.5"
node-addon-api@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
node-addon-api@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
@ -1199,6 +1239,25 @@ prebuild-install@^6.0.0:
tunnel-agent "^0.6.0"
which-pm-runs "^1.0.0"
prebuild-install@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.0.1.tgz#c10075727c318efe72412f333e0ef625beaf3870"
integrity sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==
dependencies:
detect-libc "^2.0.0"
expand-template "^2.0.3"
github-from-package "0.0.0"
minimist "^1.2.3"
mkdirp-classic "^0.5.3"
napi-build-utils "^1.0.1"
node-abi "^3.3.0"
npmlog "^4.0.1"
pump "^3.0.0"
rc "^1.2.7"
simple-get "^4.0.0"
tar-fs "^2.0.0"
tunnel-agent "^0.6.0"
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
@ -1466,6 +1525,13 @@ semver@^7.2.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@ -1512,6 +1578,15 @@ simple-get@^3.0.3:
once "^1.3.1"
simple-concat "^1.0.0"
simple-get@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543"
integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==
dependencies:
decompress-response "^6.0.0"
once "^1.3.1"
simple-concat "^1.0.0"
source-map-support@^0.4.15:
version "0.4.18"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
@ -1719,6 +1794,11 @@ uuid@^3.0.1:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
warning@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
@ -1816,3 +1896,8 @@ yallist@^3.0.0, yallist@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==

View file

@ -1,5 +1,21 @@
{
"releases": {
"2.9.7-beta1": [
"[New] Initial support for system notifications when checks fail in macOS - #13655",
"[Added] Support pushing workflow files for GitHub Actions to GitHub Enterprise Server - #13640",
"[Added] Support CLion as an external editor - #13739. Thanks @Pinzauti!",
"[Fixed] Fix close button in full screen mode on macOS - #12838",
"[Fixed] Commit message dialog background styles match dialog - #13606",
"[Fixed] Ensure job steps on pull request check run list are always present - #13531",
"[Improved] Take alias into account when sorting repositories - #13429",
"[Improved] Upgrade to Electron v14.2.3 - #13689",
"[Improved] Support avatars on GitHub Enterprise Server - #13719",
"[Improved] Fetch before trying to follow a URL link to a specific branch - #13641. Thanks @Bestra!",
"[Improved] Add \"View on GitHub\" context menu option to repository list items - #13227. Thanks @lhvy!",
"[Improved] Signal when a commit summary is getting long - #2055. Thanks @Twixes!",
"[Improved] Check run group headers and checks stay in view while scrolling the sub checks or job steps. - #13532",
"[Improved] Remove unnecessary punctuation in appearance settings- #13715. Thanks @Pinzauti!"
],
"2.9.6": [
"[Added] View and re-run the check runs for the checked out pull request.",
"[Fixed] Tooltip improvements and polish - #13452 #13449",