diff --git a/config/parser.go b/config/parser.go index 92cf691e..6ec15db8 100644 --- a/config/parser.go +++ b/config/parser.go @@ -68,6 +68,7 @@ type ColumnConfig struct { type PrsLayoutConfig struct { UpdatedAt ColumnConfig `yaml:"updatedAt,omitempty"` + CreatedAt ColumnConfig `yaml:"createdAt,omitempty"` Repo ColumnConfig `yaml:"repo,omitempty"` Author ColumnConfig `yaml:"author,omitempty"` Assignees ColumnConfig `yaml:"assignees,omitempty"` @@ -81,6 +82,7 @@ type PrsLayoutConfig struct { type IssuesLayoutConfig struct { UpdatedAt ColumnConfig `yaml:"updatedAt,omitempty"` + CreatedAt ColumnConfig `yaml:"createdAt,omitempty"` State ColumnConfig `yaml:"state,omitempty"` Repo ColumnConfig `yaml:"repo,omitempty"` Title ColumnConfig `yaml:"title,omitempty"` @@ -222,6 +224,9 @@ func (parser ConfigParser) getDefaultConfig() Config { UpdatedAt: ColumnConfig{ Width: utils.IntPtr(lipgloss.Width("2mo ")), }, + CreatedAt: ColumnConfig{ + Width: utils.IntPtr(lipgloss.Width("2mo ")), + }, Repo: ColumnConfig{ Width: utils.IntPtr(20), }, @@ -244,6 +249,9 @@ func (parser ConfigParser) getDefaultConfig() Config { UpdatedAt: ColumnConfig{ Width: utils.IntPtr(lipgloss.Width("2mo ")), }, + CreatedAt: ColumnConfig{ + Width: utils.IntPtr(lipgloss.Width("2mo ")), + }, Repo: ColumnConfig{ Width: utils.IntPtr(15), }, @@ -337,7 +345,6 @@ func (parser ConfigParser) writeDefaultConfigContents( newConfigFile *os.File, ) error { _, err := newConfigFile.WriteString(parser.getDefaultConfigYamlContents()) - if err != nil { return err } diff --git a/data/issueapi.go b/data/issueapi.go index c722fbab..86a7455e 100644 --- a/data/issueapi.go +++ b/data/issueapi.go @@ -18,6 +18,7 @@ type IssueData struct { Login string } UpdatedAt time.Time + CreatedAt time.Time Url string Repository Repository Assignees Assignees `graphql:"assignees(first: 3)"` @@ -72,6 +73,10 @@ func (data IssueData) GetUpdatedAt() time.Time { return data.UpdatedAt } +func (data IssueData) GetCreatedAt() time.Time { + return data.CreatedAt +} + func makeIssuesQuery(query string) string { return fmt.Sprintf("is:issue %s sort:updated", query) } diff --git a/data/prapi.go b/data/prapi.go index 8fd0daa9..fbb77102 100644 --- a/data/prapi.go +++ b/data/prapi.go @@ -23,6 +23,7 @@ type PullRequestData struct { Login string } UpdatedAt time.Time + CreatedAt time.Time Url string State string Mergeable string @@ -185,6 +186,10 @@ func (data PullRequestData) GetUpdatedAt() time.Time { return data.UpdatedAt } +func (data PullRequestData) GetCreatedAt() time.Time { + return data.CreatedAt +} + func makePullRequestsQuery(query string) string { return fmt.Sprintf("is:pr %s sort:updated", query) } diff --git a/git/git.go b/git/git.go index 3e958d7e..1e95ce5c 100644 --- a/git/git.go +++ b/git/git.go @@ -27,6 +27,7 @@ type Repo struct { type Branch struct { Name string LastUpdatedAt *time.Time + CreatedAt *time.Time LastCommitMsg *string CommitsAhead int CommitsBehind int @@ -103,6 +104,7 @@ func GetRepo(dir string) (*Repo, error) { branches[i] = Branch{ Name: b, LastUpdatedAt: updatedAt, + CreatedAt: updatedAt, IsCheckedOut: isHead, Remotes: remotes, LastCommitMsg: lastCommitMsg, diff --git a/ui/components/issue/issue.go b/ui/components/issue/issue.go index 4a05224f..1a696b92 100644 --- a/ui/components/issue/issue.go +++ b/ui/components/issue/issue.go @@ -28,6 +28,7 @@ func (issue *Issue) ToTableRow() table.Row { issue.renderNumComments(), issue.renderNumReactions(), issue.renderUpdateAt(), + issue.renderCreatedAt(), } } @@ -48,6 +49,19 @@ func (issue *Issue) renderUpdateAt() string { return issue.getTextStyle().Render(updatedAtOutput) } +func (issue *Issue) renderCreatedAt() string { + timeFormat := issue.Ctx.Config.Defaults.DateFormat + + createdAtOutput := "" + if timeFormat == "" || timeFormat == "relative" { + createdAtOutput = utils.TimeElapsed(issue.Data.CreatedAt) + } else { + createdAtOutput = issue.Data.CreatedAt.Format(timeFormat) + } + + return issue.getTextStyle().Render(createdAtOutput) +} + func (issue *Issue) renderRepoName() string { repoName := issue.Data.Repository.Name return issue.getTextStyle().Render(repoName) diff --git a/ui/components/issuessection/issuessection.go b/ui/components/issuessection/issuessection.go index b8b38a7a..e016e691 100644 --- a/ui/components/issuessection/issuessection.go +++ b/ui/components/issuessection/issuessection.go @@ -28,6 +28,7 @@ func NewModel( ctx *context.ProgramContext, cfg config.IssuesSectionConfig, lastUpdated time.Time, + createdAt time.Time, ) Model { m := Model{} m.BaseModel = section.NewModel( @@ -40,6 +41,7 @@ func NewModel( Singular: m.GetItemSingularForm(), Plural: m.GetItemPluralForm(), LastUpdated: lastUpdated, + CreatedAt: createdAt, }, ) m.Issues = []data.IssueData{} @@ -166,6 +168,10 @@ func GetSectionColumns( dLayout.UpdatedAt, sLayout.UpdatedAt, ) + createdAtLayout := config.MergeColumnConfigs( + dLayout.CreatedAt, + sLayout.CreatedAt, + ) stateLayout := config.MergeColumnConfigs(dLayout.State, sLayout.State) repoLayout := config.MergeColumnConfigs(dLayout.Repo, sLayout.Repo) titleLayout := config.MergeColumnConfigs(dLayout.Title, sLayout.Title) @@ -220,10 +226,15 @@ func GetSectionColumns( Hidden: reactionsLayout.Hidden, }, { - Title: "", + Title: "󱦻", Width: updatedAtLayout.Width, Hidden: updatedAtLayout.Hidden, }, + { + Title: "󱡢", + Width: createdAtLayout.Width, + Hidden: createdAtLayout.Hidden, + }, } } @@ -336,6 +347,7 @@ func FetchAllSections( ctx, sectionConfig, time.Now(), + time.Now(), ) // 0 is the search section sections = append(sections, §ionModel) fetchIssuesCmds = append( diff --git a/ui/components/listviewport/listviewport.go b/ui/components/listviewport/listviewport.go index 8591a3f7..52372e85 100644 --- a/ui/components/listviewport/listviewport.go +++ b/ui/components/listviewport/listviewport.go @@ -21,6 +21,7 @@ type Model struct { NumCurrentItems int NumTotalItems int LastUpdated time.Time + CreatedAt time.Time ItemTypeLabel string } @@ -28,6 +29,7 @@ func NewModel( ctx context.ProgramContext, dimensions constants.Dimensions, lastUpdated time.Time, + createdAt time.Time, itemTypeLabel string, numItems, listItemHeight int, ) Model { @@ -43,6 +45,7 @@ func NewModel( topBoundId: 0, ItemTypeLabel: itemTypeLabel, LastUpdated: lastUpdated, + CreatedAt: createdAt, } model.bottomBoundId = utils.Min( model.NumCurrentItems-1, diff --git a/ui/components/pr/pr.go b/ui/components/pr/pr.go index 825a9d32..e001b155 100644 --- a/ui/components/pr/pr.go +++ b/ui/components/pr/pr.go @@ -259,6 +259,28 @@ func (pr *PullRequest) renderUpdateAt() string { return pr.getTextStyle().Foreground(pr.Ctx.Theme.FaintText).Render(updatedAtOutput) } +func (pr *PullRequest) renderCreatedAt() string { + timeFormat := pr.Ctx.Config.Defaults.DateFormat + + createdAtOutput := "" + t := pr.Branch.CreatedAt + if pr.Data != nil { + t = &pr.Data.CreatedAt + } + + if t == nil { + return "" + } + + if timeFormat == "" || timeFormat == "relative" { + createdAtOutput = utils.TimeElapsed(*t) + } else { + createdAtOutput = t.Format(timeFormat) + } + + return pr.getTextStyle().Foreground(pr.Ctx.Theme.FaintText).Render(createdAtOutput) +} + func (pr *PullRequest) renderBaseName() string { if pr.Data == nil { return "" @@ -307,6 +329,7 @@ func (pr *PullRequest) ToTableRow(isSelected bool) table.Row { pr.renderCiStatus(), pr.renderLines(isSelected), pr.renderUpdateAt(), + pr.renderCreatedAt(), } } @@ -321,6 +344,7 @@ func (pr *PullRequest) ToTableRow(isSelected bool) table.Row { pr.renderCiStatus(), pr.renderLines(isSelected), pr.renderUpdateAt(), + pr.renderCreatedAt(), } } diff --git a/ui/components/prssection/prssection.go b/ui/components/prssection/prssection.go index bf4c9c61..be32d326 100644 --- a/ui/components/prssection/prssection.go +++ b/ui/components/prssection/prssection.go @@ -31,6 +31,7 @@ func NewModel( ctx *context.ProgramContext, cfg config.PrsSectionConfig, lastUpdated time.Time, + createdAt time.Time, ) Model { m := Model{} m.BaseModel = section.NewModel( @@ -43,6 +44,7 @@ func NewModel( Singular: m.GetItemSingularForm(), Plural: m.GetItemPluralForm(), LastUpdated: lastUpdated, + CreatedAt: createdAt, }, ) m.Prs = []data.PullRequestData{} @@ -203,6 +205,10 @@ func GetSectionColumns( dLayout.UpdatedAt, sLayout.UpdatedAt, ) + createdAtLayout := config.MergeColumnConfigs( + dLayout.CreatedAt, + sLayout.CreatedAt, + ) repoLayout := config.MergeColumnConfigs(dLayout.Repo, sLayout.Repo) titleLayout := config.MergeColumnConfigs(dLayout.Title, sLayout.Title) authorLayout := config.MergeColumnConfigs(dLayout.Author, sLayout.Author) @@ -258,10 +264,15 @@ func GetSectionColumns( Hidden: linesLayout.Hidden, }, { - Title: "", + Title: "󱦻", Width: updatedAtLayout.Width, Hidden: updatedAtLayout.Hidden, }, + { + Title: "󱡢", + Width: createdAtLayout.Width, + Hidden: createdAtLayout.Hidden, + }, } } @@ -313,10 +324,15 @@ func GetSectionColumns( Hidden: linesLayout.Hidden, }, { - Title: "", + Title: "󱦻", Width: updatedAtLayout.Width, Hidden: updatedAtLayout.Hidden, }, + { + Title: "󱡢", + Width: createdAtLayout.Width, + Hidden: createdAtLayout.Hidden, + }, } } @@ -444,6 +460,7 @@ func FetchAllSections( ctx, sectionConfig, time.Now(), + time.Now(), ) if len(prs) > 0 && len(prs) >= i+1 && prs[i+1] != nil { oldSection := prs[i+1].(*Model) diff --git a/ui/components/section/section.go b/ui/components/section/section.go index fe954c2a..011eecd0 100644 --- a/ui/components/section/section.go +++ b/ui/components/section/section.go @@ -49,6 +49,7 @@ type NewSectionOptions struct { Singular string Plural string LastUpdated time.Time + CreatedAt time.Time } func NewModel( @@ -78,6 +79,7 @@ func NewModel( *ctx, m.GetDimensions(), options.LastUpdated, + options.CreatedAt, m.Columns, nil, m.SingularForm, @@ -323,6 +325,10 @@ func (m *BaseModel) LastUpdated() time.Time { return m.Table.LastUpdated() } +func (m *BaseModel) CreatedAt() time.Time { + return m.Table.CreatedAt() +} + func (m *BaseModel) UpdateTotalItemsCount(count int) { m.Table.UpdateTotalItemsCount(count) } diff --git a/ui/components/table/table.go b/ui/components/table/table.go index c3e60c2f..d898fd53 100644 --- a/ui/components/table/table.go +++ b/ui/components/table/table.go @@ -40,6 +40,7 @@ func NewModel( ctx context.ProgramContext, dimensions constants.Dimensions, lastUpdated time.Time, + createdAt time.Time, columns []Column, rows []Row, itemTypeLabel string, @@ -72,6 +73,7 @@ func NewModel( ctx, dimensions, lastUpdated, + createdAt, itemTypeLabel, len(rows), itemHeight, @@ -322,6 +324,10 @@ func (m *Model) LastUpdated() time.Time { return m.rowsViewport.LastUpdated } +func (m *Model) CreatedAt() time.Time { + return m.rowsViewport.CreatedAt +} + func (m *Model) UpdateLastUpdated(t time.Time) { m.rowsViewport.LastUpdated = t } diff --git a/ui/ui.go b/ui/ui.go index 715b15fb..c695b813 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -798,6 +798,7 @@ func (m *Model) setCurrentViewSections(newSections []section.Section) { Filters: "archived:false", }, time.Now(), + time.Now(), ) m.prs = append([]section.Section{&search}, newSections...) } else { @@ -809,6 +810,7 @@ func (m *Model) setCurrentViewSections(newSections []section.Section) { Filters: "", }, time.Now(), + time.Now(), ) m.issues = append([]section.Section{&search}, newSections...) }