Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
7.6 KiB
Keyboard Shortcuts
Alga PSA ships a system-wide keyboard shortcut engine active on all MSP pages
(/msp). Shortcuts are grouped by scope: global shortcuts fire anywhere;
page shortcuts fire on the current page; panel/dialog shortcuts fire
when a drawer or dialog is open and take priority over page shortcuts.
Opening the Command Palette
Press Mod+K (⌘K on macOS, Ctrl+K on Windows/Linux) to open the command
palette. The palette merges navigation destinations, runnable shortcut actions,
and full record search into one keyboard-driven overlay. From here you can:
- Navigate to any page by typing its name (e.g.
tickets,schedule). - Search records across clients, tickets, contacts, projects, assets, and more.
- Run an action by prefixing
>(e.g.>create ticket). - Open a record by ID with
#(e.g.#1042). - Narrow by type using field scopes:
ticket:,client:,project:,asset:,contact:,user:/@name,nav://path. - Magic keywords:
$mine,$recent,$open(abbreviate to first syllable:$m,$rec,$op). - Operators: double-quoted phrases (
status:"in progress"),-/NOTexclusion,*and?wildcards, fuzzyterm~.
Discovering Shortcuts
Press ? on any MSP page (when not focused in a text field) to open the
shortcut help dialog. It lists every shortcut active in the current
context, grouped by scope, resolved for the user's operating system, and with
personalized bindings flagged.
Shortcuts are also surfaced as visible kbd hints rendered next to
instrumented controls (search field, primary action buttons, relevant menu
items). These hints use OS-native glyph notation (⌘/⌥/⇧/⌃ on macOS;
Ctrl/Alt/Shift on Windows/Linux). The aria-keyshortcuts attribute is set on
instrumented controls for screen readers.
Default Shortcut Reference
Global (fire anywhere in /msp)
| Action | macOS | Windows / Linux |
|---|---|---|
| Open command palette | ⌘K | Ctrl+K |
| Open shortcut help dialog | ? | ? |
| Quick-create dialog (multi-type) | N | N |
Navigation sequences
Press the first key, then the second key within ≈1 second. Sequences are suppressed while any input, textarea, rich-text editor, or combobox is focused, and reset on route change.
| Sequence | Destination |
|---|---|
| G → T | Tickets |
| G → C | Clients |
| G → P | Projects |
| G → A | Assets |
| G → S | Schedule |
| G → H | Dashboard (Home) |
Page-level (fire when the matching page is active)
| Action | Key |
|---|---|
| Open current page's create dialog | C |
| Save current page | ⌘S / Ctrl+S |
| Navigate to previous record | [ |
| Navigate to next record | ] |
C and N are suppressed while any editable target is focused and while a
dialog or drawer owns scope.
Panel / dialog scope
When a drawer or modal dialog is open it captures Escape (close/cancel) and
[/] (previous/next record within the panel). Global and page shortcuts do
not fire while a panel-scope owner is active.
Customizing Shortcuts
Navigate to Profile → Keyboard Shortcuts to manage personal bindings.
| Control | Effect |
|---|---|
| Click the binding chip for any action | Capture a new key combination |
| Toggle Enabled switch | Disable the shortcut without losing the binding |
| Reset icon on a row | Restore that action's default binding |
| Reset all button (confirmation required) | Clear all personal overrides |
Conflict detection runs before commit: if the captured key is already claimed by another action, the UI prompts for confirmation; the previous owner is unbound and the new binding takes effect.
Custom bindings are stored per user account and sync across devices. A binding
authored on macOS (e.g. mod+J) resolves automatically to Ctrl+J on
Windows/Linux; non-portable combos surface a non-blocking advisory on sign-in
from the other OS.
Shortcut Profiles
Three preset profiles are available from the Keyboard Shortcuts panel:
| Profile | Description |
|---|---|
| Default | Standard bindings optimized for MSP workflows |
| Vim | j/k list navigation and Vim-style action keys |
| Emacs | Emacs-inspired modifier-based bindings |
Selecting a profile applies its preset as the binding baseline. Per-action overrides stack on top of any profile. Per-action reset returns to the active profile's baseline (not the factory default).
Scope and Priority Rules
The dispatcher picks the highest-priority registered action that matches the event's active scope set:
- Dialog / panel — highest priority; owns
Escapeand record-nav keys. - Editor —
editor-scoped shortcuts (invoice designer, workflow designer, rich-text) override page shortcuts. - Page — page-scoped shortcuts fire when the registered page is active.
- Global / shell — lowest priority; fire regardless of current page.
When the same key maps to two actions in the same scope at the same priority, the conflict is reported in the settings panel and help dialog (it does not silently pick one).
Single-letter shortcuts (C, N, j, k) are always suppressed inside
<input>, <textarea>, <select>, contenteditable, and ARIA text/combobox
roots unless the action explicitly sets allowInEditable.
Architecture Overview
The engine lives in packages/ui/src/keyboard-shortcuts/ and has no imports
of @alga-psa/user-composition or any feature package — dependency direction
is enforced by a CI boundary guard (scripts/guard-keyboard-shortcuts-*.mjs
and eslint-plugin-custom-rules).
| Path | Role |
|---|---|
packages/ui/src/keyboard-shortcuts/provider.tsx |
Single delegated capture-phase keydown listener; dispatch loop |
packages/ui/src/keyboard-shortcuts/catalog.ts |
Single source of truth for action metadata (ids, default bindings, scope, priority) |
packages/ui/src/keyboard-shortcuts/parser.ts |
parseBinding / parseSequence — dual event.code + event.key matching, mod resolution |
packages/ui/src/keyboard-shortcuts/preferences.ts |
ShortcutStorage adapter interface + preference resolution (user override → profile delta → platform default) |
packages/ui/src/keyboard-shortcuts/ShortcutHintHud.tsx |
<Kbd> / ShortcutHint component rendering OS-native glyphs |
packages/ui/src/keyboard-shortcuts/command-palette-query.ts |
Command palette query parser (TeamCity-style field scopes + operators) |
server/src/components/settings/general/KeyboardShortcutsPanel.tsx |
Profile → Keyboard Shortcuts settings UI |
The provider is mounted in MspLayoutClient.tsx (wraps DefaultLayout and
AlgaDeskMspShell). It does not mount on auth or client-portal pages.
Persistence uses the existing user_preferences table via useUserPreference
(key keyboard_shortcuts_v1); no new tables or API endpoints. The stored blob
is a versioned delta ({ version, bindings, disabled, profile }), using
platform-neutral syntax (mod+k), with a v1 → v2 migration that adds the
profile field defaulting to 'default'.
Coverage and Non-Goals (v1)
The shortcut engine covers all routes under /msp. The following are
deliberately out of scope for the initial release:
- Auth screens and the client portal.
- Tenant-level shortcut defaults or admin lock-down.
- Export / import of personal override sets.
- Browser-owned combos (
mod+R,mod+F,mod+P,mod+W,mod+T,mod+N) are not overridden. - Component-local widget key handling (DatePicker, SearchableSelect, TagInput, Radix internals) retains its local handlers unchanged.