Skip to content

Commit cee7134

Browse files
committed
feat: enhance project-specific slash commands management
- Add scopeFilter prop to SlashCommandsManager for filtering by scope - Replace browser confirm() with proper delete confirmation dialog - Fix slash_command_delete to handle project commands with project_path param - Add Slash Commands tab to ProjectSettings as the default tab - Add Commands button to ClaudeCodeSession for quick access - Improve error handling and user feedback for delete operations - Better UI text when showing project-specific commands only
1 parent e6662bf commit cee7134

5 files changed

Lines changed: 213 additions & 46 deletions

File tree

src-tauri/src/commands/slash_commands.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,25 @@ pub async fn slash_command_save(
416416

417417
/// Delete a slash command
418418
#[tauri::command]
419-
pub async fn slash_command_delete(command_id: String) -> Result<String, String> {
419+
pub async fn slash_command_delete(command_id: String, project_path: Option<String>) -> Result<String, String> {
420420
info!("Deleting slash command: {}", command_id);
421421

422-
// Get the command to find its file path
423-
let command = slash_command_get(command_id.clone()).await?;
422+
// First, we need to determine if this is a project command by parsing the ID
423+
let is_project_command = command_id.starts_with("project-");
424+
425+
// If it's a project command and we don't have a project path, error out
426+
if is_project_command && project_path.is_none() {
427+
return Err("Project path required to delete project commands".to_string());
428+
}
429+
430+
// List all commands (including project commands if applicable)
431+
let commands = slash_commands_list(project_path).await?;
432+
433+
// Find the command by ID
434+
let command = commands
435+
.into_iter()
436+
.find(|cmd| cmd.id == command_id)
437+
.ok_or_else(|| format!("Command not found: {}", command_id))?;
424438

425439
// Delete the file
426440
fs::remove_file(&command.file_path)

src/components/ClaudeCodeSession.tsx

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
Settings,
1111
ChevronUp,
1212
X,
13-
Hash
13+
Hash,
14+
Command
1415
} from "lucide-react";
1516
import { Button } from "@/components/ui/button";
1617
import { Input } from "@/components/ui/input";
@@ -25,6 +26,7 @@ import { FloatingPromptInput, type FloatingPromptInputRef } from "./FloatingProm
2526
import { ErrorBoundary } from "./ErrorBoundary";
2627
import { TimelineNavigator } from "./TimelineNavigator";
2728
import { CheckpointSettings } from "./CheckpointSettings";
29+
import { SlashCommandsManager } from "./SlashCommandsManager";
2830
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
2931
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
3032
import { SplitPane } from "@/components/ui/split-pane";
@@ -87,6 +89,7 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
8789
const [timelineVersion, setTimelineVersion] = useState(0);
8890
const [showSettings, setShowSettings] = useState(false);
8991
const [showForkDialog, setShowForkDialog] = useState(false);
92+
const [showSlashCommandsSettings, setShowSlashCommandsSettings] = useState(false);
9093
const [forkCheckpointId, setForkCheckpointId] = useState<string | null>(null);
9194
const [forkSessionName, setForkSessionName] = useState("");
9295

@@ -995,6 +998,17 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
995998
Hooks
996999
</Button>
9971000
)}
1001+
{projectPath && (
1002+
<Button
1003+
variant="outline"
1004+
size="sm"
1005+
onClick={() => setShowSlashCommandsSettings(true)}
1006+
disabled={isLoading}
1007+
>
1008+
<Command className="h-4 w-4 mr-2" />
1009+
Commands
1010+
</Button>
1011+
)}
9981012
<div className="flex items-center gap-2">
9991013
{showSettings && (
10001014
<CheckpointSettings
@@ -1386,6 +1400,23 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
13861400
</DialogContent>
13871401
</Dialog>
13881402
)}
1403+
1404+
{/* Slash Commands Settings Dialog */}
1405+
{showSlashCommandsSettings && (
1406+
<Dialog open={showSlashCommandsSettings} onOpenChange={setShowSlashCommandsSettings}>
1407+
<DialogContent className="max-w-4xl max-h-[80vh] overflow-hidden">
1408+
<DialogHeader>
1409+
<DialogTitle>Slash Commands</DialogTitle>
1410+
<DialogDescription>
1411+
Manage project-specific slash commands for {projectPath}
1412+
</DialogDescription>
1413+
</DialogHeader>
1414+
<div className="flex-1 overflow-y-auto">
1415+
<SlashCommandsManager projectPath={projectPath} />
1416+
</div>
1417+
</DialogContent>
1418+
</Dialog>
1419+
)}
13891420
</div>
13901421
);
13911422
};

