jedib0t / go-pretty

Table-writer and more in golang!
MIT License
3.02k stars 119 forks source link

Nested Table Structure #316

Closed safaci2000 closed 7 months ago

safaci2000 commented 7 months ago

Is your feature request related to a problem? Please describe. I would like the ability to have a nested table embedded within an existing table.

Describe the solution you'd like This is an example of what I'd like to be able to see:

┌────────────┼──────────────────┬───────────────────┬────────────┬───────────────┬────────────────┬───────────────────────────────────────────────────────────────┐
│  ID        │ UID              │ NAME              │ SLUG       │ TYPE          │ DEFAULT        │ URL                                                           │
├────────────┼──────────────────┼───────────────────┼────────────┼───────────────┼────────────────┼───────────────────────────────────────────────────────────────┤
│ 898        │ cdhdaytdyff28e   │ test1             │ test1      │ elasticsearch │ false          │ https://grafana.com/datasource/edit/898                       │
┌────────────┬──────────────────┬───────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  PERMISSION│ EMAIL            │ ROLE              │                                                                                                             │
├────────────┼──────────────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  Query     │ user@domain.com  │ BuiltIn           │                                                                                                             │ 
│  Admin     │ admin@domain.com │ UserRole          │                                                                                                             │
│  Edit      │ editor@domain.com│ BuiltIn           │                                                                                                             │
┌────────────┼──────────────────┬───────────────────┬────────────┬───────────────┬────────────────┬───────────────────────────────────────────────────────────────┐
│  ID        │ UID              │ NAME              │ SLUG       │ TYPE          │ DEFAULT        │ URL                                                           │
├────────────┼──────────────────┼───────────────────┼────────────┼───────────────┼────────────────┼───────────────────────────────────────────────────────────────┤
│ 896        │ cdhdaytdyff28e   │ test2             │ test2      │ elasticsearch │ false          │ https://grafana.com/datasource/edit/896                       │
┌────────────┬──────────────────┬───────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  PERMISSION│ EMAIL            │ ROLE              │                                                                                                             │
├────────────┼──────────────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  Query     │ user@domain.com  │ BuiltIn           │                                                                                                             │ 
│  Admin     │ admin@domain.com │ UserRole          │                                                                                                             │
│  Edit      │ editor@domain.com│ BuiltIn           │                                                                                                             │
└────────────┴──────────────────┴───────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

If this is already possible I would love to know how to create such a structure, the closes I found is merging cells but that's not what I'm looking for.

Describe alternatives you've considered

Additional context

jedib0t commented 7 months ago

I'm not sure I understand what you mean by the example table above. It doesn't seem like nested tables... can you elaborate?

You can write tables within cells already as evidenced by the colors demo.

csg33k commented 7 months ago

So I have a structure where the first row has a ID, UID, NAME etc.... then for each of those records I have several lines I need to print that define the permissions.

Ideally it would be

Top level header Data 1-M lines. Inner Header data for inner table repeat

Ideally without generating 2 different tables. So in my example the first line is the headers for the top level table, and line 3 and 9 is the inner headers. Does that make sense?

jedib0t commented 7 months ago

Maybe you are looking for something like this:

╔════╦════════════╦═════════════════════════╗
║ ID ║ NAME       ║ CONFIGS                 ║
╠════╬════════════╬═════════════════════════╣
║  1 ║ user-num-1 ║ ┌───────┬────────────┐  ║
║    ║            ║ │ theme │ default    │  ║
║    ║            ║ │ ads   │ everything │  ║
║    ║            ║ │ mails │ everything │  ║
║    ║            ║ └───────┴────────────┘  ║
╠════╬════════════╬═════════════════════════╣
║  2 ║ user-num-2 ║ ┌───────┬─────────────┐ ║
║    ║            ║ │ ads   │ none        │ ║
║    ║            ║ │ mails │ none        │ ║
║    ║            ║ │ theme │ blue-lagoon │ ║
║    ║            ║ └───────┴─────────────┘ ║
╠════╬════════════╬═════════════════════════╣
║  3 ║ user-num-3 ║ ┌───────┬─────────┐     ║
║    ║            ║ │ ads   │ none    │     ║
║    ║            ║ │ mails │ none    │     ║
║    ║            ║ │ theme │ ui-dark │     ║
║    ║            ║ └───────┴─────────┘     ║
╚════╩════════════╩═════════════════════════╝

Code for the above:

package main

import (
    "fmt"

    "github.com/jedib0t/go-pretty/v6/table"
)

type User struct {
    ID     int
    Name   string
    Config map[string]string
}

var (
    users = []User{
        {
            ID:   1,
            Name: "user-num-1",
            Config: map[string]string{
                "ads":   "everything",
                "mails": "everything",
                "theme": "default",
            },
        }, {
            ID:   2,
            Name: "user-num-2",
            Config: map[string]string{
                "ads":   "none",
                "mails": "none",
                "theme": "blue-lagoon",
            },
        }, {
            ID:   3,
            Name: "user-num-3",
            Config: map[string]string{
                "ads":   "none",
                "mails": "none",
                "theme": "ui-dark",
            },
        },
    }
)

func main() {
    tw := table.NewWriter()
    tw.AppendHeader(table.Row{"ID", "Name", "Configs"})
    for _, user := range users {
        twConfigs := table.NewWriter()
        for k, v := range user.Config {
            twConfigs.AppendRow(table.Row{k, v})
        }
        twConfigs.SetIndexColumn(1)
        twConfigs.SetStyle(table.StyleLight)

        tw.AppendRow(table.Row{user.ID, user.Name, twConfigs.Render()})
    }
    tw.SetStyle(table.StyleDouble)
    tw.Style().Options.SeparateRows = true
    fmt.Println(tw.Render())
}
csg33k commented 7 months ago

That looks very promising. Thank you.