Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UX improvements to the custom command workflow #992

Merged
merged 35 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4d3ecea
Provide link to docs when custom config is opened
toolmantim Sep 1, 2023
44bd8d0
Clean up tooltips
toolmantim Sep 1, 2023
0f5817c
Update labels
toolmantim Sep 3, 2023
c567686
Ask for type
toolmantim Sep 5, 2023
5885fd9
Add the word repo to help people understand the location
toolmantim Sep 7, 2023
cd488d1
Let the user choose where to save the command
toolmantim Sep 7, 2023
8f3c939
Lint
toolmantim Sep 7, 2023
a913135
Set type and add 'Open Settings' button
toolmantim Sep 7, 2023
3990bd2
Formatting
toolmantim Sep 7, 2023
88f5e51
Labels
toolmantim Sep 8, 2023
7cfb54f
Remove comment
toolmantim Sep 8, 2023
6f9eede
Repos
toolmantim Sep 8, 2023
70e07dc
Repositories
toolmantim Sep 8, 2023
299e991
Label
toolmantim Sep 8, 2023
f4a04d5
Allow creating a custom command with no file yet
toolmantim Sep 8, 2023
910c4d2
Lint
toolmantim Sep 8, 2023
079f942
Abort as soon as they hit esc
toolmantim Sep 8, 2023
aa57c09
Fix notification
toolmantim Sep 8, 2023
33868d8
Remove comments
toolmantim Sep 8, 2023
9922a67
New examples and labels
toolmantim Sep 8, 2023
3f54a31
Fix accidental command override with '/' inputs
toolmantim Sep 10, 2023
e2ad5a5
Cancel as soon as you hit esc
toolmantim Sep 10, 2023
d652ffb
Improve notification message
toolmantim Sep 10, 2023
f02f638
Message
toolmantim Sep 10, 2023
e643b0a
Rely on docs for examples
toolmantim Sep 11, 2023
9933590
Use explicit 'user' | 'workspace' for custom command types
toolmantim Sep 11, 2023
1998202
Nicer labels
toolmantim Sep 11, 2023
dd7d8e1
Update docs link
toolmantim Sep 11, 2023
e2241f4
Lint
toolmantim Sep 11, 2023
fcc6213
Changelog
toolmantim Sep 11, 2023
f662a56
Merge branch 'main' into tl/custom-command-quickpick-tweaks
toolmantim Sep 11, 2023
b697163
Merge branch 'main' into tl/custom-command-quickpick-tweaks
toolmantim Sep 11, 2023
cd81b11
Mention new docs in changelog
toolmantim Sep 13, 2023
1c96984
CustomCommandType
toolmantim Sep 14, 2023
e245025
Merge branch 'main' into tl/custom-command-quickpick-tweaks
toolmantim Sep 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/shared/src/chat/prompts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export interface CodyPromptContext {

export type CodyPromptType = 'workspace' | 'user' | 'default' | 'recently used'

export type CustomCommandType = 'workspace' | 'user'

export const ConfigFileName = {
vscode: '.vscode/cody.json',
}
Expand Down
1 change: 1 addition & 0 deletions vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Starting from `0.2.0`, Cody is using `major.EVEN_NUMBER.patch` for release versi
- Remove `starter` and `premade` fields from the configuration files for custom commands (cody.json). [pull/939](https://github.com/sourcegraph/cody/pull/939)
- Enabled streaming responses for all autocomplete requests. [pull/995](https://github.com/sourcegraph/cody/pull/995)
- Sign out immediately instead of showing the quick-pick menu. [pull/1032](https://github.com/sourcegraph/cody/pull/1032)
- UX improvements to the custom command workflow (and new [custom command docs](https://docs.sourcegraph.com/cody/custom-commands)). [pull/992](https://github.com/sourcegraph/cody/pull/992)

## [0.10.1]

Expand Down
3 changes: 0 additions & 3 deletions vscode/resources/samples/README.md

This file was deleted.

23 changes: 0 additions & 23 deletions vscode/resources/samples/user-cody.json

This file was deleted.

23 changes: 0 additions & 23 deletions vscode/resources/samples/workspace-cody.json

This file was deleted.

4 changes: 2 additions & 2 deletions vscode/src/chat/ChatViewProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as vscode from 'vscode'

import { CodyPrompt, CodyPromptType } from '@sourcegraph/cody-shared/src/chat/prompts'
import { CodyPrompt, CustomCommandType } from '@sourcegraph/cody-shared/src/chat/prompts'
import { ChatMessage, UserLocalHistory } from '@sourcegraph/cody-shared/src/chat/transcript/messages'

import { View } from '../../webviews/NavBar'
Expand Down Expand Up @@ -149,7 +149,7 @@ export class ChatViewProvider extends MessageProvider implements vscode.WebviewV
/**
* Process custom command click
*/
private async onCustomPromptClicked(title: string, commandType: CodyPromptType = 'user'): Promise<void> {
private async onCustomPromptClicked(title: string, commandType: CustomCommandType = 'user'): Promise<void> {
this.telemetryService.log('CodyVSCodeExtension:command:customMenu:clicked')
logDebug('ChatViewProvider:onCustomPromptClicked', title)
if (!this.isCustomCommandAction(title)) {
Expand Down
4 changes: 2 additions & 2 deletions vscode/src/chat/MessageProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as vscode from 'vscode'
import { BotResponseMultiplexer } from '@sourcegraph/cody-shared/src/chat/bot-response-multiplexer'
import { ChatClient } from '@sourcegraph/cody-shared/src/chat/chat'
import { getPreamble } from '@sourcegraph/cody-shared/src/chat/preamble'
import { CodyPrompt, CodyPromptType } from '@sourcegraph/cody-shared/src/chat/prompts'
import { CodyPrompt, CustomCommandType } from '@sourcegraph/cody-shared/src/chat/prompts'
import { newInteraction } from '@sourcegraph/cody-shared/src/chat/prompts/utils'
import { Recipe, RecipeID } from '@sourcegraph/cody-shared/src/chat/recipes/recipe'
import { Transcript } from '@sourcegraph/cody-shared/src/chat/transcript'
Expand Down Expand Up @@ -445,7 +445,7 @@ export abstract class MessageProvider extends MessageHandler implements vscode.D
* Handle instructions returned from webview in regard to a Cody Command
* Finds and execute a Cody command
*/
public async executeCustomCommand(title: string, type?: CodyPromptType): Promise<void> {
public async executeCustomCommand(title: string, type?: CustomCommandType): Promise<void> {
title = title.trim()
switch (title) {
case 'get':
Expand Down
4 changes: 2 additions & 2 deletions vscode/src/chat/protocol.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChatContextStatus } from '@sourcegraph/cody-shared/src/chat/context'
import { CodyPrompt, CodyPromptType } from '@sourcegraph/cody-shared/src/chat/prompts'
import { CodyPrompt, CustomCommandType } from '@sourcegraph/cody-shared/src/chat/prompts'
import { RecipeID } from '@sourcegraph/cody-shared/src/chat/recipes/recipe'
import { ChatMessage, UserLocalHistory } from '@sourcegraph/cody-shared/src/chat/transcript/messages'
import { Configuration } from '@sourcegraph/cody-shared/src/configuration'
Expand Down Expand Up @@ -41,7 +41,7 @@ export type WebviewMessage =
authMethod?: AuthMethod
}
| { command: 'abort' }
| { command: 'custom-prompt'; title: string; value?: CodyPromptType }
| { command: 'custom-prompt'; title: string; value?: CustomCommandType }
| { command: 'reload' }

/**
Expand Down
35 changes: 21 additions & 14 deletions vscode/src/custom-prompts/CommandsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as vscode from 'vscode'

import {
CodyPrompt,
CodyPromptType,
CustomCommandType,
defaultCodyPromptContext,
MyPrompts,
} from '@sourcegraph/cody-shared/src/chat/prompts'
Expand Down Expand Up @@ -115,7 +115,6 @@ export class CommandsController implements VsCodeCommandsController, vscode.Disp
* then set it as the prompt in progress
*
* @param id - The id/name of the command
* @param isSlash - Whether this is a slash command
*
* @returns The prompt text for the command if found, empty string otherwise
*/
Expand Down Expand Up @@ -341,9 +340,8 @@ export class CommandsController implements VsCodeCommandsController, vscode.Disp
* Menu with an option to add a new command via UI and save it to user's cody.json file
*/
public async configMenu(lastMenu?: string): Promise<void> {
const promptSize = this.custom.promptSize.user + this.custom.promptSize.workspace
const selected = await showCommandConfigMenu()
const action = promptSize === 0 ? 'file' : selected?.id
const action = selected?.id
if (!selected || !action) {
return
}
Expand All @@ -363,18 +361,13 @@ export class CommandsController implements VsCodeCommandsController, vscode.Disp
break
}
case 'add': {
if (selected?.type === 'workspace') {
const wsFileAction = this.custom.promptSize.workspace === 0 ? 'file' : 'open'
await this.config(wsFileAction, 'workspace')
break
}
await this.config(action, selected?.type)
await this.config(action)
break
}
case 'list':
await this.customCommandMenu()
break
case 'example':
case 'docs':
await openCustomCommandDocsLink()
break
}
Expand All @@ -386,7 +379,7 @@ export class CommandsController implements VsCodeCommandsController, vscode.Disp
* Config file controller
* handles operations on config files for user and workspace commands
*/
public async config(action: string, fileType: CodyPromptType): Promise<void> {
public async config(action: string, fileType?: CustomCommandType): Promise<void> {
switch (action) {
case 'delete':
if ((await showRemoveConfirmationInput()) !== 'Yes') {
Expand All @@ -399,7 +392,9 @@ export class CommandsController implements VsCodeCommandsController, vscode.Disp
await this.custom.createConfig(fileType)
break
case 'open':
await this.open(fileType)
if (fileType) {
await this.open(fileType)
}
break
case 'add':
await this.addNewUserCommandQuick()
Expand All @@ -419,8 +414,20 @@ export class CommandsController implements VsCodeCommandsController, vscode.Disp
return
}
// Save the prompt to the current Map and Extension storage
await this.custom.save(newCommand.slashCommand, newCommand.prompt)
await this.custom.save(newCommand.slashCommand, newCommand.prompt, false, newCommand.type)
await this.refresh()
// Notify user
const buttonTitle = `Open ${newCommand.type === 'user' ? 'User' : 'Workspace'} Settings (JSON)`
void vscode.window
.showInformationMessage(
`New ${newCommand.slashCommand} command saved to ${newCommand.type} settings`,
buttonTitle
)
.then(async choice => {
if (choice === buttonTitle) {
await this.custom.openConfig(newCommand.type)
}
})

logDebug('CommandsController:updateUserCommandQuick:newPrompt:', 'saved', { verbose: newCommand })
}
Expand Down
42 changes: 22 additions & 20 deletions vscode/src/custom-prompts/CustomPromptsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import * as vscode from 'vscode'

import {
CodyPrompt,
CodyPromptType,
ConfigFileName,
CustomCommandType,
MyPrompts,
MyPromptsJSON,
} from '@sourcegraph/cody-shared/src/chat/prompts'
Expand All @@ -17,7 +17,7 @@ import {
createJSONFile,
deleteFile,
getFileContentText,
isUserType,
openCustomCommandDocsLink,
saveJSONFile,
} from './utils/helpers'
import { promptSizeInit } from './utils/menu'
Expand Down Expand Up @@ -98,7 +98,7 @@ export class CustomPromptsStore implements vscode.Disposable {
/**
* Build the map of prompts using the json string
*/
public async build(type: CodyPromptType): Promise<Map<string, CodyPrompt> | null> {
public async build(type: CustomCommandType): Promise<Map<string, CodyPrompt> | null> {
try {
const content = await this.getPromptsFromFileSystem(type)
if (!content) {
Expand Down Expand Up @@ -170,7 +170,7 @@ export class CustomPromptsStore implements vscode.Disposable {
id: string,
prompt: CodyPrompt,
deletePrompt = false,
type: CodyPromptType = 'user'
type: CustomCommandType = 'user'
): Promise<void> {
if (deletePrompt) {
this.myPromptsMap.delete(id)
Expand All @@ -196,15 +196,13 @@ export class CustomPromptsStore implements vscode.Disposable {
/**
* Updates the corresponding Cody config file with the given prompts.
*/
private async updateJSONFile(prompts: MyPromptsJSON, type: CodyPromptType): Promise<void> {
private async updateJSONFile(prompts: MyPromptsJSON, type: CustomCommandType): Promise<void> {
try {
const jsonString = JSON.stringify(prompts, null, 2)
const rootDirPath = type === 'user' ? this.jsonFileUris.user : this.jsonFileUris.workspace
if (!rootDirPath || !jsonString) {
throw new Error('Invalid file path or json string')
if (!rootDirPath) {
throw new Error('Invalid file path')
}
const isSaveMode = true
await saveJSONFile(jsonString, rootDirPath, isSaveMode)
await saveJSONFile(prompts, rootDirPath)
} catch (error) {
void vscode.window.showErrorMessage(`Failed to save to cody.json file: ${error}`)
}
Expand All @@ -213,13 +211,18 @@ export class CustomPromptsStore implements vscode.Disposable {
/**
* Create a new cody.json file to the user's workspace or home directory
*/
public async createConfig(type: CodyPromptType = 'user'): Promise<void> {
const isUser = isUserType(type)
public async createConfig(type: CustomCommandType = 'user'): Promise<void> {
const configFileUri = this.getConfigUriByType(type)
try {
if (configFileUri) {
await createJSONFile(this.extensionPath, configFileUri, isUser)
void vscode.window.showInformationMessage('A new cody.json file has been created successfully.')
await createJSONFile(this.extensionPath, configFileUri)
void vscode.window
.showInformationMessage(`Cody ${type} settings file created`, 'View Documentation')
.then(async choice => {
if (choice === 'View Documentation') {
await openCustomCommandDocsLink()
}
})
return
}
throw new Error('Please make sure you have a repository opened in your workspace.')
Expand All @@ -233,7 +236,7 @@ export class CustomPromptsStore implements vscode.Disposable {
/**
* Remove the cody.json file from the user's workspace or home directory
*/
public async deleteConfig(type: CodyPromptType = 'user'): Promise<void> {
public async deleteConfig(type: CustomCommandType = 'user'): Promise<void> {
// delete .vscode/cody.json for user command using the vs code api
const uri = this.getConfigUriByType(type)
if (this.promptSize[type] === 0 || !uri) {
Expand All @@ -248,15 +251,15 @@ export class CustomPromptsStore implements vscode.Disposable {
/**
* Open the .vscode/cody.json file for given type in the editor
*/
public async openConfig(type: CodyPromptType = 'user'): Promise<void> {
public async openConfig(type: CustomCommandType = 'user'): Promise<void> {
const uri = this.getConfigUriByType(type)
return vscode.commands.executeCommand('vscode.open', uri)
}

/**
* Get the file content of the cody.json file for the given type
*/
private async getPromptsFromFileSystem(type: CodyPromptType): Promise<string | null> {
private async getPromptsFromFileSystem(type: CustomCommandType): Promise<string | null> {
const codyJsonFilePathUri = this.getConfigUriByType(type)
if (!codyJsonFilePathUri) {
return null
Expand All @@ -277,9 +280,8 @@ export class CustomPromptsStore implements vscode.Disposable {
/**
* Get the uri of the cody.json file for the given type
*/
private getConfigUriByType(type: CodyPromptType): vscode.Uri | undefined {
const isUserType = type === 'user'
const configFileUri = isUserType ? this.jsonFileUris.user : this.jsonFileUris.workspace
private getConfigUriByType(type: CustomCommandType): vscode.Uri | undefined {
const configFileUri = type === 'user' ? this.jsonFileUris.user : this.jsonFileUris.workspace
return configFileUri
}
}
Loading