Преглед изворни кода

Allows the Graph in a view & a tab simultaneously

main
Eric Amodio пре 1 година
родитељ
комит
3254bf3c49
14 измењених фајлова са 399 додато и 196 уклоњено
  1. +6
    -0
      CHANGELOG.md
  2. +59
    -44
      package.json
  3. +1
    -0
      src/constants.ts
  4. +2
    -18
      src/container.ts
  5. +147
    -111
      src/plus/webviews/graph/graphWebview.ts
  6. +16
    -2
      src/plus/webviews/graph/registration.ts
  7. +18
    -1
      src/system/command.ts
  8. +23
    -8
      src/system/webview.ts
  9. +12
    -6
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  10. +12
    -0
      src/webviews/apps/settings/partials/commit-graph.html
  11. +8
    -3
      src/webviews/commitDetails/commitDetailsWebview.ts
  12. +70
    -0
      src/webviews/webviewCommandRegistrar.ts
  13. +11
    -0
      src/webviews/webviewController.ts
  14. +14
    -3
      src/webviews/webviewsController.ts

+ 6
- 0
CHANGELOG.md Прегледај датотеку

@ -8,8 +8,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Added
- Adds checkboxes to files in the _Search & Compare_ view to allow for tracking review progress — closes [#836](https://github.com/gitkraken/vscode-gitlens/issues/836)
- Allows the _Commit Graph_ to be open in the panel and in the editor area simultaneously
- Adds an _Open Changes_ button to commits in the file history quick pick menu — closes [#2641](https://github.com/gitkraken/vscode-gitlens/issues/2641) thanks to [PR #2800](https://github.com/gitkraken/vscode-gitlens/pull/2800) by Omar Ghazi ([@omarfesal](https://github.com/omarfesal))
### Changed
- Changes the `gitlens.graph.layout` setting to be a default preference rather than a mode change
### Fixed
- Fixes [#2885](https://github.com/gitkraken/vscode-gitlens/issues/2885) - Folder History not show changed files of commit

+ 59
- 44
package.json Прегледај датотеку

@ -2402,10 +2402,10 @@
"panel"
],
"enumDescriptions": [
"Shows the Commit Graph in an editor tab",
"Shows the Commit Graph in the bottom panel"
"Prefer showing the Commit Graph in the editor area",
"Prefer showing the Commit Graph in the bottom panel"
],
"markdownDescription": "Specifies the layout of the _Commit Graph_",
"markdownDescription": "Specifies the preferred layout of the _Commit Graph_",
"scope": "window",
"order": 99
},
@ -4711,7 +4711,7 @@
},
{
"command": "gitlens.showGraphPage",
"title": "Show Commit Graph",
"title": "Show Commit Graph in Editor Area",
"category": "GitLens",
"icon": "$(gitlens-graph)"
},
@ -4750,6 +4750,12 @@
"icon": "$(gitlens-graph)"
},
{
"command": "gitlens.showInCommitGraphView",
"title": "Open in Commit Graph",
"category": "GitLens",
"icon": "$(gitlens-graph)"
},
{
"command": "gitlens.showLineHistoryView",
"title": "Show Line History View",
"category": "GitLens"
@ -6556,6 +6562,18 @@
"category": "GitLens"
},
{
"command": "gitlens.views.graph.openInTab",
"title": "Open in Editor Area",
"category": "GitLens",
"icon": "$(link-external)"
},
{
"command": "gitlens.views.graph.refresh",
"title": "Refresh",
"category": "GitLens",
"icon": "$(refresh)"
},
{
"command": "gitlens.views.graphDetails.refresh",
"title": "Refresh",
"category": "GitLens",
@ -7211,13 +7229,15 @@
},
{
"command": "gitlens.graph.switchToEditorLayout",
"title": "Switch Commit Graph to Editor Layout",
"category": "GitLens"
"title": "Prefer Commit Graph in Editor Area",
"category": "GitLens",
"enablement": "config.gitlens.graph.layout != editor"
},
{
"command": "gitlens.graph.switchToPanelLayout",
"title": "Switch Commit Graph to Panel Layout",
"category": "GitLens"
"title": "Prefer Commit Graph in Panel",
"category": "GitLens",
"enablement": "config.gitlens.graph.layout != panel"
},
{
"command": "gitlens.graph.push",
@ -8065,23 +8085,23 @@
},
{
"command": "gitlens.showGraph",
"when": "false"
"when": "gitlens:enabled"
},
{
"command": "gitlens.showGraphPage",
"when": "gitlens:enabled && config.gitlens.graph.layout == editor"
"when": "gitlens:enabled"
},
{
"command": "gitlens.showGraphView",
"when": "gitlens:enabled && config.gitlens.graph.layout == panel"
"when": "gitlens:enabled"
},
{
"command": "gitlens.toggleGraph",
"when": "gitlens:enabled && config.gitlens.graph.layout == panel"
"when": "gitlens:enabled"
},
{
"command": "gitlens.toggleMaximizedGraph",
"when": "gitlens:enabled && config.gitlens.graph.layout == panel"
"when": "gitlens:enabled"
},
{
"command": "gitlens.showHomeView",
@ -8096,6 +8116,10 @@
"when": "false"
},
{
"command": "gitlens.showInCommitGraphView",
"when": "false"
},
{
"command": "gitlens.showLineHistoryView",
"when": "gitlens:enabled && !gitlens:hasVirtualFolders"
},
@ -9304,6 +9328,14 @@
"when": "false"
},
{
"command": "gitlens.views.graph.openInTab",
"when": "false"
},
{
"command": "gitlens.views.graph.refresh",
"when": "false"
},
{
"command": "gitlens.views.graphDetails.refresh",
"when": "false"
},
@ -10337,26 +10369,6 @@
"group": "navigation@-99"
},
{
"command": "gitlens.graph.push",
"when": "gitlens:webview:graph:active && gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders",
"group": "navigation@-103"
},
{
"command": "gitlens.graph.pull",
"when": "gitlens:webview:graph:active && gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders",
"group": "navigation@-102"
},
{
"command": "gitlens.graph.fetch",
"when": "gitlens:webview:graph:active && gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders",
"group": "navigation@-101"
},
{
"command": "gitlens.graph.switchToAnotherBranch",
"when": "gitlens:webview:graph:active && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders",
"group": "navigation@-100"
},
{
"command": "gitlens.graph.refresh",
"when": "gitlens:webview:graph:active",
"group": "navigation@-99"
@ -10875,6 +10887,16 @@
"group": "5_gitlens@0"
},
{
"command": "gitlens.views.graph.openInTab",
"when": "view =~ /^gitlens\\.views\\.graph\\b/",
"group": "navigation@-100"
},
{
"command": "gitlens.views.graph.refresh",
"when": "view =~ /^gitlens\\.views\\.graph\\b/",
"group": "navigation@-99"
},
{
"command": "gitlens.views.graphDetails.refresh",
"when": "view =~ /^gitlens\\.views\\.graphDetails/",
"group": "navigation@99"
@ -11255,11 +11277,6 @@
"group": "5_gitlens@3"
},
{
"command": "gitlens.graph.refresh",
"when": "view =~ /^gitlens\\.views\\.graph\\b/",
"group": "navigation@-99"
},
{
"submenu": "gitlens/graph/configuration",
"when": "view =~ /^gitlens\\.views\\.graph\\b/",
"group": "navigation@-98"
@ -13684,13 +13701,11 @@
"gitlens/graph/configuration": [
{
"command": "gitlens.graph.switchToEditorLayout",
"group": "1_gitlens@1",
"when": "config.gitlens.graph.layout != editor"
"group": "1_gitlens@1"
},
{
"command": "gitlens.graph.switchToPanelLayout",
"group": "1_gitlens@1",
"when": "config.gitlens.graph.layout != panel"
"group": "1_gitlens@1"
},
{
"command": "gitlens.showSettingsPage#commit-graph",
@ -14559,7 +14574,7 @@
"type": "webview",
"id": "gitlens.views.graph",
"name": "Graph",
"when": "!gitlens:disabled && gitlens:plus:enabled && config.gitlens.graph.layout == panel",
"when": "!gitlens:disabled && gitlens:plus:enabled",
"contextualTitle": "GL",
"icon": "$(gitlens-graph)",
"initialSize": 4,
@ -14569,7 +14584,7 @@
"type": "webview",
"id": "gitlens.views.graphDetails",
"name": "Graph Details",
"when": "!gitlens:disabled && gitlens:plus:enabled && config.gitlens.graph.layout == panel",
"when": "!gitlens:disabled && gitlens:plus:enabled",
"contextualTitle": "GL",
"icon": "$(gitlens-commit-view)",
"initialSize": 1,

+ 1
- 0
src/constants.ts Прегледај датотеку

@ -243,6 +243,7 @@ export const enum Commands {
ShowHomeView = 'gitlens.showHomeView',
ShowAccountView = 'gitlens.showAccountView',
ShowInCommitGraph = 'gitlens.showInCommitGraph',
ShowInCommitGraphView = 'gitlens.showInCommitGraphView',
ShowInDetailsView = 'gitlens.showInDetailsView',
ShowLastQuickPick = 'gitlens.showLastQuickPick',
ShowLineCommitInView = 'gitlens.showLineCommitInView',

+ 2
- 18
src/container.ts Прегледај датотеку

@ -226,9 +226,7 @@ export class Container {
this._disposables.push((this._graphPanel = registerGraphWebviewPanel(this._webviews)));
this._disposables.push(registerGraphWebviewCommands(this, this._graphPanel));
if (configuration.get('graph.layout') === 'panel') {
this._disposables.push((this._graphView = registerGraphWebviewView(this._webviews)));
}
this._disposables.push((this._graphView = registerGraphWebviewView(this._webviews)));
this._disposables.push(new GraphStatusBarController(this));
const settingsWebviewPanel = registerSettingsWebviewPanel(this._webviews);
@ -324,16 +322,6 @@ export class Container {
if (configuration.changed(e, 'mode')) {
this.ensureModeApplied();
}
if (configuration.changed(e, 'graph.layout')) {
if (configuration.get('graph.layout') === 'panel') {
this._graphPanel?.close();
this._graphView = registerGraphWebviewView(this._webviews);
} else {
this._graphView?.dispose();
this._graphView = undefined;
}
}
}
private _accountAuthentication: AccountAuthenticationProvider;
@ -482,12 +470,8 @@ export class Container {
}
private readonly _graphPanel: WebviewPanelProxy;
private _graphView: WebviewViewProxy | undefined;
private readonly _graphView: WebviewViewProxy;
get graphView() {
if (this._graphView == null) {
this._disposables.push((this._graphView = registerGraphWebviewView(this._webviews)));
}
return this._graphView;
}

+ 147
- 111
src/plus/webviews/graph/graphWebview.ts Прегледај датотеку

@ -347,122 +347,161 @@ export class GraphWebviewProvider implements WebviewProvider {
registerCommands(): Disposable[] {
return [
registerCommand(Commands.RefreshGraph, () => this.host.refresh(true)),
registerCommand('gitlens.graph.push', this.push, this),
registerCommand('gitlens.graph.pull', this.pull, this),
registerCommand('gitlens.graph.fetch', this.fetch, this),
registerCommand('gitlens.graph.publishBranch', this.publishBranch, this),
registerCommand('gitlens.graph.switchToAnotherBranch', this.switchToAnother, this),
registerCommand('gitlens.graph.createBranch', this.createBranch, this),
registerCommand('gitlens.graph.deleteBranch', this.deleteBranch, this),
registerCommand('gitlens.graph.copyRemoteBranchUrl', item => this.openBranchOnRemote(item, true), this),
registerCommand('gitlens.graph.openBranchOnRemote', this.openBranchOnRemote, this),
registerCommand('gitlens.graph.mergeBranchInto', this.mergeBranchInto, this),
registerCommand('gitlens.graph.rebaseOntoBranch', this.rebase, this),
registerCommand('gitlens.graph.rebaseOntoUpstream', this.rebaseToRemote, this),
registerCommand('gitlens.graph.renameBranch', this.renameBranch, this),
registerCommand('gitlens.graph.switchToBranch', this.switchTo, this),
registerCommand('gitlens.graph.hideLocalBranch', this.hideRef, this),
registerCommand('gitlens.graph.hideRemoteBranch', this.hideRef, this),
registerCommand('gitlens.graph.hideRemote', item => this.hideRef(item, { remote: true }), this),
registerCommand('gitlens.graph.hideRefGroup', item => this.hideRef(item, { group: true }), this),
registerCommand('gitlens.graph.hideTag', this.hideRef, this),
registerCommand('gitlens.graph.cherryPick', this.cherryPick, this),
registerCommand('gitlens.graph.copyRemoteCommitUrl', item => this.openCommitOnRemote(item, true), this),
registerCommand('gitlens.graph.showInDetailsView', this.openInDetailsView, this),
registerCommand('gitlens.graph.openCommitOnRemote', this.openCommitOnRemote, this),
registerCommand('gitlens.graph.openSCM', this.openSCM, this),
registerCommand('gitlens.graph.rebaseOntoCommit', this.rebase, this),
registerCommand('gitlens.graph.resetCommit', this.resetCommit, this),
registerCommand('gitlens.graph.resetToCommit', this.resetToCommit, this),
registerCommand('gitlens.graph.resetToTip', this.resetToTip, this),
registerCommand('gitlens.graph.revert', this.revertCommit, this),
registerCommand('gitlens.graph.switchToCommit', this.switchTo, this),
registerCommand('gitlens.graph.undoCommit', this.undoCommit, this),
registerCommand('gitlens.graph.saveStash', this.saveStash, this),
registerCommand('gitlens.graph.applyStash', this.applyStash, this),
registerCommand('gitlens.graph.stash.delete', this.deleteStash, this),
registerCommand('gitlens.graph.stash.rename', this.renameStash, this),
registerCommand('gitlens.graph.createTag', this.createTag, this),
registerCommand('gitlens.graph.deleteTag', this.deleteTag, this),
registerCommand('gitlens.graph.switchToTag', this.switchTo, this),
registerCommand('gitlens.graph.createWorktree', this.createWorktree, this),
registerCommand('gitlens.graph.createPullRequest', this.createPullRequest, this),
registerCommand('gitlens.graph.openPullRequestOnRemote', this.openPullRequestOnRemote, this),
registerCommand('gitlens.graph.compareWithUpstream', this.compareWithUpstream, this),
registerCommand('gitlens.graph.compareWithHead', this.compareHeadWith, this),
registerCommand('gitlens.graph.compareWithWorking', this.compareWorkingWith, this),
registerCommand('gitlens.graph.compareAncestryWithWorking', this.compareAncestryWithWorking, this),
registerCommand('gitlens.graph.copy', this.copy, this),
registerCommand('gitlens.graph.copyMessage', this.copyMessage, this),
registerCommand('gitlens.graph.copySha', this.copySha, this),
registerCommand('gitlens.graph.addAuthor', this.addAuthor, this),
registerCommand('gitlens.graph.columnAuthorOn', () => this.toggleColumn('author', true)),
registerCommand('gitlens.graph.columnAuthorOff', () => this.toggleColumn('author', false)),
registerCommand('gitlens.graph.columnDateTimeOn', () => this.toggleColumn('datetime', true)),
registerCommand('gitlens.graph.columnDateTimeOff', () => this.toggleColumn('datetime', false)),
registerCommand('gitlens.graph.columnShaOn', () => this.toggleColumn('sha', true)),
registerCommand('gitlens.graph.columnShaOff', () => this.toggleColumn('sha', false)),
registerCommand('gitlens.graph.columnChangesOn', () => this.toggleColumn('changes', true)),
registerCommand('gitlens.graph.columnChangesOff', () => this.toggleColumn('changes', false)),
registerCommand('gitlens.graph.columnGraphOn', () => this.toggleColumn('graph', true)),
registerCommand('gitlens.graph.columnGraphOff', () => this.toggleColumn('graph', false)),
registerCommand('gitlens.graph.columnMessageOn', () => this.toggleColumn('message', true)),
registerCommand('gitlens.graph.columnMessageOff', () => this.toggleColumn('message', false)),
registerCommand('gitlens.graph.columnRefOn', () => this.toggleColumn('ref', true)),
registerCommand('gitlens.graph.columnRefOff', () => this.toggleColumn('ref', false)),
registerCommand('gitlens.graph.columnGraphCompact', () => this.setColumnMode('graph', 'compact')),
registerCommand('gitlens.graph.columnGraphDefault', () => this.setColumnMode('graph', undefined)),
registerCommand('gitlens.graph.scrollMarkerLocalBranchOn', () =>
registerCommand(`${this.host.id}.refresh`, () => this.host.refresh(true)),
...(this.host.isView()
? [
registerCommand(
`${this.host.id}.openInTab`,
() => void executeCommand(Commands.ShowGraphPage, this.repository),
),
]
: []),
this.host.registerWebviewCommand('gitlens.graph.push', this.push),
this.host.registerWebviewCommand('gitlens.graph.pull', this.pull),
this.host.registerWebviewCommand('gitlens.graph.fetch', this.fetch),
this.host.registerWebviewCommand('gitlens.graph.publishBranch', this.publishBranch),
this.host.registerWebviewCommand('gitlens.graph.switchToAnotherBranch', this.switchToAnother),
this.host.registerWebviewCommand('gitlens.graph.createBranch', this.createBranch),
this.host.registerWebviewCommand('gitlens.graph.deleteBranch', this.deleteBranch),
this.host.registerWebviewCommand<GraphItemContext>('gitlens.graph.copyRemoteBranchUrl', item =>
this.openBranchOnRemote(item, true),
),
this.host.registerWebviewCommand('gitlens.graph.openBranchOnRemote', this.openBranchOnRemote),
this.host.registerWebviewCommand('gitlens.graph.mergeBranchInto', this.mergeBranchInto),
this.host.registerWebviewCommand('gitlens.graph.rebaseOntoBranch', this.rebase),
this.host.registerWebviewCommand('gitlens.graph.rebaseOntoUpstream', this.rebaseToRemote),
this.host.registerWebviewCommand('gitlens.graph.renameBranch', this.renameBranch),
this.host.registerWebviewCommand('gitlens.graph.switchToBranch', this.switchTo),
this.host.registerWebviewCommand('gitlens.graph.hideLocalBranch', this.hideRef),
this.host.registerWebviewCommand('gitlens.graph.hideRemoteBranch', this.hideRef),
this.host.registerWebviewCommand<GraphItemContext>('gitlens.graph.hideRemote', item =>
this.hideRef(item, { remote: true }),
),
this.host.registerWebviewCommand<GraphItemContext>('gitlens.graph.hideRefGroup', item =>
this.hideRef(item, { group: true }),
),
this.host.registerWebviewCommand('gitlens.graph.hideTag', this.hideRef),
this.host.registerWebviewCommand('gitlens.graph.cherryPick', this.cherryPick),
this.host.registerWebviewCommand<GraphItemContext>('gitlens.graph.copyRemoteCommitUrl', item =>
this.openCommitOnRemote(item, true),
),
this.host.registerWebviewCommand('gitlens.graph.showInDetailsView', this.openInDetailsView),
this.host.registerWebviewCommand('gitlens.graph.openCommitOnRemote', this.openCommitOnRemote),
this.host.registerWebviewCommand('gitlens.graph.openSCM', this.openSCM),
this.host.registerWebviewCommand('gitlens.graph.rebaseOntoCommit', this.rebase),
this.host.registerWebviewCommand('gitlens.graph.resetCommit', this.resetCommit),
this.host.registerWebviewCommand('gitlens.graph.resetToCommit', this.resetToCommit),
this.host.registerWebviewCommand('gitlens.graph.resetToTip', this.resetToTip),
this.host.registerWebviewCommand('gitlens.graph.revert', this.revertCommit),
this.host.registerWebviewCommand('gitlens.graph.switchToCommit', this.switchTo),
this.host.registerWebviewCommand('gitlens.graph.undoCommit', this.undoCommit),
this.host.registerWebviewCommand('gitlens.graph.saveStash', this.saveStash),
this.host.registerWebviewCommand('gitlens.graph.applyStash', this.applyStash),
this.host.registerWebviewCommand('gitlens.graph.stash.delete', this.deleteStash),
this.host.registerWebviewCommand('gitlens.graph.stash.rename', this.renameStash),
this.host.registerWebviewCommand('gitlens.graph.createTag', this.createTag),
this.host.registerWebviewCommand('gitlens.graph.deleteTag', this.deleteTag),
this.host.registerWebviewCommand('gitlens.graph.switchToTag', this.switchTo),
this.host.registerWebviewCommand('gitlens.graph.createWorktree', this.createWorktree),
this.host.registerWebviewCommand('gitlens.graph.createPullRequest', this.createPullRequest),
this.host.registerWebviewCommand('gitlens.graph.openPullRequestOnRemote', this.openPullRequestOnRemote),
this.host.registerWebviewCommand('gitlens.graph.compareWithUpstream', this.compareWithUpstream),
this.host.registerWebviewCommand('gitlens.graph.compareWithHead', this.compareHeadWith),
this.host.registerWebviewCommand('gitlens.graph.compareWithWorking', this.compareWorkingWith),
this.host.registerWebviewCommand(
'gitlens.graph.compareAncestryWithWorking',
this.compareAncestryWithWorking,
),
this.host.registerWebviewCommand('gitlens.graph.copy', this.copy),
this.host.registerWebviewCommand('gitlens.graph.copyMessage', this.copyMessage),
this.host.registerWebviewCommand('gitlens.graph.copySha', this.copySha),
this.host.registerWebviewCommand('gitlens.graph.addAuthor', this.addAuthor),
this.host.registerWebviewCommand('gitlens.graph.columnAuthorOn', () => this.toggleColumn('author', true)),
this.host.registerWebviewCommand('gitlens.graph.columnAuthorOff', () => this.toggleColumn('author', false)),
this.host.registerWebviewCommand('gitlens.graph.columnDateTimeOn', () =>
this.toggleColumn('datetime', true),
),
this.host.registerWebviewCommand('gitlens.graph.columnDateTimeOff', () =>
this.toggleColumn('datetime', false),
),
this.host.registerWebviewCommand('gitlens.graph.columnShaOn', () => this.toggleColumn('sha', true)),
this.host.registerWebviewCommand('gitlens.graph.columnShaOff', () => this.toggleColumn('sha', false)),
this.host.registerWebviewCommand('gitlens.graph.columnChangesOn', () => this.toggleColumn('changes', true)),
this.host.registerWebviewCommand('gitlens.graph.columnChangesOff', () =>
this.toggleColumn('changes', false),
),
this.host.registerWebviewCommand('gitlens.graph.columnGraphOn', () => this.toggleColumn('graph', true)),
this.host.registerWebviewCommand('gitlens.graph.columnGraphOff', () => this.toggleColumn('graph', false)),
this.host.registerWebviewCommand('gitlens.graph.columnMessageOn', () => this.toggleColumn('message', true)),
this.host.registerWebviewCommand('gitlens.graph.columnMessageOff', () =>
this.toggleColumn('message', false),
),
this.host.registerWebviewCommand('gitlens.graph.columnRefOn', () => this.toggleColumn('ref', true)),
this.host.registerWebviewCommand('gitlens.graph.columnRefOff', () => this.toggleColumn('ref', false)),
this.host.registerWebviewCommand('gitlens.graph.columnGraphCompact', () =>
this.setColumnMode('graph', 'compact'),
),
this.host.registerWebviewCommand('gitlens.graph.columnGraphDefault', () =>
this.setColumnMode('graph', undefined),
),
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerLocalBranchOn', () =>
this.toggleScrollMarker('localBranches', true),
),
registerCommand('gitlens.graph.scrollMarkerLocalBranchOff', () =>
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerLocalBranchOff', () =>
this.toggleScrollMarker('localBranches', false),
),
registerCommand('gitlens.graph.scrollMarkerRemoteBranchOn', () =>
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerRemoteBranchOn', () =>
this.toggleScrollMarker('remoteBranches', true),
),
registerCommand('gitlens.graph.scrollMarkerRemoteBranchOff', () =>
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerRemoteBranchOff', () =>
this.toggleScrollMarker('remoteBranches', false),
),
registerCommand('gitlens.graph.scrollMarkerStashOn', () => this.toggleScrollMarker('stashes', true)),
registerCommand('gitlens.graph.scrollMarkerStashOff', () => this.toggleScrollMarker('stashes', false)),
registerCommand('gitlens.graph.scrollMarkerTagOn', () => this.toggleScrollMarker('tags', true)),
registerCommand('gitlens.graph.scrollMarkerTagOff', () => this.toggleScrollMarker('tags', false)),
registerCommand('gitlens.graph.copyDeepLinkToBranch', this.copyDeepLinkToBranch, this),
registerCommand('gitlens.graph.copyDeepLinkToCommit', this.copyDeepLinkToCommit, this),
registerCommand('gitlens.graph.copyDeepLinkToRepo', this.copyDeepLinkToRepo, this),
registerCommand('gitlens.graph.copyDeepLinkToTag', this.copyDeepLinkToTag, this),
registerCommand('gitlens.graph.openChangedFiles', this.openFiles, this),
registerCommand('gitlens.graph.openOnlyChangedFiles', this.openOnlyChangedFiles, this),
registerCommand('gitlens.graph.openChangedFileDiffs', this.openAllChanges, this),
registerCommand('gitlens.graph.openChangedFileDiffsWithWorking', this.openAllChangesWithWorking, this),
registerCommand('gitlens.graph.openChangedFileRevisions', this.openRevisions, this),
registerCommand(
'gitlens.graph.resetColumnsDefault',
() => this.updateColumns(defaultGraphColumnsSettings),
this,
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerStashOn', () =>
this.toggleScrollMarker('stashes', true),
),
registerCommand(
'gitlens.graph.resetColumnsCompact',
() => this.updateColumns(compactGraphColumnsSettings),
this,
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerStashOff', () =>
this.toggleScrollMarker('stashes', false),
),
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerTagOn', () =>
this.toggleScrollMarker('tags', true),
),
this.host.registerWebviewCommand('gitlens.graph.scrollMarkerTagOff', () =>
this.toggleScrollMarker('tags', false),
),
this.host.registerWebviewCommand('gitlens.graph.copyDeepLinkToBranch', this.copyDeepLinkToBranch),
this.host.registerWebviewCommand('gitlens.graph.copyDeepLinkToCommit', this.copyDeepLinkToCommit),
this.host.registerWebviewCommand('gitlens.graph.copyDeepLinkToRepo', this.copyDeepLinkToRepo),
this.host.registerWebviewCommand('gitlens.graph.copyDeepLinkToTag', this.copyDeepLinkToTag),
this.host.registerWebviewCommand('gitlens.graph.openChangedFiles', this.openFiles),
this.host.registerWebviewCommand('gitlens.graph.openOnlyChangedFiles', this.openOnlyChangedFiles),
this.host.registerWebviewCommand('gitlens.graph.openChangedFileDiffs', this.openAllChanges),
this.host.registerWebviewCommand(
'gitlens.graph.openChangedFileDiffsWithWorking',
this.openAllChangesWithWorking,
),
this.host.registerWebviewCommand('gitlens.graph.openChangedFileRevisions', this.openRevisions),
this.host.registerWebviewCommand('gitlens.graph.resetColumnsDefault', () =>
this.updateColumns(defaultGraphColumnsSettings),
),
this.host.registerWebviewCommand('gitlens.graph.resetColumnsCompact', () =>
this.updateColumns(compactGraphColumnsSettings),
),
];
}
@ -792,10 +831,7 @@ export class GraphWebviewProvider implements WebviewProvider {
},
);
const details =
configuration.get('graph.layout') === 'panel'
? this.container.graphDetailsView
: this.container.commitDetailsView;
const details = this.host.isView() ? this.container.graphDetailsView : this.container.commitDetailsView;
if (!details.ready) {
void details.show({ preserveFocus: e.preserveFocus }, {
commit: commit,

+ 16
- 2
src/plus/webviews/graph/registration.ts Прегледај датотеку

@ -34,7 +34,6 @@ export function registerGraphWebviewPanel(controller: WebviewsController) {
const { GraphWebviewProvider } = await import(/* webpackChunkName: "graph" */ './graphWebview');
return new GraphWebviewProvider(container, host);
},
() => configuration.get('graph.layout') === 'editor',
);
}
@ -55,7 +54,6 @@ export function registerGraphWebviewView(controller: WebviewsController) {
const { GraphWebviewProvider } = await import(/* webpackChunkName: "graph" */ './graphWebview');
return new GraphWebviewProvider(container, host);
},
() => configuration.get('graph.layout') === 'panel',
);
}
@ -113,5 +111,21 @@ export function registerGraphWebviewCommands(container: Container, webview: Webv
}
},
),
registerCommand(
Commands.ShowInCommitGraphView,
(
args:
| ShowInCommitGraphCommandArgs
| Repository
| BranchNode
| CommitNode
| CommitFileNode
| StashNode
| TagNode,
) => {
const preserveFocus = 'preserveFocus' in args ? args.preserveFocus ?? false : false;
void container.graphView.show({ preserveFocus: preserveFocus }, args);
},
),
);
}

