Skip to content

Commit

Permalink
Add support for breadcrumbs (#84)
Browse files Browse the repository at this point in the history
* Implement breadcrumb header with placeholder value

* Add real breadcrumbs for all commands

* Break out palette as separate view to support breadcrumbs

* Add previously-removed navigation commands to the footer

* Add copy command to clipboard option to replace current command in header
  • Loading branch information
jakemalachowski authored Nov 1, 2024
1 parent 8dc1dd9 commit 99d89d8
Show file tree
Hide file tree
Showing 24 changed files with 315 additions and 201 deletions.
29 changes: 21 additions & 8 deletions cmd/deploycreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/renderinc/render-cli/pkg/client"
"github.com/renderinc/render-cli/pkg/command"
"github.com/renderinc/render-cli/pkg/resource"
"github.com/renderinc/render-cli/pkg/tui/views"
"github.com/renderinc/render-cli/pkg/types"
"github.com/spf13/cobra"
Expand All @@ -23,13 +24,20 @@ var deployCreateCmd = &cobra.Command{
Args: cobra.MaximumNArgs(1),
}

var InteractiveDeployCreate = func(ctx context.Context, input types.DeployInput) tea.Cmd {
return command.AddToStackFunc(ctx, deployCreateCmd, &input, views.NewDeployCreateView(ctx, input, func(d *client.Deploy) tea.Cmd {
return InteractiveLogs(ctx, views.LogInput{
ResourceIDs: []string{input.ServiceID},
Tail: true,
})
}))
var InteractiveDeployCreate = func(ctx context.Context, input types.DeployInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(
ctx,
deployCreateCmd,
breadcrumb,
&input,
views.NewDeployCreateView(ctx, input, func(d *client.Deploy) tea.Cmd {
return InteractiveLogs(
ctx,
views.LogInput{
ResourceIDs: []string{input.ServiceID},
Tail: true,
}, "Logs")
}))
}

func init() {
Expand All @@ -53,7 +61,12 @@ func init() {
return nil
}

InteractiveDeployCreate(cmd.Context(), input)
service, err := resource.GetResource(cmd.Context(), input.ServiceID)
if err != nil {
return err
}

InteractiveDeployCreate(cmd.Context(), input, "Create Deploy for " + resource.BreadcrumbForResource(service))
return nil
}

Expand Down
12 changes: 9 additions & 3 deletions cmd/deploylist.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

tea "github.com/charmbracelet/bubbletea"
"github.com/renderinc/render-cli/pkg/command"
"github.com/renderinc/render-cli/pkg/resource"
"github.com/renderinc/render-cli/pkg/tui/views"
"github.com/spf13/cobra"
)
Expand All @@ -15,8 +16,8 @@ var deployListCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
}

var InteractiveDeployList = func(ctx context.Context, input views.DeployListInput) tea.Cmd {
return command.AddToStackFunc(ctx, deployListCmd, &input, views.NewDeployListView(ctx, input))
var InteractiveDeployList = func(ctx context.Context, input views.DeployListInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, deployListCmd, breadcrumb, &input, views.NewDeployListView(ctx, input))
}

