Skip to content

Commit 0ba4140

Browse files
committed
feat: enhance prompt management with column selection and JSON output
This commit introduces enhancements to the prompt management commands, allowing users to select specific columns for display and output results in JSON format. The following changes were made: - Added column selection functionality to `src prompts list` and `src prompts tags list` commands using the `-c` flag. Users can now specify a comma-separated list of columns to display. - Implemented JSON output functionality for `src prompts list` and `src prompts tags list` commands using the `-json` flag. - Updated `src prompts update`, `src prompts tags update`, `src prompts delete`, and `src prompts tags delete` commands to accept the ID as a positional argument instead of a flag. - Updated `src prompts export` to fetch all tags with pagination.
1 parent 0f22345 commit 0ba4140

8 files changed

Lines changed: 301 additions & 53 deletions

cmd/src/prompts.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ Usage:
1616
1717
The commands are:
1818
19-
list lists prompts
20-
get get a prompt by ID
21-
create create a prompt
22-
update update a prompt
23-
delete delete a prompt
24-
export export prompts to a JSON file
25-
import import prompts from a JSON file
26-
tags manage prompt tags (use "src prompts tags [command] -h" for more info)
19+
list lists prompts
20+
get get a prompt by ID
21+
create create a prompt
22+
update update a prompt
23+
delete delete a prompt
24+
export export prompts to a JSON file
25+
import import prompts from a JSON file
26+
tags manage prompt tags (use "src prompts tags [command] -h" for more info)
2727
2828
Use "src prompts [command] -h" for more information about a command.
2929
`

cmd/src/prompts_delete.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Examples:
1616
1717
Delete a prompt by ID:
1818
19-
$ src prompts delete -id=<prompt-id>
19+
$ src prompts delete <prompt-id>
2020
2121
`
2222

@@ -27,7 +27,6 @@ Examples:
2727
fmt.Println(usage)
2828
}
2929
var (
30-
idFlag = flagSet.String("id", "", "The ID of the prompt to delete")
3130
apiFlags = api.NewFlags(flagSet)
3231
)
3332

@@ -36,9 +35,11 @@ Examples:
3635
return err
3736
}
3837

39-
if *idFlag == "" {
40-
return errors.New("provide the ID of the prompt to delete")
38+
// Check for prompt ID as positional argument
39+
if len(flagSet.Args()) != 1 {
40+
return errors.New("provide exactly one prompt ID as an argument")
4141
}
42+
promptID := flagSet.Arg(0)
4243

4344
client := cfg.apiClient(apiFlags, flagSet.Output())
4445

@@ -56,7 +57,7 @@ Examples:
5657
}
5758

5859
if ok, err := client.NewRequest(query, map[string]interface{}{
59-
"id": *idFlag,
60+
"id": promptID,
6061
}).Do(context.Background(), &result); err != nil || !ok {
6162
return err
6263
}

