Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions FILE_REGEX_UI_IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# File Regex UI Implementation for Modes Tab

## Summary

I have successfully implemented a UI in the modes tab for displaying and editing the file regex for the edit files tool group. This allows users to configure which files can be edited when a specific mode is active.

## Features Implemented

### 1. **Display Current File Regex**

- Shows the current file regex pattern and description for the edit tool group
- Displays "all files" when no regex is configured
- Shows either the description or the regex pattern (formatted as `/pattern/`)

### 2. **Edit Mode UI**

- **File Regex Input**: Text input field for entering regex patterns (e.g., `.*\.(js|ts|jsx|tsx)$`)
- **Description Input**: Text input field for entering a human-readable description (e.g., "JavaScript/TypeScript files")
- **Save/Cancel Buttons**: Action buttons to save or discard changes

### 3. **Edit Button**

- Small edit icon button that appears next to the file regex display
- Only visible for custom modes (built-in modes cannot be edited)
- Triggers the edit mode when clicked

### 4. **Input Validation**

- Handles both existing file regex configurations and new ones
- Properly converts simple "edit" groups to array format with options
- Preserves existing options when updating

## Files Modified

### 1. `webview-ui/src/components/modes/ModesView.tsx`

#### **State Added:**

```typescript
const [editingFileRegex, setEditingFileRegex] = useState<string | null>(null)
const [fileRegexValue, setFileRegexValue] = useState("")
const [fileRegexDescription, setFileRegexDescription] = useState("")
```

#### **Functions Added:**

- `startEditingFileRegex()`: Initializes edit mode with current values
- `saveFileRegex()`: Saves changes to the mode configuration
- `cancelEditingFileRegex()`: Cancels editing and resets state

#### **UI Changes:**

- Replaced static file regex display with conditional rendering
- Added input fields and buttons that appear when editing
- Added edit button that shows only for custom modes

### 2. `webview-ui/src/i18n/locales/en/prompts.json`

#### **Translation Keys Added:**

```json
{
"tools": {
"fileRegex": "File Regex",
"description": "Description",
"save": "Save",
"cancel": "Cancel",
"editFileRegex": "Edit file regex"
}
}
```

## Technical Implementation Details

### **Data Structure Handling**

The implementation properly handles the `GroupEntry` union type:

- Simple string groups: `"edit"`
- Array groups with options: `["edit", { fileRegex: "pattern", description: "desc" }]`

### **Type Safety**

- Uses proper TypeScript types throughout
- Handles the `GroupEntry` type correctly
- Maintains type safety when updating group configurations

### **User Experience**

- Immediate visual feedback when entering edit mode
- Clear labeling of input fields with placeholders
- Non-destructive editing (changes only saved on explicit save)
- Edit button only appears for modes that can be modified

## Usage

1. **Navigate to Modes Tab**: Open the prompts/modes configuration
2. **Select Custom Mode**: Choose a custom mode (not built-in)
3. **Find Edit Tool Group**: Look for the "Edit Files" tool group section
4. **Click Edit Button**: Click the small edit icon next to the file regex display
5. **Configure Regex**: Enter the desired file pattern and description
6. **Save Changes**: Click "Save" to apply or "Cancel" to discard

## Example Use Cases

- **JavaScript Projects**: `.*\.(js|jsx|ts|tsx)$` - "JavaScript/TypeScript files"
- **Python Projects**: `.*\.py$` - "Python files"
- **Documentation**: `.*\.(md|txt|rst)$` - "Documentation files"
- **Config Files**: `.*\.(json|yaml|yml|toml)$` - "Configuration files"

## Benefits

1. **Enhanced Control**: Users can precisely control which files modes can edit
2. **Safety**: Prevents accidental modification of sensitive files
3. **Workflow Optimization**: Modes can be tailored for specific file types
4. **User-Friendly**: Intuitive UI that doesn't require manual JSON editing
5. **Backward Compatible**: Works with existing mode configurations