func init() {
Expand All @@ -40,7 +41,12 @@ func init() {
return nil
}

InteractiveDeployList(cmd.Context(), input)
r, err := resource.GetResource(cmd.Context(), serviceID)
if err != nil {
return err
}

InteractiveDeployList(cmd.Context(), input, "List Deploys for " + resource.BreadcrumbForResource(r))
return nil
}
}
19 changes: 15 additions & 4 deletions cmd/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
btable "github.com/evertras/bubble-table/table"
"github.com/renderinc/render-cli/pkg/client"
"github.com/renderinc/render-cli/pkg/command"
"github.com/renderinc/render-cli/pkg/project"
"github.com/renderinc/render-cli/pkg/tui"
"github.com/renderinc/render-cli/pkg/tui/views"
"github.com/spf13/cobra"
Expand All @@ -20,12 +21,12 @@ var environmentCmd = &cobra.Command{
In interactive mode you can view the services for an environment.`,
}

var InteractiveEnvironment = func(ctx context.Context, input views.EnvironmentInput) tea.Cmd {
return command.AddToStackFunc(ctx, environmentCmd, &input, views.NewEnvironmentList(ctx, input,
var InteractiveEnvironment = func(ctx context.Context, input views.EnvironmentInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, environmentCmd, breadcrumb, &input, views.NewEnvironmentList(ctx, input,
func(ctx context.Context, e *client.Environment) tea.Cmd {
return InteractiveServices(ctx, views.ListResourceInput{
EnvironmentIDs: []string{e.Id},
})
}, e.Name)
},
tui.WithCustomOptions[*client.Environment]([]tui.CustomOption{
{
Expand Down Expand Up @@ -57,7 +58,17 @@ func init() {
return nil
}

InteractiveEnvironment(cmd.Context(), input)
c, err := client.NewDefaultClient()
if err != nil {
return err
}
projectRepo := project.NewRepo(c)
proj, err := projectRepo.GetProject(cmd.Context(), input.ProjectID)
if err != nil {
return err
}

InteractiveEnvironment(cmd.Context(), input, "Environments for " + proj.Name)
return nil
}
}
6 changes: 3 additions & 3 deletions cmd/jobcancel.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ var jobCancelCmd = &cobra.Command{
Args: cobra.ExactArgs(2),
}

var InteractiveJobCancel = func(ctx context.Context, input views.JobCancelInput) tea.Cmd {
return command.AddToStackFunc(ctx, jobCancelCmd, &input, views.NewJobCancelView(ctx, input))
var InteractiveJobCancel = func(ctx context.Context, input views.JobCancelInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, jobCancelCmd, breadcrumb, &input, views.NewJobCancelView(ctx, input))
}

func init() {
Expand All @@ -42,7 +42,7 @@ func init() {
return nil
}

InteractiveJobCancel(cmd.Context(), input)
InteractiveJobCancel(cmd.Context(), input, "Cancel job " + input.JobID)
return nil
}
}
28 changes: 20 additions & 8 deletions cmd/jobcreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
clientjob "github.com/renderinc/render-cli/pkg/client/jobs"
"github.com/renderinc/render-cli/pkg/command"
"github.com/renderinc/render-cli/pkg/resource"
"github.com/renderinc/render-cli/pkg/tui/views"
"github.com/spf13/cobra"
)
Expand All @@ -17,13 +18,19 @@ var jobCreateCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
}

var InteractiveJobCreate = func(ctx context.Context, input *views.JobCreateInput) tea.Cmd {
return command.AddToStackFunc(ctx, sshCmd, input, views.NewJobCreateView(ctx, input, jobCreateCmd, func(j *clientjob.Job) tea.Cmd {
return InteractiveLogs(ctx, views.LogInput{
ResourceIDs: []string{j.Id},
Tail: true,
})
}))
var InteractiveJobCreate = func(ctx context.Context, input *views.JobCreateInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(
ctx,
jobCreateCmd,
breadcrumb,
input,
views.NewJobCreateView(ctx, input, jobCreateCmd, func(j *clientjob.Job) tea.Cmd {
return InteractiveLogs(ctx, views.LogInput{
ResourceIDs: []string{j.Id},
Tail: true,
}, "Logs")
}),
)
}

func init() {
Expand All @@ -48,7 +55,12 @@ func init() {
return nil
}

InteractiveJobCreate(cmd.Context(), &input)
r, err := resource.GetResource(cmd.Context(), input.ServiceID)
if err != nil {
return err
}

InteractiveJobCreate(cmd.Context(), &input, "Create Job " + resource.BreadcrumbForResource(r))
return nil
}

Expand Down
112 changes: 66 additions & 46 deletions cmd/joblist.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/renderinc/render-cli/pkg/command"
"github.com/renderinc/render-cli/pkg/job"
"github.com/renderinc/render-cli/pkg/pointers"
"github.com/renderinc/render-cli/pkg/resource"
"github.com/renderinc/render-cli/pkg/tui/views"
"github.com/spf13/cobra"
)
Expand All @@ -19,58 +20,72 @@ var jobListCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
}

var InteractiveJobList = func(ctx context.Context, input views.JobListInput) tea.Cmd {
return command.AddToStackFunc(ctx, jobListCmd, &views.ProjectInput{}, views.NewJobListView(ctx,
var InteractiveJobList = func(ctx context.Context, input views.JobListInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, jobListCmd, breadcrumb, &views.ProjectInput{}, views.NewJobListView(ctx,
&input,
func(j *clientjob.Job) []views.PaletteCommand {
var startTime *string
if j.StartedAt != nil {
startTime = pointers.From(j.StartedAt.String())
}
func(j *clientjob.Job) tea.Cmd {
return InteractivePalette(ctx, commandsForJob(j), j.Id)
},
))
}

var endTime *string
if j.FinishedAt != nil {
endTime = pointers.From(j.FinishedAt.String())
}
func commandsForJob(j *clientjob.Job) []views.PaletteCommand {
var startTime *string
if j.StartedAt != nil {
startTime = pointers.From(j.StartedAt.String())
}

commands := []views.PaletteCommand{
{
Name: "logs",
Description: "View job logs",
Action: func(ctx context.Context, args []string) tea.Cmd {
return InteractiveLogs(ctx, views.LogInput{
ResourceIDs: []string{j.Id},
StartTime: startTime,
EndTime: endTime,
})
},
},
{
Name: "rerun",
Description: "Create new job with same inputs",
Action: func(ctx context.Context, args []string) tea.Cmd {
return InteractiveJobCreate(ctx, &views.JobCreateInput{
ServiceID: j.ServiceId,
StartCommand: &j.StartCommand,
PlanID: &j.PlanId,
})
var endTime *string
if j.FinishedAt != nil {
endTime = pointers.From(j.FinishedAt.String())
}

commands := []views.PaletteCommand{
{
Name: "logs",
Description: "View job logs",
Action: func(ctx context.Context, args []string) tea.Cmd {
return InteractiveLogs(
ctx,
views.LogInput{
ResourceIDs: []string{j.Id},
StartTime: startTime,
EndTime: endTime,
},
"Logs",
)
},
},
{
Name: "rerun",
Description: "Create new job with same inputs",
Action: func(ctx context.Context, args []string) tea.Cmd {
return InteractiveJobCreate(ctx, &views.JobCreateInput{
ServiceID: j.ServiceId,
StartCommand: &j.StartCommand,
PlanID: &j.PlanId,
},
}
"Rerun",
)
},
},
}

if job.IsCancellable(j.Status) {
commands = append(commands, views.PaletteCommand{
Name: "cancel",
Description: "Cancel the job",
Action: func(ctx context.Context, args []string) tea.Cmd {
return InteractiveJobCancel(ctx, views.JobCancelInput{ServiceID: j.ServiceId, JobID: j.Id})
},
})
}
if job.IsCancellable(j.Status) {
commands = append(commands, views.PaletteCommand{
Name: "cancel",
Description: "Cancel the job",
Action: func(ctx context.Context, args []string) tea.Cmd {
return InteractiveJobCancel(
ctx,
views.JobCancelInput{ServiceID: j.ServiceId, JobID: j.Id},
"Cancel job",
)
},
})
}

return commands
},
))
return commands
}

func init() {
Expand All @@ -89,7 +104,12 @@ func init() {
return nil
}

InteractiveJobList(cmd.Context(), input)
r, err := resource.GetResource(cmd.Context(), input.ServiceID)
if err != nil {
return err
}

InteractiveJobList(cmd.Context(), input, "List Jobs "+resource.BreadcrumbForResource(r))
return nil
}
}
10 changes: 5 additions & 5 deletions cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ Unlike in the dashboard you can view logs for multiple resources at once. Set --
In interactive mode you can update the filters and view logs in real time.`,
}

