Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
3 changes: 3 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ tasks:

build:
desc: build the cli
aliases: [b]
deps:
- deps
cmds:
- go build -o dist/loops ./cmd/loops

test:
desc: run tests
aliases: [t]
cmds:
- go test ./... -cover

vuln:
desc: run govulncheck
aliases: [v]
cmds:
- go tool govulncheck {{.CLI_ARGS}} ./...

Expand Down
31 changes: 29 additions & 2 deletions cmd/auth_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ var authListCmd = &cobra.Command{
Use: "list",
Short: "List stored API keys",
RunE: func(cmd *cobra.Command, args []string) error {
if err := validatePickFlags(cmd); err != nil {
return err
}

entries, activeTeam, err := runAuthList()
if err != nil {
return err
Expand All @@ -34,13 +38,35 @@ var authListCmd = &cobra.Command{
return nil
}

t := newStyledTable(cmd.OutOrStdout(), "NAME", "ACTIVE", "API KEY")
headers := []string{"NAME", "ACTIVE", "API KEY"}
rows := make([][]string, 0, len(entries))
for _, e := range entries {
active := ""
if e.Name == activeTeam {
active = "*"
}
t.Row(e.Name, active, maskKey(e.APIKey))
rows = append(rows, []string{e.Name, active, maskKey(e.APIKey)})
}

if isPicking(cmd) {
out := cmd.OutOrStdout()
return runPicker(headers, rows, []pickBinding{{
Key: "enter",
Label: "switch team",
Action: func(rowIdx int) error {
name := entries[rowIdx].Name
if err := runAuthUse(name); err != nil {
return err
}
fmt.Fprintf(out, "Active team set to %q.\n", name)
return nil
},
}})
}

t := newStyledTable(cmd.OutOrStdout(), headers...)
for _, r := range rows {
t.Row(r...)
}
return t.Render()
},
Expand All @@ -59,5 +85,6 @@ func runAuthList() ([]config.KeyEntry, string, error) {
}

func init() {
addPickFlag(authListCmd)
authCmd.AddCommand(authListCmd)
}
25 changes: 22 additions & 3 deletions cmd/campaigns.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ var campaignsListCmd = &cobra.Command{
Use: "list",
Short: "List campaigns",
RunE: func(cmd *cobra.Command, args []string) error {
if err := validatePickFlags(cmd); err != nil {
return err
}

cfg, err := loadConfig()
if err != nil {
return err
Expand All @@ -58,16 +62,30 @@ var campaignsListCmd = &cobra.Command{
return nil
}

t := newStyledTable(cmd.OutOrStdout(), "ID", "MESSAGE ID", "NAME", "STATUS", "SUBJECT", "UPDATED")
headers := []string{"ID", "MESSAGE ID", "NAME", "STATUS", "SUBJECT", "UPDATED"}
rows := make([][]string, 0, len(campaigns))
for _, c := range campaigns {
t.Row(
rows = append(rows, []string{
c.CampaignID,
deref(c.EmailMessageID),
c.Name,
c.Status,
c.Subject,
c.UpdatedAt,
)
})
}

if isPicking(cmd) {
out := cmd.OutOrStdout()
return runPicker(headers, rows, []pickBinding{
copyColumnBinding("enter", "copy id", "campaign ID", rows, 0, out),
copyColumnBinding("alt-enter", "copy messageId", "message ID", rows, 1, out),
})
}

t := newStyledTable(cmd.OutOrStdout(), headers...)
for _, r := range rows {
t.Row(r...)
}
return t.Render()
},
Expand Down Expand Up @@ -172,6 +190,7 @@ var campaignsGetCmd = &cobra.Command{

func init() {
addPaginationFlags(campaignsListCmd)
addPickFlag(campaignsListCmd)
campaignsCmd.AddCommand(campaignsListCmd)
campaignsCmd.AddCommand(campaignsGetCmd)

Expand Down
21 changes: 19 additions & 2 deletions cmd/contact_properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ var contactPropertiesListCmd = &cobra.Command{
Use: "list",
Short: "List contact properties",
RunE: func(cmd *cobra.Command, args []string) error {
if err := validatePickFlags(cmd); err != nil {
return err
}

customOnly, _ := cmd.Flags().GetBool("custom")

cfg, err := loadConfig()
Expand All @@ -49,9 +53,21 @@ var contactPropertiesListCmd = &cobra.Command{
return nil
}

t := newStyledTable(cmd.OutOrStdout(), "KEY", "LABEL", "TYPE")
headers := []string{"KEY", "LABEL", "TYPE"}
rows := make([][]string, 0, len(props))
for _, p := range props {
t.Row(p.Key, p.Label, p.Type)
rows = append(rows, []string{p.Key, p.Label, p.Type})
}

if isPicking(cmd) {
return runPicker(headers, rows, []pickBinding{
copyColumnBinding("enter", "copy key", "property key", rows, 0, cmd.OutOrStdout()),
})
}

t := newStyledTable(cmd.OutOrStdout(), headers...)
for _, r := range rows {
t.Row(r...)
}
return t.Render()
},
Expand Down Expand Up @@ -83,6 +99,7 @@ var contactPropertiesCreateCmd = &cobra.Command{

func init() {
contactPropertiesListCmd.Flags().Bool("custom", false, "Only list custom properties")
addPickFlag(contactPropertiesListCmd)
contactPropertiesCmd.AddCommand(contactPropertiesListCmd)

contactPropertiesCreateCmd.Flags().String("name", "", "Property name (camelCase, e.g. planName)")
Expand Down
44 changes: 41 additions & 3 deletions cmd/email_messages.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package cmd

import (
"bytes"
"fmt"
"io"
"os"
"strings"

"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/charmbracelet/colorprofile"
"github.com/loops-so/cli/internal/api"
"github.com/loops-so/cli/internal/config"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -198,9 +204,41 @@ func printEmailMessage(cmd *cobra.Command, msg *api.EmailMessage) error {
}

fmt.Fprintln(cmd.OutOrStdout())
fmt.Fprintln(cmd.OutOrStdout(), "LMX:")
fmt.Fprintln(cmd.OutOrStdout(), msg.LMX)
return nil
return renderLMX(cmd.OutOrStdout(), msg.LMX)
}

// renderLMX prints the LMX body with chroma syntax highlighting via the xml
// lexer (LMX is JSX/XML-tag-shaped). The chroma style maps two token kinds to
// fang.ColorScheme colors so highlighting reuses the same palette as the rest
// of the CLI's output.
func renderLMX(out io.Writer, lmx string) error {
lexer := lexers.Get("xml")
if lexer == nil {
lexer = lexers.Fallback
}
iterator, err := lexer.Tokenise(nil, lmx)
if err != nil {
return err
}
formatter := formatters.Get("terminal256")
if formatter == nil {
formatter = formatters.Fallback
}
var buf bytes.Buffer
if err := formatter.Format(&buf, lmxChromaStyle(), iterator); err != nil {
return err
}
cw := colorprofile.NewWriter(out, os.Environ())
_, err = fmt.Fprintln(cw, strings.TrimRight(buf.String(), "\n"))
return err
}

func lmxChromaStyle() *chroma.Style {
cs := fangColorScheme()
return chroma.MustNewStyle("lmx", chroma.StyleEntries{
chroma.NameTag: hexColor(cs.Program),
chroma.LiteralString: hexColor(cs.QuotedString),
})
}

func printLmxWarnings(cmd *cobra.Command, warnings []api.LmxWarning) {
Expand Down
21 changes: 19 additions & 2 deletions cmd/lists.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ var listsListCmd = &cobra.Command{
Use: "list",
Short: "List mailing lists",
RunE: func(cmd *cobra.Command, args []string) error {
if err := validatePickFlags(cmd); err != nil {
return err
}

cfg, err := loadConfig()
if err != nil {
return err
Expand All @@ -43,15 +47,28 @@ var listsListCmd = &cobra.Command{
return nil
}

t := newStyledTable(cmd.OutOrStdout(), "ID", "NAME", "DESCRIPTION", "PUBLIC")
headers := []string{"ID", "NAME", "DESCRIPTION", "PUBLIC"}
rows := make([][]string, 0, len(lists))
for _, l := range lists {
t.Row(l.ID, l.Name, l.Description, fmt.Sprintf("%v", l.IsPublic))
rows = append(rows, []string{l.ID, l.Name, l.Description, fmt.Sprintf("%v", l.IsPublic)})
}

if isPicking(cmd) {
return runPicker(headers, rows, []pickBinding{
copyColumnBinding("enter", "copy id", "list ID", rows, 0, cmd.OutOrStdout()),
})
}

t := newStyledTable(cmd.OutOrStdout(), headers...)
for _, r := range rows {
t.Row(r...)
}
return t.Render()
},
}

func init() {
addPickFlag(listsListCmd)
listsCmd.AddCommand(listsListCmd)
rootCmd.AddCommand(listsCmd)
}
Loading