+ 18
- 1
src/system/command.ts Прегледај датотеку

@ -5,6 +5,9 @@ import type { Command } from '../commands/base';
import type { CoreCommands, CoreGitCommands, TreeViewCommands } from '../constants';
import { Commands } from '../constants';
import { Container } from '../container';
import { isWebviewContext } from './webview';
export type CommandCallback = Parameters<typeof commands.registerCommand>[1];
type CommandConstructor = new (container: Container) => Command;
const registrableCommands: CommandConstructor[] = [];
@ -15,7 +18,7 @@ export function command(): ClassDecorator {
};
}
export function registerCommand(command: string, callback: (...args: any[]) => any, thisArg?: any): Disposable {
export function registerCommand(command: string, callback: CommandCallback, thisArg?: any): Disposable {
return commands.registerCommand(
command,
function (this: any, ...args) {
@ -26,6 +29,20 @@ export function registerCommand(command: string, callback: (...args: any[]) => a
);
}
export function registerWebviewCommand(command: string, callback: CommandCallback, thisArg?: any): Disposable {
return commands.registerCommand(
command,
function (this: any, ...args) {
Container.instance.telemetry.sendEvent('command', {
command: command,
webview: isWebviewContext(args[0]) ? args[0].webview : '<missing>',
});
callback.call(this, ...args);
},
thisArg,
);
}
export function registerCommands(container: Container): Disposable[] {
return registrableCommands.map(c => new c(container));
}

+ 23
- 8
src/system/webview.ts Прегледај датотеку

@ -1,31 +1,46 @@
import type { WebviewIds, WebviewViewIds } from '../constants';
export interface WebviewItemContext<TValue = unknown> {
webview?: WebviewIds | WebviewViewIds;
export function createWebviewCommandLink(
command: `${WebviewIds | WebviewViewIds}.${string}`,
webviewId: WebviewIds | WebviewViewIds,
): string {
return `command:${command}?${encodeURIComponent(JSON.stringify({ webview: webviewId } satisfies WebviewContext))}`;
}
export interface WebviewContext {
webview: WebviewIds | WebviewViewIds;
}
export function isWebviewContext(item: object | null | undefined): item is WebviewContext {
if (item == null) return false;
return 'webview' in item && item.webview != null;
}
export interface WebviewItemContext<TValue = unknown> extends Partial<WebviewContext> {
webviewItem: string;
webviewItemValue: TValue;
}
export function isWebviewItemContext<TValue = unknown>(
item: object | null | undefined,
): item is WebviewItemContext<TValue> {
): item is WebviewItemContext<TValue> & WebviewContext {
if (item == null) return false;
return 'webview' in item && 'webviewItem' in item;
return 'webview' in item && item.webview != null && 'webviewItem' in item;
}
export interface WebviewItemGroupContext<TValue = unknown> {
webview?: WebviewIds | WebviewViewIds;
export interface WebviewItemGroupContext<TValue = unknown> extends Partial<WebviewContext> {
webviewItemGroup: string;
webviewItemGroupValue: TValue;
}
export function isWebviewItemGroupContext<TValue = unknown>(
item: object | null | undefined,
): item is WebviewItemGroupContext<TValue> {
): item is WebviewItemGroupContext<TValue> & WebviewContext {
if (item == null) return false;
return 'webview' in item && 'webviewItemGroup' in item;
return 'webview' in item && item.webview != null && 'webviewItemGroup' in item;
}
export function serializeWebviewItemContext<T = WebviewItemContext | WebviewItemGroupContext>(context: T): string {

+ 12
- 6
src/webviews/apps/plus/graph/GraphWrapper.tsx Прегледај датотеку

@ -55,6 +55,7 @@ import {
} from '../../../../plus/webviews/graph/protocol';
import type { Subscription } from '../../../../subscription';
import { pluralize } from '../../../../system/string';
import { createWebviewCommandLink } from '../../../../system/webview';
import type { IpcNotificationType } from '../../../protocol';
import { MenuDivider, MenuItem, MenuLabel, MenuList } from '../../shared/components/menu/react';
import { PopMenu } from '../../shared/components/overlays/pop-menu/react';
@ -978,9 +979,10 @@ export function GraphWrapper({
const lastFetchedDate = lastFetched && new Date(lastFetched);
const fetchedText = lastFetchedDate && lastFetchedDate.getTime() !== 0 ? fromNow(lastFetchedDate) : undefined;
let action: 'fetch' | 'pull' | 'push' = 'fetch';
let icon = 'sync';
let label = 'Fetch';
let action = 'command:gitlens.graph.fetch';
let isBehind = false;
let isAhead = false;
@ -993,12 +995,12 @@ export function GraphWrapper({
const branchPrefix = `Branch ${branchName} is`;
remote = `${branchState.upstream}${branchState.provider?.name ? ` on ${branchState.provider?.name}` : ''}`;
if (isBehind) {
action = 'command:gitlens.graph.pull';
action = 'pull';
icon = 'arrow-down';
label = 'Pull';
tooltip = `Pull from ${remote}\n${branchPrefix} ${pluralize('commit', branchState.behind)} behind of`;
} else if (isAhead) {
action = 'command:gitlens.graph.push';
action = 'push';
icon = 'arrow-up';
label = 'Push';
tooltip = `Push to ${remote}\n${branchPrefix} ${pluralize('commit', branchState.ahead)} ahead of`;
@ -1017,7 +1019,7 @@ export function GraphWrapper({
<div className="titlebar__group">
{(isBehind || isAhead) && (
<a
href={action}
href={createWebviewCommandLink(`gitlens.graph.${action}`, state.webviewId)}
className={`action-button${isBehind ? ' is-behind' : ''}${isAhead ? ' is-ahead' : ''}`}
title={tooltip}
>
@ -1041,7 +1043,11 @@ export function GraphWrapper({
)}
</a>
)}
<a href="command:gitlens.graph.fetch" className="action-button" title={fetchTooltip}>
<a
href={createWebviewCommandLink('gitlens.graph.fetch', state.webviewId)}
className="action-button"
title={fetchTooltip}
>
<span className="codicon codicon-sync action-button__icon"></span>
Fetch
{fetchedText && <span className="action-button__small">({fetchedText})</span>}
@ -1099,7 +1105,7 @@ export function GraphWrapper({
<span className="codicon codicon-chevron-right"></span>
</span>
<a
href="command:gitlens.graph.switchToAnotherBranch"
href={createWebviewCommandLink('gitlens.graph.switchToAnotherBranch', state.webviewId)}
className="action-button"
title="Switch to Another Branch..."
aria-label="Switch to Another Branch..."

+ 12
- 0
src/webviews/apps/settings/partials/commit-graph.html Прегледај датотеку

@ -26,6 +26,18 @@
<div class="settings settings--fixed ml-1">
<div class="setting">
<div class="setting__input">
<label for="graph.layout">Prefer showing the Commit Graph in the </label>
<div class="select-container">
<select id="graph.layout" name="graph.layout" data-setting>
<option value="editor">editor area</option>
<option value="panel">bottom panel</option>
</select>
</div>
</div>
</div>
<div class="setting">
<div class="setting__input">
<label for="graph.defaultItemLimit">Show </label>
<input
id="graph.defaultItemLimit"

+ 8
- 3
src/webviews/commitDetails/commitDetailsWebview.ts Прегледај датотеку

@ -369,9 +369,14 @@ export class CommitDetailsWebviewProvider implements WebviewProvider
case 'graph':
if (this._context.commit == null) return;
void executeCommand<ShowInCommitGraphCommandArgs>(Commands.ShowInCommitGraph, {
ref: getReferenceFromRevision(this._context.commit),
});
void executeCommand<ShowInCommitGraphCommandArgs>(
this.options.mode === 'graph'
? Commands.ShowInCommitGraphView
: Commands.ShowInCommitGraph,
{
ref: getReferenceFromRevision(this._context.commit),
},
);
break;
case 'more':
this.showCommitActions();

+ 70
- 0
src/webviews/webviewCommandRegistrar.ts Прегледај датотеку

@ -0,0 +1,70 @@
import type { Disposable } from 'vscode';
import type { CommandCallback } from '../system/command';
import { registerWebviewCommand } from '../system/command';
import type { WebviewContext } from '../system/webview';
import { isWebviewContext } from '../system/webview';
import type { WebviewProvider } from './webviewController';
export type WebviewCommandCallback<T extends Partial<WebviewContext>> = (arg?: T | undefined) => any;
export class WebviewCommandRegistrar implements Disposable {
private readonly _commandRegistrations = new Map<
string,
{ handlers: Map<string, { callback: CommandCallback; thisArg: any }>; subscription: Disposable }
>();
dispose() {
this._commandRegistrations.forEach(({ subscription }) => void subscription.dispose());
}
registerCommand<T extends WebviewProvider<any>>(
provider: T,
id: string,
command: string,
callback: CommandCallback,
) {
let registration = this._commandRegistrations.get(command);
if (registration == null) {
const handlers = new Map();
registration = {
subscription: registerWebviewCommand(
command,
(...args: any[]) => {
const item = args[0];
if (!isWebviewContext(item)) {
debugger;
return;
}
const handler = handlers.get(item.webview);
if (handler == null) {
throw new Error(
`Unable to find Command '${command}' registration for Webview '${item.webview}'`,
);
}
handler.callback.call(handler.thisArg, item);
},
this,
),
handlers: handlers,
};
this._commandRegistrations.set(command, registration);
}
if (registration.handlers.has(id)) {
throw new Error(`Command '${command}' has already been registered for Webview '${id}'`);
}
registration.handlers.set(id, { callback: callback, thisArg: provider });
return {
dispose: () => {
registration!.handlers.delete(id);
if (registration!.handlers.size === 0) {
this._commandRegistrations.delete(command);
registration!.subscription.dispose();
}
},
};
}
}

+ 11
- 0
src/webviews/webviewController.ts Прегледај датотеку

@ -8,8 +8,10 @@ import { setContext } from '../system/context';
import { debug, logName } from '../system/decorators/log';
import { serialize } from '../system/decorators/serialize';
import { isPromise } from '../system/promise';
import type { WebviewContext } from '../system/webview';
import type { IpcMessage, IpcMessageParams, IpcNotificationType, WebviewFocusChangedParams } from './protocol';
import { ExecuteCommandType, onIpc, WebviewFocusChangedCommandType, WebviewReadyCommandType } from './protocol';
import type { WebviewCommandCallback, WebviewCommandRegistrar } from './webviewCommandRegistrar';
import type { WebviewPanelDescriptor, WebviewViewDescriptor } from './webviewsController';
const maxSmallIntegerV8 = 2 ** 30; // Max number that can be stored in V8's smis (small integers)
@ -75,6 +77,7 @@ export class WebviewController<
{
static async create<State, SerializedState = State>(
container: Container,
commandRegistrar: WebviewCommandRegistrar,
descriptor: WebviewPanelDescriptor,
parent: WebviewPanel,
resolveProvider: (
@ -84,6 +87,7 @@ export class WebviewController<
): Promise<WebviewController<State, SerializedState, WebviewPanelDescriptor>>;
static async create<State, SerializedState = State>(
container: Container,
commandRegistrar: WebviewCommandRegistrar,
descriptor: WebviewViewDescriptor,
parent: WebviewView,
resolveProvider: (
@ -93,6 +97,7 @@ export class WebviewController<
): Promise<WebviewController<State, SerializedState, WebviewViewDescriptor>>;
static async create<State, SerializedState = State>(
container: Container,
commandRegistrar: WebviewCommandRegistrar,
descriptor: WebviewPanelDescriptor | WebviewViewDescriptor,
parent: WebviewPanel | WebviewView,
resolveProvider: (
@ -102,6 +107,7 @@ export class WebviewController<
): Promise<WebviewController<State, SerializedState>> {
const controller = new WebviewController<State, SerializedState>(
container,
commandRegistrar,
descriptor,
parent,
resolveProvider,
@ -128,6 +134,7 @@ export class WebviewController<
private constructor(
private readonly container: Container,
private readonly _commandRegistrar: WebviewCommandRegistrar,
private readonly descriptor: Descriptor,
public readonly parent: GetParentType<Descriptor>,
resolveProvider: (
@ -179,6 +186,10 @@ export class WebviewController<
this.disposable?.dispose();
}
registerWebviewCommand<T extends Partial<WebviewContext>>(command: string, callback: WebviewCommandCallback<T>) {
return this._commandRegistrar.registerCommand(this.provider, this.id, command, callback);
}
private _initializing: Promise<void> | undefined;
private async initialize() {
if (this._initializing == null) return;

+ 14
- 3
src/webviews/webviewsController.ts Прегледај датотеку

@ -15,6 +15,7 @@ import { debug } from '../system/decorators/log';
import { Logger } from '../system/logger';
import { getLogScope } from '../system/logger.scope';
import type { TrackedUsageFeatures } from '../telemetry/usageTracker';
import { WebviewCommandRegistrar } from './webviewCommandRegistrar';
import type { WebviewProvider } from './webviewController';
import { WebviewController } from './webviewController';
@ -74,10 +75,13 @@ export interface WebviewViewProxy extends Disposable {
export class WebviewsController implements Disposable {
private readonly disposables: Disposable[] = [];
private readonly _commandRegistrar: WebviewCommandRegistrar;
private readonly _panels = new Map<string, WebviewPanelRegistration<any>>();
private readonly _views = new Map<string, WebviewViewRegistration<any>>();
constructor(private readonly container: Container) {}
constructor(private readonly container: Container) {
this.disposables.push((this._commandRegistrar = new WebviewCommandRegistrar()));
}
dispose() {
this.disposables.forEach(d => void d.dispose());
@ -135,6 +139,7 @@ export class WebviewsController implements Disposable {
const controller = await WebviewController.create(
this.container,
this._commandRegistrar,
descriptor,
webviewView,
resolveProvider,
@ -219,7 +224,7 @@ export class WebviewsController implements Disposable {
this._panels.set(descriptor.id, registration);
const disposables: Disposable[] = [];
const { container } = this;
const { container, _commandRegistrar: commandRegistrar } = this;
let serializedPanel: WebviewPanel | undefined;
@ -273,7 +278,13 @@ export class WebviewsController implements Disposable {
panel.iconPath = Uri.file(container.context.asAbsolutePath(descriptor.iconPath));
controller = await WebviewController.create(container, descriptor, panel, resolveProvider);
controller = await WebviewController.create(
container,
commandRegistrar,
descriptor,
panel,
resolveProvider,
);
registration.controller = controller;
disposables.push(

Loading…
Откажи
Сачувај