From 3c7a64fb63c9b5786ae7f47c6ad93e9b868f524f Mon Sep 17 00:00:00 2001 From: Dawn Walker Date: Wed, 9 Nov 2022 14:46:17 +1100 Subject: [PATCH 01/29] Updated Registry Uninstall Keys --- app/src/lib/editors/win32.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/lib/editors/win32.ts b/app/src/lib/editors/win32.ts index d24776e5ee..11dd5d7e53 100644 --- a/app/src/lib/editors/win32.ts +++ b/app/src/lib/editors/win32.ts @@ -206,17 +206,17 @@ const editors: WindowsExternalEditor[] = [ // 64-bit version of VSCodium (user) CurrentUserUninstallKey('{2E1F05D1-C245-4562-81EE-28188DB6FD17}_is1'), // 32-bit version of VSCodium (user) - CurrentUserUninstallKey('{C6065F05-9603-4FC4-8101-B9781A25D88E}}_is1'), + CurrentUserUninstallKey('{0FD05EB4-651E-4E78-A062-515204B47A3A}}_is1'), // ARM64 version of VSCodium (user) - CurrentUserUninstallKey('{3AEBF0C8-F733-4AD4-BADE-FDB816D53D7B}_is1'), + CurrentUserUninstallKey('{57FD70A5-1B8D-4875-9F40-C5553F094828}_is1'), // 64-bit version of VSCodium (system) - LocalMachineUninstallKey('{D77B7E06-80BA-4137-BCF4-654B95CCEBC5}_is1'), + LocalMachineUninstallKey('{88DA3577-054F-4CA1-8122-7D820494CFFB}_is1'), // 32-bit version of VSCodium (system) Wow64LocalMachineUninstallKey( - '{E34003BB-9E10-4501-8C11-BE3FAA83F23F}_is1' + '{763CBF88-25C6-4B10-952F-326AE657F16B}_is1' ), // ARM64 version of VSCodium (system) - LocalMachineUninstallKey('{D1ACE434-89C5-48D1-88D3-E2991DF85475}_is1'), + LocalMachineUninstallKey('{67DEE444-3D04-4258-B92A-BC1F0FF2CAE4}_is1'), ], executableShimPaths: [['bin', 'codium.cmd']], displayNamePrefix: 'VSCodium', From cc86b15ad8f00ba1ffdc7a60820223f8b8a2e7e8 Mon Sep 17 00:00:00 2001 From: Dawn Walker Date: Wed, 9 Nov 2022 20:30:27 +1100 Subject: [PATCH 02/29] Fixed VSCodium registry keys --- app/src/lib/editors/win32.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/lib/editors/win32.ts b/app/src/lib/editors/win32.ts index 11dd5d7e53..2d52eec78b 100644 --- a/app/src/lib/editors/win32.ts +++ b/app/src/lib/editors/win32.ts @@ -206,7 +206,7 @@ const editors: WindowsExternalEditor[] = [ // 64-bit version of VSCodium (user) CurrentUserUninstallKey('{2E1F05D1-C245-4562-81EE-28188DB6FD17}_is1'), // 32-bit version of VSCodium (user) - CurrentUserUninstallKey('{0FD05EB4-651E-4E78-A062-515204B47A3A}}_is1'), + CurrentUserUninstallKey('{0FD05EB4-651E-4E78-A062-515204B47A3A}_is1'), // ARM64 version of VSCodium (user) CurrentUserUninstallKey('{57FD70A5-1B8D-4875-9F40-C5553F094828}_is1'), // 64-bit version of VSCodium (system) @@ -214,13 +214,13 @@ const editors: WindowsExternalEditor[] = [ // 32-bit version of VSCodium (system) Wow64LocalMachineUninstallKey( '{763CBF88-25C6-4B10-952F-326AE657F16B}_is1' - ), + ), // ARM64 version of VSCodium (system) LocalMachineUninstallKey('{67DEE444-3D04-4258-B92A-BC1F0FF2CAE4}_is1'), ], executableShimPaths: [['bin', 'codium.cmd']], displayNamePrefix: 'VSCodium', - publisher: 'Microsoft Corporation', + publisher: 'VSCodium', }, { name: 'Sublime Text', From d79f74bf432321193b1f1a1c712995d7e5fae23f Mon Sep 17 00:00:00 2001 From: Dawn Walker Date: Wed, 9 Nov 2022 23:56:18 +1100 Subject: [PATCH 03/29] Run yarn lint:fix --- app/src/lib/editors/win32.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/lib/editors/win32.ts b/app/src/lib/editors/win32.ts index 2d52eec78b..7beb1a0b74 100644 --- a/app/src/lib/editors/win32.ts +++ b/app/src/lib/editors/win32.ts @@ -214,7 +214,7 @@ const editors: WindowsExternalEditor[] = [ // 32-bit version of VSCodium (system) Wow64LocalMachineUninstallKey( '{763CBF88-25C6-4B10-952F-326AE657F16B}_is1' - ), + ), // ARM64 version of VSCodium (system) LocalMachineUninstallKey('{67DEE444-3D04-4258-B92A-BC1F0FF2CAE4}_is1'), ], From 7290059f2a79b56964dea9ebe90822eb65b88a99 Mon Sep 17 00:00:00 2001 From: Dawn Walker Date: Sun, 27 Nov 2022 20:46:07 +1100 Subject: [PATCH 04/29] Update win32.ts --- app/src/lib/editors/win32.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/src/lib/editors/win32.ts b/app/src/lib/editors/win32.ts index 7beb1a0b74..62617bbe93 100644 --- a/app/src/lib/editors/win32.ts +++ b/app/src/lib/editors/win32.ts @@ -201,6 +201,7 @@ const editors: WindowsExternalEditor[] = [ publisher: 'Microsoft Corporation', }, { + // current version of codium with updated registry keys. name: 'Visual Studio Codium', registryKeys: [ // 64-bit version of VSCodium (user) @@ -222,6 +223,27 @@ const editors: WindowsExternalEditor[] = [ displayNamePrefix: 'VSCodium', publisher: 'VSCodium', }, + { + // older version of codium, with the old keys + name: 'Visual Studio Codium', + registryKeys: [ + // 32-bit version of old codium (user) + CurrentUserUninstallKey('{C6065F05-9603-4FC4-8101-B9781A25D88E}}_is1'), + // ARM64 version of old codium (user) + CurrentUserUninstallKey('{3AEBF0C8-F733-4AD4-BADE-FDB816D53D7B}_is1'), + // 64-bit version of old codium (system) + LocalMachineUninstallKey('{D77B7E06-80BA-4137-BCF4-654B95CCEBC5}_is1'), + // 32-bit version of old codium (system) + Wow64LocalMachineUninstallKey( + '{E34003BB-9E10-4501-8C11-BE3FAA83F23F}_is1' + ), + // ARM64 version of old codium (system) + LocalMachineUninstallKey('{D1ACE434-89C5-48D1-88D3-E2991DF85475}_is1'), + ], + executableShimPaths: [['bin', 'codium.cmd']], + displayNamePrefix: 'VSCodium', + publisher: 'Microsoft Corporation', + }, { name: 'Sublime Text', registryKeys: [ From b4ae30c9504c9954580fe7dee6cf6e7c85cff318 Mon Sep 17 00:00:00 2001 From: Dawn Walker Date: Sun, 27 Nov 2022 20:48:26 +1100 Subject: [PATCH 05/29] Update win32.ts Support for codium insiders --- app/src/lib/editors/win32.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/src/lib/editors/win32.ts b/app/src/lib/editors/win32.ts index 62617bbe93..d1e25eef8b 100644 --- a/app/src/lib/editors/win32.ts +++ b/app/src/lib/editors/win32.ts @@ -244,6 +244,28 @@ const editors: WindowsExternalEditor[] = [ displayNamePrefix: 'VSCodium', publisher: 'Microsoft Corporation', }, + { + name: 'Visual Studio Codium (Insiders)', + registryKeys: [ + // 64-bit version of VSCodium - Insiders (user) + CurrentUserUninstallKey('{20F79D0D-A9AC-4220-9A81-CE675FFB6B41}_is1'), + // 32-bit version of VSCodium - Insiders (user) + CurrentUserUninstallKey('{ED2E5618-3E7E-4888-BF3C-A6CCC84F586F}_is1'), + // ARM64 version of VSCodium - Insiders (user) + CurrentUserUninstallKey('{2E362F92-14EA-455A-9ABD-3E656BBBFE71}_is1'), + // 64-bit version of VSCodium - Insiders (system) + LocalMachineUninstallKey('{B2E0DDB2-120E-4D34-9F7E-8C688FF839A2}_is1'), + // 32-bit version of VSCodium - Insiders (system) + Wow64LocalMachineUninstallKey( + '{EF35BB36-FA7E-4BB9-B7DA-D1E09F2DA9C9}_is1' + ), + // ARM64 version of VSCodium - Insiders (system) + LocalMachineUninstallKey('{44721278-64C6-4513-BC45-D48E07830599}_is1'), + ], + executableShimPaths: [['bin', 'codium-insiders.cmd']], + displayNamePrefix: 'VSCodium (Insiders)', + publisher: 'VSCodium', + }, { name: 'Sublime Text', registryKeys: [ From 40784476838e21068ff448a2e7e487721f352127 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Fri, 16 Dec 2022 14:55:29 +0100 Subject: [PATCH 06/29] Add new script to validate the Electron version included in our builds --- script/validate-electron-version.ts | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 script/validate-electron-version.ts diff --git a/script/validate-electron-version.ts b/script/validate-electron-version.ts new file mode 100644 index 0000000000..46bd8c4310 --- /dev/null +++ b/script/validate-electron-version.ts @@ -0,0 +1,53 @@ +/* eslint-disable no-sync */ +/// + +import * as distInfo from './dist-info' + +type ChannelToValidate = 'production' | 'beta' + +/** + * This object states the valid/expected Electron versions for each publishable + * channel of GitHub Desktop. + * + * The purpose of this is to ensure that we don't accidentally publish a + * production/beta/test build with the wrong version of Electron, which could + * cause really bad regressions to our users, and also the inability to go back + * to a previous version of GitHub Desktop without losing all settings. + */ +const ValidElectronVersions: Record = { + production: '19.0.0', + beta: '19.0.0', +} + +const channel = getChannelToValidate() + +if (channel === null) { + console.log( + `No need to validate the Electron version of a ${distInfo.getChannel()} build.` + ) + process.exit(0) +} + +const expectedVersion = ValidElectronVersions[channel] +const pkg: Package = require('../package.json') +const actualVersion = pkg.devDependencies?.electron + +if (actualVersion !== expectedVersion) { + console.error( + `The Electron version for the ${channel} channel is incorrect. Expected ${expectedVersion} but found ${actualVersion}.` + ) + process.exit(1) +} + +console.log( + `The Electron version for the ${channel} channel is correct: ${actualVersion}.` +) + +function getChannelToValidate(): ChannelToValidate | null { + const channel = distInfo.getChannel() + return isChannelToValidate(channel) ? channel : null +} + +function isChannelToValidate(channel: string): channel is ChannelToValidate { + return Object.keys(ValidElectronVersions).includes(channel) +} From 9d7df85edd33e3dc758eaf7632f10f0965bb1498 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Fri, 16 Dec 2022 14:55:42 +0100 Subject: [PATCH 07/29] Run the new script in our CI workflow --- .github/workflows/ci.yml | 2 ++ package.json | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8c8771aff..fd92d2afdb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,6 +57,8 @@ jobs: env: npm_config_arch: ${{ matrix.arch }} TARGET_ARCH: ${{ matrix.arch }} + - name: Validate Electron version + run: yarn run validate-electron-version - name: Lint run: yarn lint - name: Validate changelog diff --git a/package.json b/package.json index 7c345c3e80..50a7bfbb41 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "eslint": "eslint --cache --rulesdir ./eslint-rules \"./eslint-rules/**/*.js\" \"./script/**/*.ts{,x}\" \"./app/{src,typings,test}/**/*.{j,t}s{,x}\" \"./changelog.json\"", "eslint-check": "eslint --print-config .eslintrc.* | eslint-config-prettier-check", "publish": "ts-node -P script/tsconfig.json script/publish.ts", + "validate-electron-version": "ts-node -P script/tsconfig.json script/validate-electron-version.ts", "clean-slate": "rimraf out node_modules app/node_modules && yarn", "rebuild-hard:dev": "yarn clean-slate && yarn build:dev", "rebuild-hard:prod": "yarn clean-slate && yarn build:prod", From 682752be4c11fa1912be02fe4ab18611350648e0 Mon Sep 17 00:00:00 2001 From: Samyek Date: Sun, 1 Jan 2023 09:48:19 +0000 Subject: [PATCH 08/29] updated year --- script/build.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/build.ts b/script/build.ts index 34ae530b78..6fee894d64 100755 --- a/script/build.ts +++ b/script/build.ts @@ -199,7 +199,7 @@ function packageApp() { new RegExp('/\\.git($|/)'), new RegExp('/node_modules/\\.bin($|/)'), ], - appCopyright: 'Copyright © 2017 GitHub, Inc.', + appCopyright: 'Copyright © 20123 GitHub, Inc.', // macOS appBundleId: getBundleID(), From 39aaae548d656a6ab37882165da89525714bb27b Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 23 Nov 2022 13:57:35 +0100 Subject: [PATCH 09/29] (WIP) Trying to get an accessible dropdown working! --- app/src/ui/toolbar/button.tsx | 3 + app/src/ui/toolbar/push-pull-button.tsx | 65 +++++++++++++++++++- app/styles/_ui.scss | 1 + app/styles/ui/toolbar/_button.scss | 9 +++ app/styles/ui/toolbar/_push-pull-button.scss | 50 +++++++++++++++ 5 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 app/styles/ui/toolbar/_push-pull-button.scss diff --git a/app/src/ui/toolbar/button.tsx b/app/src/ui/toolbar/button.tsx index 8f5e35fb7a..1909c7f8bd 100644 --- a/app/src/ui/toolbar/button.tsx +++ b/app/src/ui/toolbar/button.tsx @@ -130,6 +130,8 @@ export interface IToolbarButtonProps { * the tooltip. */ readonly isOverflowed?: ((target: TooltipTarget) => boolean) | boolean + + readonly auxiliaryView?: JSX.Element } /** @@ -227,6 +229,7 @@ export class ToolbarButton extends React.Component { {this.renderText()} {this.props.children} + {this.props.auxiliaryView} ) } diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index 8cbce44c3d..05dfd56be4 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -7,12 +7,16 @@ import { TipState } from '../../models/tip' import { FetchType } from '../../models/fetch' import { Dispatcher } from '../dispatcher' -import { Octicon, syncClockwise } from '../octicons' +import { Octicon, OcticonSymbolType, syncClockwise } from '../octicons' import * as OcticonSymbol from '../octicons/octicons.generated' import { RelativeTime } from '../relative-time' import { ToolbarButton, ToolbarButtonStyle } from './button' import classNames from 'classnames' +import { assertNever } from '../../lib/fatal-error' +import { DropdownState } from './dropdown' +import { Button } from '../lib/button' +import FocusTrap from 'focus-trap-react' interface IPushPullButtonProps { /** @@ -151,6 +155,32 @@ function unbornRepositoryButton() { ) } +function dropdownIcon(state: DropdownState): OcticonSymbolType { + // @TODO: Remake triangle octicon in a 12px version, + // right now it's scaled badly on normal dpi monitors. + if (state === 'open') { + return OcticonSymbol.triangleUp + } else if (state === 'closed') { + return OcticonSymbol.triangleDown + } else { + return assertNever(state, `Unknown dropdown state ${state}`) + } +} + +function renderDropdownButton(): JSX.Element { + // if (this.props.showDisclosureArrow === false) { + // return null + // } + + // const state = this.props.dropdownState + + return ( + + ) +} + function detachedHeadButton(rebaseInProgress: boolean) { const description = rebaseInProgress ? 'Rebase in progress' @@ -207,6 +237,7 @@ function fetchButton( description={renderLastFetched(lastFetched)} icon={syncClockwise} onClick={onClick} + auxiliaryView={renderDropdownButton()} > {renderAheadBehind(aheadBehind, numTagsToPush)} @@ -318,6 +349,38 @@ export class PushPullButton extends React.Component { } public render() { + return ( +
+ {this.renderButton()} + +
+ {this.renderDropdownItem()} + {this.renderDropdownItem()} + {this.renderDropdownItem()} +
+
+
+ ) + } + + public renderDropdownItem() { + return ( + + ) + } + + private renderButton() { const { progress, networkActionInProgress, diff --git a/app/styles/_ui.scss b/app/styles/_ui.scss index 1122e15c7d..f43653c03a 100644 --- a/app/styles/_ui.scss +++ b/app/styles/_ui.scss @@ -21,6 +21,7 @@ @import 'ui/toolbar/toolbar'; @import 'ui/toolbar/button'; @import 'ui/toolbar/dropdown'; +@import 'ui/toolbar/push-pull-button'; @import 'ui/tab-bar'; @import 'ui/panel'; @import 'ui/popup'; diff --git a/app/styles/ui/toolbar/_button.scss b/app/styles/ui/toolbar/_button.scss index 5d981d5d29..9d3bbc1df9 100644 --- a/app/styles/ui/toolbar/_button.scss +++ b/app/styles/ui/toolbar/_button.scss @@ -1,4 +1,8 @@ .toolbar-button { + display: flex; + flex-direction: row; + align-items: stretch; + // Make sure the contents shrink beyond their intrinsic width // See https://css-tricks.com/flexbox-truncated-text/ min-width: 0; @@ -11,6 +15,11 @@ // above all the other content. position: relative; + .toolbar-dropdown-button { + width: 40px; + height: 49px; + } + // General button behavior, mostly resets. // For the button content styling see second button style. Note that we // explicitly use > here to only target the direct descendant button since diff --git a/app/styles/ui/toolbar/_push-pull-button.scss b/app/styles/ui/toolbar/_push-pull-button.scss new file mode 100644 index 0000000000..fe045a3086 --- /dev/null +++ b/app/styles/ui/toolbar/_push-pull-button.scss @@ -0,0 +1,50 @@ +.push-pull-dropdown-button { + display: flex; + flex-direction: column; + max-width: min-content; + + .push-pull-dropdown { + display: flex; + flex-direction: column; + margin-top: 1px; + z-index: 0; + border: 1px solid var(--box-border-color); + + .push-pull-dropdown-item { + padding: 10px; + display: flex; + flex-direction: row; + gap: 10px; + color: var(--text-color); + background-color: var(--box-background-color); + + &:not(:last-child) { + border-bottom: 1px solid var(--box-border-color); + } + + .octicon { + height: 16px; + width: 16px; + } + + &:hover { + background-color: var(--box-hover-background-color); + color: var(--box-hover-text-color); + } + + .text-container { + display: flex; + flex-direction: column; + row-gap: 3px; + + .title { + font-weight: 600; + } + + .detail { + color: var(--text-secondary-color); + } + } + } + } +} From a507ce9b112196956d1e71603133435a5494b3ae Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Thu, 24 Nov 2022 19:09:21 +0100 Subject: [PATCH 10/29] (WIP) First steps refactoring ToolbarDropdown --- app/src/ui/toolbar/branch-dropdown.tsx | 2 +- app/src/ui/toolbar/button.tsx | 3 - app/src/ui/toolbar/dropdown.tsx | 88 +++- app/src/ui/toolbar/push-pull-button.tsx | 466 ++++++++++--------- app/styles/ui/toolbar/_dropdown.scss | 10 +- app/styles/ui/toolbar/_push-pull-button.scss | 18 +- app/styles/ui/toolbar/_toolbar.scss | 10 +- 7 files changed, 332 insertions(+), 265 deletions(-) diff --git a/app/src/ui/toolbar/branch-dropdown.tsx b/app/src/ui/toolbar/branch-dropdown.tsx index 0004087378..4996d243ed 100644 --- a/app/src/ui/toolbar/branch-dropdown.tsx +++ b/app/src/ui/toolbar/branch-dropdown.tsx @@ -183,7 +183,7 @@ export class BranchDropdown extends React.Component< const isOpen = this.props.isOpen const currentState: DropdownState = isOpen && canOpen ? 'open' : 'closed' - const buttonClassName = classNames('nudge-arrow', { + const buttonClassName = classNames('branch-toolbar-button', 'nudge-arrow', { 'nudge-arrow-up': this.props.shouldNudge, }) diff --git a/app/src/ui/toolbar/button.tsx b/app/src/ui/toolbar/button.tsx index 1909c7f8bd..8f5e35fb7a 100644 --- a/app/src/ui/toolbar/button.tsx +++ b/app/src/ui/toolbar/button.tsx @@ -130,8 +130,6 @@ export interface IToolbarButtonProps { * the tooltip. */ readonly isOverflowed?: ((target: TooltipTarget) => boolean) | boolean - - readonly auxiliaryView?: JSX.Element } /** @@ -229,7 +227,6 @@ export class ToolbarButton extends React.Component { {this.renderText()} {this.props.children} - {this.props.auxiliaryView} ) } diff --git a/app/src/ui/toolbar/dropdown.tsx b/app/src/ui/toolbar/dropdown.tsx index f49b03c640..c59328854c 100644 --- a/app/src/ui/toolbar/dropdown.tsx +++ b/app/src/ui/toolbar/dropdown.tsx @@ -13,7 +13,26 @@ import { TooltipTarget } from '../lib/tooltip' export type DropdownState = 'open' | 'closed' +/** Represents the style of the dropdown */ +export enum ToolbarDropdownStyle { + /** + * The dropdown is rendered as a single button and, when expanded, takes the + * full height of the window. + */ + Foldout, + + /** + * The dropdown is rendered as two buttons: one is the toolbar button itself, + * and the other one is the expand/collapse button. + * When expanded, it only takes the height of the content. + */ + MultiOption, +} + export interface IToolbarDropdownProps { + /** The style of the dropdown. Default: Foldout */ + readonly dropdownStyle?: ToolbarDropdownStyle + /** The primary button text, describing its function */ readonly title?: string @@ -74,6 +93,8 @@ export interface IToolbarDropdownProps { */ readonly onContextMenu?: (event: React.MouseEvent) => void + readonly onClick?: (event: React.MouseEvent) => void + /** * A function that's called whenever something is dragged over the * dropdown. @@ -185,7 +206,8 @@ export class ToolbarDropdown extends React.Component< IToolbarDropdownProps, IToolbarDropdownState > { - private innerButton: ToolbarButton | null = null + private innerButton = React.createRef() + private rootDiv = React.createRef() private focusTrapOptions: FocusTrapOptions public constructor(props: IToolbarDropdownProps) { @@ -224,13 +246,25 @@ export class ToolbarDropdown extends React.Component< } const state = this.props.dropdownState - - return ( + const dropdownIcon = ( ) + + return this.props.dropdownStyle === ToolbarDropdownStyle.MultiOption ? ( + + {dropdownIcon} + + ) : ( + dropdownIcon + ) } - private onClick = (event: React.MouseEvent) => { + private onToggleDropdownClick = ( + event: React.MouseEvent + ) => { const newState: DropdownState = this.props.dropdownState === 'open' ? 'closed' : 'open' @@ -247,13 +281,22 @@ export class ToolbarDropdown extends React.Component< this.props.onDropdownStateChanged(newState, source) } + private onMainButtonClick = (event: React.MouseEvent) => { + if (this.props.dropdownStyle === ToolbarDropdownStyle.MultiOption) { + this.props.onClick?.(event) + return + } + + this.onToggleDropdownClick(event) + } + private onContextMenu = (event: React.MouseEvent) => { this.props.onContextMenu?.(event) } private updateClientRectIfNecessary() { - if (this.props.dropdownState === 'open' && this.innerButton) { - const newRect = this.innerButton.getButtonBoundingClientRect() + if (this.props.dropdownState === 'open' && this.rootDiv.current) { + const newRect = this.rootDiv.current.getBoundingClientRect() if (newRect) { const currentRect = this.state.clientRect @@ -268,10 +311,6 @@ export class ToolbarDropdown extends React.Component< this.updateClientRectIfNecessary() } - public componentWillUnmount() { - this.innerButton = null - } - public componentDidUpdate() { this.updateClientRectIfNecessary() } @@ -305,12 +344,16 @@ export class ToolbarDropdown extends React.Component< return undefined } + const heightStyle: React.CSSProperties = + this.props.dropdownStyle === ToolbarDropdownStyle.MultiOption + ? { maxHeight: '100%', width: rect.width } + : { height: '100%', minWidth: rect.width } + return { position: 'absolute', marginLeft: rect.left, - minWidth: rect.width, - height: '100%', top: 0, + ...heightStyle, } } @@ -354,22 +397,21 @@ export class ToolbarDropdown extends React.Component< ) } - private onRef = (ref: ToolbarButton | null) => { - this.innerButton = ref - } - /** * Programmatically move keyboard focus to the button element. */ public focusButton = () => { - if (this.innerButton) { - this.innerButton.focusButton() + if (this.innerButton.current) { + this.innerButton.current.focusButton() } } public render() { const className = classNames( 'toolbar-dropdown', + this.props.dropdownStyle === ToolbarDropdownStyle.MultiOption + ? 'multi-option-style' + : 'foldout-style', this.props.dropdownState, this.props.className ) @@ -383,16 +425,17 @@ export class ToolbarDropdown extends React.Component< role={this.props.role} aria-expanded={ariaExpanded} onDragOver={this.props.onDragOver} + ref={this.rootDiv} > {this.renderDropdownContents()} {this.props.children} - {this.renderDropdownArrow()} + {this.props.dropdownStyle !== ToolbarDropdownStyle.MultiOption && + this.renderDropdownArrow()} + {this.props.dropdownStyle === ToolbarDropdownStyle.MultiOption && + this.renderDropdownArrow()} ) } diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index 05dfd56be4..af31d9082d 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -7,16 +7,19 @@ import { TipState } from '../../models/tip' import { FetchType } from '../../models/fetch' import { Dispatcher } from '../dispatcher' -import { Octicon, OcticonSymbolType, syncClockwise } from '../octicons' +import { Octicon, syncClockwise } from '../octicons' import * as OcticonSymbol from '../octicons/octicons.generated' import { RelativeTime } from '../relative-time' -import { ToolbarButton, ToolbarButtonStyle } from './button' +import { ToolbarButtonStyle } from './button' import classNames from 'classnames' -import { assertNever } from '../../lib/fatal-error' -import { DropdownState } from './dropdown' +import { + DropdownState, + IToolbarDropdownProps, + ToolbarDropdown, + ToolbarDropdownStyle, +} from './dropdown' import { Button } from '../lib/button' -import FocusTrap from 'focus-trap-react' interface IPushPullButtonProps { /** @@ -68,6 +71,10 @@ interface IPushPullButtonProps { readonly numTagsToPush: number } +interface IPushPullButtonState { + readonly isOpen: boolean +} + function renderAheadBehind(aheadBehind: IAheadBehind, numTagsToPush: number) { const { ahead, behind } = aheadBehind if (ahead === 0 && behind === 0 && numTagsToPush === 0) { @@ -108,187 +115,6 @@ function renderLastFetched(lastFetched: Date | null): JSX.Element | string { } } -/** The common props for all button states */ -const defaultProps = { - className: 'push-pull-button', - style: ToolbarButtonStyle.Subtitle, -} - -function progressButton(progress: Progress, networkActionInProgress: boolean) { - return ( - - ) -} - -function publishRepositoryButton(onClick: () => void) { - return ( - - ) -} - -function unbornRepositoryButton() { - return ( - - ) -} - -function dropdownIcon(state: DropdownState): OcticonSymbolType { - // @TODO: Remake triangle octicon in a 12px version, - // right now it's scaled badly on normal dpi monitors. - if (state === 'open') { - return OcticonSymbol.triangleUp - } else if (state === 'closed') { - return OcticonSymbol.triangleDown - } else { - return assertNever(state, `Unknown dropdown state ${state}`) - } -} - -function renderDropdownButton(): JSX.Element { - // if (this.props.showDisclosureArrow === false) { - // return null - // } - - // const state = this.props.dropdownState - - return ( - - ) -} - -function detachedHeadButton(rebaseInProgress: boolean) { - const description = rebaseInProgress - ? 'Rebase in progress' - : 'Cannot publish detached HEAD' - - return ( - - ) -} - -function publishBranchButton( - isGitHub: boolean, - onClick: () => void, - shouldNudge: boolean -) { - const description = isGitHub - ? 'Publish this branch to GitHub' - : 'Publish this branch to the remote' - - const className = classNames(defaultProps.className, 'nudge-arrow', { - 'nudge-arrow-up': shouldNudge, - }) - - return ( - - ) -} - -function fetchButton( - remoteName: string, - aheadBehind: IAheadBehind, - numTagsToPush: number, - lastFetched: Date | null, - onClick: () => void -) { - const title = `Fetch ${remoteName}` - return ( - - {renderAheadBehind(aheadBehind, numTagsToPush)} - - ) -} - -function pullButton( - remoteName: string, - aheadBehind: IAheadBehind, - numTagsToPush: number, - lastFetched: Date | null, - pullWithRebase: boolean, - onClick: () => void -) { - const title = pullWithRebase - ? `Pull ${remoteName} with rebase` - : `Pull ${remoteName}` - - return ( - - {renderAheadBehind(aheadBehind, numTagsToPush)} - - ) -} - -function pushButton( - remoteName: string, - aheadBehind: IAheadBehind, - numTagsToPush: number, - lastFetched: Date | null, - onClick: () => void -) { - return ( - - {renderAheadBehind(aheadBehind, numTagsToPush)} - - ) -} - /** * This represents the "double arrow" icon used to show a force-push, and is a * less complicated icon than the generated Octicon from the `octicons` package. @@ -304,31 +130,31 @@ const forcePushIcon: OcticonSymbol.OcticonSymbolType = { fr: 'evenodd', } -function forcePushButton( - remoteName: string, - aheadBehind: IAheadBehind, - numTagsToPush: number, - lastFetched: Date | null, - onClick: () => void -) { - return ( - - {renderAheadBehind(aheadBehind, numTagsToPush)} - - ) -} - /** * A button which pushes, pulls, or updates depending on the state of the * repository. */ -export class PushPullButton extends React.Component { +export class PushPullButton extends React.Component< + IPushPullButtonProps, + IPushPullButtonState +> { + public constructor(props: IPushPullButtonProps) { + super(props) + this.state = { isOpen: false } + } + + /** The common props for all button states */ + private defaultDropdownProps(): IToolbarDropdownProps { + return { + dropdownStyle: ToolbarDropdownStyle.MultiOption, + dropdownState: this.state.isOpen ? 'open' : 'closed', + onDropdownStateChanged: this.onDropdownStateChanged, + dropdownContentRenderer: this.dropdownContentRenderer, + buttonClassName: 'push-pull-button', + style: ToolbarButtonStyle.Subtitle, + } + } + private push = () => { this.props.dispatcher.push(this.props.repository) } @@ -348,24 +174,36 @@ export class PushPullButton extends React.Component { ) } - public render() { + private dropdownContentRenderer = () => { return (
- {this.renderButton()} - -
- {this.renderDropdownItem()} - {this.renderDropdownItem()} - {this.renderDropdownItem()} -
-
+ {/* {this.renderButton()} + */} +
+ {this.renderDropdownItem()} + {this.renderDropdownItem()} + {this.renderDropdownItem()} +
+ {/* //
+ //
*/}
) } + private onDropdownStateChanged = ( + state: DropdownState, + source: 'keyboard' | 'pointer' + ) => { + this.setState({ isOpen: state === 'open' }) + } + + public render() { + return this.renderButton() + } + public renderDropdownItem() { return ( ) @@ -302,8 +345,8 @@ export class PushPullButton extends React.Component< private progressButton(progress: Progress, networkActionInProgress: boolean) { return ( - void) { return ( - ) } @@ -395,15 +441,13 @@ export class PushPullButton extends React.Component< ) { const title = `Fetch ${remoteName}` return ( - - {renderAheadBehind(aheadBehind, numTagsToPush)} - + /> ) } @@ -426,6 +470,10 @@ export class PushPullButton extends React.Component< description={renderLastFetched(lastFetched)} icon={OcticonSymbol.arrowDown} onClick={onClick} + dropdownContentRenderer={this.getDropdownContentRenderer([ + DropdownItemType.Fetch, + DropdownItemType.ForcePush, + ])} > {renderAheadBehind(aheadBehind, numTagsToPush)} @@ -446,6 +494,9 @@ export class PushPullButton extends React.Component< description={renderLastFetched(lastFetched)} icon={OcticonSymbol.arrowUp} onClick={onClick} + dropdownContentRenderer={this.getDropdownContentRenderer([ + DropdownItemType.Fetch, + ])} > {renderAheadBehind(aheadBehind, numTagsToPush)} @@ -466,6 +517,9 @@ export class PushPullButton extends React.Component< description={renderLastFetched(lastFetched)} icon={forcePushIcon} onClick={onClick} + dropdownContentRenderer={this.getDropdownContentRenderer([ + DropdownItemType.Fetch, + ])} > {renderAheadBehind(aheadBehind, numTagsToPush)} From 8920fb29a96aa71fc7b4c2f0db10bcd952fdbe5c Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Tue, 10 Jan 2023 17:29:06 +0100 Subject: [PATCH 12/29] Refactor rendering push-pull dropdown items --- app/src/lib/app-state.ts | 2 + app/src/ui/app.tsx | 15 ++++++ app/src/ui/toolbar/push-pull-button.tsx | 63 +++++++++++++------------ 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/app/src/lib/app-state.ts b/app/src/lib/app-state.ts index 0e9525456d..5e1ebe43c4 100644 --- a/app/src/lib/app-state.ts +++ b/app/src/lib/app-state.ts @@ -327,6 +327,7 @@ export enum FoldoutType { Branch, AppMenu, AddMenu, + PushPull, } export type AppMenuFoldout = { @@ -358,6 +359,7 @@ export type Foldout = | { type: FoldoutType.AddMenu } | BranchFoldout | AppMenuFoldout + | { type: FoldoutType.PushPull } export enum RepositorySectionTab { Changes, diff --git a/app/src/ui/app.tsx b/app/src/ui/app.tsx index 04935d73be..ff1968d0df 100644 --- a/app/src/ui/app.tsx +++ b/app/src/ui/app.tsx @@ -2800,6 +2800,11 @@ export class App extends React.Component { remoteName = tip.branch.upstreamRemoteName } + const currentFoldout = this.state.currentFoldout + + const isDropdownOpen = + currentFoldout !== null && currentFoldout.type === FoldoutType.PushPull + const isForcePush = getCurrentBranchForcePushState(branchesState, aheadBehind) === ForcePushBranchState.Recommended @@ -2821,6 +2826,8 @@ export class App extends React.Component { shouldNudge={ this.state.currentOnboardingTutorialStep === TutorialStep.PushBranch } + isDropdownOpen={isDropdownOpen} + onDropdownStateChanged={this.onPushPullDropdownStateChanged} /> ) } @@ -2884,6 +2891,14 @@ export class App extends React.Component { this.props.dispatcher.openCreatePullRequestInBrowser(repository, branch) } + private onPushPullDropdownStateChanged = (newState: DropdownState) => { + if (newState === 'open') { + this.props.dispatcher.showFoldout({ type: FoldoutType.PushPull }) + } else { + this.props.dispatcher.closeFoldout(FoldoutType.PushPull) + } + } + private onBranchDropdownStateChanged = (newState: DropdownState) => { if (newState === 'open') { this.props.dispatcher.showFoldout({ type: FoldoutType.Branch }) diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index 480de309f0..c8783fbe8d 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -20,6 +20,7 @@ import { ToolbarDropdownStyle, } from './dropdown' import { Button } from '../lib/button' +import { FoldoutType } from '../../lib/app-state' interface IPushPullButtonProps { /** @@ -69,15 +70,22 @@ interface IPushPullButtonProps { * The number of tags that would get pushed if the user performed a push. */ readonly numTagsToPush: number -} -interface IPushPullButtonState { - readonly isOpen: boolean + /** Whether or not the push-pull dropdown is currently open */ + readonly isDropdownOpen: boolean + + /** + * An event handler for when the drop down is opened, or closed, by a pointer + * event or by pressing the space or enter key while focused. + * + * @param state - The new state of the drop down + */ + readonly onDropdownStateChanged: (state: DropdownState) => void } enum DropdownItemType { - Fetch, - ForcePush, + Fetch = 'fetch', + ForcePush = 'force-push', } type DropdownItem = { @@ -146,19 +154,11 @@ const forcePushIcon: OcticonSymbol.OcticonSymbolType = { * A button which pushes, pulls, or updates depending on the state of the * repository. */ -export class PushPullButton extends React.Component< - IPushPullButtonProps, - IPushPullButtonState -> { - public constructor(props: IPushPullButtonProps) { - super(props) - this.state = { isOpen: false } - } - +export class PushPullButton extends React.Component { /** The common props for all button states */ private defaultButtonProps() { return { - buttonClassName: 'push-pull-button', + className: 'push-pull-button', style: ToolbarButtonStyle.Subtitle, } } @@ -169,26 +169,35 @@ export class PushPullButton extends React.Component< 'dropdownContentRenderer' > { return { - ...this.defaultButtonProps(), + buttonClassName: 'push-pull-button', + style: ToolbarButtonStyle.Subtitle, dropdownStyle: ToolbarDropdownStyle.MultiOption, - dropdownState: this.state.isOpen ? 'open' : 'closed', - onDropdownStateChanged: this.onDropdownStateChanged, + dropdownState: this.props.isDropdownOpen ? 'open' : 'closed', + onDropdownStateChanged: this.props.onDropdownStateChanged, } } + private closeDropdown() { + this.props.dispatcher.closeFoldout(FoldoutType.PushPull) + } + private push = () => { + this.closeDropdown() this.props.dispatcher.push(this.props.repository) } private forcePushWithLease = () => { + this.closeDropdown() this.props.dispatcher.confirmOrForcePush(this.props.repository) } private pull = () => { + this.closeDropdown() this.props.dispatcher.pull(this.props.repository) } private fetch = () => { + this.closeDropdown() this.props.dispatcher.fetch( this.props.repository, FetchType.UserInitiatedTask @@ -201,7 +210,7 @@ export class PushPullButton extends React.Component< return () => { return (
- {/* {this.renderButton()} + {/* {itemTypes.map(this.renderDropdownItem)}
- {/* // - //
*/} + {/* */}
) } } - private onDropdownStateChanged = ( - state: DropdownState, - source: 'keyboard' | 'pointer' - ) => { - this.setState({ isOpen: state === 'open' }) - } - public render() { return this.renderButton() } @@ -251,7 +252,11 @@ export class PushPullButton extends React.Component< public renderDropdownItem = (type: DropdownItemType) => { const item = this.getDropdownItemWithType(type) return ( -
+ ) } } + private onDropdownKeyDown = (event: React.KeyboardEvent) => { + // Allow using Up and Down arrow keys to navigate the dropdown items + // (equivalent to Tab and Shift+Tab) + if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') { + return + } + + event.preventDefault() + const dropdown = event.currentTarget + const items = dropdown.querySelectorAll( + '.push-pull-dropdown-item' + ) + const focusedItem = dropdown.querySelector(':focus') + if (!focusedItem) { + return + } + + const focusedIndex = Array.from(items).indexOf(focusedItem) + const nextIndex = + event.key === 'ArrowDown' ? focusedIndex + 1 : focusedIndex - 1 + const nextItem = items[nextIndex % items.length] + nextItem?.focus() + } + public render() { return this.renderButton() } diff --git a/app/styles/ui/toolbar/_push-pull-button.scss b/app/styles/ui/toolbar/_push-pull-button.scss index e5536b9227..d3ec620bdf 100644 --- a/app/styles/ui/toolbar/_push-pull-button.scss +++ b/app/styles/ui/toolbar/_push-pull-button.scss @@ -1,61 +1,56 @@ -.push-pull-dropdown-button { +.push-pull-dropdown { display: flex; flex-direction: column; + margin-top: 1px; + z-index: 0; max-width: 100%; - .push-pull-dropdown { + .push-pull-dropdown-item { display: flex; - flex-direction: column; - margin-top: 1px; - z-index: 0; + flex-direction: row; + height: fit-content; + padding: 10px; + gap: 10px; + color: var(--text-color); + background-color: var(--box-background-color); + white-space: normal; - .push-pull-dropdown-item { + // Unset styles from Button component + text-align: unset; + border: unset; + border-radius: unset; + + .octicon { + height: 16px; + width: 16px; + } + + &:hover { + background-color: var(--box-hover-background-color); + color: var(--box-hover-text-color); + } + + &:not(:last-child) { + border-bottom: 1px solid var(--box-border-color); + } + + .text-container { display: flex; - flex-direction: row; - height: fit-content; - padding: 10px; - gap: 10px; - color: var(--text-color); - background-color: var(--box-background-color); - white-space: normal; + flex-direction: column; + row-gap: 3px; - // Unset styles from Button component - text-align: unset; - border: unset; - border-radius: unset; - - .octicon { - height: 16px; - width: 16px; + .title { + font-weight: 600; } - &:hover { - background-color: var(--box-hover-background-color); - color: var(--box-hover-text-color); - } + .detail { + color: var(--text-secondary-color); - &:not(:last-child) { - border-bottom: 1px solid var(--box-border-color); - } + .warning { + color: var(--toolbar-dropdown-text-warning-color); - .text-container { - display: flex; - flex-direction: column; - row-gap: 3px; - - .title { - font-weight: 600; - } - - .detail { - color: var(--text-secondary-color); - - .warning { - color: var(--toolbar-dropdown-text-warning-color); - - .warning-title { - font-weight: 600; - } + .warning-title { + font-weight: 600; } } } From 746c32a407d2e11cf6d66b34478a915ceee83478 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 11 Jan 2023 13:30:14 +0100 Subject: [PATCH 17/29] Extract class name into constant --- app/src/ui/toolbar/push-pull-button.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index 0b0104780f..62757cc399 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -23,6 +23,8 @@ import { Button } from '../lib/button' import { FoldoutType } from '../../lib/app-state' import { ForcePushBranchState } from '../../lib/rebase' +const DropdownItemClassName = 'push-pull-dropdown-item' + interface IPushPullButtonProps { /** * The ahead/behind count for the current branch. If null, it indicates the @@ -211,7 +213,10 @@ export class PushPullButton extends React.Component { return () => { return ( <> - {/* The
element has a child + ) + } + + public render() { + const { itemTypes } = this.props + return ( +
+ {itemTypes.map(this.renderDropdownItem)} +
+ ) + } +} diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index a5c6a879bb..43bfdf2c09 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -19,11 +19,11 @@ import { ToolbarDropdown, ToolbarDropdownStyle, } from './dropdown' -import { Button } from '../lib/button' import { FoldoutType } from '../../lib/app-state' import { ForcePushBranchState } from '../../lib/rebase' +import { PushPullButtonDropDown } from './push-pull-button-dropdown' -const DropdownItemClassName = 'push-pull-dropdown-item' +export const DropdownItemClassName = 'push-pull-dropdown-item' interface IPushPullButtonProps { /** @@ -86,12 +86,12 @@ interface IPushPullButtonProps { readonly onDropdownStateChanged: (state: DropdownState) => void } -enum DropdownItemType { +export enum DropdownItemType { Fetch = 'fetch', ForcePush = 'force-push', } -type DropdownItem = { +export type DropdownItem = { readonly title: string readonly description: string | JSX.Element readonly action: () => void @@ -142,7 +142,7 @@ function renderLastFetched(lastFetched: Date | null): JSX.Element | string { * This represents the "double arrow" icon used to show a force-push, and is a * less complicated icon than the generated Octicon from the `octicons` package. */ -const forcePushIcon: OcticonSymbol.OcticonSymbolType = { +export const forcePushIcon: OcticonSymbol.OcticonSymbolType = { w: 10, h: 16, d: @@ -212,102 +212,20 @@ export class PushPullButton extends React.Component { ) { return () => { return ( - <> - {/* - This
is not interactive, but its children are, so we need to - disable the jsx-a11y/no-static-element-interactions rule. - */} - {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} -
- {itemTypes.map(this.renderDropdownItem)} -
- + ) } } - private onDropdownKeyDown = (event: React.KeyboardEvent) => { - // Allow using Up and Down arrow keys to navigate the dropdown items - // (equivalent to Tab and Shift+Tab) - if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') { - return - } - - event.preventDefault() - const dropdown = event.currentTarget - const items = dropdown.querySelectorAll( - `.${DropdownItemClassName}` - ) - const focusedItem = dropdown.querySelector(':focus') - if (!focusedItem) { - return - } - - const focusedIndex = Array.from(items).indexOf(focusedItem) - const nextIndex = - event.key === 'ArrowDown' ? focusedIndex + 1 : focusedIndex - 1 - // http://javascript.about.com/od/problemsolving/a/modulobug.htm - const nextItem = items[(nextIndex + items.length) % items.length] - nextItem?.focus() - } - public render() { return this.renderButton() } - private getDropdownItemWithType(type: DropdownItemType): DropdownItem { - const { remoteName } = this.props - - switch (type) { - case DropdownItemType.Fetch: - return { - title: `Fetch ${remoteName}`, - description: `Fetch the latest changes from ${remoteName}`, - action: this.fetch, - icon: syncClockwise, - } - case DropdownItemType.ForcePush: - return { - title: `Force push ${remoteName}`, - description: ( - <> - Overwrite any changes on {remoteName} with your local changes -
-
-
- Warning: A force push - will rewrite history on the remote. Any collaborators working on - this branch will need to reset their own local branch to match - the history of the remote. -
- - ), - action: this.forcePushWithLease, - icon: forcePushIcon, - } - } - } - - public renderDropdownItem = (type: DropdownItemType) => { - const item = this.getDropdownItemWithType(type) - return ( - - ) - } - private renderButton() { const { progress, From 18c155346252412b1b3fd9a1ce0be92039ce6d24 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Fri, 20 Jan 2023 13:10:05 +0100 Subject: [PATCH 28/29] Feature-flag push-pull-fetch dropdown for beta builds --- app/src/lib/feature-flag.ts | 5 ++ app/src/ui/toolbar/push-pull-button.tsx | 64 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/app/src/lib/feature-flag.ts b/app/src/lib/feature-flag.ts index 67c445ba3e..ee5716f0d6 100644 --- a/app/src/lib/feature-flag.ts +++ b/app/src/lib/feature-flag.ts @@ -122,3 +122,8 @@ export function enableStackedPopups(): boolean { export function enablePreventClosingWhileUpdating(): boolean { return enableBetaFeatures() } + +/** Should we enable the new push-pull-fetch dropdown? */ +export function enablePushPullFetchDropdown(): boolean { + return enableBetaFeatures() +} diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index 43bfdf2c09..7080307e8c 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -22,6 +22,7 @@ import { import { FoldoutType } from '../../lib/app-state' import { ForcePushBranchState } from '../../lib/rebase' import { PushPullButtonDropDown } from './push-pull-button-dropdown' +import { enablePushPullFetchDropdown } from '../../lib/feature-flag' export const DropdownItemClassName = 'push-pull-dropdown-item' @@ -375,6 +376,27 @@ export class PushPullButton extends React.Component { ? 'Publish this branch to GitHub' : 'Publish this branch to the remote' + if (!enablePushPullFetchDropdown()) { + const className = classNames( + this.defaultButtonProps().className, + 'nudge-arrow', + { + 'nudge-arrow-up': shouldNudge, + } + ) + + return ( + + ) + } + const className = classNames( this.defaultDropdownProps().className, 'nudge-arrow', @@ -436,6 +458,20 @@ export class PushPullButton extends React.Component { dropdownItemTypes.push(DropdownItemType.ForcePush) } + if (!enablePushPullFetchDropdown()) { + return ( + + {renderAheadBehind(aheadBehind, numTagsToPush)} + + ) + } + return ( { lastFetched: Date | null, onClick: () => void ) { + if (!enablePushPullFetchDropdown()) { + return ( + + {renderAheadBehind(aheadBehind, numTagsToPush)} + + ) + } + return ( { lastFetched: Date | null, onClick: () => void ) { + if (!enablePushPullFetchDropdown()) { + return ( + + {renderAheadBehind(aheadBehind, numTagsToPush)} + + ) + } + return ( Date: Fri, 20 Jan 2023 13:25:48 +0100 Subject: [PATCH 29/29] Remove unnecessary parameters --- app/src/ui/toolbar/push-pull-button.tsx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/src/ui/toolbar/push-pull-button.tsx b/app/src/ui/toolbar/push-pull-button.tsx index 7080307e8c..101d852093 100644 --- a/app/src/ui/toolbar/push-pull-button.tsx +++ b/app/src/ui/toolbar/push-pull-button.tsx @@ -270,13 +270,7 @@ export class PushPullButton extends React.Component { const { ahead, behind } = aheadBehind if (ahead === 0 && behind === 0 && numTagsToPush === 0) { - return this.fetchButton( - remoteName, - aheadBehind, - numTagsToPush, - lastFetched, - this.fetch - ) + return this.fetchButton(remoteName, lastFetched, this.fetch) } if (forcePushBranchState === ForcePushBranchState.Recommended) { @@ -422,8 +416,6 @@ export class PushPullButton extends React.Component { private fetchButton( remoteName: string, - aheadBehind: IAheadBehind, - numTagsToPush: number, lastFetched: Date | null, onClick: () => void ) {