Add tm_server with SQLite, Svelte UI, and task-master TUI sync.
Introduces the web backend (auth, RBAC, project tokens, revisions), YouTrack-or-taskmaster backend choice in the TUI, and a first-pass embedded Svelte UI. The frontend is functional but needs a major rework. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"task/internal/project"
|
||||
"task/internal/ticket"
|
||||
)
|
||||
|
||||
// ImportJSONDataDir copies projects/tickets/time from a local JSON DataDir into SQLite.
|
||||
func (s *Server) ImportJSONDataDir(dataDir string, ownerUserID string) error {
|
||||
ps := project.NewDirStore(dataDir)
|
||||
ts := ticket.NewJSONStore(dataDir)
|
||||
timeStore := ticket.NewJSONTimeStore(dataDir)
|
||||
|
||||
projects, err := ps.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range projects {
|
||||
if err := s.Projects.Ensure(p.ID); err != nil {
|
||||
return fmt.Errorf("project %s: %w", p.ID, err)
|
||||
}
|
||||
if ownerUserID != "" {
|
||||
_ = s.DB.SetMember(p.ID, ownerUserID, "owner")
|
||||
}
|
||||
meta, err := ps.LoadMeta(p.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if meta.YouTrack != nil && meta.YouTrack.Configured() {
|
||||
if err := s.Projects.SaveMeta(p.ID, meta); err != nil {
|
||||
return fmt.Errorf("meta %s: %w", p.ID, err)
|
||||
}
|
||||
}
|
||||
tickets, err := ts.List(p.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, t := range tickets {
|
||||
if _, err := s.Tickets.Get(t.ID); err == nil {
|
||||
continue // already imported
|
||||
}
|
||||
if _, err := s.Tickets.Create(t); err != nil {
|
||||
return fmt.Errorf("ticket %s: %w", t.ID, err)
|
||||
}
|
||||
_, _ = s.DB.AppendRevision("ticket", t.ID, p.ID, "import", ownerUserID, t)
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := timeStore.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing, _ := s.Times.List()
|
||||
have := map[string]bool{}
|
||||
for _, e := range existing {
|
||||
have[e.ID] = true
|
||||
}
|
||||
for _, e := range entries {
|
||||
if have[e.ID] {
|
||||
continue
|
||||
}
|
||||
if _, err := s.Times.Create(e); err != nil {
|
||||
return fmt.Errorf("time %s: %w", e.ID, err)
|
||||
}
|
||||
}
|
||||
if active, err := timeStore.LoadActiveTimer(); err == nil && active != nil {
|
||||
_ = s.Times.SaveActiveTimer(active)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user