diff --git a/go.sum b/go.sum index 9d07281fc..bc519a292 100644 --- a/go.sum +++ b/go.sum @@ -501,9 +501,13 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305023407-0d6cb8bd5a4b h1:zQ+/dCJWTuLZNCt92+rfDzgYfIWkoCRrcMAPBiQ6bt4= golang.org/x/sys v0.0.0-20210305023407-0d6cb8bd5a4b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d h1:jbzgAvDZn8aEnytae+4ou0J0GwFZoHR0hOrTg4qH8GA= +golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs= +golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/display/apis.go b/internal/display/apis.go index 6f7aab390..2e27fa5e3 100644 --- a/internal/display/apis.go +++ b/internal/display/apis.go @@ -2,10 +2,12 @@ package display import ( "fmt" - "strconv" + "os" + "strings" "github.com/auth0/auth0-cli/internal/ansi" "github.com/auth0/auth0-cli/internal/auth0" + "golang.org/x/term" "gopkg.in/auth0.v5/management" ) @@ -13,7 +15,7 @@ type apiView struct { ID string Name string Identifier string - Scopes int + Scopes string raw interface{} } @@ -28,10 +30,10 @@ func (v *apiView) AsTableRow() []string { func (v *apiView) KeyValues() [][]string { return [][]string{ - []string{"ID", ansi.Faint(v.ID)}, - []string{"NAME", v.Name}, - []string{"IDENTIFIER", v.Identifier}, - []string{"SCOPES", strconv.Itoa(v.Scopes)}, + {"ID", ansi.Faint(v.ID)}, + {"NAME", v.Name}, + {"IDENTIFIER", v.Identifier}, + {"SCOPES", v.Scopes}, } } @@ -39,6 +41,27 @@ func (v *apiView) Object() interface{} { return v.raw } +type apiTableView struct { + ID string + Name string + Identifier string + Scopes int + + raw interface{} +} + +func (v *apiTableView) AsTableHeader() []string { + return []string{"ID", "Name", "Identifier", "Scopes"} +} + +func (v *apiTableView) AsTableRow() []string { + return []string{ansi.Faint(v.ID), v.Name, v.Identifier, fmt.Sprint(v.Scopes)} +} + +func (v *apiTableView) Object() interface{} { + return v.raw +} + func (r *Renderer) ApiList(apis []*management.ResourceServer) { resource := "APIs" @@ -53,7 +76,7 @@ func (r *Renderer) ApiList(apis []*management.ResourceServer) { results := []View{} for _, api := range apis { - results = append(results, makeApiView(api)) + results = append(results, makeApiTableView(api)) } r.Results(results) @@ -61,23 +84,43 @@ func (r *Renderer) ApiList(apis []*management.ResourceServer) { func (r *Renderer) ApiShow(api *management.ResourceServer) { r.Heading("API") - r.Result(makeApiView(api)) + view, scopesTruncated := makeApiView(api) + r.Result(view) + if scopesTruncated { + r.Newline() + r.Infof("Scopes truncated for display. To see the full list, run %s", ansi.Faint(fmt.Sprintf("apis scopes list %s", *api.ID))) + } } func (r *Renderer) ApiCreate(api *management.ResourceServer) { r.Heading("API created") - r.Result(makeApiView(api)) + view, _ := makeApiView(api) + r.Result(view) } func (r *Renderer) ApiUpdate(api *management.ResourceServer) { r.Heading("API updated") - r.Result(makeApiView(api)) + view, _ := makeApiView(api) + r.Result(view) +} + +func makeApiView(api *management.ResourceServer) (*apiView, bool) { + scopes, scopesTruncated := getScopes(api.Scopes) + view := &apiView{ + ID: auth0.StringValue(api.ID), + Name: auth0.StringValue(api.Name), + Identifier: auth0.StringValue(api.Identifier), + Scopes: auth0.StringValue(scopes), + + raw: api, + } + return view, scopesTruncated } -func makeApiView(api *management.ResourceServer) *apiView { +func makeApiTableView(api *management.ResourceServer) *apiTableView { scopes := len(api.Scopes) - return &apiView{ + return &apiTableView{ ID: auth0.StringValue(api.ID), Name: auth0.StringValue(api.Name), Identifier: auth0.StringValue(api.Identifier), @@ -125,3 +168,40 @@ func makeScopeView(scope *management.ResourceServerScope) *scopeView { Description: auth0.StringValue(scope.Description), } } + +func getScopes(scopes []*management.ResourceServerScope) (*string, bool) { + ellipsis := "..." + separator := " " + padding := 16 // the longest apiView key plus two spaces before and after in the label column + terminalWidth, _, err := term.GetSize(int(os.Stdin.Fd())) + if err != nil { + terminalWidth = 80 + } + + var scopesForDisplay string + maxCharacters := terminalWidth - padding + + for i, scope := range scopes { + prepend := separator + + // no separator prepended for first value + if i == 0 { + prepend = "" + } + scopesForDisplay += fmt.Sprintf("%s%s", prepend, *scope.Value) + } + + if len(scopesForDisplay) <= maxCharacters { + return &scopesForDisplay, false + } + + truncationIndex := maxCharacters - len(ellipsis) + lastSeparator := strings.LastIndex(string(scopesForDisplay[:truncationIndex]), separator) + if lastSeparator != -1 { + truncationIndex = lastSeparator + } + + scopesForDisplay = fmt.Sprintf("%s%s", string(scopesForDisplay[:truncationIndex]), ellipsis) + + return &scopesForDisplay, true +}