diff --git a/package.json b/package.json index 87917ff..f9eaceb 100644 --- a/package.json +++ b/package.json @@ -210,6 +210,28 @@ ".node-version" ], "description": "The file to be used to store the Node version for the selected Node version manager. Remember that the .node-version file is supported only while using nvs." + }, + "spfx-toolkit.projectUpgradeOutputMode": { + "title": "Project upgrade output mode", + "type": "string", + "default": "both", + "enum": [ + "both", + "markdown", + "code tour" + ], + "description": "Choose the output mode for the project upgrade. You can choose between `both`, `markdown`, or `code tour`." + }, + "spfx-toolkit.projectValidateOutputMode": { + "title": "Project validate output mode", + "type": "string", + "default": "both", + "enum": [ + "both", + "markdown", + "code tour" + ], + "description": "Choose the output mode for the project validation. You can choose between `both`, `markdown`, or `code tour`." } } }, diff --git a/src/services/actions/CliActions.ts b/src/services/actions/CliActions.ts index 132b31c..d9160aa 100644 --- a/src/services/actions/CliActions.ts +++ b/src/services/actions/CliActions.ts @@ -1,6 +1,6 @@ import { readFileSync, writeFileSync } from 'fs'; import { Folders } from '../check/Folders'; -import { commands, Progress, ProgressLocation, Uri, window, workspace } from 'vscode'; +import { commands, Progress, ProgressLocation, Uri, window, workspace, WorkspaceFolder } from 'vscode'; import { Commands, ContextKeys, WebViewType, WebviewCommand, WorkflowType } from '../../constants'; import { AppCatalogApp, GenerateWorkflowCommandInput, SiteAppCatalog, SolutionAddResult, Subscription } from '../../models'; import { Extension } from '../dataType/Extension'; @@ -17,7 +17,8 @@ import { parseCliCommand } from '../../utils/parseCliCommand'; import { CertificateActions } from './CertificateActions'; import path = require('path'); import { ActionTreeItem } from '../../providers/ActionTreeDataProvider'; - +import { getExtensionSettings } from '../../utils/getExtensionSettings'; +import * as fs from 'fs'; export class CliActions { @@ -501,21 +502,16 @@ export class CliActions { cancellable: true }, async (progress: Progress<{ message?: string; increment?: number }>) => { try { - const result = await CliExecuter.execute('spfx project upgrade', 'md'); - - if (result.stdout) { - // Create a file to allow the Markdown preview to correctly open the linked/referenced files - let savePath = wsFolder?.uri.fsPath; + const projectUpgradeOutputMode: string = getExtensionSettings('projectUpgradeOutputMode', 'both'); - if (savePath && TeamsToolkitIntegration.isTeamsToolkitProject) { - savePath = join(savePath, 'src'); - } + if (projectUpgradeOutputMode === 'markdown' || projectUpgradeOutputMode === 'both') { + const resultMd = await CliExecuter.execute('spfx project upgrade', 'md'); + CliActions.handleMarkdownResult(resultMd, wsFolder, 'upgrade'); + } - const filePath = join(savePath || '', 'spfx.upgrade.md'); - writeFileSync(filePath, result.stdout); - await commands.executeCommand('markdown.showPreview', Uri.file(filePath)); - } else if (result.stderr) { - Notifications.error(result.stderr); + if (projectUpgradeOutputMode === 'code tour' || projectUpgradeOutputMode === 'both') { + await CliExecuter.execute('spfx project upgrade', 'tour'); + CliActions.handleTourResult(wsFolder, 'upgrade'); } } catch (e: any) { const message = e?.error?.message; @@ -680,21 +676,16 @@ export class CliActions { cancellable: true }, async (progress: Progress<{ message?: string; increment?: number }>) => { try { - const result = await CliExecuter.execute('spfx project doctor', 'md'); - - if (result.stdout) { - // Create a file to allow the Markdown preview to correctly open the linked/referenced files - let savePath = wsFolder?.uri.fsPath; + const projectValidateOutputMode: string = getExtensionSettings('projectValidateOutputMode', 'both'); - if (savePath && TeamsToolkitIntegration.isTeamsToolkitProject) { - savePath = join(savePath, 'src'); - } + if (projectValidateOutputMode === 'markdown' || projectValidateOutputMode === 'both') { + const resultMd = await CliExecuter.execute('spfx project doctor', 'md'); + CliActions.handleMarkdownResult(resultMd, wsFolder, 'validate'); + } - const filePath = join(savePath || '', 'spfx.validate.md'); - writeFileSync(filePath, result.stdout); - await commands.executeCommand('markdown.showPreview', Uri.file(filePath)); - } else if (result.stderr) { - Notifications.error(result.stderr); + if (projectValidateOutputMode === 'code tour' || projectValidateOutputMode === 'both') { + await CliExecuter.execute('spfx project doctor', 'tour'); + CliActions.handleTourResult(wsFolder, 'validation'); } } catch (e: any) { const message = e?.error?.message; @@ -810,4 +801,49 @@ export class CliActions { } }); } + + /** + * Handles the Markdown result + * @param result The result of the (CLI) command execution + * @param wsFolder The workspace folder + */ + private static handleMarkdownResult(result: any, wsFolder: WorkspaceFolder | undefined, fileName: string) { + if (result?.stderr) { + Notifications.error(result.stderr); + return; + } + + let savePath = wsFolder?.uri.fsPath; + + if (savePath && TeamsToolkitIntegration.isTeamsToolkitProject) { + savePath = join(savePath, 'src'); + } + + const filePath = join(savePath || '', `spfx.${fileName}.md`); + writeFileSync(filePath, result.stdout); + commands.executeCommand('markdown.showPreview', Uri.file(filePath)); + } + + /** + * Handles the Tour result + * @param wsFolder The workspace folder + */ + private static async handleTourResult(wsFolder: WorkspaceFolder | undefined, fileName: string): Promise { + if (!wsFolder) { + Notifications.error('Workspace folder is undefined. Cannot start Code Tour.'); + return; + } + + const tourFilePath = path.join(wsFolder.uri.fsPath, '.tours', `${fileName}.tour`); + await workspace.fs.stat(Uri.file(tourFilePath)); + + // A timeout is needed so Codetour can find the tour file + if (fs.existsSync(tourFilePath)) { + setTimeout(() => { + commands.executeCommand('codetour.startTour'); + }, 500); + } else { + Notifications.error(`${fileName}.tour file not found in path ${path.join(wsFolder.uri.fsPath, '.tours')}. Cannot start Code Tour.`); + } + } } \ No newline at end of file