From ec079ef4cd87c140e1cac7d57a6e8c62cc7f817d Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Tue, 13 Apr 2021 19:29:46 +0200 Subject: [PATCH 1/8] (WIP) Initial work to set repository aliases --- .../lib/databases/repositories-database.ts | 1 + app/src/lib/stores/app-store.ts | 8 +++ app/src/lib/stores/repositories-store.ts | 21 ++++++ app/src/models/popup.ts | 2 + app/src/models/repository.ts | 1 + app/src/ui/app.tsx | 10 +++ .../change-repository-alias-dialog.tsx | 68 +++++++++++++++++++ app/src/ui/dispatcher/dispatcher.ts | 8 +++ .../repositories-list/group-repositories.ts | 15 +++- .../repositories-list/repositories-list.tsx | 10 ++- .../repository-list-item.tsx | 63 ++++++++++++++--- app/styles/ui/_repository-list.scss | 20 +++++- 12 files changed, 215 insertions(+), 12 deletions(-) create mode 100644 app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx diff --git a/app/src/lib/databases/repositories-database.ts b/app/src/lib/databases/repositories-database.ts index cb777337dcd..106c026968a 100644 --- a/app/src/lib/databases/repositories-database.ts +++ b/app/src/lib/databases/repositories-database.ts @@ -44,6 +44,7 @@ export interface IDatabaseRepository { readonly id?: number readonly gitHubRepositoryID: number | null readonly path: string + readonly alias: string | null readonly missing: boolean /** The last time the stash entries were checked for the repository */ diff --git a/app/src/lib/stores/app-store.ts b/app/src/lib/stores/app-store.ts index 118ed050357..80925f24d43 100644 --- a/app/src/lib/stores/app-store.ts +++ b/app/src/lib/stores/app-store.ts @@ -3408,6 +3408,14 @@ export class AppStore extends TypedBaseStore { return Promise.resolve() } + /** This shouldn't be called directly. See `Dispatcher`. */ + public async _changeRepositoryAlias( + repository: Repository, + newAlias: string + ): Promise { + return this.repositoriesStore.updateRepositoryAlias(repository, newAlias) + } + /** This shouldn't be called directly. See `Dispatcher`. */ public async _renameBranch( repository: Repository, diff --git a/app/src/lib/stores/repositories-store.ts b/app/src/lib/stores/repositories-store.ts index 1a35762be46..116272439c5 100644 --- a/app/src/lib/stores/repositories-store.ts +++ b/app/src/lib/stores/repositories-store.ts @@ -132,6 +132,7 @@ export class RepositoriesStore extends TypedBaseStore< ? await this.findGitHubRepositoryByID(repo.gitHubRepositoryID) : await Promise.resolve(null), // Dexie gets confused if we return null repo.missing, + repo.alias, repo.workflowPreferences, repo.isTutorialRepository ) @@ -194,6 +195,7 @@ export class RepositoriesStore extends TypedBaseStore< return await this.db.repositories.put({ ...(existingRepo?.id !== undefined && { id: existingRepo.id }), path, + alias: null, gitHubRepositoryID: ghRepo.dbID, missing: false, lastStashCheckDate: null, @@ -228,6 +230,7 @@ export class RepositoriesStore extends TypedBaseStore< gitHubRepositoryID: null, missing: false, lastStashCheckDate: null, + alias: null, } const id = await this.db.repositories.add(dbRepo) return this.toRepository({ id, ...dbRepo }) @@ -261,11 +264,27 @@ export class RepositoriesStore extends TypedBaseStore< repository.id, repository.gitHubRepository, missing, + repository.alias, repository.workflowPreferences, repository.isTutorialRepository ) } + /** + * Update the alias for the specified repository. + * + * @param repository The repository to update. + * @param alias The new alias to use. + */ + public async updateRepositoryAlias( + repository: Repository, + alias: string + ): Promise { + await this.db.repositories.update(repository.id, { alias }) + + this.emitUpdatedRepositories() + } + /** * Update the workflow preferences for the specified repository. * @@ -295,6 +314,7 @@ export class RepositoriesStore extends TypedBaseStore< repository.id, repository.gitHubRepository, false, + repository.alias, repository.workflowPreferences, repository.isTutorialRepository ) @@ -421,6 +441,7 @@ export class RepositoriesStore extends TypedBaseStore< repo.id, ghRepo, repo.missing, + repo.alias, repo.workflowPreferences, repo.isTutorialRepository ) diff --git a/app/src/models/popup.ts b/app/src/models/popup.ts index 7c38dcfc939..b04af27bb86 100644 --- a/app/src/models/popup.ts +++ b/app/src/models/popup.ts @@ -69,6 +69,7 @@ export enum PopupType { ConfirmDiscardSelection, CherryPick, MoveToApplicationsFolder, + ChangeRepositoryAlias, } export type Popup = @@ -276,3 +277,4 @@ export type Popup = sourceBranch: Branch | null } | { type: PopupType.MoveToApplicationsFolder } + | { type: PopupType.ChangeRepositoryAlias; repository: Repository } diff --git a/app/src/models/repository.ts b/app/src/models/repository.ts index 7fe6623c48c..2356c25acb0 100644 --- a/app/src/models/repository.ts +++ b/app/src/models/repository.ts @@ -51,6 +51,7 @@ export class Repository { public readonly id: number, public readonly gitHubRepository: GitHubRepository | null, public readonly missing: boolean, + public readonly alias: string | null = null, public readonly workflowPreferences: WorkflowPreferences = {}, /** * True if the repository is a tutorial repository created as part of the diff --git a/app/src/ui/app.tsx b/app/src/ui/app.tsx index e750d612970..9bb09229453 100644 --- a/app/src/ui/app.tsx +++ b/app/src/ui/app.tsx @@ -135,6 +135,7 @@ import { CherryPickCommit } from './drag-elements/cherry-pick-commit' import classNames from 'classnames' import { dragAndDropManager } from '../lib/drag-and-drop-manager' import { MoveToApplicationsFolder } from './move-to-applications-folder' +import { ChangeRepositoryAlias } from './change-repository-alias/change-repository-alias-dialog' const MinuteInMilliseconds = 1000 * 60 const HourInMilliseconds = MinuteInMilliseconds * 60 @@ -2048,6 +2049,15 @@ export class App extends React.Component { /> ) } + case PopupType.ChangeRepositoryAlias: { + return ( + + ) + } default: return assertNever(popup, `Unknown popup type: ${popup}`) } diff --git a/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx b/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx new file mode 100644 index 00000000000..cc7d214b5a4 --- /dev/null +++ b/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx @@ -0,0 +1,68 @@ +import * as React from 'react' + +import { Dispatcher } from '../dispatcher' +import { Repository } from '../../models/repository' +import { Dialog, DialogContent, DialogFooter } from '../dialog' +import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group' +import { TextBox } from '../lib/text-box' + +interface IChangeRepositoryAliasProps { + readonly dispatcher: Dispatcher + readonly onDismissed: () => void + readonly repository: Repository +} + +interface IChangeRepositoryAliasState { + readonly newAlias: string +} + +export class ChangeRepositoryAlias extends React.Component< + IChangeRepositoryAliasProps, + IChangeRepositoryAliasState +> { + public constructor(props: IChangeRepositoryAliasProps) { + super(props) + + this.state = { newAlias: props.repository.alias ?? props.repository.name } + } + + public render() { + return ( + + + + + + + + + + ) + } + + private onNameChanged = (newAlias: string) => { + this.setState({ newAlias }) + } + + private changeAlias = () => { + this.props.dispatcher.changeRepositoryAlias( + this.props.repository, + this.state.newAlias + ) + this.props.onDismissed() + } +} diff --git a/app/src/ui/dispatcher/dispatcher.ts b/app/src/ui/dispatcher/dispatcher.ts index 5f5b89e4bb4..928e39b50a0 100644 --- a/app/src/ui/dispatcher/dispatcher.ts +++ b/app/src/ui/dispatcher/dispatcher.ts @@ -695,6 +695,14 @@ export class Dispatcher { }) } + /** Changes the repository alias to a new name. */ + public changeRepositoryAlias( + repository: Repository, + newAlias: string + ): Promise { + return this.appStore._changeRepositoryAlias(repository, newAlias) + } + /** Rename the branch to a new name. */ public renameBranch( repository: Repository, diff --git a/app/src/ui/repositories-list/group-repositories.ts b/app/src/ui/repositories-list/group-repositories.ts index 4f6b4e36b20..55ca5c32b11 100644 --- a/app/src/ui/repositories-list/group-repositories.ts +++ b/app/src/ui/repositories-list/group-repositories.ts @@ -89,7 +89,13 @@ export function groupRepositories( const { aheadBehind, changedFilesCount } = localRepositoryStateLookup.get(r.id) || fallbackValue const repositoryText = - r instanceof Repository ? [r.name, nameOf(r)] : [r.name] + r instanceof Repository + ? [ + r.name, + nameOf(r), // Add the alias if it exists + ...(r.alias !== null ? [r.alias] : []), + ] + : [r.name] return { text: repositoryText, @@ -149,7 +155,12 @@ export function makeRecentRepositoriesGroup( localRepositoryStateLookup.get(id) || fallbackValue const repositoryText = repository instanceof Repository - ? [repository.name, nameOf(repository)] + ? [ + repository.name, + nameOf(repository), + // Add the alias if it exists + ...(repository.alias !== null ? [repository.alias] : []), + ] : [repository.name] const nameCount = names.get(repository.name) || 0 items.push({ diff --git a/app/src/ui/repositories-list/repositories-list.tsx b/app/src/ui/repositories-list/repositories-list.tsx index cc3c5e8f75d..7128e983f85 100644 --- a/app/src/ui/repositories-list/repositories-list.tsx +++ b/app/src/ui/repositories-list/repositories-list.tsx @@ -11,7 +11,7 @@ import { } from './group-repositories' import { FilterList, IFilterListGroup } from '../lib/filter-list' import { IMatches } from '../../lib/fuzzy-find' -import { ILocalRepositoryState } from '../../models/repository' +import { ILocalRepositoryState, Repository } from '../../models/repository' import { Dispatcher } from '../dispatcher' import { Button } from '../lib/button' import { Octicon, OcticonSymbol } from '../octicons' @@ -138,6 +138,7 @@ export class RepositoriesList extends React.Component< onShowRepository={this.props.onShowRepository} onOpenInShell={this.props.onOpenInShell} onOpenInExternalEditor={this.props.onOpenInExternalEditor} + onChangeRepositoryAlias={this.onChangeRepositoryAlias} externalEditorLabel={this.props.externalEditorLabel} shellLabel={this.props.shellLabel} matches={matches} @@ -320,4 +321,11 @@ export class RepositoriesList extends React.Component< private onCreateNewRepository = () => { this.props.dispatcher.showPopup({ type: PopupType.CreateRepository }) } + + private onChangeRepositoryAlias = (repository: Repository) => { + this.props.dispatcher.showPopup({ + type: PopupType.ChangeRepositoryAlias, + repository, + }) + } } diff --git a/app/src/ui/repositories-list/repository-list-item.tsx b/app/src/ui/repositories-list/repository-list-item.tsx index d4fed1996e9..af1b3e3e7fd 100644 --- a/app/src/ui/repositories-list/repository-list-item.tsx +++ b/app/src/ui/repositories-list/repository-list-item.tsx @@ -30,6 +30,9 @@ interface IRepositoryListItemProps { /** Called when the repository should be opened in an external editor */ readonly onOpenInExternalEditor: (repository: Repositoryish) => void + /** Called when the repository alias should be changed */ + readonly onChangeRepositoryAlias: (repository: Repository) => void + /** The current external editor selected by the user */ readonly externalEditorLabel?: string @@ -70,6 +73,9 @@ export class RepositoryListItem extends React.Component< prefix = `${gitHubRepo.owner.login}/` } + const alias: string | null = + repository instanceof Repository ? repository.alias : null + return (
-
- {prefix ? {prefix} : null} - -
+ + {this.renderRepositoryTitle(repository, alias, prefix)} {repository instanceof Repository && renderRepoIndicators({ @@ -97,6 +98,36 @@ export class RepositoryListItem extends React.Component< ) } + private renderRepositoryTitle( + repository: Repositoryish, + alias: string | null, + prefix: string | null + ) { + if (alias !== null) { + return ( +
+ + + {prefix ? {prefix} : null} + + +
+ ) + } + return ( +
+ {prefix ? {prefix} : null} + +
+ ) + } + public shouldComponentUpdate(nextProps: IRepositoryListItemProps): boolean { if ( nextProps.repository instanceof Repository && @@ -120,7 +151,7 @@ export class RepositoryListItem extends React.Component< ? `Open in ${this.props.externalEditorLabel}` : DefaultEditorLabel - const items: ReadonlyArray = [ + const items: Array = [ { label: `Open in ${this.props.shellLabel}`, action: this.openInShell, @@ -144,6 +175,16 @@ export class RepositoryListItem extends React.Component< action: this.removeRepository, }, ] + + // If this is not a cloning repository, insert at the beginning an item to + // change the repository alias. + if (this.props.repository instanceof Repository) { + items.splice(0, 0, { + label: __DARWIN__ ? 'Change Alias' : 'Change alias…', + action: this.changeAlias, + }) + } + showContextualMenu(items) } @@ -162,6 +203,12 @@ export class RepositoryListItem extends React.Component< private openInExternalEditor = () => { this.props.onOpenInExternalEditor(this.props.repository) } + + private changeAlias = () => { + if (this.props.repository instanceof Repository) { + this.props.onChangeRepositoryAlias(this.props.repository) + } + } } const renderRepoIndicators: React.FunctionComponent<{ diff --git a/app/styles/ui/_repository-list.scss b/app/styles/ui/_repository-list.scss index 54c42874bc4..3054f65905b 100644 --- a/app/styles/ui/_repository-list.scss +++ b/app/styles/ui/_repository-list.scss @@ -45,7 +45,8 @@ width: 16px; } - .name { + .name, + .alias { // Long repository names truncate and ellipse @include ellipsis; @@ -53,6 +54,23 @@ color: var(--text-secondary-color); } + &.alias { + display: flex; + // flex: auto; + width: 100%; + justify-content: space-between; + // flex-direction: row; + // flex-grow: 1; + } + + // :not(.originalName) { + // flex-grow: 1; + // } + + .originalName { + color: var(--text-secondary-color); + } + /* Used to highlight substring matches in filtered lists */ mark { font-weight: bold; From af875e1ba775f384384ca0b2c5fca18ab3c37e5e Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 10:38:14 +0200 Subject: [PATCH 2/8] Many changes --- .../repositories-list/group-repositories.ts | 15 +----- .../repository-list-item.tsx | 50 ++++++------------- app/styles/ui/_repository-list.scss | 20 +------- 3 files changed, 17 insertions(+), 68 deletions(-) diff --git a/app/src/ui/repositories-list/group-repositories.ts b/app/src/ui/repositories-list/group-repositories.ts index 55ca5c32b11..c97db1a6720 100644 --- a/app/src/ui/repositories-list/group-repositories.ts +++ b/app/src/ui/repositories-list/group-repositories.ts @@ -89,13 +89,7 @@ export function groupRepositories( const { aheadBehind, changedFilesCount } = localRepositoryStateLookup.get(r.id) || fallbackValue const repositoryText = - r instanceof Repository - ? [ - r.name, - nameOf(r), // Add the alias if it exists - ...(r.alias !== null ? [r.alias] : []), - ] - : [r.name] + r instanceof Repository ? [r.alias ?? r.name, nameOf(r)] : [r.name] return { text: repositoryText, @@ -155,12 +149,7 @@ export function makeRecentRepositoriesGroup( localRepositoryStateLookup.get(id) || fallbackValue const repositoryText = repository instanceof Repository - ? [ - repository.name, - nameOf(repository), - // Add the alias if it exists - ...(repository.alias !== null ? [repository.alias] : []), - ] + ? [repository.alias ?? repository.name, nameOf(repository)] : [repository.name] const nameCount = names.get(repository.name) || 0 items.push({ diff --git a/app/src/ui/repositories-list/repository-list-item.tsx b/app/src/ui/repositories-list/repository-list-item.tsx index af1b3e3e7fd..cecd7aeff7d 100644 --- a/app/src/ui/repositories-list/repository-list-item.tsx +++ b/app/src/ui/repositories-list/repository-list-item.tsx @@ -68,14 +68,14 @@ export class RepositoryListItem extends React.Component< ? gitHubRepo.fullName + '\n' + gitHubRepo.htmlURL + '\n' + path : path + const alias: string | null = + repository instanceof Repository ? repository.alias : null + let prefix: string | null = null - if (this.props.needsDisambiguation && gitHubRepo) { + if (this.props.needsDisambiguation && gitHubRepo && alias === null) { prefix = `${gitHubRepo.owner.login}/` } - const alias: string | null = - repository instanceof Repository ? repository.alias : null - return (
- {this.renderRepositoryTitle(repository, alias, prefix)} +
+ {prefix ? {prefix} : null} + +
{repository instanceof Repository && renderRepoIndicators({ @@ -98,36 +104,6 @@ export class RepositoryListItem extends React.Component< ) } - private renderRepositoryTitle( - repository: Repositoryish, - alias: string | null, - prefix: string | null - ) { - if (alias !== null) { - return ( -
- - - {prefix ? {prefix} : null} - - -
- ) - } - return ( -
- {prefix ? {prefix} : null} - -
- ) - } - public shouldComponentUpdate(nextProps: IRepositoryListItemProps): boolean { if ( nextProps.repository instanceof Repository && @@ -179,8 +155,10 @@ export class RepositoryListItem extends React.Component< // If this is not a cloning repository, insert at the beginning an item to // change the repository alias. if (this.props.repository instanceof Repository) { + const verb = this.props.repository.alias == null ? 'Create' : 'Change' + items.splice(0, 0, { - label: __DARWIN__ ? 'Change Alias' : 'Change alias…', + label: __DARWIN__ ? `${verb} Alias` : `${verb} alias`, action: this.changeAlias, }) } diff --git a/app/styles/ui/_repository-list.scss b/app/styles/ui/_repository-list.scss index 3054f65905b..54c42874bc4 100644 --- a/app/styles/ui/_repository-list.scss +++ b/app/styles/ui/_repository-list.scss @@ -45,8 +45,7 @@ width: 16px; } - .name, - .alias { + .name { // Long repository names truncate and ellipse @include ellipsis; @@ -54,23 +53,6 @@ color: var(--text-secondary-color); } - &.alias { - display: flex; - // flex: auto; - width: 100%; - justify-content: space-between; - // flex-direction: row; - // flex-grow: 1; - } - - // :not(.originalName) { - // flex-grow: 1; - // } - - .originalName { - color: var(--text-secondary-color); - } - /* Used to highlight substring matches in filtered lists */ mark { font-weight: bold; From f8ca09199c6447fc31547c31c6b9bd296be438a8 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 12:52:37 +0200 Subject: [PATCH 3/8] Take alias into consideration to disambiguate repos --- app/src/ui/repositories-list/group-repositories.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/ui/repositories-list/group-repositories.ts b/app/src/ui/repositories-list/group-repositories.ts index c97db1a6720..f11b5f1776b 100644 --- a/app/src/ui/repositories-list/group-repositories.ts +++ b/app/src/ui/repositories-list/group-repositories.ts @@ -132,8 +132,10 @@ export function makeRecentRepositoriesGroup( for (const id of recentRepositories) { const repository = repositories.find(r => r.id === id) if (repository !== undefined) { - const existingCount = names.get(repository.name) || 0 - names.set(repository.name, existingCount + 1) + const alias = repository instanceof Repository ? repository.alias : null + const name = alias ?? repository.name + const existingCount = names.get(name) || 0 + names.set(name, existingCount + 1) } } @@ -147,11 +149,13 @@ export function makeRecentRepositoriesGroup( const { aheadBehind, changedFilesCount } = localRepositoryStateLookup.get(id) || fallbackValue + const repositoryAlias = + repository instanceof Repository ? repository.alias : null const repositoryText = repository instanceof Repository - ? [repository.alias ?? repository.name, nameOf(repository)] + ? [repositoryAlias ?? repository.name, nameOf(repository)] : [repository.name] - const nameCount = names.get(repository.name) || 0 + const nameCount = names.get(repositoryAlias ?? repository.name) || 0 items.push({ text: repositoryText, id: id.toString(), From 09102b63040716113a042976340cc8ae0f916624 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 12:53:16 +0200 Subject: [PATCH 4/8] Allow removing aliases --- app/src/lib/stores/repositories-store.ts | 2 +- app/src/ui/dispatcher/dispatcher.ts | 2 +- .../repositories-list/repositories-list.tsx | 5 +++ .../repository-list-item.tsx | 42 +++++++++++++++---- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/app/src/lib/stores/repositories-store.ts b/app/src/lib/stores/repositories-store.ts index 116272439c5..ce16510a524 100644 --- a/app/src/lib/stores/repositories-store.ts +++ b/app/src/lib/stores/repositories-store.ts @@ -278,7 +278,7 @@ export class RepositoriesStore extends TypedBaseStore< */ public async updateRepositoryAlias( repository: Repository, - alias: string + alias: string | null ): Promise { await this.db.repositories.update(repository.id, { alias }) diff --git a/app/src/ui/dispatcher/dispatcher.ts b/app/src/ui/dispatcher/dispatcher.ts index 928e39b50a0..dffa76257a0 100644 --- a/app/src/ui/dispatcher/dispatcher.ts +++ b/app/src/ui/dispatcher/dispatcher.ts @@ -698,7 +698,7 @@ export class Dispatcher { /** Changes the repository alias to a new name. */ public changeRepositoryAlias( repository: Repository, - newAlias: string + newAlias: string | null ): Promise { return this.appStore._changeRepositoryAlias(repository, newAlias) } diff --git a/app/src/ui/repositories-list/repositories-list.tsx b/app/src/ui/repositories-list/repositories-list.tsx index 7128e983f85..0d00b8411fe 100644 --- a/app/src/ui/repositories-list/repositories-list.tsx +++ b/app/src/ui/repositories-list/repositories-list.tsx @@ -139,6 +139,7 @@ export class RepositoriesList extends React.Component< onOpenInShell={this.props.onOpenInShell} onOpenInExternalEditor={this.props.onOpenInExternalEditor} onChangeRepositoryAlias={this.onChangeRepositoryAlias} + onRemoveRepositoryAlias={this.onRemoveRepositoryAlias} externalEditorLabel={this.props.externalEditorLabel} shellLabel={this.props.shellLabel} matches={matches} @@ -328,4 +329,8 @@ export class RepositoriesList extends React.Component< repository, }) } + + private onRemoveRepositoryAlias = (repository: Repository) => { + this.props.dispatcher.changeRepositoryAlias(repository, null) + } } diff --git a/app/src/ui/repositories-list/repository-list-item.tsx b/app/src/ui/repositories-list/repository-list-item.tsx index cecd7aeff7d..3dc22449463 100644 --- a/app/src/ui/repositories-list/repository-list-item.tsx +++ b/app/src/ui/repositories-list/repository-list-item.tsx @@ -33,6 +33,9 @@ interface IRepositoryListItemProps { /** Called when the repository alias should be changed */ readonly onChangeRepositoryAlias: (repository: Repository) => void + /** Called when the repository alias should be removed */ + readonly onRemoveRepositoryAlias: (repository: Repository) => void + /** The current external editor selected by the user */ readonly externalEditorLabel?: string @@ -72,7 +75,7 @@ export class RepositoryListItem extends React.Component< repository instanceof Repository ? repository.alias : null let prefix: string | null = null - if (this.props.needsDisambiguation && gitHubRepo && alias === null) { + if (this.props.needsDisambiguation && gitHubRepo) { prefix = `${gitHubRepo.owner.login}/` } @@ -127,7 +130,8 @@ export class RepositoryListItem extends React.Component< ? `Open in ${this.props.externalEditorLabel}` : DefaultEditorLabel - const items: Array = [ + const items: ReadonlyArray = [ + ...this.buildAliasMenuItems(), { label: `Open in ${this.props.shellLabel}`, action: this.openInShell, @@ -152,18 +156,34 @@ export class RepositoryListItem extends React.Component< }, ] - // If this is not a cloning repository, insert at the beginning an item to - // change the repository alias. - if (this.props.repository instanceof Repository) { - const verb = this.props.repository.alias == null ? 'Create' : 'Change' + showContextualMenu(items) + } - items.splice(0, 0, { + private buildAliasMenuItems(): ReadonlyArray { + const repository = this.props.repository + + if (!(repository instanceof Repository)) { + return [] + } + + const verb = repository.alias == null ? 'Create' : 'Change' + const items: Array = [ + { label: __DARWIN__ ? `${verb} Alias` : `${verb} alias`, action: this.changeAlias, + }, + ] + + if (repository.alias !== null) { + items.push({ + label: __DARWIN__ ? 'Remove Alias' : 'Remove alias', + action: this.removeAlias, }) } - showContextualMenu(items) + items.push({ type: 'separator' }) + + return items } private removeRepository = () => { @@ -187,6 +207,12 @@ export class RepositoryListItem extends React.Component< this.props.onChangeRepositoryAlias(this.props.repository) } } + + private removeAlias = () => { + if (this.props.repository instanceof Repository) { + this.props.onRemoveRepositoryAlias(this.props.repository) + } + } } const renderRepoIndicators: React.FunctionComponent<{ From 7a83268fbcb9f5a22a6b735fb1a15ce30d312aa4 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 12:53:33 +0200 Subject: [PATCH 5/8] Change verbiage in change alias dialog --- .../change-repository-alias-dialog.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx b/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx index cc7d214b5a4..f547572f82c 100644 --- a/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx +++ b/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx @@ -27,11 +27,13 @@ export class ChangeRepositoryAlias extends React.Component< } public render() { + const verb = this.props.repository.alias === null ? 'Create' : 'Change' + return ( From 318db91fb3c16d280bdaa013ffa450c6a68d6c76 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 12:53:48 +0200 Subject: [PATCH 6/8] Reflect alias in repo dropdown title --- app/src/lib/stores/app-store.ts | 9 ++++++++- app/src/models/repository.ts | 1 + app/src/ui/app.tsx | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/lib/stores/app-store.ts b/app/src/lib/stores/app-store.ts index 80925f24d43..d5a87e1ae6b 100644 --- a/app/src/lib/stores/app-store.ts +++ b/app/src/lib/stores/app-store.ts @@ -1451,6 +1451,13 @@ export class AppStore extends TypedBaseStore { previousRepositoryId: number | null, currentRepositoryId: number ) { + // No need to update the recent repositories if the selected repository is + // the same as the old one (this could happen when the alias of the selected + // repository is changed). + if (previousRepositoryId === currentRepositoryId) { + return + } + const recentRepositories = getNumberArray(RecentRepositoriesKey).filter( el => el !== currentRepositoryId && el !== previousRepositoryId ) @@ -3411,7 +3418,7 @@ export class AppStore extends TypedBaseStore { /** This shouldn't be called directly. See `Dispatcher`. */ public async _changeRepositoryAlias( repository: Repository, - newAlias: string + newAlias: string | null ): Promise { return this.repositoriesStore.updateRepositoryAlias(repository, newAlias) } diff --git a/app/src/models/repository.ts b/app/src/models/repository.ts index 2356c25acb0..e299d051bdd 100644 --- a/app/src/models/repository.ts +++ b/app/src/models/repository.ts @@ -68,6 +68,7 @@ export class Repository { this.id, gitHubRepository?.hash, this.missing, + this.alias, this.workflowPreferences.forkContributionTarget, this.isTutorialRepository ) diff --git a/app/src/ui/app.tsx b/app/src/ui/app.tsx index 9bb09229453..a4e9c892356 100644 --- a/app/src/ui/app.tsx +++ b/app/src/ui/app.tsx @@ -2377,8 +2377,9 @@ export class App extends React.Component { let icon: OcticonSymbol let title: string if (repository) { + const alias = repository instanceof Repository ? repository.alias : null icon = iconForRepository(repository) - title = repository.name + title = alias ?? repository.name } else if (this.state.repositories.length > 0) { icon = OcticonSymbol.repo title = __DARWIN__ ? 'Select a Repository' : 'Select a repository' From 62b3da8bc1f8c0e695e336daf03609fc018e6217 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 17:50:57 +0200 Subject: [PATCH 7/8] Show context when creating/changing a repo alias --- .../change-repository-alias-dialog.tsx | 24 ++++++++++++------- app/styles/ui/_dialog.scss | 3 ++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx b/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx index f547572f82c..26ec91cd719 100644 --- a/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx +++ b/app/src/ui/change-repository-alias/change-repository-alias-dialog.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { Dispatcher } from '../dispatcher' -import { Repository } from '../../models/repository' +import { nameOf, Repository } from '../../models/repository' import { Dialog, DialogContent, DialogFooter } from '../dialog' import { OkCancelButtonGroup } from '../dialog/ok-cancel-button-group' import { TextBox } from '../lib/text-box' @@ -27,11 +27,12 @@ export class ChangeRepositoryAlias extends React.Component< } public render() { - const verb = this.props.repository.alias === null ? 'Create' : 'Change' + const repository = this.props.repository + const verb = repository.alias === null ? 'Create' : 'Change' return ( - +

Choose a new alias for the repository "{nameOf(repository)}".

+

+ +

+ {repository.gitHubRepository !== null && ( +

+ This will not affect the original repository name on GitHub. +

+ )}
diff --git a/app/styles/ui/_dialog.scss b/app/styles/ui/_dialog.scss index 03e4197355d..10bcadab351 100644 --- a/app/styles/ui/_dialog.scss +++ b/app/styles/ui/_dialog.scss @@ -375,7 +375,8 @@ dialog { width: 400px; } - &#confirm-remove-repository { + &#confirm-remove-repository, + &#change-repository-alias { width: 450px; .description { From b8eb98d241ce5f833aacdcb00a5b2fcd8c007029 Mon Sep 17 00:00:00 2001 From: Sergio Padrino Date: Wed, 14 Apr 2021 17:56:00 +0200 Subject: [PATCH 8/8] Hide repo aliases behind a feature flag --- app/src/lib/feature-flag.ts | 5 +++++ app/src/lib/stores/repositories-store.ts | 3 ++- app/src/ui/repositories-list/repository-list-item.tsx | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/lib/feature-flag.ts b/app/src/lib/feature-flag.ts index d1ef18d4f44..b457c9b8b83 100644 --- a/app/src/lib/feature-flag.ts +++ b/app/src/lib/feature-flag.ts @@ -175,3 +175,8 @@ export function enableUpdateFromRosettaToARM64(): boolean { export function enableSaveDialogOnCloneRepository(): boolean { return enableBetaFeatures() } + +/** Should we allow setting repository aliases? */ +export function enableRepositoryAliases(): boolean { + return enableBetaFeatures() +} diff --git a/app/src/lib/stores/repositories-store.ts b/app/src/lib/stores/repositories-store.ts index ce16510a524..44a4a3c0c6c 100644 --- a/app/src/lib/stores/repositories-store.ts +++ b/app/src/lib/stores/repositories-store.ts @@ -22,6 +22,7 @@ import { WorkflowPreferences } from '../../models/workflow-preferences' import { clearTagsToPush } from './helpers/tags-to-push-storage' import { IMatchedGitHubRepository } from '../repository-matching' import { shallowEquals } from '../equality' +import { enableRepositoryAliases } from '../feature-flag' /** The store for local repositories. */ export class RepositoriesStore extends TypedBaseStore< @@ -132,7 +133,7 @@ export class RepositoriesStore extends TypedBaseStore< ? await this.findGitHubRepositoryByID(repo.gitHubRepositoryID) : await Promise.resolve(null), // Dexie gets confused if we return null repo.missing, - repo.alias, + enableRepositoryAliases() ? repo.alias : null, repo.workflowPreferences, repo.isTutorialRepository ) diff --git a/app/src/ui/repositories-list/repository-list-item.tsx b/app/src/ui/repositories-list/repository-list-item.tsx index 3dc22449463..a6645483427 100644 --- a/app/src/ui/repositories-list/repository-list-item.tsx +++ b/app/src/ui/repositories-list/repository-list-item.tsx @@ -11,6 +11,7 @@ import { RevealInFileManagerLabel, DefaultEditorLabel, } from '../lib/context-menu' +import { enableRepositoryAliases } from '../../lib/feature-flag' interface IRepositoryListItemProps { readonly repository: Repositoryish @@ -162,7 +163,7 @@ export class RepositoryListItem extends React.Component< private buildAliasMenuItems(): ReadonlyArray { const repository = this.props.repository - if (!(repository instanceof Repository)) { + if (!(repository instanceof Repository) || !enableRepositoryAliases()) { return [] }