Skip to main content

build-tui-view

Provides instructions for building Hatchet TUI views in the Hatchet CLI.

Informações da origem

Repositório
hatchet-dev/hatchet
Última atividade na origem
14 de janeiro de 2026 às 19:37
Idioma detectado do SKILL.md
inglês
Estrelas
8.099
Forks
519

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
build-tui-view
description
Provides instructions for building Hatchet TUI views in the Hatchet CLI.
version
1
last_updated
2026-01-09T00:00:00.000Z
self_updating
true
**📝 SELF-UPDATING DOCUMENT**: This skill automatically updates itself when inaccuracies are discovered or new patterns are learned. Always verify information against the actual codebase and update this file when needed. ## Overview This skill provides instructions for creating and maintaining Terminal User Interface (TUI) views in the Hatchet CLI using bubbletea and lipgloss. The TUI system uses a modular view architecture where individual views are isolated in separate files within the `views/` directory. **IMPORTANT**: Always start by finding the corresponding view in the frontend application to understand the structure, columns, and API calls. ## Self-Updating Skill Instructions **CRITICAL - READ FIRST**: This skill document is designed to be continuously improved and kept accurate. ### When to Update This Skill You MUST update this skill file in the following situations: 1. **Discovering Inaccuracies** - When you find incorrect file paths or directory structures - When code examples don't compile or don't match actual implementations - When API signatures have changed - When referenced files don't exist at specified locations 2. **Learning New Patterns** - When implementing a new view and discovering better approaches - When the user teaches you new conventions or patterns - When you find reusable patterns that should be documented - When you discover common pitfalls that should be warned about 3. **Finding Missing Information** - When you need information that isn't documented here - When new components or utilities are added to the codebase - When new bubbletea/lipgloss patterns are adopted 4. **User Corrections** - When the user corrects any information in this document - When the user provides updated approaches or conventions - When the user points out outdated information ### How to Update This Skill When updating this skill: 1. **Verify Before Adding**: Always verify paths, code, and API signatures against the actual codebase before adding to this document 2. **Use Read/Glob/Grep**: Check the actual files to ensure accuracy 3. **Test Code Examples**: Ensure code examples compile and follow current patterns 4. **Be Specific**: Include exact file paths, function signatures, and working code examples 5. **Update Immediately**: Make updates as soon as inaccuracies are discovered, not at the end of a session 6. **Preserve Structure**: Maintain the existing document structure and formatting 7. **Add Context**: When adding new sections, explain why the pattern is recommended ### Verification Checklist Before using information from this skill, verify: - [ ] File paths exist and are correct - [ ] Code examples match current implementations - [ ] API signatures match the generated REST client - [ ] Reusable components are correctly referenced - [ ] Directory structures are accurate ### Self-Correction Process If you discover an inaccuracy while working: 1. Immediately note the issue 2. Verify the correct information by reading the actual files 3. Update this skill document with the correction 4. Continue with the user's task using the corrected information **Remember**: This skill should be a living document that grows more accurate and comprehensive with each use. ## Project Context - **Framework**: [bubbletea](https://github.com/charmbracelet/bubbletea) (TUI framework) - **Styling**: [lipgloss](https://github.com/charmbracelet/lipgloss) (style definitions) - **TUI Command Location**: `cmd/hatchet-cli/cli/tui.go` - **Views Location**: `cmd/hatchet-cli/cli/tui/` directory - **Theme**: Pre-defined Hatchet theme in `cmd/hatchet-cli/cli/internal/styles/styles.go` - **Frontend Reference**: `frontend/app/src/pages/main/v1/` directory ## Finding Frontend Prior Art **CRITICAL FIRST STEP**: Before implementing any TUI view, locate the corresponding frontend view to understand: 1. Column structure and names 2. API endpoints and query parameters 3. Data types and fields used 4. Filtering and sorting logic ### Process for Finding Frontend Reference: 1. **Locate the Frontend View** ```bash # Navigate to frontend pages cd frontend/app/src/pages/main/v1/ # Find views related to your feature (e.g., workflow-runs, tasks, events) ls -la ``` 2. **Study the Column Definitions** - Look for files like `{feature}-columns.tsx` - Note the column keys, titles, and accessors - Example: `frontend/app/src/pages/main/v1/workflow-runs-v1/components/v1/task-runs-columns.tsx` ```typescript export const TaskRunColumn = { taskName: "Task Name", status: "Status", workflow: "Workflow", createdAt: "Created At", startedAt: "Started At", duration: "Duration", }; ``` 3. **Identify the Data Hook** - Look for `use-{feature}.tsx` files in the `hooks/` directory - These contain the API query logic - Example: `frontend/app/src/pages/main/v1/workflow-runs-v1/hooks/use-runs.tsx` 4. **Find the API Query** - Check `frontend/app/src/lib/api/queries.ts` for the query definition - Note the endpoint name and parameters - Example: ```typescript v1WorkflowRuns: { list: (tenant: string, query: V2ListWorkflowRunsQuery) => ({ queryKey: ['v1:workflow-run:list', tenant, query], queryFn: async () => (await api.v1WorkflowRunList(tenant, query)).data, }), } ``` 5. **Map to Go REST Client** - The frontend `api.v1WorkflowRunList()` maps to Go's `client.API().V1WorkflowRunListWithResponse()` - Frontend query parameters map to Go struct parameters - Example mapping: ```typescript // Frontend api.v1WorkflowRunList(tenantId, { offset: 0, limit: 100, since: createdAfter, only_tasks: true, }) // Go equivalent client.API().V1WorkflowRunListWithResponse( ctx, client.TenantId(), &rest.V1WorkflowRunListParams{ Offset: int64Ptr(0), Limit: int64Ptr(100), Since: &since, OnlyTasks: true, }, ) ``` ### Example: Implementing Tasks View from Frontend Reference 1. **Frontend Structure**: `frontend/app/src/pages/main/v1/workflow-runs-v1/` - Columns: `task-runs-columns.tsx` - Hook: `use-runs.tsx` - Table: `runs-table.tsx` 2. **Extract Column Names**: ```typescript taskName, status, workflow, createdAt, startedAt, duration; ``` 3. **Identify API Call**: ```typescript queries.v1WorkflowRuns.list(tenantId, { offset, limit, statuses, workflow_ids, since, until, only_tasks: true, }); ``` 4. **Implement in TUI**: ```go // Create matching columns columns := []table.Column{ {Title: "Task Name", Width: 30}, {Title: "Status", Width: 12}, {Title: "Workflow", Width: 25}, {Title: "Created At", Width: 16}, {Title: "Started At", Width: 16}, {Title: "Duration", Width: 12}, } // Call matching API endpoint response, err := client.API().V1WorkflowRunListWithResponse( ctx, client.TenantId(), &rest.V1WorkflowRunListParams{ Offset: int64Ptr(0), Limit: int64Ptr(100), Since: &since, OnlyTasks: true, }, ) ``` ## Reusable Components (CRITICAL - READ FIRST) **IMPORTANT**: All TUI views MUST use the standardized reusable components defined in `view.go` to ensure consistency across the application. **DO NOT** copy-paste header/footer styling code. ### Header Component **CRITICAL**: ALL headers throughout the TUI use the magenta highlight color (`styles.HighlightColor`) for the title to provide consistent visual emphasis across all views (primary views, detail views, modals, etc.). #### For Detail Views and Modals **Always use `RenderHeader()` for detail views, modals, and secondary screens:** ```go header := RenderHeader("Workflow Details", v.Ctx.ProfileName, v.Width) header := RenderHeader("Task Details", v.Ctx.ProfileName, v.Width) header := RenderHeader("Filter Tasks", v.Ctx.ProfileName, v.Width) ``` #### For Primary Views **Use `RenderHeaderWithViewIndicator()` for primary/list views:** ```go // For primary list views - shows just the view name, no repetitive "Hatchet Workflows [Workflows]" header := RenderHeaderWithViewIndicator("Runs", v.Ctx.ProfileName, v.Width) header := RenderHeaderWithViewIndicator("Workflows", v.Ctx.ProfileName, v.Width) ``` This function renders just the view name (e.g., "Runs" or "Workflows") in the highlight color, keeping it simple and non-repetitive. **Features of both header functions:** - Title rendered in magenta highlight color (`styles.HighlightColor`) - **consistent across ALL views** - Includes the logo (text-based: "HATCHET TUI") on the right - Shows profile name - Bordered bottom edge - Responsive to terminal width **❌ NEVER do this:** ```go // Bad: Copy-pasting header styles headerStyle := lipgloss.NewStyle(). Bold(true). Foreground(styles.AccentColor). BorderStyle(lipgloss.NormalBorder()). // ... more styling header := headerStyle.Render(fmt.Sprintf("My View - Profile: %s", profile)) // Bad: Calling RenderHeaderWithLogo directly (bypasses highlight color) header := RenderHeaderWithLogo(fmt.Sprintf("My View - Profile: %s", profile), v.Width) ``` **✅ ALWAYS do this:** ```go // Good: Use the reusable component for detail views header := RenderHeader("Task Details", v.Ctx.ProfileName, v.Width) // Good: Use the view indicator variant for primary views header := RenderHeaderWithViewIndicator("Runs", v.Ctx.ProfileName, v.Width) ``` ### Instructions Component Use `RenderInstructions()` to display contextual help text: ```go instructions := RenderInstructions( "Your instructions here • Use bullets to separate items", v.Width, ) ``` **Features:** - Muted color styling for reduced visual noise - Automatically handles width constraints - Consistent padding - Uses bullet separators (•) ### Footer Component **Always use `RenderFooter()` for navigation/control hints:** ```go footer := RenderFooter([]string{ "↑/↓: Navigate", "Enter: Select", "Esc: Cancel", "q: Quit", }, v.Width) ``` **Features:** - Consistent styling with top border - Automatically joins control items with bullets (•) - Muted color for non-intrusive display - Responsive to terminal width ## Standard View Structure **Every view should follow this consistent structure:** ```go func (v *YourView) View() string { var b strings.Builder // 1. Header (always) - USE REUSABLE COMPONENT header := RenderHeader("View Title", v.Ctx.ProfileName, v.Width) b.WriteString(header) b.WriteString("\n\n") // 2. Instructions (when helpful) - USE REUSABLE COMPONENT instructions := RenderInstructions("Your instructions", v.Width) b.WriteString(instructions) b.WriteString("\n\n") // 3. Main content // ... your view-specific content ... // 4. Footer (always) - USE REUSABLE COMPONENT footer := RenderFooter([]string{ "control1: Action1", "control2: Action2", }, v.Width) b.WriteString(footer) return b.String() } ``` ## Architecture ### Root TUI Model (`tui.go`) The root TUI command is responsible for: 1. Profile selection and validation 2. Initializing the Hatchet client 3. Creating the view context 4. Managing the current view 5. Delegating updates to views ### View System (`views/` directory) Each view is a separate file that implements the `View` interface: - `view.go` - Base view interface, context, and **reusable components** - `{viewname}.go` - Individual view implementations (e.g., `tasks.go`) ## Core Principles ### 1. File Structure #### TUI Command File - File: `cmd/hatchet-cli/cli/tui.go` - Purpose: Command setup, profile selection, client initialization, view management #### View Files - Location: `cmd/hatchet-cli/cli/tui/` - Files: - `view.go` - View interface and base types - `{viewname}.go` - Individual view implementations ### 2. View Interface All views must implement this interface (defined in `views/view.go`): ```go package views import ( tea "github.com/charmbracelet/bubbletea" "github.com/hatchet-dev/hatchet/pkg/client" ) // ViewContext contains the shared context passed to all views type ViewContext struct { // Profile name for display ProfileName string // Hatchet client for API calls Client client.Client // Terminal dimensions Width int Height int } // View represents a TUI view component type View interface { // Init initializes the view and returns any initial commands Init() tea.Cmd // Update handles messages and updates the view state Update(msg tea.Msg) (View, tea.Cmd) // View renders the view to a string View() string // SetSize updates the view dimensions SetSize(width, height int) } ``` ### 3. Base Model Pattern Use `BaseModel` for common view fields: ```go // BaseModel contains common fields for all views type BaseModel struct { Ctx ViewContext Width int Height int Err error } // Your view embeds BaseModel type YourView struct { BaseModel // Your view-specific fields table table.Model items []YourDataType } ``` ### 4. Creating a New View #### Step 1: Create View File Create `cmd/hatchet-cli/cli/tui/{viewname}.go`: ```go package views import ( tea "github.com/charmbracelet/bubbletea" "github.com/hatchet-dev/hatchet/cmd/hatchet-cli/cli/internal/styles" "github.com/hatchet-dev/hatchet/pkg/client/rest" ) type YourView struct { BaseModel // View-specific fields } // NewYourView creates a new instance of your view func NewYourView(ctx ViewContext) *YourView { v := &YourView{ BaseModel: BaseModel{ Ctx: ctx, }, } // Initialize view components return v }
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub