Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt

Use this file to discover all available pages before exploring further.

Using the command palette

Open the command palette with Cmd+K on macOS or Ctrl+K on Windows and Linux. It opens from any page.
  • Type to filter commands by name
  • Arrow keys to navigate between results
  • Enter to execute the selected command
  • Escape to close
The palette is permission-aware: commands the current user does not have access to are not shown. An admin user sees the Admin and Users commands; a regular member does not.

Available commands

CommandGroupRequired permission
DashboardNavigationNone
BillingNavigationtenant.billing.read
SettingsNavigationtenant.settings.read
MembersNavigationtenant.members.read
ProfileNavigationNone
Admin DashboardNavigationis_admin
Admin UsersNavigationis_admin
Admin TenantsNavigationis_admin
Invite MemberActionstenant.members.invite
Switch WorkspaceActionsNone (user must have multiple tenants)
Manage BillingActionstenant.billing.manage
Sign OutActionsNone
Switch to LightThemeNone
Switch to DarkThemeNone
Use System ThemeThemeNone

Adding a navigation command

// frontend/src/components/command-palette/CommandPalette.tsx

// Navigation commands are in the navigationCommands array.
// Add your new command:
{
  id: 'nav-projects',
  label: 'Projects',
  group: 'Navigation',
  icon: FolderOpen,       // from lucide-react
  requiredPermission: Permissions.TenantProjectsRead,  // omit if no permission needed
  action: () => navigate('/projects'),
},

Adding a permission-gated action command

// Action commands with a required permission:
{
  id: 'action-create-project',
  label: 'Create Project',
  group: 'Actions',
  icon: Plus,
  requiredPermission: Permissions.TenantProjectsManage,
  action: () => {
    setCreateProjectModalOpen(true);
    closeCommandPalette();
  },
},
The requiredPermission field is checked against the current user’s JWT permissions. If the user does not have the permission, the command is filtered out before the list renders.

Adding a command that opens a modal

{
  id: 'action-invite-member',
  label: 'Invite Member',
  group: 'Actions',
  icon: UserPlus,
  requiredPermission: Permissions.TenantMembersInvite,
  action: () => {
    // Close the palette first, then open the modal.
    // Opening both simultaneously causes focus trap conflicts.
    closeCommandPalette();
    setTimeout(() => setInviteModalOpen(true), 50);
  },
},

Customizing the keyboard shortcut

The shortcut is set in CommandPalette.tsx in the useEffect that registers the keydown listener:
useEffect(() => {
  const down = (e: KeyboardEvent) => {
    if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
      e.preventDefault();
      setOpen((open) => !open);
    }
  };
  document.addEventListener('keydown', down);
  return () => document.removeEventListener('keydown', down);
}, []);
To change to Cmd+P / Ctrl+P:
if (e.key === 'p' && (e.metaKey || e.ctrlKey)) {

Adding command groups

Commands are grouped by their group property. Groups appear as headings in the palette. To add a new group:
// Just set a new group name on your command object.
// The palette renders groups automatically — no group registration needed.
{
  id: 'projects-create',
  label: 'New Project',
  group: 'Projects',    // new group — renders as "Projects" heading
  icon: Plus,
  action: () => navigate('/projects/new'),
},
Groups appear in the order their first command appears in the allCommands array. Put frequently used groups (Navigation, Actions) at the top of the array.