Convenient, unobtrusive, dev-oriented Rails engine that allows you to run custom actions and quick admin tasks through a floating panel without opening the Rails console.
Define panels/tabs/actions with a minimal class-based DSL. Each action can declare parameters (text, boolean, number, selector), run Ruby code, and return a JSON result shown in the UI.
Add the gem to your application:
# Gemfile (development and test recommended for Sorbet/Tapioca)
group :development, :test do
gem 'command_deck'
endMount the engine:
# config/routes.rb
mount CommandDeck::Engine => '/command_deck' if defined?(CommandDeck::Engine)Enable it in your development environment:
# .env.development.local (or your environment config)
COMMAND_DECK_ENABLED=trueThat's it! The gem automatically:
- Discovers panel files in
app/command_deck/**/*.rbandpacks/**/command_deck/**/*.rb - Adds them to autoload paths
- Inserts middleware when
COMMAND_DECK_ENABLED=truein development - Stays completely inactive in production
Create panel classes anywhere under a command_deck directory. Use descriptive namespaces:
# app/command_deck/panels/utilities.rb
module CommandDeck::Panels
class Utilities < CommandDeck::BasePanel
panel 'Utilities' do
tab 'Demo' do
action 'Greet', key: 'utils.greet' do
param :name, :string, label: 'Your name', required: true
perform do |p, _ctx|
{ message: "Hello, #{p[:name]}!" }
end
end
action 'Pick a Color', key: 'utils.color' do
# You can pass simple arrays, pairs, or hashes as choices
param :color, :selector,
options: [
['Red', 'red'],
['Green', 'green'],
['Blue', 'blue']
],
include_blank: true
perform do |p, _ctx|
{ chosen: p[:color] }
end
end
action 'Update Setting', key: 'utils.update_setting' do
# Selector with current values in meta
param :setting_name, :selector,
collection: -> {
# Example: fetch settings with current values
[
{ label: 'Max Users (100)', value: 'max_users', meta: { value: 100 } },
{ label: 'Timeout (30)', value: 'timeout', meta: { value: 30 } }
]
}
# Auto-populate this input with the value from meta
param :new_value, :string, required: true, auto_populate: true
perform do |p, _ctx|
# Update the setting with new value
{ ok: true, setting: p[:setting_name], new_value: p[:new_value] }
end
end
end
end
end
endYou can organize panels within your packs:
# packs/dev_tools/command_deck/panels/database.rb
module DevTools::Panels
class Database < CommandDeck::BasePanel
panel 'Database Tools' do
tab 'Maintenance' do
action 'Rebuild Cache', key: 'db.rebuild_cache' do
perform do |_p, _ctx|
Rails.cache.clear
{ ok: true, message: 'Cache cleared' }
end
end
end
end
end
endThe gem auto-discovers panels in any command_deck directory under your app or packs. Use namespaces that match your project structure.
Panels inherit from CommandDeck::BasePanel. Define tabs within a panel:
tab(title) { ... }Define actions within a tab:
action(title, key:) { ... }Declare params and execution logic within an action:
param(name, type, **opts)
perform { |params, ctx| ... }Supported param types:
:string– free text input.:boolean– checkbox; coerces to true/false.:integer– number input; coerces to Integer or nil when blank.:selector– dropdown. See options below.
Common param options:
label:String – UI label. Defaults to a humanizedname.required:true/false – disables Run button until filled. Default: false.auto_populate:true/false – for text/number inputs, automatically populate with value from previous selector'smeta: { value: ... }. Default: false.
Selector-specific options:
options:Enumerable – static choices.collection:-> Enumerable – dynamic choices (block is called each render).include_blank:true/false – prepend an empty choice. Default: false.return::value(default),:label, or:both({ label:, value: }).- Choice shapes accepted:
- Values:
%w[a b c] - Pairs:
[['Label A', 'a'], ['Label B', 'b']] - Objects:
{ label:, value:, meta?: { ... } }
- Values:
The perform block receives coerced params and a context hash. Return any JSON-serializable object (Hash recommended).
Intended for development only. DO NOT ENABLE IN PRODUCTION.
Run tests and lint:
bundle install
bundle exec rake test
bundle exec rubocopMIT License. See LICENSE.txt.
Everyone interacting in this project is expected to follow the Code of Conduct.