diff --git a/package.json b/package.json
index fde7b2520..72c76832e 100644
--- a/package.json
+++ b/package.json
@@ -87,20 +87,35 @@
}
],
"scm/resource/context": [
+ {
+ "command": "tfvc.Include",
+ "when": "scmProvider == tfvc && scmResourceGroup == excluded",
+ "group": "navigation"
+ },
+ {
+ "command": "tfvc.Include",
+ "when": "scmProvider == tfvc && scmResourceGroup == included",
+ "group": "navigation"
+ },
{
"command": "tfvc.Exclude",
"when": "scmProvider == tfvc && scmResourceGroup == included",
"group": "1_sync"
},
+ {
+ "command": "tfvc.Undo",
+ "when": "scmProvider == tfvc",
+ "group": "inline@1"
+ },
{
"command": "tfvc.Include",
"when": "scmProvider == tfvc && scmResourceGroup == excluded",
- "group": "navigation"
+ "group": "inline@2"
},
{
- "command": "tfvc.Include",
+ "command": "tfvc.Exclude",
"when": "scmProvider == tfvc && scmResourceGroup == included",
- "group": "navigation"
+ "group": "inline@2"
}
]
},
@@ -233,7 +248,11 @@
{
"command": "tfvc.Exclude",
"title": "Exclude",
- "category": "TFVC"
+ "category": "TFVC",
+ "icon": {
+ "light": "resources/icons/light/unstage.svg",
+ "dark": "resources/icons/dark/unstage.svg"
+ }
},
{
"command": "tfvc.IncludeAll",
@@ -243,7 +262,11 @@
{
"command": "tfvc.Include",
"title": "Include",
- "category": "TFVC"
+ "category": "TFVC",
+ "icon": {
+ "light": "resources/icons/light/stage.svg",
+ "dark": "resources/icons/dark/stage.svg"
+ }
},
{
"command": "tfvc.ShowOutput",
@@ -262,7 +285,11 @@
{
"command": "tfvc.Undo",
"title": "Undo",
- "category": "TFVC"
+ "category": "TFVC",
+ "icon": {
+ "light": "resources/icons/light/clean.svg",
+ "dark": "resources/icons/dark/clean.svg"
+ }
}
]
},
diff --git a/resources/icons/dark/clean.svg b/resources/icons/dark/clean.svg
new file mode 100644
index 000000000..9f1756333
--- /dev/null
+++ b/resources/icons/dark/clean.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/dark/stage.svg b/resources/icons/dark/stage.svg
new file mode 100644
index 000000000..3475c1e19
--- /dev/null
+++ b/resources/icons/dark/stage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/dark/unstage.svg b/resources/icons/dark/unstage.svg
new file mode 100644
index 000000000..2de46fcf5
--- /dev/null
+++ b/resources/icons/dark/unstage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/light/clean.svg b/resources/icons/light/clean.svg
new file mode 100644
index 000000000..1fa6ba48a
--- /dev/null
+++ b/resources/icons/light/clean.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/light/stage.svg b/resources/icons/light/stage.svg
new file mode 100644
index 000000000..bdecdb0e4
--- /dev/null
+++ b/resources/icons/light/stage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/light/unstage.svg b/resources/icons/light/unstage.svg
new file mode 100644
index 000000000..f5d128b2d
--- /dev/null
+++ b/resources/icons/light/unstage.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index 1f262a336..0ba46f447 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -45,7 +45,15 @@ export async function activate(context: ExtensionContext) {
// TFVC Commands
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Status, () => _extensionManager.Tfvc.TfvcStatus()));
- context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Undo, () => _extensionManager.Tfvc.TfvcUndo()));
+ context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Undo, (...args) => {
+ if (args) {
+ //TODO: Multi-select?
+ _extensionManager.Tfvc.TfvcUndo(args[0]);
+ } else {
+ _extensionManager.Tfvc.TfvcUndo();
+ }
+ }
+ ));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Exclude, () => _extensionManager.Tfvc.TfvcExclude()));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ExcludeAll, () => _extensionManager.Tfvc.TfvcExcludeAll()));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Include, () => _extensionManager.Tfvc.TfvcInclude()));
diff --git a/src/helpers/strings.ts b/src/helpers/strings.ts
index 566311d94..88d952f5e 100644
--- a/src/helpers/strings.ts
+++ b/src/helpers/strings.ts
@@ -64,6 +64,7 @@ export class Strings {
static TfExecFailedError: string = "Execution of the TFVC command line failed unexpectedly.";
static TfVersionWarning: string = "The installed version of the TF command line does not meet the minimum suggested version. You may run into errors or limitations with certain commands until you upgrade. Minimum suggested version: ";
static TfNoPendingChanges: string = "There are no matching pending changes.";
+ static UndoChanges: string = "Undo Changes";
// TFVC viewlet Strings
static ExcludedGroupName: string = "Excluded changes";
diff --git a/src/tfvc/tfvc-extension.ts b/src/tfvc/tfvc-extension.ts
index 50bbc0b5a..f02c0c5a3 100644
--- a/src/tfvc/tfvc-extension.ts
+++ b/src/tfvc/tfvc-extension.ts
@@ -4,14 +4,17 @@
*--------------------------------------------------------------------------------------------*/
"use strict";
+import * as path from "path";
import url = require("url");
-import { TextEditor, window, workspace } from "vscode";
+import { Uri, window, workspace } from "vscode";
import { RepositoryType } from "../contexts/repositorycontext";
import { TfvcContext } from "../contexts/tfvccontext";
import { ExtensionManager } from "../extensionmanager";
import { TfvcTelemetryEvents } from "../helpers/constants";
+import { Strings } from "../helpers/strings";
import { Utils } from "../helpers/utils";
import { Tfvc } from "./tfvc";
+import { TfvcSCMProvider } from "./tfvcscmprovider";
import { TfvcErrorCodes } from "./tfvcerror";
import { Repository } from "./repository";
import { UIHelper } from "./uihelper";
@@ -78,18 +81,32 @@ export class TfvcExtension {
* editor. If the undo command applies to the file, the pending changes will be undone. The
* file system watcher will update the UI soon thereafter. No results are displayed to the user.
*/
- public async TfvcUndo(): Promise {
+ public async TfvcUndo(uri?: Uri): Promise {
if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) {
this._manager.DisplayErrorMessage();
return;
}
try {
- this._manager.Telemetry.SendEvent(TfvcTelemetryEvents.Undo);
- //TODO: When calling from UI, UI will need to call repository.Undo([filePath]);
- let editor: TextEditor = window.activeTextEditor;
- if (editor) {
- await this._repo.Undo([editor.document.fileName]);
+ //When calling from UI, we have the uri of the resource from which the command was invoked
+ let pathToUndo: string = TfvcSCMProvider.GetPathFromUri(uri);
+ if (!pathToUndo) {
+ //This is called from the command palette, so check for an open file in the editor
+ if (window.activeTextEditor) {
+ pathToUndo = window.activeTextEditor.document.fileName;
+ }
+ }
+ if (pathToUndo) {
+ const basename: string = path.basename(pathToUndo);
+ const message: string = `Are you sure you want to undo changes in ${basename}?`;
+ //TODO: use Modal api once vscode.d.ts exposes it (currently proposed)
+ const pick: string = await window.showWarningMessage(message, /*{ modal: true },*/ Strings.UndoChanges);
+ if (pick !== Strings.UndoChanges) {
+ return;
+ }
+
+ this._manager.Telemetry.SendEvent(TfvcTelemetryEvents.Undo);
+ await this._repo.Undo([pathToUndo]);
}
} catch (err) {
this._manager.DisplayErrorMessage(err.message);
diff --git a/src/tfvc/tfvcscmprovider.ts b/src/tfvc/tfvcscmprovider.ts
index 430de11f0..cdad5c507 100644
--- a/src/tfvc/tfvcscmprovider.ts
+++ b/src/tfvc/tfvcscmprovider.ts
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
"use strict";
-import { commands, scm, Uri, Disposable, SCMProvider, SCMResourceGroup, Event, ProviderResult, workspace } from "vscode";
+import { commands, scm, Uri, Disposable, SCMProvider, SCMResource, SCMResourceGroup, Event, ProviderResult, workspace } from "vscode";
import { Model } from "./scm/model";
import { Status } from "./scm/status";
import { Resource } from "./scm/resource";
@@ -173,4 +173,33 @@ export class TfvcSCMProvider implements SCMProvider {
return "";
}
+
+ private static ResolveTfvcURI(uri: Uri): SCMResource | SCMResourceGroup | undefined {
+ if (uri.authority !== TfvcSCMProvider.scmScheme) {
+ return;
+ }
+
+ return scm.getResourceFromURI(uri);
+ }
+
+ private static ResolveTfvcResource(uri: Uri): Resource {
+ const resource = TfvcSCMProvider.ResolveTfvcURI(uri);
+
+ if (!(resource instanceof Resource)) {
+ return;
+ }
+
+ return resource;
+ }
+
+ public static GetPathFromUri(uri: Uri): string {
+ if (uri) {
+ const resource = TfvcSCMProvider.ResolveTfvcResource(uri);
+ if (resource) {
+ return resource.uri.fsPath;
+ }
+ }
+ return undefined;
+ }
+
}