Linear/Notion-style
⌘K/Ctrl+Kpalette for Perfex CRM. Fuzzy-search anything, jump anywhere, create anything — without leaving your keyboard.
Press ⌘K (or Ctrl+K). Type. Hit Enter. That's it.
A keyboard-driven launcher that searches across:
- Clients (company, VAT)
- Invoices (number, prefix, client)
- Estimates (number, prefix, client)
- Projects (name, client)
- Tasks (name)
- Tickets (subject, ticket key)
- Leads (name, company, email)
- Contracts (subject, client)
- Expenses (name, note)
Plus quick-create actions: new invoice, new estimate, new client, new project, new task, new lead, new ticket, new expense, and jumps to dashboard / reports / settings.
Recent items are tracked in localStorage and shown when you open the palette with an empty query.
- Speed: hitting "Invoices → list → filter → find INV-001234" is 6 clicks.
⌘K, type1234, Enter is 4 keystrokes. - Discovery: new staff members find features they didn't know existed.
- Muscle memory: it works the way every modern app works (Linear, Notion, GitHub, Slack, VS Code).
- Zero footprint: no menu entry, no setup, no external API. Just a keyboard shortcut.
- Copy the
command_palette/folder into<perfex-root>/modules/. - Setup → Modules → activate Command Palette.
- Press
⌘K(macOS) orCtrl+K(Windows/Linux) from any admin page.
That's the whole installation. No DB migration, no permissions setup, no config.
app_admin_footerhook injects the palette HTML +command_palette.js+command_palette.cssinto every admin page.- The JS listens for
⌘K/Ctrl+Kglobally, opens the modal, and proxies queries to/admin/command_palette/search?q=…(debounced 130 ms, AbortController for in-flight cancellation). - The PHP controller runs ~9
LIKEqueries withLIMIT 5-8each → typically under 30 ms on a populated CRM. - Results are flat-rendered with highlight of the matched substring. Arrow keys to navigate, Enter to open.
If you use perfex-multi-entity, search results are automatically scoped by the listing hooks — staff only see records from entities they have access to. No extra config needed.
Two filter hooks let any custom module plug in:
// Add custom quick actions (always shown when palette is empty / matched by keyword)
hooks()->add_filter('cmdpal_extra_actions', function ($actions) {
$actions[] = [
'type' => 'action',
'icon' => 'fa-solid fa-bolt',
'label'=> 'My custom action',
'sub' => '',
'url' => admin_url('my_module/do_thing'),
];
return $actions;
});
// Add custom live search results
hooks()->add_filter('cmdpal_extra_results', function ($results, $query) {
$rows = get_instance()->db->like('name', $query)->limit(5)->get('tblmy_thing')->result_array();
foreach ($rows as $r) {
$results[] = [
'type' => 'mything',
'icon' => 'fa-solid fa-cube',
'label'=> $r['name'],
'sub' => 'My thing',
'url' => admin_url('my_module/view/' . $r['id']),
];
}
return $results;
}, 10, 2);- Configurable keyboard shortcut — v1.1 (Cmd+K, Cmd+P, Alt+K, Alt+Space, Ctrl+Space)
- Search inside invoice line items, project notes, ticket replies — v1.1
- Custom actions defined by other modules via a hook — v1.1
- Recently viewed records synced server-side — v1.1 (DB table
tblcmdpal_recent, per-staff)