cmd/src/prompts_export.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,9 @@ func fetchAllPrompts(client api.Client, tagIDs []string) ([]Prompt, error) {
225225

226226
// resolveTagNamesToIDs resolves tag names to their IDs
227227
func resolveTagNamesToIDs(client api.Client, tagNames []string) ([]string, error) {
228-
// Query to get all tags
229-
query := `query PromptTags {
230-
promptTags {
228+
// Query to get all tags with required pagination parameter
229+
query := `query PromptTags($first: Int!) {
230+
promptTags(first: $first) {
231231
nodes {
232232
...PromptTagFields
233233
}
@@ -240,7 +240,11 @@ func resolveTagNamesToIDs(client api.Client, tagNames []string) ([]string, error
240240
}
241241
}
242242

243-
if ok, err := client.NewRequest(query, nil).Do(context.Background(), &result); err != nil || !ok {
243+
vars := map[string]interface{}{
244+
"first": 1000, // Get enough tags to cover all possible names
245+
}
246+
247+
if ok, err := client.NewRequest(query, vars).Do(context.Background(), &result); err != nil || !ok {
244248
return nil, err
245249
}
246250

cmd/src/prompts_list.go

Lines changed: 137 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,126 @@ import (
99
"github.com/sourcegraph/src-cli/internal/api"
1010
)
1111

12+
// availablePromptColumns defines the available column names for output
13+
var availablePromptColumns = map[string]bool{
14+
"id": true,
15+
"name": true,
16+
"description": true,
17+
"draft": true,
18+
"visibility": true,
19+
"mode": true,
20+
"tags": true,
21+
}
22+
23+
// defaultPromptColumns defines the default columns to display
24+
var defaultPromptColumns = []string{"id", "name", "visibility", "tags"}
25+
26+
// displayPrompts formats and outputs multiple prompts
27+
func displayPrompts(prompts []Prompt, columns []string, asJSON bool) error {
28+
if asJSON {
29+
return outputAsJSON(prompts)
30+
}
31+
32+
// Collect all data first to calculate column widths
33+
allRows := make([][]string, 0, len(prompts)+1)
34+
35+
// Add header row
36+
headers := make([]string, 0, len(columns))
37+
for _, col := range columns {
38+
headers = append(headers, strings.ToUpper(col))
39+
}
40+
allRows = append(allRows, headers)
41+
42+
// Collect all data rows
43+
for _, p := range prompts {
44+
row := make([]string, 0, len(columns))
45+
46+
// Prepare tag names for display
47+
tagNames := []string{}
48+
for _, tag := range p.Tags.Nodes {
49+
tagNames = append(tagNames, tag.Name)
50+
}
51+
tagsStr := joinStrings(tagNames, ", ")
52+
53+
for _, col := range columns {
54+
switch col {
55+
case "id":
56+
row = append(row, p.ID)
57+
case "name":
58+
row = append(row, p.Name)
59+
case "description":
60+
row = append(row, p.Description)
61+
case "draft":
62+
row = append(row, fmt.Sprintf("%t", p.Draft))
63+
case "visibility":
64+
row = append(row, p.Visibility)
65+
case "mode":
66+
row = append(row, p.Mode)
67+
case "tags":
68+
row = append(row, tagsStr)
69+
}
70+
}
71+
allRows = append(allRows, row)
72+
}
73+
74+
// Calculate max width for each column
75+
colWidths := make([]int, len(columns))
76+
for _, row := range allRows {
77+
for i, cell := range row {
78+
if len(cell) > colWidths[i] {
79+
colWidths[i] = len(cell)
80+
}
81+
}
82+
}
83+
84+
// Print all rows with proper padding
85+
for i, row := range allRows {
86+
for j, cell := range row {
87+
fmt.Print(cell)
88+
// Add padding (at least 2 spaces between columns)
89+
padding := colWidths[j] - len(cell) + 2
90+
fmt.Print(strings.Repeat(" ", padding))
91+
}
92+
fmt.Println()
93+
94+
// Add separator line after headers
95+
if i == 0 {
96+
for j, width := range colWidths {
97+
fmt.Print(strings.Repeat("-", width))
98+
if j < len(colWidths)-1 {
99+
fmt.Print(" ")
100+
}
101+
}
102+
fmt.Println()
103+
}
104+
}
105+
106+
return nil
107+
}
108+
109+
// parsePromptColumns parses and validates the columns flag
110+
func parsePromptColumns(columnsFlag string) []string {
111+
if columnsFlag == "" {
112+
return defaultPromptColumns
113+
}
114+
115+
columns := strings.Split(columnsFlag, ",")
116+
var validColumns []string
117+
118+
for _, col := range columns {
119+
col = strings.ToLower(strings.TrimSpace(col))
120+
if availablePromptColumns[col] {
121+
validColumns = append(validColumns, col)
122+
}
123+
}
124+
125+
if len(validColumns) == 0 {
126+
return defaultPromptColumns
127+
}
128+
129+
return validColumns
130+
}
131+
12132
func init() {
13133
usage := `
14134
Examples:
@@ -32,6 +152,14 @@ Examples:
32152
Paginate through results:
33153
34154
$ src prompts list -after=<cursor>
155+
156+
Select specific columns to display:
157+
158+
$ src prompts list -c id,name,visibility,tags
159+
160+
Output results as JSON:
161+
162+
$ src prompts list -json
35163
36164
`
37165

@@ -52,6 +180,8 @@ Examples:
52180
includeBuiltinFlag = flagSet.Bool("include-builtin", false, "Whether to include builtin prompts")
53181
limitFlag = flagSet.Int("limit", 100, "Maximum number of prompts to list")
54182
afterFlag = flagSet.String("after", "", "Cursor for pagination (from previous page's endCursor)")
183+
columnsFlag = flagSet.String("c", strings.Join(defaultPromptColumns, ","), "Comma-separated list of columns to display. Available: id,name,description,draft,visibility,mode,tags")
184+
jsonFlag = flagSet.Bool("json", false, "Output results as JSON for programmatic access")
55185
apiFlags = api.NewFlags(flagSet)
56186
)
57187

@@ -171,24 +301,18 @@ Examples:
171301
return err
172302
}
173303

174-
fmt.Printf("Showing %d of %d prompts\n\n", len(result.Prompts.Nodes), result.Prompts.TotalCount)
304+
// Parse columns
305+
columns := parsePromptColumns(*columnsFlag)
175306

176-
for _, p := range result.Prompts.Nodes {
177-
tagNames := []string{}
178-
for _, tag := range p.Tags.Nodes {
179-
tagNames = append(tagNames, tag.Name)
180-
}
307+
fmt.Printf("Showing %d of %d prompts\n\n", len(result.Prompts.Nodes), result.Prompts.TotalCount)
181308

182-
fmt.Printf("ID: %s\nName: %s\nDescription: %s\n", p.ID, p.Name, p.Description)
183-
fmt.Printf("Draft: %t | Visibility: %s | Mode: %s\n", p.Draft, p.Visibility, p.Mode)
184-
if len(tagNames) > 0 {
185-
fmt.Printf("Tags: %s\n", joinStrings(tagNames, ", "))
186-
}
187-
fmt.Println()
309+
// Display prompts in tabular format
310+
if err := displayPrompts(result.Prompts.Nodes, columns, *jsonFlag); err != nil {
311+
return err
188312
}
189313

190314
if result.Prompts.PageInfo.HasNextPage {
191-
fmt.Printf("More results available. Use -after=%s to fetch the next page.\n", result.Prompts.PageInfo.EndCursor)
315+
fmt.Printf("\nMore results available. Use -after=%s to fetch the next page.\n", result.Prompts.PageInfo.EndCursor)
192316
}
193317

194318
return nil

cmd/src/prompts_tags_delete.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Examples:
1616
1717
Delete a prompt tag by ID:
1818
19-
$ src prompts tags delete -id=<tag-id>
19+
$ src prompts tags delete <tag-id>
2020
2121
`
2222

@@ -27,7 +27,6 @@ Examples:
2727
fmt.Println(usage)
2828
}
2929
var (
30-
idFlag = flagSet.String("id", "", "The ID of the tag to delete")
3130
apiFlags = api.NewFlags(flagSet)
3231
)
3332

@@ -36,9 +35,11 @@ Examples:
3635
return err
3736
}
3837

39-
if *idFlag == "" {
40-
return errors.New("provide the ID of the tag to delete")
38+
// Check for tag ID as positional argument
39+
if len(flagSet.Args()) != 1 {
40+
return errors.New("provide exactly one tag ID as an argument")
4141
}
42+
tagID := flagSet.Arg(0)
4243

4344
client := cfg.apiClient(apiFlags, flagSet.Output())
4445

@@ -56,7 +57,7 @@ Examples:
5657
}
5758

5859
if ok, err := client.NewRequest(query, map[string]interface{}{
59-
"id": *idFlag,
60+
"id": tagID,
6061
}).Do(context.Background(), &result); err != nil || !ok {
6162
return err
6263
}

0 commit comments

Comments
 (0)