Documentation
¶
Overview ¶
Package workspace provides the persistent TUI application.
Index ¶
- func ApplyOverrides(km *GlobalKeyMap, overrides map[string]string)
- func LoadKeyOverrides(path string) (map[string]string, error)
- func Navigate(target ViewTarget, scope Scope) tea.Cmd
- func NavigateBack() tea.Cmd
- func OpenURL(url string) tea.Cmd
- func ReportError(err error, context string) tea.Cmd
- func SetStatus(text string, isError bool) tea.Cmd
- type AccountInfo
- type AccountNameMsg
- type AccountsDiscoveredMsg
- type Action
- type ActivityEntryInfo
- type AssignmentInfo
- type BlurMsg
- type BoostCreatedMsg
- type BoostPicker
- type BoostSelectedMsg
- type BoostTarget
- type CampfireLineInfo
- type CampfireLineSentMsg
- type CampfireLinesLoadedMsg
- type CardColumnInfo
- type CardInfo
- type CheckinQuestionInfo
- type ChromeSyncMsg
- type CommentCreatedMsg
- type ComposeType
- type DockLoadedMsg
- type DocsFilesItemInfo
- type EpochMsg
- type ErrorMsg
- type Filterable
- type FocusMsg
- type FocusedItemScope
- type FocusedRecording
- type GlobalKeyMap
- type HeyEntryInfo
- type InputCapturer
- type ListKeyMap
- type MessageCreatedMsg
- type MessageDetailLoadedMsg
- type MessageInfo
- type ModalActive
- type NavigateBackMsg
- type NavigateMsg
- type NavigateToDepthMsg
- type OpenBoostPickerMsg
- type PersonInfo
- type PingRoomInfo
- type ProjectBookmarkedMsg
- type RefreshMsg
- type Registry
- type Router
- func (r *Router) Breadcrumbs() []string
- func (r *Router) CanGoBack() bool
- func (r *Router) Current() View
- func (r *Router) CurrentScope() Scope
- func (r *Router) CurrentTarget() ViewTarget
- func (r *Router) Depth() int
- func (r *Router) Pop() View
- func (r *Router) PopToDepth(depth int) View
- func (r *Router) Push(view View, scope Scope, target ViewTarget)
- func (r *Router) Reset()
- type ScheduleEntryInfo
- type Scope
- type ScopeRequirement
- type SearchResultInfo
- type SearchResultsMsg
- type Session
- func (s *Session) AccountClient() *basecamp.AccountClient
- func (s *Session) App() *appctx.App
- func (s *Session) ConsumeInitialView() (ViewTarget, Scope, bool)
- func (s *Session) Context() context.Context
- func (s *Session) Epoch() uint64
- func (s *Session) HasAccount() bool
- func (s *Session) Hub() *data.Hub
- func (s *Session) MultiStore() *data.MultiStore
- func (s *Session) Recents() *recents.Store
- func (s *Session) ReloadTheme()
- func (s *Session) ResetContext()
- func (s *Session) Scope() Scope
- func (s *Session) SetInitialView(target ViewTarget, scope Scope)
- func (s *Session) SetScope(scope Scope)
- func (s *Session) Shutdown()
- func (s *Session) Styles() *tui.Styles
- type SplitPaneFocuser
- type StatusClearMsg
- type StatusMsg
- type ThemeChangedMsg
- type TimelineEventInfo
- type TodoCreatedMsg
- type TodoInfo
- type TodolistInfo
- type ToggleHelpMsg
- type TogglePaletteMsg
- type View
- type ViewFactory
- type ViewTarget
- type Workspace
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyOverrides ¶
func ApplyOverrides(km *GlobalKeyMap, overrides map[string]string)
ApplyOverrides remaps keybindings in km according to the overrides map. Keys are action names (e.g. "hey"), values are key strings (e.g. "ctrl+h"). Unknown actions are silently ignored.
func LoadKeyOverrides ¶
LoadKeyOverrides reads keybinding overrides from a JSON file. Returns an empty map (not an error) if the file doesn't exist.
func Navigate ¶
func Navigate(target ViewTarget, scope Scope) tea.Cmd
Navigate returns a command that sends a NavigateMsg.
func NavigateBack ¶
NavigateBack returns a command that sends a NavigateBackMsg.
func ReportError ¶
ReportError returns a command that sends an ErrorMsg.
Types ¶
type AccountInfo ¶
AccountInfo represents a discovered Basecamp account.
type AccountNameMsg ¶
type AccountNameMsg struct {
AccountID string // which account this name belongs to
Name string
Err error
}
AccountNameMsg is sent when the account name is resolved.
type AccountsDiscoveredMsg ¶
type AccountsDiscoveredMsg struct {
Accounts []AccountInfo
Err error
}
AccountsDiscoveredMsg is sent when multi-account discovery completes.
type Action ¶
type Action struct {
Name string
Aliases []string
Description string
Category string // "navigation", "project", "mutation", etc.
Scope ScopeRequirement // what scope context is needed
Available func(Scope) bool // optional; narrows scope check further
Execute func(session *Session) tea.Cmd
}
Action represents a registered command/action in the workspace.
type ActivityEntryInfo ¶
type ActivityEntryInfo = data.ActivityEntryInfo
ActivityEntryInfo is a type alias for data.ActivityEntryInfo.
type AssignmentInfo ¶
type AssignmentInfo = data.AssignmentInfo
AssignmentInfo is a type alias for data.AssignmentInfo.
type BoostCreatedMsg ¶
type BoostCreatedMsg struct {
Target BoostTarget
Emoji string
}
BoostCreatedMsg is sent when a boost has been successfully created. Views can use this to optimistically update their local item counts.
type BoostPicker ¶
type BoostPicker struct {
// contains filtered or unexported fields
}
func NewBoostPicker ¶
func NewBoostPicker(styles *tui.Styles) *BoostPicker
func (*BoostPicker) Blur ¶
func (p *BoostPicker) Blur()
func (*BoostPicker) Focus ¶
func (p *BoostPicker) Focus()
func (*BoostPicker) SetSize ¶
func (p *BoostPicker) SetSize(width, height int)
func (*BoostPicker) Update ¶
func (p *BoostPicker) Update(msg tea.Msg) (*BoostPicker, tea.Cmd)
func (*BoostPicker) View ¶
func (p *BoostPicker) View() string
type BoostSelectedMsg ¶
type BoostSelectedMsg struct {
Emoji string
}
type BoostTarget ¶
type BoostTarget struct {
ProjectID int64
RecordingID int64
AccountID string
Title string // brief context for the picker UI
}
BoostTarget defines the context needed to apply a boost.
type CampfireLineInfo ¶
type CampfireLineInfo = data.CampfireLineInfo
CampfireLineInfo is a type alias for data.CampfireLineInfo.
type CampfireLineSentMsg ¶
type CampfireLineSentMsg struct {
Err error
}
CampfireLineSentMsg is sent after posting a line.
type CampfireLinesLoadedMsg ¶
type CampfireLinesLoadedMsg struct {
Lines []CampfireLineInfo
TotalCount int // total lines available from X-Total-Count
Prepend bool // true when loading older messages (prepend to existing)
Err error
}
CampfireLinesLoadedMsg is sent when campfire lines are fetched.
type CardColumnInfo ¶
type CardColumnInfo = data.CardColumnInfo
CardColumnInfo is a type alias for data.CardColumnInfo.
type CheckinQuestionInfo ¶
type CheckinQuestionInfo = data.CheckinQuestionInfo
CheckinQuestionInfo is a type alias for data.CheckinQuestionInfo.
type ChromeSyncMsg ¶
type ChromeSyncMsg struct{}
ChromeSyncMsg signals the workspace to re-sync chrome (breadcrumb, hints). Emitted by views when their Title() changes dynamically (e.g., folder navigation).
type CommentCreatedMsg ¶
CommentCreatedMsg is sent after a comment is successfully posted.
type ComposeType ¶
type ComposeType int
ComposeType identifies what kind of content is being composed.
const (
ComposeMessage ComposeType = iota
)
type DockLoadedMsg ¶
DockLoadedMsg is sent when a project's dock is loaded.
type DocsFilesItemInfo ¶
type DocsFilesItemInfo = data.DocsFilesItemInfo
DocsFilesItemInfo is a type alias for data.DocsFilesItemInfo.
type EpochMsg ¶
EpochMsg wraps an async result with the session epoch at Cmd creation time. The workspace drops EpochMsgs whose epoch differs from the current session epoch, preventing stale results from a previous account from reaching the active view after an account switch.
type Filterable ¶
type Filterable interface {
StartFilter()
}
Filterable is an optional interface for views with lists that support interactive filtering. When the workspace receives "/" it calls StartFilter on the current view instead of navigating to global search.
type FocusedItemScope ¶
FocusedItemScope holds the account/project/recording context of the currently focused list item. Zero-valued fields mean "unknown/same as the session scope".
type FocusedRecording ¶
type FocusedRecording interface {
FocusedItem() FocusedItemScope
}
FocusedRecording is an optional interface for views that can identify the scope of the currently focused item. Used by open-in-browser to route through the correct account/project.
type GlobalKeyMap ¶
type GlobalKeyMap struct {
Quit key.Binding
Help key.Binding
Back key.Binding
Search key.Binding
Palette key.Binding
AccountSwitch key.Binding
Hey key.Binding
MyStuff key.Binding
Activity key.Binding
Sidebar key.Binding
SidebarFocus key.Binding
Refresh key.Binding
Open key.Binding
Jump key.Binding
Metrics key.Binding
}
GlobalKeyMap defines keybindings that work in every context.
func DefaultGlobalKeyMap ¶
func DefaultGlobalKeyMap() GlobalKeyMap
DefaultGlobalKeyMap returns the default global keybindings.
func (GlobalKeyMap) FullHelp ¶
func (k GlobalKeyMap) FullHelp() [][]key.Binding
FullHelp returns all global key bindings for the help overlay.
func (GlobalKeyMap) ShortHelp ¶
func (k GlobalKeyMap) ShortHelp() []key.Binding
ShortHelp returns the global key bindings for the status bar. The budget-aware renderer in the status bar shows as many as fit.
type HeyEntryInfo ¶
type HeyEntryInfo = data.HeyEntryInfo
HeyEntryInfo is a type alias for data.HeyEntryInfo.
type InputCapturer ¶
type InputCapturer interface {
InputActive() bool
}
InputCapturer is an optional interface views can implement to signal they are in text input mode. When InputActive returns true, the workspace will skip global single-key bindings (q, r, 1-9, etc.) and forward all keys directly to the view.
type ListKeyMap ¶
type ListKeyMap struct {
Up key.Binding
Down key.Binding
Top key.Binding
Bottom key.Binding
PageDown key.Binding
PageUp key.Binding
Open key.Binding
Filter key.Binding
}
ListKeyMap defines keybindings for list navigation.
func DefaultListKeyMap ¶
func DefaultListKeyMap() ListKeyMap
DefaultListKeyMap returns the default list navigation keybindings.
type MessageCreatedMsg ¶
type MessageCreatedMsg struct {
Message MessageInfo
Err error
}
MessageCreatedMsg is sent after a message is successfully posted.
type MessageDetailLoadedMsg ¶
type MessageDetailLoadedMsg struct {
MessageID int64
Subject string
Creator string
CreatedAt string
Category string
Content string // HTML body
Err error
}
MessageDetailLoadedMsg is sent when a single message's full content is fetched.
type MessageInfo ¶
type MessageInfo = data.MessageInfo
MessageInfo is a type alias for data.MessageInfo.
type ModalActive ¶
type ModalActive interface {
IsModal() bool
}
ModalActive is an optional interface views can implement to signal they have an active modal state (e.g., cards move mode, search results focus). When ModalActive returns true, Esc is forwarded to the view instead of triggering global back navigation.
type NavigateBackMsg ¶
type NavigateBackMsg struct{}
NavigateBackMsg requests navigation to the previous view.
type NavigateToDepthMsg ¶
type NavigateToDepthMsg struct {
}
NavigateToDepthMsg jumps to a specific breadcrumb depth.
type OpenBoostPickerMsg ¶
type OpenBoostPickerMsg struct {
Target BoostTarget
}
OpenBoostPickerMsg signals the workspace to open the boost emoji picker for the given target.
type PingRoomInfo ¶
type PingRoomInfo = data.PingRoomInfo
PingRoomInfo is a type alias for data.PingRoomInfo.
type ProjectBookmarkedMsg ¶
ProjectBookmarkedMsg is sent after toggling a project bookmark.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds all registered actions.
func DefaultActions ¶
func DefaultActions() *Registry
DefaultActions returns a registry pre-populated with the standard navigation actions.
func (*Registry) ForScope ¶
ForScope returns actions available for the given scope. Available refines the scope check but does not bypass it.
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router manages the navigation stack with state preservation.
func (*Router) Breadcrumbs ¶
Breadcrumbs returns the title chain for all views in the stack.
func (*Router) CurrentScope ¶
CurrentScope returns the scope of the current view.
func (*Router) CurrentTarget ¶
func (r *Router) CurrentTarget() ViewTarget
CurrentTarget returns the ViewTarget of the current view, or 0 if empty.
func (*Router) Pop ¶
Pop removes and returns the top view from the stack. Returns nil if the stack has one or fewer entries (never pops the root).
func (*Router) PopToDepth ¶
PopToDepth pops entries until the stack is at the given depth. Returns the view at the target depth, or nil if invalid.
type ScheduleEntryInfo ¶
type ScheduleEntryInfo = data.ScheduleEntryInfo
ScheduleEntryInfo is a type alias for data.ScheduleEntryInfo.
type Scope ¶
type Scope struct {
AccountID string
AccountName string
ProjectID int64
ProjectName string
ToolType string // "todoset", "chat", "card_table", "message_board", etc.
ToolID int64
RecordingID int64
RecordingType string
// Ephemeral origin context — meaningful only for the target view, not session state.
// Stripped from session scope during navigate() and restored in the view scope.
OriginView string // source view name ("Activity", "Hey!", "Pulse")
OriginHint string // context ("completed Todo", "needs your attention")
}
Scope represents the current position in the Basecamp hierarchy.
type ScopeRequirement ¶
type ScopeRequirement int
ScopeRequirement defines what scope context an action needs.
const ( // ScopeAny means the action works anywhere. ScopeAny ScopeRequirement = iota // ScopeAccount means the action needs an account selected. ScopeAccount // ScopeProject means the action needs a project selected. ScopeProject )
type SearchResultInfo ¶
type SearchResultInfo = data.SearchResultInfo
SearchResultInfo is a type alias for data.SearchResultInfo.
type SearchResultsMsg ¶
type SearchResultsMsg struct {
Results []SearchResultInfo
Query string
Err error
PartialErr error // non-nil when some accounts failed but results exist
}
SearchResultsMsg is sent when search results arrive.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session holds the active workspace state: auth, SDK access, scope, and styles.
func NewSession ¶
NewSession creates a session from the fully-initialized App.
func NewTestSession ¶
func NewTestSession() *Session
NewTestSession returns a minimal Session for use in external package tests. It provides styles and an empty MultiStore (no accounts discovered), but no app, hub, or recents.
func NewTestSessionWithHub ¶
func NewTestSessionWithHub() *Session
NewTestSessionWithHub returns a test Session that includes a Hub. The Hub's MultiStore has nil SDK, so ClientFor returns nil and Hub mutation methods return an error — but the Hub itself is non-nil, which is enough for key handler tests that exercise the state machine.
func NewTestSessionWithRecents ¶
NewTestSessionWithRecents is like NewTestSession but includes a recents store.
func NewTestSessionWithScope ¶
NewTestSessionWithScope returns a test Session with a Hub and a pre-set scope.
func (*Session) AccountClient ¶
func (s *Session) AccountClient() *basecamp.AccountClient
AccountClient returns the SDK client for the current account. Panics if AccountID is not set — call RequireAccount first. Thread-safe: reads scope under lock.
func (*Session) ConsumeInitialView ¶
func (s *Session) ConsumeInitialView() (ViewTarget, Scope, bool)
ConsumeInitialView returns and clears the deep-link target, if any. Returns (target, scope, true) when a deep-link was set, or (0, {}, false) otherwise.
func (*Session) Context ¶
Context returns the session's cancellable context for SDK operations. Canceled on account switch or shutdown, aborting in-flight requests. Thread-safe: may be called from Cmd goroutines concurrently with ResetContext.
func (*Session) Epoch ¶
Epoch returns the session's monotonic epoch counter. Incremented on every account switch; used by the workspace to discard stale async results that were initiated under a previous account. Thread-safe: may be called from Cmd goroutines.
func (*Session) HasAccount ¶
HasAccount returns true if an account is selected. Thread-safe: may be called from Cmd goroutines.
func (*Session) MultiStore ¶
func (s *Session) MultiStore() *data.MultiStore
MultiStore returns the cross-account data layer.
func (*Session) ReloadTheme ¶ added in v0.2.0
func (s *Session) ReloadTheme()
ReloadTheme re-reads the theme from disk and updates the shared Styles in place. All components holding *Styles see new colors on the next render.
func (*Session) ResetContext ¶
func (s *Session) ResetContext()
ResetContext cancels the current context (aborting in-flight operations), creates a fresh one, and advances the epoch counter. Called on account switch.
func (*Session) Scope ¶
Scope returns the current scope. Thread-safe: may be called from Cmd goroutines.
func (*Session) SetInitialView ¶
func (s *Session) SetInitialView(target ViewTarget, scope Scope)
SetInitialView configures a deep-link target to navigate to on startup instead of Home. Called from the tui command when a URL argument is provided.
type SplitPaneFocuser ¶
type SplitPaneFocuser interface {
HasSplitPane() bool
}
SplitPaneFocuser is an optional interface for views that use a split-pane layout with internal tab-cycling. When the sidebar is open, the workspace routes tab to the view instead of consuming it for sidebar focus switching.
type StatusClearMsg ¶
type StatusClearMsg struct {
Gen uint64
}
StatusClearMsg clears an expired status message.
type ThemeChangedMsg ¶ added in v0.2.0
type ThemeChangedMsg struct{}
ThemeChangedMsg signals that the theme file changed on disk.
type TimelineEventInfo ¶
type TimelineEventInfo = data.TimelineEventInfo
TimelineEventInfo is a type alias for data.TimelineEventInfo.
type TodoCreatedMsg ¶
TodoCreatedMsg is sent after a todo is created.
type TodolistInfo ¶
type TodolistInfo = data.TodolistInfo
TodolistInfo is a type alias for data.TodolistInfo.
type TogglePaletteMsg ¶
type TogglePaletteMsg struct{}
TogglePaletteMsg toggles the command palette.
type View ¶
type View interface {
tea.Model
// Title returns the breadcrumb segment for this view.
Title() string
// ShortHelp returns key bindings shown in the status bar.
ShortHelp() []key.Binding
// FullHelp returns all key bindings for the help overlay.
FullHelp() [][]key.Binding
// SetSize updates the view's available dimensions.
SetSize(width, height int)
}
View is the interface that all workspace views must implement.
type ViewFactory ¶
type ViewFactory func(target ViewTarget, session *Session, scope Scope) View
ViewFactory creates views for navigation targets.
type ViewTarget ¶
type ViewTarget int
ViewTarget identifies which view to navigate to.
const ( ViewProjects ViewTarget = iota ViewDock ViewTodos ViewCampfire ViewHey ViewCards ViewMessages ViewSearch ViewMyStuff ViewPeople ViewDetail ViewSchedule ViewDocsFiles ViewCheckins ViewForwards ViewPulse ViewAssignments ViewPings ViewCompose ViewHome ViewActivity ViewTimeline // project-scoped timeline )
func (ViewTarget) IsGlobal ¶
func (t ViewTarget) IsGlobal() bool
IsGlobal returns true for view targets that aggregate across all accounts.
type Workspace ¶
type Workspace struct {
// contains filtered or unexported fields
}
Workspace is the root tea.Model for the persistent TUI application.
func New ¶
func New(session *Session, factory ViewFactory) *Workspace
New creates a new Workspace model.
func (*Workspace) CloseWatcher ¶ added in v0.2.0
func (w *Workspace) CloseWatcher()
CloseWatcher shuts down the theme file watcher, if running. Safe to call multiple times.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package chrome provides always-visible shell components for the workspace.
|
Package chrome provides always-visible shell components for the workspace. |
|
Package views provides the individual screens for the workspace TUI.
|
Package views provides the individual screens for the workspace TUI. |
|
Package widget provides reusable TUI components.
|
Package widget provides reusable TUI components. |