Enhance status component and dashboard functionality
- Updated the status component template to include a new trigger for task status checks. - Modified the status component's Go implementation to reflect the new trigger in the HTML output. - Improved the UpdateIssue handler to conditionally set the assignee based on form input. - Enhanced the dashboard template to include a new dependencies section for issues, allowing users to add dependencies dynamically. - Refactored the dashboard's issue rows to utilize JavaScript functions for rendering status, type, and priority badges, improving maintainability and readability.
This commit is contained in:
@@ -2,7 +2,7 @@ package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"charm.land/huh/v2"
|
||||
"github.com/LazyBachelor/LazyPM/internal/models"
|
||||
@@ -18,7 +18,7 @@ You need to groom the backlog:
|
||||
2. Find two issues that have the same name.
|
||||
3. Open one of these issues.
|
||||
4. Select "Close issue"
|
||||
5. Choose "Duplicate issue" as closing reason.
|
||||
5. Set the closing reason to "Duplicate issue".
|
||||
6. Save/close issue.
|
||||
|
||||
Focus on making the backlog a reliable source of upcoming work.`
|
||||
@@ -126,17 +126,31 @@ func (t *BacklogRefinementTask) Validate(ctx context.Context) ValidationFeedback
|
||||
return expect.Fatal("Could not fetch issues")
|
||||
}
|
||||
|
||||
fmt.Printf("DEBUG: Found %d issues\n", len(issues))
|
||||
|
||||
var closedDuplicate *models.Issue
|
||||
for _, issue := range issues {
|
||||
if issue.Status == models.StatusClosed &&
|
||||
strings.Contains(strings.ToLower(issue.CloseReason), "duplicate") {
|
||||
fmt.Printf("DEBUG: Issue '%s' has status: %v\n", issue.Title, issue.Status)
|
||||
if issue.Status == models.StatusClosed {
|
||||
closedDuplicate = issue
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
expect.Assert(closedDuplicate != nil,
|
||||
"Expected one duplicate issue to be closed with 'Duplicate issue' as closing reason")
|
||||
fmt.Printf("DEBUG: closedDuplicate is nil: %v\n", closedDuplicate == nil)
|
||||
if closedDuplicate == nil {
|
||||
expect.Fail("Closed duplicate issue is wrong")
|
||||
} else {
|
||||
expect.Pass("Closed duplicate issue is correct")
|
||||
title := closedDuplicate.Title
|
||||
isDuplicate := title == "User profile page" || title == "Fix login timeout"
|
||||
expect.Assert(isDuplicate, "Closed issue was one of the duplicates")
|
||||
}
|
||||
|
||||
return expect.Complete()
|
||||
feedback := expect.Complete()
|
||||
fmt.Printf("DEBUG: Validation Success=%v, Checks=%d\n", feedback.Success, len(feedback.Checks))
|
||||
for i, check := range feedback.Checks {
|
||||
fmt.Printf("DEBUG: Check[%d]: Valid=%v, Message=%s\n", i, check.Valid, check.Message)
|
||||
}
|
||||
return feedback
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"charm.land/huh/v2"
|
||||
"github.com/LazyBachelor/LazyPM/internal/models"
|
||||
@@ -37,9 +38,10 @@ function Add(a, b int) int {
|
||||
var textFileContent = codingDescription + textFileDescription + "\n" + code
|
||||
|
||||
type CodingTask struct {
|
||||
done bool
|
||||
app *App
|
||||
issue *Issue
|
||||
done bool
|
||||
app *App
|
||||
issue *Issue
|
||||
lastModified time.Time
|
||||
}
|
||||
|
||||
func NewCodingTask(app *App) *CodingTask {
|
||||
@@ -89,6 +91,10 @@ func (t *CodingTask) Setup(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if stat, err := os.Stat("./code.txt"); err == nil {
|
||||
t.lastModified = stat.ModTime()
|
||||
}
|
||||
|
||||
t.issue = NewIssueBuilder().
|
||||
WithTitle("Fix major error").
|
||||
WithDescription(desc).
|
||||
@@ -96,7 +102,45 @@ func (t *CodingTask) Setup(ctx context.Context) error {
|
||||
WithPriority(4).
|
||||
Build()
|
||||
|
||||
return t.app.Issues.CreateIssue(ctx, t.issue, "")
|
||||
if err := t.app.Issues.CreateIssue(ctx, t.issue, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start file watcher goroutine
|
||||
t.startFileWatcher(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *CodingTask) startFileWatcher(ctx context.Context) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
if t.app.SubmitChan == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
stat, err := os.Stat("./code.txt")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if stat.ModTime().After(t.lastModified) {
|
||||
t.lastModified = stat.ModTime()
|
||||
select {
|
||||
case t.app.SubmitChan <- models.ValidationTrigger{Source: models.ValidationTriggerAutoPoll}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (t *CodingTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"charm.land/huh/v2"
|
||||
"github.com/LazyBachelor/LazyPM/internal/models"
|
||||
@@ -33,10 +34,11 @@ The repository is in the task folder (./task).`
|
||||
const gitTaskReadmeContent = "This is a Git task. Add your name or a short note below this line to complete it, then commit your change."
|
||||
|
||||
type GitTask struct {
|
||||
app *App
|
||||
done bool
|
||||
repo *git.Repository
|
||||
setupIssue *Issue
|
||||
app *App
|
||||
done bool
|
||||
repo *git.Repository
|
||||
setupIssue *Issue
|
||||
lastModified time.Time
|
||||
}
|
||||
|
||||
var gitTaskInProgress = false
|
||||
@@ -102,9 +104,46 @@ func (t *GitTask) Setup(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize lastModified and start file watcher
|
||||
if stat, err := os.Stat("./task/README.md"); err == nil {
|
||||
t.lastModified = stat.ModTime()
|
||||
}
|
||||
t.startFileWatcher(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *GitTask) startFileWatcher(ctx context.Context) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
if t.app.SubmitChan == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
stat, err := os.Stat("./task/README.md")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if stat.ModTime().After(t.lastModified) {
|
||||
t.lastModified = stat.ModTime()
|
||||
select {
|
||||
case t.app.SubmitChan <- models.ValidationTrigger{Source: models.ValidationTriggerAutoPoll}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (t *GitTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
expect := check.NewExpector()
|
||||
|
||||
@@ -117,7 +156,7 @@ func (t *GitTask) Validate(ctx context.Context) ValidationFeedback {
|
||||
return expect.ValidationFeedback
|
||||
}
|
||||
|
||||
expect.Equal(issue.Assignee, "Me", "Issue Assignee")
|
||||
expect.NotEmptyAndEqual(issue.Assignee, "Me", "Issue Assignee")
|
||||
|
||||
if !expect.Valid() {
|
||||
return expect.ValidationFeedback
|
||||
|
||||
Reference in New Issue
Block a user