fix(ui): provider-aware context rail branding for GitLab
This commit is contained in:
@@ -24,7 +24,7 @@ import { useEffectiveDirectory } from '@/hooks/useEffectiveDirectory';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { useBrowserFaviconStore } from '@/stores/useBrowserFaviconStore';
|
||||
import { useGitProvider } from '@/lib/gitProvider';
|
||||
import { useGitProvider, type GitProvider } from '@/lib/gitProvider';
|
||||
import { useFilesViewTabsStore } from '@/stores/useFilesViewTabsStore';
|
||||
import { useUIStore, type ContextPanelMode, type PendingDiffScope } from '@/stores/useUIStore';
|
||||
import { markSessionViewed } from '@/sync/notification-store';
|
||||
@@ -110,7 +110,8 @@ const getRelativePathLabel = (filePath: string | null, directory: string): strin
|
||||
|
||||
const getModeLabel = (
|
||||
mode: ContextPanelMode,
|
||||
t: TranslateFn
|
||||
t: TranslateFn,
|
||||
gitProvider: GitProvider | null,
|
||||
): string => {
|
||||
if (mode === 'chat') return t('contextPanel.mode.chat');
|
||||
if (mode === 'file') return t('contextPanel.mode.files');
|
||||
@@ -119,7 +120,7 @@ const getModeLabel = (
|
||||
if (mode === 'plan') return t('contextPanel.mode.plan');
|
||||
if (mode === 'browser') return t('contextPanel.mode.browser');
|
||||
if (mode === 'git') return t('layout.rightSidebar.git');
|
||||
if (mode === 'pr') return t('contextPanel.mode.pr');
|
||||
if (mode === 'pr') return gitProvider === 'gitlab' ? t('contextPanel.mode.mr') : t('contextPanel.mode.pr');
|
||||
if (mode === 'notes') return t('contextRail.surface.notes');
|
||||
if (mode === 'terminal') return t('layout.mainTab.terminal');
|
||||
return t('contextPanel.mode.context');
|
||||
@@ -146,7 +147,8 @@ const getFileNameFromPath = (path: string | null): string | null => {
|
||||
const getTabLabel = (
|
||||
tab: { mode: ContextPanelMode; label: string | null; targetPath: string | null; dedupeKey?: string; sessionTitleFallback?: string | null; stagedDiff?: boolean },
|
||||
sessionTitleById: ReadonlyMap<string, string>,
|
||||
t: TranslateFn
|
||||
t: TranslateFn,
|
||||
gitProvider: GitProvider | null,
|
||||
): string => {
|
||||
if (tab.mode === 'chat') {
|
||||
const sessionID = getSessionIDFromDedupeKey(tab.dedupeKey);
|
||||
@@ -185,7 +187,7 @@ const getTabLabel = (
|
||||
return t('contextPanel.mode.diff');
|
||||
}
|
||||
|
||||
return getModeLabel(tab.mode, t);
|
||||
return getModeLabel(tab.mode, t, gitProvider);
|
||||
};
|
||||
|
||||
const getTabIcon = (
|
||||
@@ -922,7 +924,7 @@ export const ContextPanel: React.FC = () => {
|
||||
);
|
||||
|
||||
const tabItems = React.useMemo(() => activeModeTabs.map((tab) => {
|
||||
const rawLabel = getTabLabel(tab, sessionTitleById, t);
|
||||
const rawLabel = getTabLabel(tab, sessionTitleById, t, gitProvider);
|
||||
const label = truncateTabLabel(rawLabel, CONTEXT_TAB_LABEL_MAX_CHARS);
|
||||
const tabPathLabel = getRelativePathLabel(tab.targetPath, effectiveDirectory);
|
||||
return {
|
||||
@@ -932,7 +934,7 @@ export const ContextPanel: React.FC = () => {
|
||||
title: tabPathLabel ? `${rawLabel}: ${tabPathLabel}` : rawLabel,
|
||||
closeLabel: t('contextPanel.tab.closeTabAria', { label }),
|
||||
};
|
||||
}), [activeModeTabs, effectiveDirectory, faviconByOrigin, sessionTitleById, t]);
|
||||
}), [activeModeTabs, effectiveDirectory, faviconByOrigin, gitProvider, sessionTitleById, t]);
|
||||
|
||||
const activeNonChatContent = activeTab?.mode === 'context'
|
||||
? <ContextPanelContent />
|
||||
@@ -1006,7 +1008,7 @@ export const ContextPanel: React.FC = () => {
|
||||
<div className="flex min-w-0 flex-1 items-center gap-1.5 px-3">
|
||||
{activeTab ? getTabIcon(activeTab, faviconByOrigin) : null}
|
||||
<span className="truncate typography-ui-label text-foreground">
|
||||
{activeTab ? getModeLabel(activeTab.mode, t) : null}
|
||||
{activeTab ? getModeLabel(activeTab.mode, t, gitProvider) : null}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -17,11 +17,13 @@ import {
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
|
||||
import { Icon } from '@/components/icon/Icon';
|
||||
import type { IconName } from '@/components/icon/icons';
|
||||
import { DiffViewIcon } from '@/components/icons/DiffIcon';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { useEffectiveDirectory } from '@/hooks/useEffectiveDirectory';
|
||||
import { useDeviceInfo } from '@/lib/device';
|
||||
import { isVSCodeRuntime } from '@/lib/desktop';
|
||||
import { useGitProvider } from '@/lib/gitProvider';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import {
|
||||
getVisibleContextRailSurfaces,
|
||||
@@ -167,6 +169,9 @@ export const ContextPanelRail: React.FC = () => {
|
||||
const planModeEnabled = useFeatureFlagsStore((state) => state.planModeEnabled);
|
||||
const { screenWidth } = useDeviceInfo();
|
||||
const gitStatus = useGitStatus(directoryKey || null);
|
||||
// Provider-aware 'pr' branding: GitLab repositories get the MR descriptor
|
||||
// (icon + labels) on the rail instead of the GitHub pull-request branding.
|
||||
const gitProvider = useGitProvider(directoryKey);
|
||||
|
||||
const surfaceSwitchPrefix = React.useMemo(
|
||||
() => getEffectiveShortcutPrefix('switch_context_surface', shortcutOverrides),
|
||||
@@ -260,8 +265,9 @@ export const ContextPanelRail: React.FC = () => {
|
||||
isVSCode: isVSCodeRuntime(),
|
||||
screenWidth,
|
||||
tabs,
|
||||
gitProvider,
|
||||
});
|
||||
}, [contextRailOrder, planModeEnabled, screenWidth, tabs]);
|
||||
}, [contextRailOrder, gitProvider, planModeEnabled, screenWidth, tabs]);
|
||||
|
||||
const handleDragEnd = React.useCallback((event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
@@ -291,7 +297,17 @@ export const ContextPanelRail: React.FC = () => {
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
||||
<SortableContext items={surfaces.map((surface) => surface.id)} strategy={verticalListSortingStrategy}>
|
||||
{surfaces.map((surface, index) => {
|
||||
const label = t(surface.labelKey);
|
||||
// The 'pr' surface renders the GitLab MR view in GitLab repos, so
|
||||
// it borrows GitLab's merge-request branding instead of GitHub's.
|
||||
const gitlabMrSurface: ContextSurfaceDescriptor = surface.id === 'pr' && gitProvider === 'gitlab'
|
||||
? {
|
||||
...surface,
|
||||
icon: 'git-merge' as IconName,
|
||||
labelKey: 'contextPanel.mode.mr',
|
||||
descriptionKey: 'contextRail.surface.mr.description',
|
||||
}
|
||||
: surface;
|
||||
const label = t(gitlabMrSurface.labelKey);
|
||||
// Git shows a numeric badge instead of the old activity dot.
|
||||
// Other surfaces never inherit git's changed-files signal.
|
||||
// The work-status panel reports the same count in words a few
|
||||
@@ -301,11 +317,11 @@ export const ContextPanelRail: React.FC = () => {
|
||||
return (
|
||||
<ContextPanelRailItem
|
||||
key={surface.id}
|
||||
surface={surface}
|
||||
surface={gitlabMrSurface}
|
||||
isActive={activeMode === surface.mode}
|
||||
showActivityDot={false}
|
||||
label={label}
|
||||
description={t(surface.descriptionKey)}
|
||||
description={t(gitlabMrSurface.descriptionKey)}
|
||||
badgeCount={badgeCount}
|
||||
badgeAriaLabel={badgeCount !== null
|
||||
? t(
|
||||
|
||||
Reference in New Issue
Block a user