diff --git a/packages/ui/src/components/sections/git-identities/GitPage.tsx b/packages/ui/src/components/sections/git-identities/GitPage.tsx index 92e7e6c4..4f5b0dec 100644 --- a/packages/ui/src/components/sections/git-identities/GitPage.tsx +++ b/packages/ui/src/components/sections/git-identities/GitPage.tsx @@ -29,6 +29,8 @@ import { cn } from '@/lib/utils'; import { useI18n } from '@/lib/i18n'; import { SettingsPageLayout } from '@/components/sections/shared/SettingsPageLayout'; import { SettingsSection } from '@/components/sections/shared/SettingsSection'; +import { SortableTabsStrip, type SortableTabsStripItem } from '@/components/ui/sortable-tabs-strip'; +import { providerTabForSettingsItem, type GitProviderTabId } from './providerTabs'; const ICON_MAP: Record = { branch: 'git-branch', @@ -47,7 +49,11 @@ const COLOR_MAP: Record = { type: 'var(--syntax-type)', }; -export const GitPage: React.FC = () => { +export interface GitPageProps { + revealItemId?: string | null; +} + +export const GitPage: React.FC = (props) => { const { t } = useI18n(); const { profiles, @@ -79,6 +85,44 @@ export const GitPage: React.FC = () => { const [deleteDialogProfile, setDeleteDialogProfile] = React.useState(null); const [isDeletePending, setIsDeletePending] = React.useState(false); + const [activeProviderTab, setActiveProviderTab] = React.useState('github'); + + const providerTabs = React.useMemo(() => [ + { + id: 'github', + label: t('settings.git.tabs.github'), + icon: , + }, + { + id: 'gitlab', + label: t('settings.git.tabs.gitlab'), + icon: , + }, + { + id: 'gitea', + label: t('settings.git.tabs.gitea'), + icon: , + }, + ], [t]); + + const revealItemId = props.revealItemId; + const lastHandledRevealRef = React.useRef(null); + + React.useLayoutEffect(() => { + if (revealItemId == null) { + lastHandledRevealRef.current = null; + return; + } + if (lastHandledRevealRef.current === revealItemId) { + return; + } + lastHandledRevealRef.current = revealItemId; + const tab = providerTabForSettingsItem(revealItemId); + if (tab) { + setActiveProviderTab(tab); + } + }, [revealItemId]); + React.useEffect(() => { loadProfiles(); loadGlobalIdentity(); @@ -123,9 +167,26 @@ export const GitPage: React.FC = () => { title={t('settings.page.git.title')} showSaveStatus > - - - +
+ setActiveProviderTab(tabId as GitProviderTabId)} + layoutMode="fit" + variant="active-pill" + activePillButtonClassName="h-7" + /> +
+ + + + { + test('maps GitHub settings ids to the github tab', () => { + expect(providerTabForSettingsItem('git.github-account')).toBe('github'); + expect(providerTabForSettingsItem('git.github-api-base-url')).toBe('github'); + expect(providerTabForSettingsItem('git.github-detect-urls')).toBe('github'); + }); + + test('maps GitLab settings ids to the gitlab tab', () => { + expect(providerTabForSettingsItem('git.gitlab-account')).toBe('gitlab'); + expect(providerTabForSettingsItem('git.gitlab-api-base-url')).toBe('gitlab'); + expect(providerTabForSettingsItem('git.gitlab-detect-urls')).toBe('gitlab'); + }); + + test('maps Gitea settings ids to the gitea tab', () => { + expect(providerTabForSettingsItem('git.gitea-account')).toBe('gitea'); + expect(providerTabForSettingsItem('git.gitea-api-base-url')).toBe('gitea'); + expect(providerTabForSettingsItem('git.gitea-detect-urls')).toBe('gitea'); + }); + + test('returns null for settings ids below the tabs', () => { + expect(providerTabForSettingsItem('git.identities')).toBeNull(); + expect(providerTabForSettingsItem('git.gitmoji')).toBeNull(); + expect(providerTabForSettingsItem('git.changes-view')).toBeNull(); + expect(providerTabForSettingsItem('git.gitignored-files')).toBeNull(); + }); + + test('returns null for empty or missing ids', () => { + expect(providerTabForSettingsItem(null)).toBeNull(); + expect(providerTabForSettingsItem(undefined)).toBeNull(); + expect(providerTabForSettingsItem('')).toBeNull(); + }); +}); diff --git a/packages/ui/src/components/sections/git-identities/providerTabs.ts b/packages/ui/src/components/sections/git-identities/providerTabs.ts new file mode 100644 index 00000000..fc1e6628 --- /dev/null +++ b/packages/ui/src/components/sections/git-identities/providerTabs.ts @@ -0,0 +1,9 @@ +export type GitProviderTabId = 'github' | 'gitlab' | 'gitea'; + +export const providerTabForSettingsItem = (settingsItemId: string | null | undefined): GitProviderTabId | null => { + if (!settingsItemId) return null; + if (settingsItemId.startsWith('git.github-')) return 'github'; + if (settingsItemId.startsWith('git.gitlab-')) return 'gitlab'; + if (settingsItemId.startsWith('git.gitea-')) return 'gitea'; + return null; +}; diff --git a/packages/ui/src/components/views/SettingsView.tsx b/packages/ui/src/components/views/SettingsView.tsx index 50f501c0..8569379c 100644 --- a/packages/ui/src/components/views/SettingsView.tsx +++ b/packages/ui/src/components/views/SettingsView.tsx @@ -667,7 +667,7 @@ export const SettingsView: React.FC = ({ onClose, forceMobile case 'snippets': return ; case 'git': - return ; + return ; case 'integrations': return ( = ({ onClose, forceMobile default: return null; } - }, [openChamberSectionBySlug, openPage, openThirdPartyProviderSetup, renderUnavailable, runtimeCtx, t]); + }, [openChamberSectionBySlug, openPage, openThirdPartyProviderSetup, pendingSearchItemId, renderUnavailable, runtimeCtx, t]); // Mobile: if opened via deep-link / palette to a non-home page, jump into it once. React.useEffect(() => { diff --git a/packages/ui/src/lib/i18n/messages/de.settings.ts b/packages/ui/src/lib/i18n/messages/de.settings.ts index a6edc9f3..8f05c53f 100644 --- a/packages/ui/src/lib/i18n/messages/de.settings.ts +++ b/packages/ui/src/lib/i18n/messages/de.settings.ts @@ -619,6 +619,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': 'Agent auswählen', 'settings.commands.agentSelector.notSelected': 'Nicht ausgewählt', 'settings.commands.agentSelector.selectAgentPlaceholder': 'Agent auswählen...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': 'Identitäten', 'settings.gitIdentities.page.empty.title': 'Keine Identitäten konfiguriert', 'settings.gitIdentities.page.empty.description': 'Erstellen Sie eine, um Git-Autoreneinstellungen pro Projekt zu verwalten', diff --git a/packages/ui/src/lib/i18n/messages/en.settings.ts b/packages/ui/src/lib/i18n/messages/en.settings.ts index 6b12697d..7ba76268 100644 --- a/packages/ui/src/lib/i18n/messages/en.settings.ts +++ b/packages/ui/src/lib/i18n/messages/en.settings.ts @@ -671,6 +671,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': 'Select agent', 'settings.commands.agentSelector.notSelected': 'Not selected', 'settings.commands.agentSelector.selectAgentPlaceholder': 'Select agent...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': 'Identities', 'settings.gitIdentities.page.empty.title': 'No identities configured', 'settings.gitIdentities.page.empty.description': 'Create one to manage Git author settings per project', diff --git a/packages/ui/src/lib/i18n/messages/es.settings.ts b/packages/ui/src/lib/i18n/messages/es.settings.ts index fb4ad670..501be41b 100644 --- a/packages/ui/src/lib/i18n/messages/es.settings.ts +++ b/packages/ui/src/lib/i18n/messages/es.settings.ts @@ -639,6 +639,9 @@ export const settingsDict = { "settings.commands.agentSelector.title": "Seleccionar agente", "settings.commands.agentSelector.notSelected": "No seleccionado", "settings.commands.agentSelector.selectAgentPlaceholder": "Seleccionar agente...", + "settings.git.tabs.gitea": "Gitea", + "settings.git.tabs.github": "GitHub", + "settings.git.tabs.gitlab": "GitLab", "settings.gitIdentities.page.section.title": "Identidades", "settings.gitIdentities.page.empty.title": "No hay identidades configuradas", "settings.gitIdentities.page.empty.description": "Crea una para gestionar la configuración del autor de Git por proyecto", diff --git a/packages/ui/src/lib/i18n/messages/fr.settings.ts b/packages/ui/src/lib/i18n/messages/fr.settings.ts index 8c9efad2..9a18d5d5 100644 --- a/packages/ui/src/lib/i18n/messages/fr.settings.ts +++ b/packages/ui/src/lib/i18n/messages/fr.settings.ts @@ -557,6 +557,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': 'Sélectionnez un agent', 'settings.commands.agentSelector.notSelected': 'Non sélectionné', 'settings.commands.agentSelector.selectAgentPlaceholder': 'Sélectionnez un agent...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': 'Identités', 'settings.gitIdentities.page.empty.title': 'Aucune identité configurée', 'settings.gitIdentities.page.empty.description': 'Créez-en un pour gérer les paramètres d\'auteur Git par projet', diff --git a/packages/ui/src/lib/i18n/messages/ja.settings.ts b/packages/ui/src/lib/i18n/messages/ja.settings.ts index 39e4feb8..0366e198 100644 --- a/packages/ui/src/lib/i18n/messages/ja.settings.ts +++ b/packages/ui/src/lib/i18n/messages/ja.settings.ts @@ -672,6 +672,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': 'Agent を選択', 'settings.commands.agentSelector.notSelected': '選択されていません', 'settings.commands.agentSelector.selectAgentPlaceholder': 'Agent を選択...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': 'ID', 'settings.gitIdentities.page.empty.title': 'Identity が設定されていません', 'settings.gitIdentities.page.empty.description': 'プロジェクトごとの Git 作成者設定を管理するために作成してください', diff --git a/packages/ui/src/lib/i18n/messages/ko.settings.ts b/packages/ui/src/lib/i18n/messages/ko.settings.ts index f20aa405..88e4e5a9 100644 --- a/packages/ui/src/lib/i18n/messages/ko.settings.ts +++ b/packages/ui/src/lib/i18n/messages/ko.settings.ts @@ -639,6 +639,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': '에이전트 선택', 'settings.commands.agentSelector.notSelected': '선택 안 됨', 'settings.commands.agentSelector.selectAgentPlaceholder': '에이전트 선택...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': 'Git 자격 증명', 'settings.gitIdentities.page.empty.title': '설정된 Git 자격 증명이 없습니다', 'settings.gitIdentities.page.empty.description': '프로젝트별 Git author를 관리하려면 하나를 생성하세요', diff --git a/packages/ui/src/lib/i18n/messages/pl.settings.ts b/packages/ui/src/lib/i18n/messages/pl.settings.ts index 2922ee2b..1fa1ec4a 100644 --- a/packages/ui/src/lib/i18n/messages/pl.settings.ts +++ b/packages/ui/src/lib/i18n/messages/pl.settings.ts @@ -285,6 +285,9 @@ export const settingsDict = { 'settings.gitIdentities.page.discoveredCredentials.title': 'Znaleziono w ~/.git-credentials', 'settings.gitIdentities.page.empty.description': 'Utwórz profil, aby zarządzać ustawieniami autora Git dla każdego projektu', 'settings.gitIdentities.page.empty.title': 'Brak skonfigurowanych tożsamości', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': 'Tożsamości', 'settings.gitIdentities.page.toast.defaultUnset': 'Domyślna tożsamość została usunięta', 'settings.gitIdentities.page.toast.defaultUpdated': 'Domyślna tożsamość została zaktualizowana', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts b/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts index 97fd9f3c..f4f56ff0 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.settings.ts @@ -639,6 +639,9 @@ export const settingsDict = { "settings.commands.agentSelector.title": "Selecionar agente", "settings.commands.agentSelector.notSelected": "Não selecionado", "settings.commands.agentSelector.selectAgentPlaceholder": "Selecionar agente...", + "settings.git.tabs.gitea": "Gitea", + "settings.git.tabs.github": "GitHub", + "settings.git.tabs.gitlab": "GitLab", "settings.gitIdentities.page.section.title": "Identidades", "settings.gitIdentities.page.empty.title": "Não há identidades configuradas", "settings.gitIdentities.page.empty.description": "Crie uma para gerenciar as configurações de autor Git por projeto", diff --git a/packages/ui/src/lib/i18n/messages/uk.settings.ts b/packages/ui/src/lib/i18n/messages/uk.settings.ts index 3448af19..55ca5691 100644 --- a/packages/ui/src/lib/i18n/messages/uk.settings.ts +++ b/packages/ui/src/lib/i18n/messages/uk.settings.ts @@ -639,6 +639,9 @@ export const settingsDict = { "settings.commands.agentSelector.title": "Виберіть агента", "settings.commands.agentSelector.notSelected": "Не вибрано", "settings.commands.agentSelector.selectAgentPlaceholder": "Виберіть агента...", + "settings.git.tabs.gitea": "Gitea", + "settings.git.tabs.github": "GitHub", + "settings.git.tabs.gitlab": "GitLab", "settings.gitIdentities.page.section.title": "Ідентичності", "settings.gitIdentities.page.empty.title": "Ідентичності не налаштовано", "settings.gitIdentities.page.empty.description": "Створіть профіль, щоб керувати автором Git для кожного проєкту", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts b/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts index 5dfd3a47..d5410567 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.settings.ts @@ -639,6 +639,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': '选择智能体', 'settings.commands.agentSelector.notSelected': '未选择', 'settings.commands.agentSelector.selectAgentPlaceholder': '选择智能体...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': '身份', 'settings.gitIdentities.page.empty.title': '未配置身份', 'settings.gitIdentities.page.empty.description': '创建一个以按项目管理 Git 作者设置', diff --git a/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts b/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts index ca783789..d3e7eea3 100644 --- a/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts +++ b/packages/ui/src/lib/i18n/messages/zh-TW.settings.ts @@ -636,6 +636,9 @@ export const settingsDict = { 'settings.commands.agentSelector.title': '選擇 agent', 'settings.commands.agentSelector.notSelected': '未選擇', 'settings.commands.agentSelector.selectAgentPlaceholder': '選擇 agent...', + 'settings.git.tabs.gitea': 'Gitea', + 'settings.git.tabs.github': 'GitHub', + 'settings.git.tabs.gitlab': 'GitLab', 'settings.gitIdentities.page.section.title': '身分', 'settings.gitIdentities.page.empty.title': '未設定身分', 'settings.gitIdentities.page.empty.description': '建立一個以按專案管理 Git 作者設定',