The implementation follows the existing code patterns and design system used throughout the Roo Code extension, ensuring consistency and maintainability.
175 changes: 161 additions & 14 deletions webview-ui/src/components/modes/ModesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ const ModesView = ({ onDone }: ModesViewProps) => {
const [searchValue, setSearchValue] = useState("")
const searchInputRef = useRef<HTMLInputElement>(null)

// State for editing file regex
const [editingFileRegex, setEditingFileRegex] = useState<string | null>(null)
const [fileRegexValue, setFileRegexValue] = useState("")
const [fileRegexDescription, setFileRegexDescription] = useState("")

// Direct update functions
const updateAgentPrompt = useCallback(
(mode: Mode, promptData: PromptComponent) => {
Expand Down Expand Up @@ -399,6 +404,82 @@ const ModesView = ({ onDone }: ModesViewProps) => {
})
}

// File regex editing functions
const startEditingFileRegex = useCallback(
(modeSlug: string) => {
const currentMode = getCurrentMode()
if (!currentMode) return

const editGroup = currentMode.groups?.find((g: GroupEntry) => Array.isArray(g) && g[0] === "edit")

if (Array.isArray(editGroup)) {
setFileRegexValue(editGroup[1]?.fileRegex || "")
setFileRegexDescription(editGroup[1]?.description || "")
} else {
setFileRegexValue("")
setFileRegexDescription("")
}
setEditingFileRegex(modeSlug)
},
[getCurrentMode],
)

const saveFileRegex = useCallback(() => {
const currentMode = getCurrentMode()
if (!currentMode || !editingFileRegex) return

const isCustomMode = Boolean(findModeBySlug(editingFileRegex, customModes))
if (!isCustomMode) return

// Update the groups array with the new file regex
const newGroups: GroupEntry[] = currentMode.groups.map((group: GroupEntry) => {
if (Array.isArray(group) && group[0] === "edit") {
// Update existing edit group with options
return [
"edit",
{
...(group[1] || {}),
fileRegex: fileRegexValue.trim() || undefined,
description: fileRegexDescription.trim() || undefined,
},
] as GroupEntry
} else if (group === "edit") {
// Convert simple edit group to array with options
return [
"edit",
{
fileRegex: fileRegexValue.trim() || undefined,
description: fileRegexDescription.trim() || undefined,
},
] as GroupEntry
}
return group
})

updateCustomMode(editingFileRegex, {
...currentMode,
groups: newGroups,
})

setEditingFileRegex(null)
setFileRegexValue("")
setFileRegexDescription("")
}, [
getCurrentMode,
editingFileRegex,
fileRegexValue,
fileRegexDescription,
findModeBySlug,
customModes,
updateCustomMode,
])

const cancelEditingFileRegex = useCallback(() => {
setEditingFileRegex(null)
setFileRegexValue("")
setFileRegexDescription("")
}, [])

return (
<Tab>
<TabHeader className="flex justify-between items-center">
Expand Down Expand Up @@ -806,20 +887,86 @@ const ModesView = ({ onDone }: ModesViewProps) => {
{group === "edit" && (
<div className="text-xs text-vscode-descriptionForeground mt-0.5">
{t("prompts:tools.allowedFiles")}{" "}
{(() => {
const currentMode = getCurrentMode()
const editGroup = currentMode?.groups?.find(
(g) =>
Array.isArray(g) &&
g[0] === "edit" &&
g[1]?.fileRegex,
)
if (!Array.isArray(editGroup)) return t("prompts:allFiles")
return (
editGroup[1].description ||
`/${editGroup[1].fileRegex}/`
)
})()}
{editingFileRegex === visualMode ? (
<div className="mt-2 space-y-2">
<div>
<label className="block text-xs font-medium mb-1">
{t("prompts:tools.fileRegex")}
</label>
<Input
type="text"
value={fileRegexValue}
onChange={(e) =>
setFileRegexValue(e.target.value)
}
placeholder="e.g., .*\\.(js|ts|jsx|tsx)$"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The placeholder texts for the file regex and description inputs are hardcoded (e.g. 'e.g., .*.(js|ts|jsx|tsx)$'). To support localization consistently, please use translation keys instead of inline examples.

Suggested change
placeholder="e.g., .*\\.(js|ts|jsx|tsx)$"
placeholder={t("prompts:tools.fileRegexPlaceholder")}

This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.

className="text-xs h-6"
/>
</div>
<div>
<label className="block text-xs font-medium mb-1">
{t("prompts:tools.description")}
</label>
<Input
type="text"
value={fileRegexDescription}
onChange={(e) =>
setFileRegexDescription(e.target.value)
}
placeholder="e.g., JavaScript/TypeScript files"
className="text-xs h-6"
/>
</div>
<div className="flex gap-1">
<Button
variant="default"
size="sm"
onClick={saveFileRegex}
className="text-xs px-2 py-1 h-6">
{t("prompts:tools.save")}
</Button>
<Button
variant="ghost"
size="sm"
onClick={cancelEditingFileRegex}
className="text-xs px-2 py-1 h-6">
{t("prompts:tools.cancel")}
</Button>
</div>
</div>
) : (
<div className="flex items-center gap-1">
<span>
{(() => {
const currentMode = getCurrentMode()
const editGroup = currentMode?.groups?.find(
(g: GroupEntry) =>
Array.isArray(g) &&
g[0] === "edit" &&
g[1]?.fileRegex,
)
if (!Array.isArray(editGroup))
return t("prompts:allFiles")
return (
editGroup[1].description ||
`/${editGroup[1].fileRegex}/`
)
})()}
</span>
{isCustomMode && (
<Button
variant="ghost"
size="icon"
onClick={() =>
startEditingFileRegex(visualMode)
}
title={t("prompts:tools.editFileRegex")}
className="h-4 w-4 p-0.5">
<span className="codicon codicon-edit text-xs"></span>
</Button>
)}
</div>
)}
</div>
)}
</VSCodeCheckbox>
Expand Down
5 changes: 5 additions & 0 deletions webview-ui/src/i18n/locales/en/prompts.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
"editTools": "Edit tools",
"doneEditing": "Done editing",
"allowedFiles": "Allowed files:",
"fileRegex": "File Regex",
"description": "Description",
"save": "Save",
"cancel": "Cancel",
"editFileRegex": "Edit file regex",
"toolNames": {
"read": "Read Files",
"edit": "Edit Files",
Expand Down
Loading