feat: add scope indicators (Global/Project) to mode selector and editor

- Add visual badges showing 'Global' or 'Project' scope for custom modes
- Display scope in mode selector dropdown items
- Display scope in currently selected mode button
- Display scope in modes editor view
- Use existing translations from common.json

Fixes #8238
This commit is contained in:
Roo Code 2025-09-23 00:02:02 +00:00
parent 0e1b23d09c
commit 1ecbc9741c
2 changed files with 56 additions and 15 deletions

View file

@ -198,7 +198,7 @@ export const ModeSelector = ({
disabled={disabled}
data-testid="mode-selector-trigger"
className={cn(
"inline-flex items-center relative whitespace-nowrap px-1.5 py-1 text-xs",
"inline-flex items-center gap-1 relative whitespace-nowrap px-1.5 py-1 text-xs",
"bg-transparent border border-[rgba(255,255,255,0.08)] rounded-md text-vscode-foreground",
"transition-all duration-150 focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder focus-visible:ring-inset",
disabled
@ -210,6 +210,11 @@ export const ModeSelector = ({
: null,
)}>
<span className="truncate">{selectedMode?.name || ""}</span>
{selectedMode?.source && (
<span className="text-[10px] px-1 py-0.5 rounded bg-vscode-badge-background text-vscode-badge-foreground">
{selectedMode.source === "project" ? t("common:scope.project") : t("common:scope.global")}
</span>
)}
</PopoverTrigger>
</StandardTooltip>
<PopoverContent
@ -255,6 +260,7 @@ export const ModeSelector = ({
<div className="py-1">
{filteredModes.map((mode) => {
const isSelected = mode.slug === value
const isCustomMode = mode.source !== undefined
return (
<div
key={mode.slug}
@ -269,7 +275,16 @@ export const ModeSelector = ({
)}
data-testid="mode-selector-item">
<div className="flex-1 min-w-0">
<div className="font-bold truncate">{mode.name}</div>
<div className="flex items-center gap-1.5">
<span className="font-bold truncate">{mode.name}</span>
{isCustomMode && (
<span className="text-[10px] px-1 py-0.5 rounded bg-vscode-badge-background text-vscode-badge-foreground">
{mode.source === "project"
? t("common:scope.project")
: t("common:scope.global")}
</span>
)}
</div>
{mode.description && (
<div className="text-xs text-vscode-descriptionForeground truncate">
{mode.description}

View file

@ -619,8 +619,17 @@ const ModesView = ({ onDone }: ModesViewProps) => {
aria-expanded={open}
className="justify-between w-full"
data-testid="mode-select-trigger">
<div className="truncate">
{getCurrentMode()?.name || t("prompts:modes.selectMode")}
<div className="flex items-center gap-1.5 truncate">
<span className="truncate">
{getCurrentMode()?.name || t("prompts:modes.selectMode")}
</span>
{getCurrentMode()?.source && (
<span className="text-[10px] px-1 py-0.5 rounded bg-vscode-badge-background text-vscode-badge-foreground">
{getCurrentMode()?.source === "project"
? t("common:scope.project")
: t("common:scope.global")}
</span>
)}
</div>
<ChevronDown className="opacity-50" />
</Button>
@ -672,16 +681,24 @@ const ModesView = ({ onDone }: ModesViewProps) => {
}}
data-testid={`mode-option-${modeConfig.slug}`}>
<div className="flex items-center justify-between w-full">
<span
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
flex: 2,
minWidth: 0,
}}>
{modeConfig.name}
</span>
<div className="flex items-center gap-1.5 flex-1 min-w-0">
<span
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
minWidth: 0,
}}>
{modeConfig.name}
</span>
{modeConfig.source && (
<span className="text-[10px] px-1 py-0.5 rounded bg-vscode-badge-background text-vscode-badge-foreground">
{modeConfig.source === "project"
? t("common:scope.project")
: t("common:scope.global")}
</span>
)}
</div>
<span
className="text-foreground"
style={{
@ -741,7 +758,16 @@ const ModesView = ({ onDone }: ModesViewProps) => {
{visualMode && findModeBySlug(visualMode, customModes) && (
<div className="flex gap-3 mb-4">
<div className="flex-1">
<div className="font-bold mb-1">{t("prompts:createModeDialog.name.label")}</div>
<div className="flex items-center gap-1.5 mb-1">
<span className="font-bold">{t("prompts:createModeDialog.name.label")}</span>
{findModeBySlug(visualMode, customModes)?.source && (
<span className="text-[10px] px-1 py-0.5 rounded bg-vscode-badge-background text-vscode-badge-foreground">
{findModeBySlug(visualMode, customModes)?.source === "project"
? t("common:scope.project")
: t("common:scope.global")}
</span>
)}
</div>
<div className="flex gap-2">
<Input
type="text"