Skip to content

Commit

Permalink
Enhance GitHub workflow handling and state management
Browse files Browse the repository at this point in the history
- Filter triggerable workflows to only include those from the ".github/workflows/" directory.
- Introduce lastBranch tracking in ModelGithubTrigger for improved workflow synchronization.
- Refactor ModelGithubWorkflow to manage repository and branch states more effectively.
- Implement state management for available workflows, updating UI components based on workflow presence.
- Improve user feedback with updated placeholders and blur effects when no workflows are available.

These changes improve the usability and responsiveness of the terminal handler components.
  • Loading branch information
canack committed Jan 6, 2025
1 parent f5f501e commit b57e81e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 26 deletions.
8 changes: 7 additions & 1 deletion internal/github/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,13 @@ func (r *Repo) GetTriggerableWorkflows(ctx context.Context, repository string) (

// Filter workflows to only include those that are dispatchable and manually triggerable
for _, workflow := range workflows.Workflows {
go r.workerGetTriggerableWorkflows(ctx, repository, workflow, results, errs)
// if workflow.Path starts with .github/workflows/
if strings.HasPrefix(workflow.Path, ".github/workflows/") {
go r.workerGetTriggerableWorkflows(ctx, repository, workflow, results, errs)
} else {
// do not send but we created a channel for it
results <- nil
}
}

// Collect the results and errors
Expand Down
7 changes: 6 additions & 1 deletion internal/terminal/handler/ghtrigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ type ModelGithubTrigger struct {

// Shared state
selectedRepository *SelectedRepository

// Track last branch for refresh
lastBranch string
}

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -170,6 +173,7 @@ func (m *ModelGithubTrigger) handleWorkflowChange() tea.Cmd {
}

if m.shouldSyncWorkflow() {
m.lastBranch = m.selectedRepository.BranchName
return m.initializeWorkflowSync()
}

Expand All @@ -185,7 +189,8 @@ func (m *ModelGithubTrigger) handleNoWorkflow() {
func (m *ModelGithubTrigger) shouldSyncWorkflow() bool {
return m.selectedRepository.WorkflowName != "" &&
(m.selectedRepository.WorkflowName != m.selectedWorkflow ||
m.selectedRepository.RepositoryName != m.selectedRepositoryName)
m.selectedRepository.RepositoryName != m.selectedRepositoryName ||
m.lastBranch != m.selectedRepository.BranchName)
}

func (m *ModelGithubTrigger) initializeWorkflowSync() tea.Cmd {
Expand Down
135 changes: 111 additions & 24 deletions internal/terminal/handler/ghworkflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,30 @@ type ModelGithubWorkflow struct {
textInput textinput.Model

// Table state
tableReady bool
lastRepository string
mainBranch string
tableReady bool

// Context management
syncTriggerableWorkflowsContext context.Context
cancelSyncTriggerableWorkflows context.CancelFunc

// Shared state
selectedRepository *SelectedRepository

// Indicates if there are any available workflows
hasWorkflows bool
lastSelectedRepository string // Track last repository for state persistence

// State management
state struct {
Ready bool
Repository struct {
Current string
Last string
Branch string
HasFlows bool
}
Syncing bool
}
}

// -----------------------------------------------------------------------------
Expand All @@ -67,8 +81,10 @@ func SetupModelGithubWorkflow(sk *skeleton.Skeleton, githubUseCase gu.UseCase) *
cancelSyncTriggerableWorkflows: func() {},
}

// Setup table
// Setup table and blur initially
m.tableTriggerableWorkflow = setupWorkflowTable()
m.tableTriggerableWorkflow.Blur()
m.textInput.Blur()

return m
}
Expand Down Expand Up @@ -121,10 +137,18 @@ func setupWorkflowTable() table.Model {
// -----------------------------------------------------------------------------

func (m *ModelGithubWorkflow) Init() tea.Cmd {
// Check initial state
if m.lastSelectedRepository == m.selectedRepository.RepositoryName && !m.hasWorkflows {
m.skeleton.LockTab("trigger")
// Blur components initially
m.tableTriggerableWorkflow.Blur()
m.textInput.Blur()
}
return nil
}

func (m *ModelGithubWorkflow) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Check repository change and return command if exists
if cmd := m.handleRepositoryChange(); cmd != nil {
return m, cmd
}
Expand Down Expand Up @@ -159,17 +183,13 @@ func (m *ModelGithubWorkflow) View() string {
// -----------------------------------------------------------------------------

func (m *ModelGithubWorkflow) handleRepositoryChange() tea.Cmd {
if m.lastRepository != m.selectedRepository.RepositoryName {
m.tableReady = false
m.cancelSyncTriggerableWorkflows()

m.lastRepository = m.selectedRepository.RepositoryName
m.mainBranch = m.selectedRepository.BranchName

m.syncTriggerableWorkflowsContext, m.cancelSyncTriggerableWorkflows = context.WithCancel(context.Background())

go m.syncTriggerableWorkflows(m.syncTriggerableWorkflowsContext)
go m.syncBranches(m.syncTriggerableWorkflowsContext)
if m.state.Repository.Current != m.selectedRepository.RepositoryName {
m.state.Ready = false
m.state.Repository.Current = m.selectedRepository.RepositoryName
m.state.Repository.Branch = m.selectedRepository.BranchName
m.syncWorkflows()
} else if !m.state.Repository.HasFlows {
m.skeleton.LockTab("trigger")
}
return nil
}
Expand All @@ -180,19 +200,20 @@ func (m *ModelGithubWorkflow) handleRepositoryChange() tea.Cmd {

func (m *ModelGithubWorkflow) handleBranchSelection() {
selectedBranch := m.textInput.Value()
if selectedBranch == "" {
m.selectedRepository.BranchName = m.mainBranch
m.skeleton.UnlockTabs()
return
}

if m.isBranchValid(selectedBranch) {
// Set branch
if selectedBranch == "" {
m.selectedRepository.BranchName = m.state.Repository.Branch
} else if m.isBranchValid(selectedBranch) {
m.selectedRepository.BranchName = selectedBranch
m.skeleton.UnlockTabs()
} else {
m.status.SetErrorMessage(fmt.Sprintf("Branch %s does not exist", selectedBranch))
m.skeleton.LockTabsToTheRight()
return
}

// Update tab state
m.updateTabState()
}

func (m *ModelGithubWorkflow) isBranchValid(branch string) bool {
Expand All @@ -208,6 +229,26 @@ func (m *ModelGithubWorkflow) isBranchValid(branch string) bool {
// Workflow Sync & Management
// -----------------------------------------------------------------------------

func (m *ModelGithubWorkflow) syncWorkflows() {
if m.state.Syncing {
m.cancelSyncTriggerableWorkflows()
}

ctx, cancel := context.WithCancel(context.Background())
m.cancelSyncTriggerableWorkflows = cancel
m.state.Syncing = true

go func() {
defer func() {
m.state.Syncing = false
m.skeleton.TriggerUpdate()
}()

m.syncBranches(ctx)
m.syncTriggerableWorkflows(ctx)
}()
}

func (m *ModelGithubWorkflow) syncTriggerableWorkflows(ctx context.Context) {
defer m.skeleton.TriggerUpdate()

Expand Down Expand Up @@ -245,19 +286,49 @@ func (m *ModelGithubWorkflow) fetchTriggerableWorkflows(ctx context.Context) (*g
}

func (m *ModelGithubWorkflow) processWorkflows(workflows *gu.GetTriggerableWorkflowsOutput) {
if len(workflows.TriggerableWorkflows) == 0 {
m.state.Repository.HasFlows = len(workflows.TriggerableWorkflows) > 0
m.state.Repository.Current = m.selectedRepository.RepositoryName
m.state.Ready = true

if !m.state.Repository.HasFlows {
m.handleEmptyWorkflows()
return
}

m.updateWorkflowTable(workflows.TriggerableWorkflows)
m.updateTabState()
m.finalizeUpdate()

// Focus components when workflows exist
m.tableTriggerableWorkflow.Focus()
m.textInput.Focus()
}

func (m *ModelGithubWorkflow) handleEmptyWorkflows() {
m.selectedRepository.WorkflowName = ""
m.skeleton.LockTab("trigger")

// Blur components when no workflows
m.tableTriggerableWorkflow.Blur()
m.textInput.Blur()

m.status.SetDefaultMessage(fmt.Sprintf("[%s@%s] No triggerable workflow found.",
m.selectedRepository.RepositoryName, m.selectedRepository.BranchName))

m.fillTableWithEmptyMessage()
}

func (m *ModelGithubWorkflow) fillTableWithEmptyMessage() {
var rows []table.Row
for i := 0; i < 100; i++ {
rows = append(rows, table.Row{
"EMPTY",
"No triggerable workflow found",
})
}

m.tableTriggerableWorkflow.SetRows(rows)
m.tableTriggerableWorkflow.SetCursor(0)
}

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -381,7 +452,11 @@ func (m *ModelGithubWorkflow) renderBranchInput() string {
MarginLeft(1)

if len(m.textInput.AvailableSuggestions()) > 0 && m.textInput.Value() == "" {
m.textInput.Placeholder = fmt.Sprintf("Type to switch branch (default: %s)", m.mainBranch)
if !m.state.Repository.HasFlows {
m.textInput.Placeholder = "Branch selection disabled - No triggerable workflows available"
} else {
m.textInput.Placeholder = fmt.Sprintf("Type to switch branch (default: %s)", m.state.Repository.Branch)
}
}

return style.Render(m.textInput.View())
Expand Down Expand Up @@ -409,3 +484,15 @@ func (m *ModelGithubWorkflow) updateTableDimensions() {
m.tableTriggerableWorkflow.SetHeight(termHeight - 17)
}
}

// -----------------------------------------------------------------------------
// Tab Management
// -----------------------------------------------------------------------------

func (m *ModelGithubWorkflow) updateTabState() {
if !m.state.Repository.HasFlows {
m.skeleton.LockTab("trigger")
return
}
m.skeleton.UnlockTabs()
}

0 comments on commit b57e81e

Please sign in to comment.