diff --git a/extensions/mssql/l10n/bundle.l10n.json b/extensions/mssql/l10n/bundle.l10n.json index 71d9c3f369..d156566173 100644 --- a/extensions/mssql/l10n/bundle.l10n.json +++ b/extensions/mssql/l10n/bundle.l10n.json @@ -560,6 +560,8 @@ }, "Chat": "Chat", "Open in GitHub Copilot Chat": "Open in GitHub Copilot Chat", + "Ask GitHub Copilot to Fix": "Ask GitHub Copilot to Fix", + "Open GitHub Copilot Chat to help fix these errors": "Open GitHub Copilot Chat to help fix these errors", "Design Schemas with GitHub Copilot": "Design Schemas with GitHub Copilot", "Ask questions or propose schema changes in chat, and GitHub Copilot updates the schema instantly in the diagram.": "Ask questions or propose schema changes in chat, and GitHub Copilot updates the schema instantly in the diagram.", "Build APIs with GitHub Copilot": "Build APIs with GitHub Copilot", diff --git a/extensions/mssql/src/controllers/mainController.ts b/extensions/mssql/src/controllers/mainController.ts index 4ae2144e5a..1556f615ff 100644 --- a/extensions/mssql/src/controllers/mainController.ts +++ b/extensions/mssql/src/controllers/mainController.ts @@ -937,6 +937,7 @@ export default class MainController implements vscode.Disposable { private async openCopilotChatFromUi(args?: CopilotChat.OpenFromUiArgs): Promise { const scenario = args?.scenario ?? "schemaDesigner"; const entryPoint = args?.entryPoint ?? "schemaDesignerToolbar"; + const promptOverride = args?.prompt?.trim(); const sendCopilotChatEntryTelemetry = ( success: boolean, reason?: "noActiveDesigner" | "chatCommandMissing", @@ -967,10 +968,11 @@ export default class MainController implements vscode.Disposable { return; } - await vscode.commands.executeCommand( - chatCommand, - this.getCopilotChatPromptForScenario(scenario), - ); + const promptToUse = + promptOverride && promptOverride.length > 0 + ? promptOverride + : this.getCopilotChatPromptForScenario(scenario); + await vscode.commands.executeCommand(chatCommand, promptToUse); sendCopilotChatEntryTelemetry(true); } diff --git a/extensions/mssql/src/reactviews/common/locConstants.ts b/extensions/mssql/src/reactviews/common/locConstants.ts index de5ae7d776..e0b1f297c0 100644 --- a/extensions/mssql/src/reactviews/common/locConstants.ts +++ b/extensions/mssql/src/reactviews/common/locConstants.ts @@ -808,6 +808,10 @@ export class LocConstants { publishChanges: l10n.t("Apply Changes"), openCopilotForSchemaDesigner: l10n.t("Chat"), openCopilotForSchemaDesignerTooltip: l10n.t("Open in GitHub Copilot Chat"), + askGithubCopilotToFix: l10n.t("Ask GitHub Copilot to Fix"), + askGithubCopilotToFixTooltip: l10n.t( + "Open GitHub Copilot Chat to help fix these errors", + ), schemaDesignerCopilotDiscoveryTitle: l10n.t("Design Schemas with GitHub Copilot"), schemaDesignerCopilotDiscoveryBody: l10n.t( "Ask questions or propose schema changes in chat, and GitHub Copilot updates the schema instantly in the diagram.", diff --git a/extensions/mssql/src/reactviews/pages/SchemaDesigner/toolbar/publishChangesDialogButton.tsx b/extensions/mssql/src/reactviews/pages/SchemaDesigner/toolbar/publishChangesDialogButton.tsx index 5b970326c8..35c7946ee3 100644 --- a/extensions/mssql/src/reactviews/pages/SchemaDesigner/toolbar/publishChangesDialogButton.tsx +++ b/extensions/mssql/src/reactviews/pages/SchemaDesigner/toolbar/publishChangesDialogButton.tsx @@ -26,8 +26,17 @@ import Markdown from "react-markdown"; import { SchemaDesigner } from "../../../../sharedInterfaces/schemaDesigner"; import { useMarkdownStyles } from "../../../common/styles"; import { useSchemaDesignerChangeContext } from "../definition/changes/schemaDesignerChangeContext"; +import { useSchemaDesignerSelector } from "../schemaDesignerSelector"; +import { CopilotChat } from "../../../../sharedInterfaces/copilotChat"; +import { ExecuteCommandRequest } from "../../../../sharedInterfaces/webview"; +import { GithubCopilot16Regular } from "../../../common/icons/fluentIcons"; +import { + schemaDesignerPublishErrorDetailsLabel, + schemaDesignerPublishErrorFallbackDetails, + schemaDesignerPublishErrorPrompt, +} from "./publishChangesDialogPrompts"; -enum PublishDialogStages { +export enum PublishDialogStages { NotStarted = "notStarted", ReportLoading = "reportLoading", ReportError = "reportError", @@ -47,6 +56,45 @@ type PublishChangesDialogState = { currentStage: PublishDialogStages; }; +export function buildSchemaDesignerPublishErrorPrompt(errorString: string): string { + const errorDetails = errorString.trim() || schemaDesignerPublishErrorFallbackDetails; + return `${schemaDesignerPublishErrorPrompt} + +${schemaDesignerPublishErrorDetailsLabel} +\`\`\` +${errorDetails} +\`\`\``; +} + +export function isReportOrPublishErrorStage(currentStage: PublishDialogStages): boolean { + return ( + currentStage === PublishDialogStages.ReportError || + currentStage === PublishDialogStages.PublishError + ); +} + +export function getReportOrPublishErrorForStage( + currentStage: PublishDialogStages, + reportError: string | undefined, + publishError: string | undefined, +): string { + if (currentStage === PublishDialogStages.ReportError) { + return reportError ?? ""; + } + if (currentStage === PublishDialogStages.PublishError) { + return publishError ?? ""; + } + return ""; +} + +export function shouldShowGithubCopilotFixButton( + currentStage: PublishDialogStages, + isCopilotChatInstalled: boolean, + isDabEnabled: boolean, +): boolean { + return isReportOrPublishErrorStage(currentStage) && isCopilotChatInstalled && isDabEnabled; +} + const useStyles = makeStyles({ errorSection: { marginBottom: "15px", @@ -67,6 +115,8 @@ export function PublishChangesDialogButton() { const markdownClasses = useMarkdownStyles(); const context = useContext(SchemaDesignerContext); const changeContext = useSchemaDesignerChangeContext(); + const isCopilotChatInstalled = + useSchemaDesignerSelector((s) => s?.isCopilotChatInstalled) ?? false; const [open, setOpen] = useState(false); const [publishButtonDisabled, setPublishButtonDisabled] = useState(false); const hasSchemaChanges = changeContext.schemaChangesCount > 0; @@ -372,6 +422,42 @@ export function PublishChangesDialogButton() { ); }; + const isGithubCopilotFixButtonVisible = () => { + return shouldShowGithubCopilotFixButton( + state.currentStage, + isCopilotChatInstalled, + context.isDabEnabled(), + ); + }; + + const getCurrentError = () => { + return getReportOrPublishErrorForStage( + state.currentStage, + state.reportError, + state.publishError, + ); + }; + + const openGithubCopilotToFixError = async () => { + const prompt = buildSchemaDesignerPublishErrorPrompt(getCurrentError()); + setOpen(false); + setState({ + ...state, + isConfirmationChecked: false, + }); + + await context.extensionRpc.sendRequest(ExecuteCommandRequest.type, { + command: CopilotChat.openFromUiCommand, + args: [ + { + scenario: "schemaDesigner", + entryPoint: "schemaDesignerPublishDialogError", + prompt, + }, + ], + }); + }; + const footerButtons = () => { return ( <> @@ -428,6 +514,21 @@ export function PublishChangesDialogButton() { )} + {isGithubCopilotFixButtonVisible() && ( + + + + )} {state.currentStage !== PublishDialogStages.PublishLoading && (