-
Notifications
You must be signed in to change notification settings - Fork 2.6k
fix: add visual indicators for custom mode sources (#6502) #6520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
efaaed9
57d3fbe
ef61905
f5a51c4
bcbf329
80413c0
ab10140
39c5cf7
00a0b63
080b61b
7a5ad14
2c73ff2
05ccf57
fdb1f35
10ce509
ab1f9fc
74fd8b4
6745c8f
faf2ee5
b2dadf9
f648e4c
a6d1e60
be90907
ed3a077
856313f
4dd68ea
b10fa5e
f016d7b
23855f2
3803c29
8e396b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -46,6 +46,32 @@ export const ModeSelector = ({ | |||||||||||||||||||||||||||||||||
| const { hasOpenedModeSelector, setHasOpenedModeSelector } = useExtensionState() | ||||||||||||||||||||||||||||||||||
| const { t } = useAppTranslation() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Helper function to get mode source | ||||||||||||||||||||||||||||||||||
| const getModeSource = React.useCallback( | ||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||||||||||||||||||
| (modeSlug: string): "global" | "project" | null => { | ||||||||||||||||||||||||||||||||||
| const customMode = customModes?.find((mode) => mode.slug === modeSlug) | ||||||||||||||||||||||||||||||||||
| if (!customMode) return null | ||||||||||||||||||||||||||||||||||
| return customMode.source || "global" // Default to "global" if source is undefined | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| [customModes], | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Helper function to get source display text | ||||||||||||||||||||||||||||||||||
| const getSourceDisplayText = React.useCallback( | ||||||||||||||||||||||||||||||||||
| (source: "global" | "project" | null, isShort: boolean = false): string => { | ||||||||||||||||||||||||||||||||||
| if (!source) return "" | ||||||||||||||||||||||||||||||||||
| if (isShort) { | ||||||||||||||||||||||||||||||||||
| return source === "global" | ||||||||||||||||||||||||||||||||||
| ? ` (${t("common:customModes.scope.globalShort")})` | ||||||||||||||||||||||||||||||||||
| : ` (${t("common:customModes.scope.projectShort")})` | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| return source === "global" | ||||||||||||||||||||||||||||||||||
| ? ` (${t("common:customModes.scope.global")})` | ||||||||||||||||||||||||||||||||||
| : ` (${t("common:customModes.scope.project")})` | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| [t], | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const trackModeSelectorOpened = React.useCallback(() => { | ||||||||||||||||||||||||||||||||||
| // Track telemetry every time the mode selector is opened | ||||||||||||||||||||||||||||||||||
| telemetryClient.capture(TelemetryEventName.MODE_SELECTOR_OPENED) | ||||||||||||||||||||||||||||||||||
|
|
@@ -159,6 +185,9 @@ export const ModeSelector = ({ | |||||||||||||||||||||||||||||||||
| // Combine instruction text for tooltip | ||||||||||||||||||||||||||||||||||
| const instructionText = `${t("chat:modeSelector.description")} ${modeShortcutText}` | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Get source for selected mode | ||||||||||||||||||||||||||||||||||
| const selectedModeSource = React.useMemo(() => getModeSource(value), [value, getModeSource]) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const trigger = ( | ||||||||||||||||||||||||||||||||||
| <PopoverTrigger | ||||||||||||||||||||||||||||||||||
| disabled={disabled} | ||||||||||||||||||||||||||||||||||
|
|
@@ -176,7 +205,14 @@ export const ModeSelector = ({ | |||||||||||||||||||||||||||||||||
| : null, | ||||||||||||||||||||||||||||||||||
| )}> | ||||||||||||||||||||||||||||||||||
| <ChevronUp className="pointer-events-none opacity-80 flex-shrink-0 size-3" /> | ||||||||||||||||||||||||||||||||||
| <span className="truncate">{selectedMode?.name || ""}</span> | ||||||||||||||||||||||||||||||||||
| <span className="truncate"> | ||||||||||||||||||||||||||||||||||
| {selectedMode?.name || ""} | ||||||||||||||||||||||||||||||||||
| {selectedModeSource && ( | ||||||||||||||||||||||||||||||||||
| <span className="text-vscode-descriptionForeground"> | ||||||||||||||||||||||||||||||||||
| {getSourceDisplayText(selectedModeSource)} | ||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||
| </PopoverTrigger> | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -225,29 +261,39 @@ export const ModeSelector = ({ | |||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| ) : ( | ||||||||||||||||||||||||||||||||||
| <div className="py-1"> | ||||||||||||||||||||||||||||||||||
| {filteredModes.map((mode) => ( | ||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||
| key={mode.slug} | ||||||||||||||||||||||||||||||||||
| onClick={() => handleSelect(mode.slug)} | ||||||||||||||||||||||||||||||||||
| className={cn( | ||||||||||||||||||||||||||||||||||
| "px-3 py-1.5 text-sm cursor-pointer flex items-center", | ||||||||||||||||||||||||||||||||||
| "hover:bg-vscode-list-hoverBackground", | ||||||||||||||||||||||||||||||||||
| mode.slug === value | ||||||||||||||||||||||||||||||||||
| ? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground" | ||||||||||||||||||||||||||||||||||
| : "", | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| data-testid="mode-selector-item"> | ||||||||||||||||||||||||||||||||||
| <div className="flex-1 min-w-0"> | ||||||||||||||||||||||||||||||||||
| <div className="font-bold truncate">{mode.name}</div> | ||||||||||||||||||||||||||||||||||
| {mode.description && ( | ||||||||||||||||||||||||||||||||||
| <div className="text-xs text-vscode-descriptionForeground truncate"> | ||||||||||||||||||||||||||||||||||
| {mode.description} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| {filteredModes.map((mode) => { | ||||||||||||||||||||||||||||||||||
| const modeSource = getModeSource(mode.slug) | ||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||
| key={mode.slug} | ||||||||||||||||||||||||||||||||||
| onClick={() => handleSelect(mode.slug)} | ||||||||||||||||||||||||||||||||||
| className={cn( | ||||||||||||||||||||||||||||||||||
| "px-3 py-1.5 text-sm cursor-pointer flex items-center", | ||||||||||||||||||||||||||||||||||
| "hover:bg-vscode-list-hoverBackground", | ||||||||||||||||||||||||||||||||||
| mode.slug === value | ||||||||||||||||||||||||||||||||||
| ? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground" | ||||||||||||||||||||||||||||||||||
| : "", | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| data-testid="mode-selector-item"> | ||||||||||||||||||||||||||||||||||
| <div className="flex-1 min-w-0"> | ||||||||||||||||||||||||||||||||||
| <div className="font-bold truncate"> | ||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
|
||||||||||||||||||||||||||||||||||
| {mode.name} | ||||||||||||||||||||||||||||||||||
| {modeSource && ( | ||||||||||||||||||||||||||||||||||
| <span className="text-vscode-descriptionForeground font-normal"> | ||||||||||||||||||||||||||||||||||
| {getSourceDisplayText(modeSource, true)} | ||||||||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| {mode.description && ( | ||||||||||||||||||||||||||||||||||
| <div className="text-xs text-vscode-descriptionForeground truncate"> | ||||||||||||||||||||||||||||||||||
| {mode.description} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| {mode.slug === value && <Check className="ml-auto size-4 p-0.5" />} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| {mode.slug === value && <Check className="ml-auto size-4 p-0.5" />} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| })} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
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: