Wassup is a scriptable terminal dashboard that creates real-time, interactive displays of data from various sources. Configure panes and content logic in a Supfile
and then run wassup
to launch your customized dashboard.
- ๐ Multi-pane dashboard with flexible grid layout
- ๐ Real-time updates with configurable refresh intervals
- โจ๏ธ Interactive navigation with keyboard controls
- ๐จ Color-coded display with alert levels
- ๐ Built-in integrations for GitHub, CircleCI, Netlify, and Shortcut
- ๐ Multi-page content within individual panes
- ๐ก๏ธ Rate limiting for API calls
- ๐ง Debug mode for testing configurations
- โก Performance optimizations with battery-conscious updates
wassup-demo.mov
add_pane do |pane|
pane.height = 0.5
pane.width = 0.5
pane.top = 0
pane.left = 0
pane.title = "Current Time"
pane.interval = 1
pane.content do |content|
content.add_row(`date`)
end
end
add_pane do |pane|
pane.height = 0.5
pane.width = 0.5
pane.top = 0
pane.left = 0
pane.title = "GitHub PRs"
pane.highlight = true
pane.interval = 60 * 5
pane.type = Panes::GitHub::PullRequests.new(
org: 'fastlane',
repo: 'fastlane',
show_username: true,
show_interactions: true
)
end
require 'json'
require 'rest-client'
add_pane do |pane|
pane.height = 0.5
pane.width = 0.5
pane.top = 0
pane.left = 0
pane.highlight = true
pane.title = "Open PRs - fastlane/fastlane"
pane.interval = 60 * 5
pane.content do |content|
resp = RestClient.get "https://api.github.com/repos/fastlane/fastlane/pulls"
json = JSON.parse(resp)
json.each do |pr|
display = "##{pr["number"]} #{pr["title"]}"
content.add_row(display, pr["html_url"])
end
end
pane.selection do |url|
`open #{url}`
end
end
Add this line to your application's Gemfile:
gem 'wassup'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install wassup
Monitor pull requests, releases, and search results across your repositories.
# Pull Requests
pane.type = Panes::GitHub::PullRequests.new(
org: 'organization',
repo: 'repository',
show_username: true, # Show PR author
show_interactions: true # Show comments/reactions
)
# Releases
pane.type = Panes::GitHub::Releases.new(
org: 'organization',
repo: 'repository'
)
# Search
pane.type = Panes::GitHub::Search.new(
org: 'organization',
repo: 'repository', # Optional - searches all org repos if nil
query: 'is:pr is:open', # GitHub search query
show_repo: true, # Show repository name
show_username: true, # Show author
show_interactions: true # Show interaction counts
)
Monitor workflow status across your projects.
pane.type = Panes::CircleCI::Workflows.new(
vcs: 'github',
org: 'organization',
repo: 'repository'
)
Track deployment status for your sites.
pane.type = Panes::Netlify::Deploys.new(
site_id: 'your-netlify-site-id'
)
Monitor stories and tasks in your project management.
# Single query
pane.type = Panes::Shortcut::Stories.new(
query: 'owner:username'
)
# Multiple queries as pages
pane.type = Panes::Shortcut::Stories.new(
query_pages: {
"My Stories": "owner:username",
"Team Stories": "team:development",
"In Progress": "state:\"In Progress\""
}
)
Property | Type | Description |
---|---|---|
height |
Float | Height as percentage of terminal (0.0 to 1.0) |
width |
Float | Width as percentage of terminal (0.0 to 1.0) |
top |
Float | Top position as percentage (0.0 to 1.0) |
left |
Float | Left position as percentage (0.0 to 1.0) |
title |
String | Pane title displayed in border |
description |
String | Description shown in help mode |
highlight |
Boolean | Enable row highlighting and selection |
interval |
Integer/Float | Refresh interval in seconds |
show_refresh |
Boolean | Show refresh animation |
alert_level |
AlertLevel | Alert level for visual emphasis |
pane.alert_level = AlertLevel::HIGH # Red - Critical alerts
pane.alert_level = AlertLevel::MEDIUM # Yellow - Warnings
pane.alert_level = AlertLevel::LOW # Cyan - Information
pane.content do |content|
# Add rows to display
content.add_row("Display text", data_object)
# Add rows to specific pages
content.add_row("Page 1 content", data, page: "Page 1")
content.add_row("Page 2 content", data, page: "Page 2")
# Color-coded text
content.add_row("[fg=red]Error[fg=white] - [fg=green]Success")
end
# Define selection actions
pane.selection do |selected_data|
# Default action (Enter key)
`open #{selected_data['url']}`
end
pane.selection('o', 'Open in browser') do |data|
`open #{data['html_url']}`
end
pane.selection('c', 'Copy to clipboard') do |data|
`echo '#{data['title']}' | pbcopy`
end
# GitHub integration
export WASSUP_GITHUB_USERNAME="your-username"
export WASSUP_GITHUB_ACCESS_TOKEN="your-personal-access-token"
# CircleCI integration
export WASSUP_CIRCLE_CI_API_TOKEN="your-circleci-token"
# Netlify integration
export WASSUP_NETLIFY_TOKEN="your-netlify-token"
# Shortcut integration
export WASSUP_SHORTCUT_TOKEN="your-shortcut-token"
- Go to GitHub Settings โ Developer settings โ Personal access tokens
- Generate a new token with these scopes:
repo
- Full control of private repositoriespublic_repo
- Access public repositoriesuser
- Read user profile data
Key | Action |
---|---|
1-9 |
Focus specific panes |
j/k |
Move selection up/down |
h/l |
Navigate between pages |
Enter |
Execute selection action |
r |
Force refresh current pane |
? |
Show help |
q |
Quit |
c |
Copy error to clipboard (when error occurs) |
# Run with default Supfile
wassup
# Run with custom file
wassup MySupfile
# Debug mode to test individual panes
wassup --debug
# Run with socket port for external monitoring
wassup Supfile 8080
# Top row - GitHub PRs and Releases
add_pane do |pane|
pane.height = 0.5; pane.width = 0.5; pane.top = 0; pane.left = 0
pane.title = "GitHub PRs"
pane.type = Panes::GitHub::PullRequests.new(org: 'myorg', repo: 'myrepo')
end
add_pane do |pane|
pane.height = 0.5; pane.width = 0.5; pane.top = 0; pane.left = 0.5
pane.title = "Releases"
pane.type = Panes::GitHub::Releases.new(org: 'myorg', repo: 'myrepo')
end
# Bottom row - CircleCI and custom content
add_pane do |pane|
pane.height = 0.5; pane.width = 0.5; pane.top = 0.5; pane.left = 0
pane.title = "CI Status"
pane.type = Panes::CircleCI::Workflows.new(vcs: 'github', org: 'myorg', repo: 'myrepo')
end
add_pane do |pane|
pane.height = 0.5; pane.width = 0.5; pane.top = 0.5; pane.left = 0.5
pane.title = "System Status"
pane.interval = 30
pane.content do |content|
uptime = `uptime`.strip
load_avg = uptime.match(/load average: (.+)$/)[1]
content.add_row("Load: #{load_avg}")
content.add_row("Uptime: #{uptime}")
end
end
add_pane do |pane|
pane.height = 1.0; pane.width = 1.0; pane.top = 0; pane.left = 0
pane.title = "Multi-page Dashboard"
pane.highlight = true
pane.interval = 60
pane.content do |content|
# GitHub PRs page
github_prs = fetch_github_prs()
github_prs.each do |pr|
content.add_row("##{pr['number']} #{pr['title']}", pr, page: "GitHub PRs")
end
# CircleCI page
workflows = fetch_circleci_workflows()
workflows.each do |workflow|
content.add_row("#{workflow['name']} - #{workflow['status']}", workflow, page: "CircleCI")
end
# System metrics page
content.add_row("CPU: #{`top -l 1 | grep "CPU usage"`}", nil, page: "System")
content.add_row("Memory: #{`top -l 1 | grep "PhysMem"`}", nil, page: "System")
end
end
add_pane do |pane|
pane.height = 0.5; pane.width = 1.0; pane.top = 0; pane.left = 0
pane.title = "Service Status"
pane.interval = 60
pane.alert_level = AlertLevel::HIGH
pane.content do |content|
begin
services = check_services()
services.each do |service|
status_color = service[:status] == 'up' ? 'green' : 'red'
content.add_row("[fg=#{status_color}]#{service[:name]}: #{service[:status]}")
end
rescue => e
content.add_row("[fg=red]Error: #{e.message}")
end
end
end
GitHub API has rate limits. Wassup includes built-in rate limiting:
- Authenticated requests: 5,000 per hour
- Search API: 30 requests per minute
- Rate limit information is displayed in debug mode
# Check if your tokens are set correctly
echo $WASSUP_GITHUB_ACCESS_TOKEN
echo $WASSUP_GITHUB_USERNAME
# Test token validity
curl -H "Authorization: token $WASSUP_GITHUB_ACCESS_TOKEN" https://api.github.com/user
Wassup requires a minimum terminal size. If panes appear corrupted:
- Resize your terminal window
- Press
r
to refresh the display - Check that your pane dimensions don't exceed 1.0
Use debug mode to test individual panes:
wassup --debug
This will:
- Show detailed error messages
- Display API rate limit information
- Allow testing panes in isolation
Wassup includes battery-conscious updates:
- Longer refresh intervals when on battery power
- Reduced API calls during low battery
- Configurable performance settings
For large datasets:
- Use pagination in your content blocks
- Limit the number of rows returned
- Consider using shorter refresh intervals for critical data only
git clone https://github.com/joshdholtz/wassup.git
cd wassup
bin/setup
rake spec
bin/console
# Install locally
bundle exec rake install
# Release new version
bundle exec rake release
- Create a new class in
lib/wassup/panes/
- Inherit from
Wassup::Pane
- Implement the required methods:
content
- Returns the pane contentselection
- Handles selection actions
Example:
module Wassup
module Panes
module MyService
class MyPane < Wassup::Pane
def initialize(api_key:)
@api_key = api_key
end
def content
# Fetch and return content
end
def selection(data)
# Handle selection
end
end
end
end
end
We welcome contributions! Please see our Contributing Guide for details.
- Bug Reports - Found a bug? Open an issue
- Feature Requests - Have an idea? Start a discussion
- Code Contributions - Submit a pull request
- Documentation - Help improve our docs
- New Integrations - Add support for new services
- Follow existing code style and patterns
- Add tests for new features
- Update documentation for new functionality
- Ensure all tests pass before submitting PR
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the Wassup project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.