Skip to content

Conversation

@MuriloFP
Copy link
Contributor

@MuriloFP MuriloFP commented Jul 31, 2025

Related GitHub Issue

Closes: #6502

Roo Code Task Context (Optional)

No Roo Code task context for this PR

Description

This PR adds visual indicators to distinguish between global and project-level custom modes in the mode selector, addressing user confusion when working with modes at both levels.

Key implementation details:

  • Added helper functions getModeSource() and getSourceDisplayText() to identify custom modes and format their source display
  • Shows abbreviated "(G)" or "(P)" indicators in the dropdown list for space efficiency
  • Shows full "(Global)" or "(Project)" text in the selected mode button
  • Built-in modes show no indicators, keeping the UI clean for standard modes
  • Used text-vscode-descriptionForeground color class for subtle, non-intrusive styling
  • Source defaults to "global" when undefined for backward compatibility

Test Procedure

Automated Testing:

  • Added comprehensive unit tests in ModeSelector.spec.tsx covering all scenarios
  • All tests pass successfully: cd webview-ui && npm test -- src/components/chat/__tests__/ModeSelector.spec.tsx

Manual Testing:

  1. Create both global and project-level custom modes
  2. Open the mode selector dropdown
  3. Verify "(G)" appears next to global custom modes
  4. Verify "(P)" appears next to project custom modes
  5. Verify built-in modes show no indicators
  6. Select a custom mode and verify the button shows "(Global)" or "(Project)"
  7. Create modes with the same name at both levels and verify project mode shows "(P)" due to precedence

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Screenshots / Videos

UI changes implemented but screenshots not available in this environment. The changes add text indicators "(G)"/"(P)" in dropdown and "(Global)"/"(Project)" in the selector button for custom modes.

Documentation Updates

  • No documentation updates are required.

Additional Notes

  • All 18 language files have been updated with the new translation keys
  • The implementation is minimal and focused solely on displaying existing data
  • No breaking changes or performance impacts

Get in Touch

@MuriloFP


Important

Adds visual indicators in ModeSelector.tsx to distinguish global and project-level custom modes, with tests and localization updates.

  • Behavior:
    • Adds visual indicators for custom modes in ModeSelector.tsx to distinguish between global and project-level modes.
    • Uses helper functions getModeSource() and getSourceDisplayText() to determine and display mode source.
    • Shows "(G)" or "(P)" in dropdown and "(Global)" or "(Project)" in selected mode button.
    • Built-in modes show no indicators.
  • Tests:
    • Adds tests in ModeSelector.spec.tsx to verify source indicators for custom modes, absence for built-in modes, and default to global when source is undefined.
    • Tests search functionality and UI behavior with different numbers of modes.
  • Localization:
    • Updates 18 language files to include new translation keys for mode source indicators.

This description was created by Ellipsis for 8e396b9. You can customize this summary. It will automatically update as commits are pushed.

MuriloFP and others added 30 commits July 3, 2025 15:26
- Add (G)/(P) indicators in mode dropdown for custom modes
- Add (Global)/(Project) text in selected mode button
- Built-in modes show no indicators
- Add helper functions getModeSource() and getSourceDisplayText()
- Use text-vscode-descriptionForeground for subtle styling
- Add comprehensive tests for source indicator functionality
- Add translation keys to all 18 supported languages
@MuriloFP MuriloFP requested review from cte, jr and mrubens as code owners July 31, 2025 22:13
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. UI/UX UI/UX related or focused labels Jul 31, 2025
@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Jul 31, 2025
Copy link
Contributor

@roomote roomote bot left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution! I've reviewed the changes and the implementation looks solid overall. The visual indicators for custom mode sources will definitely help users distinguish between global and project-level modes. I've left some suggestions inline to improve accessibility, performance, and type safety.

)}
data-testid="mode-selector-item">
<div className="flex-1 min-w-0">
<div className="font-bold truncate">
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding aria-label attributes for better accessibility. Screen reader users might not understand what "(G)" or "(P)" means. You could add:

Suggested change
<div className="font-bold truncate">
<div className="font-bold truncate">
{mode.name}
{modeSource && (
<span
className="text-vscode-descriptionForeground font-normal"
aria-label={modeSource === "global" ? "Global custom mode" : "Project custom mode"}
>
{getSourceDisplayText(modeSource, true)}
</span>
)}
</div>

const { t } = useAppTranslation()

// Helper function to get mode source
const getModeSource = React.useCallback(
Copy link
Contributor

Choose a reason for hiding this comment

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

The getModeSource function is called for every mode during rendering. Since custom modes are passed as props and don't change frequently, consider memoizing the source mapping:

Suggested change
const getModeSource = React.useCallback(
// Helper function to get mode source
const modeSourceMap = React.useMemo(() => {
const map = new Map<string, "global" | "project">();
customModes?.forEach(mode => {
map.set(mode.slug, mode.source || "global");
});
return map;
}, [customModes]);
const getModeSource = React.useCallback(
(modeSlug: string): "global" | "project" | null => {
return modeSourceMap.get(modeSlug) || null;
},
[modeSourceMap],
)

const { hasOpenedModeSelector, setHasOpenedModeSelector } = useExtensionState()
const { t } = useAppTranslation()

// Helper function to get mode source
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding JSDoc comments to explain the default behavior when source is undefined:

Suggested change
// Helper function to get mode source
/**
* Gets the source of a custom mode (global or project).
* @param modeSlug - The slug of the mode to check
* @returns "global" or "project" for custom modes, null for built-in modes.
* Defaults to "global" if a custom mode has no source field.
*/
const getModeSource = React.useCallback(

// Check trigger shows global source (default)
const trigger = screen.getByTestId("mode-selector-trigger")
expect(trigger.textContent).toContain("(common:customModes.scope.global)")
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding a test case for invalid source values to ensure graceful handling:

Suggested change
})
test("handles invalid source values gracefully", () => {
const customModes: ModeConfig[] = [
{
slug: "custom-invalid-source",
name: "Custom Invalid Source",
description: "A custom mode with invalid source",
roleDefinition: "Role definition",
groups: ["read"],
source: "invalid" as any, // Invalid source value
},
];
mockModes = [...customModes];
render(
<ModeSelector
value={"custom-invalid-source" as Mode}
onChange={vi.fn()}
modeShortcutText="Ctrl+M"
customModes={customModes}
/>,
);
// Should handle gracefully - perhaps default to no indicator or "global"
const trigger = screen.getByTestId("mode-selector-trigger");
expect(trigger.textContent).toContain("Custom Invalid Source");
// Add assertion for expected behavior with invalid source
});

@MuriloFP MuriloFP marked this pull request as draft July 31, 2025 22:26
@daniel-lxs daniel-lxs moved this from Triage to PR [Draft / In Progress] in Roo Code Roadmap Aug 1, 2025
@hannesrudolph hannesrudolph added PR - Draft / In Progress and removed Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. labels Aug 1, 2025
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Sep 22, 2025
@github-project-automation github-project-automation bot moved this from PR [Draft / In Progress] to Done in Roo Code Roadmap Sep 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR - Draft / In Progress size:L This PR changes 100-499 lines, ignoring generated files. UI/UX UI/UX related or focused

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Add visual indicator to show if a mode is global or project-based in the mode edit screen

2 participants