src/components/ProjectSettings.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44

55
import React, { useState, useEffect } from 'react';
66
import { HooksEditor } from '@/components/HooksEditor';
7+
import { SlashCommandsManager } from '@/components/SlashCommandsManager';
78
import { api } from '@/lib/api';
89
import {
910
AlertTriangle,
1011
ArrowLeft,
1112
Settings,
1213
FolderOpen,
1314
GitBranch,
14-
Shield
15+
Shield,
16+
Command
1517
} from 'lucide-react';
1618
import { Button } from '@/components/ui/button';
1719
import { Card } from '@/components/ui/card';
@@ -31,7 +33,7 @@ export const ProjectSettings: React.FC<ProjectSettingsProps> = ({
3133
onBack,
3234
className
3335
}) => {
34-
const [activeTab, setActiveTab] = useState('project');
36+
const [activeTab, setActiveTab] = useState('commands');
3537
const [toast, setToast] = useState<{ message: string; type: 'success' | 'error' } | null>(null);
3638

3739
// Other hooks settings
@@ -88,7 +90,7 @@ export const ProjectSettings: React.FC<ProjectSettingsProps> = ({
8890
</Button>
8991
<div className="flex items-center gap-2">
9092
<Settings className="h-5 w-5 text-muted-foreground" />
91-
<h2 className="text-xl font-semibold">Hooks</h2>
93+
<h2 className="text-xl font-semibold">Project Settings</h2>
9294
</div>
9395
</div>
9496
</div>
@@ -106,6 +108,10 @@ export const ProjectSettings: React.FC<ProjectSettingsProps> = ({
106108
<div className="p-6">
107109
<Tabs value={activeTab} onValueChange={setActiveTab}>
108110
<TabsList className="mb-6">
111+
<TabsTrigger value="commands" className="gap-2">
112+
<Command className="h-4 w-4" />
113+
Slash Commands
114+
</TabsTrigger>
109115
<TabsTrigger value="project" className="gap-2">
110116
<GitBranch className="h-4 w-4" />
111117
Project Hooks
@@ -116,6 +122,26 @@ export const ProjectSettings: React.FC<ProjectSettingsProps> = ({
116122
</TabsTrigger>
117123
</TabsList>
118124

125+
<TabsContent value="commands" className="space-y-6">
126+
<Card className="p-6">
127+
<div className="space-y-4">
128+
<div>
129+
<h3 className="text-lg font-semibold mb-2">Project Slash Commands</h3>
130+
<p className="text-sm text-muted-foreground mb-4">
131+
Custom commands that are specific to this project. These commands are stored in
132+
<code className="mx-1 px-2 py-1 bg-muted rounded text-xs">.claude/slash-commands/</code>
133+
and can be committed to version control.
134+
</p>
135+
</div>
136+
137+
<SlashCommandsManager
138+
projectPath={project.path}
139+
scopeFilter="project"
140+
/>
141+
</div>
142+
</Card>
143+
</TabsContent>
144+
119145
<TabsContent value="project" className="space-y-6">
120146
<Card className="p-6">
121147
<div className="space-y-4">

0 commit comments

Comments
 (0)