diff --git a/api/resource_organizations.go b/api/resource_organizations.go index 96efd6f9ac..73dd189323 100644 --- a/api/resource_organizations.go +++ b/api/resource_organizations.go @@ -24,30 +24,6 @@ func (client *Client) GetOrganizations() ([]Organization, error) { return data.Organizations.Nodes, nil } -func (client *Client) GetOrganization(slug string) ([]Organization, error) { - q := ` - { - organizations { - nodes { - id - slug - name - type - } - } - } - ` - - req := client.NewRequest(q) - - data, err := client.Run(req) - if err != nil { - return []Organization{}, err - } - - return data.Organizations.Nodes, nil -} - func (client *Client) GetCurrentOrganizations() (Organization, []Organization, error) { query := ` query { @@ -82,6 +58,91 @@ func (client *Client) GetCurrentOrganizations() (Organization, []Organization, e return data.UserOrganizations.PersonalOrganization, data.UserOrganizations.Organizations.Nodes, nil } +func (client *Client) GetOrganizationBySlug(slug string) (*OrganizationDetails, error) { + query := `query($slug: String!) { + organizationdetails: organization(slug: $slug) { + id + slug + name + type + viewerRole + databases { + nodes { + id + key + name + organization { + id + name + slug + type + } + publicUrl + vmUrl + backendId + createdAt + engine + } + } + dnsZones { + nodes { + id + domain + organization { + id + name + slug + type + } + records { + nodes { + id + name + ttl + values + createdAt + updatedAt + fqdn + isApex + isSystem + isWildcard + zone { + id + domain + } + } + } + createdAt + updatedAt + } + } + members { + edges { + cursor + node { + id + name + email + } + joinedAt + role + } + } + } + } + ` + + req := client.NewRequest(query) + req.Var("slug", slug) + + data, err := client.Run(req) + if err != nil { + return nil, err + } + + return &data.OrganizationDetails, nil +} + func (c *Client) CreateOrganization(organizationname string) (*Organization, error) { query := ` mutation($input: CreateOrganizationInput!) { diff --git a/api/types.go b/api/types.go index 2c5d40bc2c..47579d458c 100644 --- a/api/types.go +++ b/api/types.go @@ -19,9 +19,9 @@ type Query struct { Organizations struct { Nodes []Organization } - UserOrganizations UserOrganizations - - Build Build + UserOrganizations UserOrganizations + OrganizationDetails OrganizationDetails + Build Build Platform struct { Regions []Region @@ -210,6 +210,77 @@ type Organization struct { Type string } +type OrganizationDetails struct { + ID string + Name string + Slug string + Type string + ViewerRole string + Apps struct { + Nodes []App + } + // Billables []*Billable + Databases struct { + Nodes []Database + } + DNSZones struct { + Nodes []DNSZone + } + Members struct { + Edges []OrganizationMembershipEdge + } +} + +type OrganizationMembershipEdge struct { + Cursor string + Node User + Role string + JoinedAt time.Time +} + +type Billable struct { + Category string + Product string + Time time.Time + Quantity float64 + App App +} + +type Database struct { + ID string + Key string + Name string + Organization Organization + PublicURL string + VmUrl string + BackendId string + CreatedAt time.Time + Engine string +} + +type DNSZone struct { + ID string + Domain string + Organization Organization + Records []*DNSRecords + CreatedAt time.Time + UpdatedAt time.Time +} + +type DNSRecords struct { + ID string + Name string + Ttl int + Values []string + CreatedAt time.Time + UpdatedAt time.Time + Fqdn string + IsApex bool + IsSystem bool + IsWildcard bool + Zone DNSZone +} + type IPAddress struct { ID string Address string diff --git a/cmd/orgs.go b/cmd/orgs.go index 433044431e..d0fd742684 100644 --- a/cmd/orgs.go +++ b/cmd/orgs.go @@ -4,10 +4,10 @@ import ( "fmt" "os" + "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" "github.com/superfly/flyctl/api" "github.com/superfly/flyctl/cmdctx" - "github.com/superfly/flyctl/docstrings" ) @@ -55,23 +55,6 @@ func newOrgsCommand() *Command { return orgscmd } -func getOrgId(ctx *cmdctx.CmdContext, slug string) (id string, err error) { - - personalOrganization, organizations, err := ctx.Client.API().GetCurrentOrganizations() - - if personalOrganization.Slug == slug { - return personalOrganization.ID, nil - } - - for _, o := range organizations { - if o.Slug == slug { - return o.ID, nil - } - } - - return "", fmt.Errorf("slug %s not found", slug) -} - func runOrgsList(cmdctx *cmdctx.CmdContext) error { asJSON := cmdctx.OutputJSON() @@ -111,8 +94,56 @@ func printOrg(o api.Organization, headers bool) { } +// func makeTable(ctx *cmdctx.CmdContext, heading...) (tablewriter.Table) { + +// } + func runOrgsShow(ctx *cmdctx.CmdContext) error { - return fmt.Errorf("Show Not implemented") + asJSON := ctx.OutputJSON() + orgslug := ctx.Args[0] + + org, err := ctx.Client.API().GetOrganizationBySlug(orgslug) + + if err != nil { + return err + } + + if asJSON { + ctx.WriteJSON(org) + return nil + } + + ctx.Statusf("fyctl", cmdctx.STITLE, "Organization\n") + + ctx.Statusf("flyctl", cmdctx.SINFO, "%-10s: %-20s\n", "Name", org.Name) + ctx.Statusf("flyctl", cmdctx.SINFO, "%-10s: %-20s\n", "Slug", org.Slug) + ctx.Statusf("flyctl", cmdctx.SINFO, "%-10s: %-20s\n", "Type", org.Type) + + ctx.StatusLn() + + ctx.Statusf("fyctl", cmdctx.STITLE, "Summary\n") + + ctx.Statusf("flyctl", cmdctx.SINFO, "You have %s permissions on this organizaton\n", org.ViewerRole) + + ctx.StatusLn() + + ctx.Statusf("flyctl", cmdctx.SINFO, "There are %d databases associated with this organization\n", len(org.Databases.Nodes)) + ctx.Statusf("flyctl", cmdctx.SINFO, "There are %d DNS zones associated with this organization\n", len(org.DNSZones.Nodes)) + ctx.Statusf("flyctl", cmdctx.SINFO, "There are %d members associated with this organization\n", len(org.Members.Edges)) + + ctx.StatusLn() + + ctx.Statusf("fyctl", cmdctx.STITLE, "Organization Members\n") + + membertable := tablewriter.NewWriter(ctx.Out) + membertable.SetHeader([]string{"Name", "Email", "Role"}) + + for _, m := range org.Members.Edges { + membertable.Append([]string{m.Node.Name, m.Node.Email, m.Role}) + } + membertable.Render() + + return nil } func runOrgsInvite(ctx *cmdctx.CmdContext) error { @@ -149,7 +180,7 @@ func runOrgsRevoke(ctx *cmdctx.CmdContext) error { func runOrgsDelete(ctx *cmdctx.CmdContext) error { orgslug := ctx.Args[0] - orgid, err := getOrgId(ctx, orgslug) + org, err := ctx.Client.API().GetOrganizationBySlug(orgslug) if err != nil { return err @@ -161,7 +192,7 @@ func runOrgsDelete(ctx *cmdctx.CmdContext) error { return nil } - _, err = ctx.Client.API().DeleteOrganization(orgid) + _, err = ctx.Client.API().DeleteOrganization(org.ID) if err != nil { return err diff --git a/cmd/presenters/allocations.go b/cmd/presenters/allocations.go index a4f94b39a2..dfb9b85166 100644 --- a/cmd/presenters/allocations.go +++ b/cmd/presenters/allocations.go @@ -9,7 +9,8 @@ import ( ) type Allocations struct { - Allocations []*api.AllocationStatus + Allocations []*api.AllocationStatus + BackupRegions []api.Region } func (p *Allocations) APIStruct() interface{} { @@ -22,7 +23,6 @@ func (p *Allocations) FieldNames() []string { func (p *Allocations) Records() []map[string]string { out := []map[string]string{} - multipleVersions := hasMultipleVersions(p.Allocations) for _, alloc := range p.Allocations { @@ -31,12 +31,24 @@ func (p *Allocations) Records() []map[string]string { version = version + " " + aurora.Green("⇡").String() } + region := alloc.Region + if len(p.BackupRegions) > 0 { + for _, r := range p.BackupRegions { + fmt.Println(r) + fmt.Println(region) + if alloc.Region == r.Code { + region = alloc.Region + "(B)" + break + } + } + } + out = append(out, map[string]string{ "ID": alloc.IDShort, "Version": version, "Status": formatAllocStatus(alloc), "Desired": alloc.DesiredStatus, - "Region": alloc.Region, + "Region": region, "Created": formatRelativeTime(alloc.CreatedAt), "Health Checks": FormatHealthChecksSummary(alloc), "Restarts": strconv.Itoa(alloc.Restarts), diff --git a/cmd/status.go b/cmd/status.go index 7ff56acf25..dcca7b6c2a 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -31,10 +31,13 @@ func newStatusCommand() *Command { func runStatus(ctx *cmdctx.CmdContext) error { app, err := ctx.Client.API().GetAppStatus(ctx.AppName, ctx.Config.GetBool("all")) + if err != nil { return err } + _, backupregions, err := ctx.Client.API().ListAppRegions(ctx.AppName) + err = ctx.Frender(cmdctx.PresenterOption{Presentable: &presenters.AppStatus{AppStatus: *app}, HideHeader: true, Vertical: true, Title: "App"}) if err != nil { return err @@ -64,9 +67,10 @@ func runStatus(ctx *cmdctx.CmdContext) error { } err = ctx.Frender(cmdctx.PresenterOption{ - Presentable: &presenters.Allocations{Allocations: app.Allocations}, + Presentable: &presenters.Allocations{Allocations: app.Allocations, BackupRegions: backupregions}, Title: "Allocations", }) + if err != nil { return err }