Add YouTrack pull/push sync with project settings and time tracking.
CI / test-and-build (push) Failing after 1m19s
CI / demo (push) Skipped

Wire manual Y menu and CLI sync for issues and work items, persist
per-project credentials, and keep local edits until an explicit push.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-24 00:17:51 +02:00
co-authored by Cursor
parent 19ae1f1b62
commit 98d2253f44
23 changed files with 2874 additions and 44 deletions
+26 -7
View File
@@ -10,25 +10,39 @@ import (
// ProjectItem wraps a project for bubbles/list.
type ProjectItem struct {
Project project.Project
Active bool
Project project.Project
Active bool
YouTrack bool // true when YouTrack sync is configured
}
func (i ProjectItem) Title() string {
if i.Active {
return i.Project.Name + " *"
name := i.Project.Name
if i.YouTrack {
name += " [YT]"
}
return i.Project.Name
if i.Active {
return name + " *"
}
return name
}
func (i ProjectItem) Description() string { return i.Project.ID }
func (i ProjectItem) FilterValue() string { return i.Project.Name }
// NewProjectList builds a list of projects.
func NewProjectList(projects []project.Project, activeID string, width, height int) list.Model {
return NewProjectListWithYT(projects, activeID, nil, width, height)
}
// NewProjectListWithYT builds a list, marking projects with YouTrack config.
func NewProjectListWithYT(projects []project.Project, activeID string, ytConfigured map[string]bool, width, height int) list.Model {
items := make([]list.Item, len(projects))
selected := 0
for i, p := range projects {
items[i] = ProjectItem{Project: p, Active: p.ID == activeID}
items[i] = ProjectItem{
Project: p,
Active: p.ID == activeID,
YouTrack: ytConfigured[p.ID],
}
if p.ID == activeID {
selected = i
}
@@ -77,9 +91,14 @@ func JumpProjectByLetter(l *list.Model, r rune) bool {
// ProjectsToItems converts projects to list items.
func ProjectsToItems(projects []project.Project, activeID string) []list.Item {
return ProjectsToItemsWithYT(projects, activeID, nil)
}
// ProjectsToItemsWithYT converts projects to list items with YouTrack flags.
func ProjectsToItemsWithYT(projects []project.Project, activeID string, ytConfigured map[string]bool) []list.Item {
items := make([]list.Item, len(projects))
for i, p := range projects {
items[i] = ProjectItem{Project: p, Active: p.ID == activeID}
items[i] = ProjectItem{Project: p, Active: p.ID == activeID, YouTrack: ytConfigured[p.ID]}
}
return items
}