mirror of
https://github.com/warmbly/warmbly.git
synced 2026-09-05 16:02:48 +00:00
145 lines
4.2 KiB
Go
145 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/warmbly/warmbly/internal/cli/config"
|
|
)
|
|
|
|
// browseTargets maps a noun to its dashboard path, so `warmbly browse
|
|
// campaigns` does not require anyone to remember the URL layout.
|
|
var browseTargets = map[string]string{
|
|
"campaigns": "/app/campaigns",
|
|
"campaign": "/app/campaigns",
|
|
"contacts": "/app/contacts",
|
|
"contact": "/app/contacts",
|
|
"mailboxes": "/app/emails",
|
|
"mailbox": "/app/emails",
|
|
"emails": "/app/emails",
|
|
"inbox": "/app/unibox",
|
|
"unibox": "/app/unibox",
|
|
"analytics": "/app/analytics",
|
|
"automations": "/app/automations",
|
|
"forms": "/app/forms",
|
|
"templates": "/app/templates",
|
|
"crm": "/app/crm",
|
|
"audit": "/app/audit",
|
|
"keys": "/app/api-keys",
|
|
"api-keys": "/app/api-keys",
|
|
"settings": "/app/settings/profile",
|
|
"webhooks": "/app/settings/webhooks",
|
|
"billing": "/app/settings/billing",
|
|
"members": "/app/settings/members",
|
|
"deliverability": "/app/deliverability",
|
|
}
|
|
|
|
// browseDetail is the subset that has a per-record page, for `warmbly browse
|
|
// campaign <id>`.
|
|
var browseDetail = map[string]string{
|
|
"campaign": "/app/campaigns",
|
|
"campaigns": "/app/campaigns",
|
|
"contact": "/app/contacts",
|
|
"contacts": "/app/contacts",
|
|
"mailbox": "/app/emails",
|
|
"mailboxes": "/app/emails",
|
|
"automation": "/app/automations",
|
|
"form": "/app/forms",
|
|
"forms": "/app/forms",
|
|
}
|
|
|
|
func newBrowseCmd(f *Factory) *cobra.Command {
|
|
var printOnly bool
|
|
cmd := &cobra.Command{
|
|
Use: "browse [<section>] [<id>]",
|
|
Short: "Open the dashboard in a browser",
|
|
GroupID: groupCore,
|
|
Long: `Open the Warmbly dashboard for the host you are signed in to.
|
|
|
|
With a section it goes straight there; with a section and an id it opens that
|
|
record. --no-browser prints the URL instead, which is what you want over SSH.`,
|
|
Example: ` $ warmbly browse
|
|
$ warmbly browse campaigns
|
|
$ warmbly browse campaign 6f1c...
|
|
$ warmbly browse inbox --no-browser`,
|
|
Args: cobra.MaximumNArgs(2),
|
|
RunE: func(c *cobra.Command, args []string) error {
|
|
cfg, err := f.Config()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, err := f.Resolved()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
path := "/app/emails"
|
|
if len(args) > 0 {
|
|
section := strings.ToLower(args[0])
|
|
if len(args) > 1 {
|
|
detail, ok := browseDetail[section]
|
|
if !ok {
|
|
return fmt.Errorf("%q has no detail page to open by id. Sections with one: %s", args[0], keysOf(browseDetail))
|
|
}
|
|
path = detail + "/" + args[1]
|
|
} else {
|
|
target, ok := browseTargets[section]
|
|
if !ok {
|
|
return fmt.Errorf("nothing to browse called %q. Try one of: %s", args[0], keysOf(browseTargets))
|
|
}
|
|
path = target
|
|
}
|
|
}
|
|
|
|
url := dashboardURL(r) + path
|
|
if printOnly || !f.IO.IsStdoutTTY() {
|
|
f.IO.Println(url)
|
|
return nil
|
|
}
|
|
f.IO.Errorf("%s Opening %s\n", f.IO.Gray("→"), url)
|
|
if err := openBrowser(cfg, url); err != nil {
|
|
f.IO.Println(url)
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().BoolVar(&printOnly, "no-browser", false, "Print the URL instead of opening it")
|
|
return cmd
|
|
}
|
|
|
|
// dashboardURL is where this host's dashboard lives. The instance reports its
|
|
// own APP_URL at sign-in, which is exact; the derivation below is the fallback
|
|
// for a credential that came from the environment and never signed in.
|
|
func dashboardURL(r *config.Resolved) string {
|
|
if r.Entry != nil && strings.TrimSpace(r.Entry.AppURL) != "" {
|
|
return strings.TrimRight(r.Entry.AppURL, "/")
|
|
}
|
|
return appBaseURL(r.Host)
|
|
}
|
|
|
|
// appBaseURL is the dashboard for a host, following the layout the installer
|
|
// writes: app.<host> for a real deployment, the host itself for a local one.
|
|
func appBaseURL(host string) string {
|
|
host = config.NormalizeHost(host)
|
|
if strings.HasPrefix(host, "localhost") || strings.HasPrefix(host, "127.0.0.1") {
|
|
return "http://" + host
|
|
}
|
|
if strings.Contains(host, ":") {
|
|
return "http://" + host
|
|
}
|
|
return "https://app." + host
|
|
}
|
|
|
|
// keysOf lists a target map's names, sorted, for an error message.
|
|
func keysOf(m map[string]string) string {
|
|
out := make([]string, 0, len(m))
|
|
for name := range m {
|
|
out = append(out, name)
|
|
}
|
|
sort.Strings(out)
|
|
return strings.Join(out, ", ")
|
|
}
|