func filterLogs(ctx context.Context, in views.LogInput) tea.Cmd {
return command.AddToStackFunc(ctx, logsCmd, &in, views.NewLogsView(ctx, logsCmd, filterLogs, in))
func filterLogs(ctx context.Context, in views.LogInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, logsCmd, breadcrumb, &in, views.NewLogsView(ctx, logsCmd, filterLogs, in))
}

func writeLog(format command.Output, out io.Writer, log *lclient.Log) error {
Expand Down Expand Up @@ -74,8 +74,8 @@ func nonInteractiveLogs(format *command.Output, cmd *cobra.Command, input views.
return nil
}

var InteractiveLogs = func(ctx context.Context, input views.LogInput) tea.Cmd {
return command.AddToStackFunc(ctx, logsCmd, &input, views.NewLogsView(ctx, logsCmd, filterLogs, input))
var InteractiveLogs = func(ctx context.Context, input views.LogInput, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, logsCmd, breadcrumb, &input, views.NewLogsView(ctx, logsCmd, filterLogs, input))
}

func init() {
Expand All @@ -91,7 +91,7 @@ func init() {
return nonInteractiveLogs(format, cmd, input)
}

InteractiveLogs(cmd.Context(), input)
InteractiveLogs(cmd.Context(), input, "Logs")
return nil
}

Expand Down
16 changes: 16 additions & 0 deletions cmd/palette.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import (
"context"

tea "github.com/charmbracelet/bubbletea"
"github.com/renderinc/render-cli/pkg/command"
"github.com/renderinc/render-cli/pkg/tui/views"
)

func InteractivePalette(ctx context.Context, commands []views.PaletteCommand, breadcrumb string) tea.Cmd {
return command.AddToStackFunc(ctx, servicesCmd, breadcrumb, &views.PaletteCommand{},
views.NewPaletteView(ctx, commands),
)
}

Loading

0 comments on commit 99d89d8

Please sign in to comment.