Standardize Settings layout and save feedback (#2122)
* Group settings navigation menu Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Revert "Group settings navigation menu" This reverts commit 5983a4e82074b8dab1084af1cadd803ba28ea65d. * Standardize settings layout feedback Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Fix settings save status timer typing Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Retain settings save status Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Report color mode save state Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Match Appearance settings to two-column layout Rebuild Appearance into Color mode & Theme, Localization, and Density & type sections with responsive two-column grids, consistent section headers, page description, and green save status. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Migrate settings pages to SettingsPageLayout and SettingsSection Replace ScrollableOverlay/max-w-3xl shells with the shared settings layout primitives across entity and static settings pages, normalize section headers, and add settings.page.behavior.description locales. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Unify remaining settings pages on shared section chrome Wire Appearance, Projects, and Remote Instances through SettingsSection/SettingsPageLayout so every settings surface shares the same header, divider, and page shell treatment. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Align settings UI with OpenChamber design system kit Apply kit geometry and control specs: 840px content width, 32/48 padding, fixed 260/280 sidebars, radius/spacing tokens, settings select height, stepper dimensions, and shared field/link typography. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Migrate OpenChamberVisualSettings to shared settings primitives Replace ad-hoc radio/checkbox/chip/field layouts with SettingsSection shared chrome for Appearance, Density, Navigation, Chat/behavior, and Privacy while preserving handlers and data-settings-item anchors. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Migrate settings pages to shared field/checkbox/radio primitives Unify Defaults, Notifications, Behavior, Git, Session Retention, Passkeys, OpenCode CLI, Commands, About, Keyboard Shortcuts, and Desktop Network on SettingsFieldRow / SettingsCheckboxRow / SettingsRadioGroup / SettingsChipGroup for consistent grid, spacing, and DRY layout. Also remove the GitPage double SettingsSection wrap around GitHubSettings. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Unify remaining settings pages onto shared field primitives Migrate Agents, Snippets, Skills, Usage, MCP identity rows and selects to SettingsFieldRow/CheckboxRow/ChipGroup and SETTINGS_SELECT_*; align page titles; light-touch Voice/Tunnel/Providers/Plugins without rewriting complex OAuth, permissions, or tunnel flows. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Polish settings section dividers and transport helper text Slightly stronger section borders for clearer group separation, and keep message-stream transport description under the chip control. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Fix settings grid alignment, control heights, and Chat section titles Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Tighten settings grid: flat Chat 2x2 and full-width stacked selects Message options use a flat two-column grid so row headers share a baseline. Stacked selects fill their column; field-row selects keep a fixed sm:w-56 width. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Align mixed settings controls to shared FieldRow/CheckboxRow grid Separate FieldRows from CheckboxRows with SettingsInset, move enum radios into ControlGroups, and convert misplaced StackedFields to full-width FieldRows so left edges no longer clash. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Translate Behavior response-style preset labels for es and pl Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Group settings nav into categories and improve icons/order Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Fix settings layout: fewer hrs, shared control widths, chat transport section Remove SettingsInset top borders, align App install/Density controls to full cluster width, give Message Stream Transport its own Chat section, and fold Sessions Small Model into the first section to cut extra dividers. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Align Voice and MCP settings labels with shared heading classes Swap form field labels to SETTINGS_FIELD_LABEL_CLASS and use SettingsGroupTitle for MCP control-group headings (manual auth fallback, request headers). Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Differentiate settings heading levels by context Page titles are larger and quieter than section titles; group and field labels use dedicated shared classes so hierarchy is consistent across settings surfaces without ad-hoc typography mixes. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Use shared settings title classes in SettingsView home Wire home and unavailable headings through the shared L1/L2 class constants so they stay aligned with SettingsPageLayout. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Keep settings number steppers from stretching +/- buttons Density & type NumberInputs no longer flex-grow across the row, and NumberInput locks minus/plus to fixed width so the plus side cannot inflate when the control is placed in a full-width cluster. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Place spacing and input-bar offset on their own row Density & type now lays out as font families, then font sizes, then Spacing Density / Input Bar Offset on the row below. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Regroup settings nav and improve Voice layout Drop Advanced/Usage/Git nav categories: Voice and About under Interface, Usage under OpenCode, Git under Workspace. Voice provider chips and STT model cards use shared settings primitives with roomier spacing and a two-column model grid. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> * Space out chat feature groups in visual settings * Polish settings: save-state wiring, container-query layouts, unified dropdown triggers - Wire shared save indicator into Behavior page saves and git identity CRUD - Convert settings layout primitives and page rows from viewport to container queries so narrow panes stack instead of clipping - Unify custom dropdown triggers (model/agent/provider pickers) and remaining page selects on the settings control size - Bump global radius scale by 1px; align variant input with select size - Migrate stray raw controls (MCP OAuth checkbox, worktree remove button, git identity dialog rows, skills dialog labels) onto shared primitives - Make settings nav items span full sidebar width; trim nav to 240px * Add General settings page, regroup nav, cap control widths, promote chat feature headers * Mobile settings nav: plain background and touch-sized rows * Hide secondary settings descriptions behind clickable info hints * Move quota credentials to Usage, navigation settings to General, rename External Tunnel * Quiet settings save indicator: silent success, delayed spinner, visible errors * Rewrite settings-ui-patterns skill around shared primitives and refactored conventions * Remove settings starter page; open last visited page, defaulting to General * Settings polish: spacing, control sizes, trigger widths, readable model names, device dates * Centralize dropdown trigger chrome, settings nav polish, mobile-only input bar offset * Fix global line-height regression, auto-hide first-section divider, shortcut row spacing * Global line-height 1.45, align scheduled tasks header button with select * Hide editor toolbar and About in VS Code, animate chat render preview outside desktop dialog * Rebuild agent tool permissions on source-of-truth model Edit the agent's own permission map verbatim (inherit vs explicit actions, pattern rules only for pattern-capable keys), save permission-only, drop the server-side non-wildcard re-merge that resurrected deleted rules, and surface session-granted rules as read-only. * Agents model parameters polish: row spacing, variant dropdown, unified widths, dash for unset numbers --------- Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Serhii Dziupin
Bohdan Triapitsyn
parent
1b402fcb67
commit
17f1b24709
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { SettingsCheckboxRow, SETTINGS_FIELD_LABEL_CLASS } from '@/components/sections/shared/SettingsSection';
|
||||
import { SettingsInfoHint } from '@/components/sections/shared/SettingsInfoHint';
|
||||
import { toast } from '@/components/ui';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -11,7 +12,6 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { Icon } from "@/components/icon/Icon";
|
||||
import type { IconName } from "@/components/icon/icons";
|
||||
import { useGitIdentitiesStore, type GitIdentityProfile, type GitIdentityAuthType } from '@/stores/useGitIdentitiesStore';
|
||||
@@ -235,7 +235,7 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
{!isGlobalProfile && (
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<label className="typography-ui-label text-foreground block mb-1.5">{t('settings.gitIdentities.editor.field.profileName')}</label>
|
||||
<label className={`${SETTINGS_FIELD_LABEL_CLASS} block mb-1.5`}>{t('settings.gitIdentities.editor.field.profileName')}</label>
|
||||
<Input
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
@@ -302,16 +302,11 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.userName')}</label>
|
||||
<label className={SETTINGS_FIELD_LABEL_CLASS}>{t('settings.gitIdentities.editor.field.userName')}</label>
|
||||
{!isGlobalProfile && <span className="text-[var(--status-error)] text-xs">*</span>}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Icon name="information" className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent sideOffset={8} className="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.userNameTooltip')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<SettingsInfoHint contentClassName="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.userNameTooltip')}
|
||||
</SettingsInfoHint>
|
||||
</div>
|
||||
<Input
|
||||
value={userName}
|
||||
@@ -326,16 +321,11 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.emailAddress')}</label>
|
||||
<label className={SETTINGS_FIELD_LABEL_CLASS}>{t('settings.gitIdentities.editor.field.emailAddress')}</label>
|
||||
{!isGlobalProfile && <span className="text-[var(--status-error)] text-xs">*</span>}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Icon name="information" className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent sideOffset={8} className="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.emailAddressTooltip')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<SettingsInfoHint contentClassName="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.emailAddressTooltip')}
|
||||
</SettingsInfoHint>
|
||||
</div>
|
||||
<Input
|
||||
type="email"
|
||||
@@ -380,15 +370,10 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
{authType === 'ssh' && (
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.sshKeyPath')}</label>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Icon name="information" className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent sideOffset={8} className="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.sshKeyPathTooltip')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<label className={SETTINGS_FIELD_LABEL_CLASS}>{t('settings.gitIdentities.editor.field.sshKeyPath')}</label>
|
||||
<SettingsInfoHint contentClassName="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.sshKeyPathTooltip')}
|
||||
</SettingsInfoHint>
|
||||
</div>
|
||||
<Input
|
||||
value={sshKey}
|
||||
@@ -400,25 +385,17 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
)}
|
||||
|
||||
<div className="border-t border-border/40 pt-3 space-y-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<Checkbox
|
||||
checked={signCommits}
|
||||
onChange={setSignCommits}
|
||||
ariaLabel={t('settings.gitIdentities.editor.field.signCommits')}
|
||||
/>
|
||||
<div className="min-w-0">
|
||||
<div className="typography-ui-label text-foreground">
|
||||
{t('settings.gitIdentities.editor.field.signCommits')}
|
||||
</div>
|
||||
<div className="typography-micro text-muted-foreground/70">
|
||||
{t('settings.gitIdentities.editor.section.commitSigning')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsCheckboxRow
|
||||
checked={signCommits}
|
||||
onChange={setSignCommits}
|
||||
label={t('settings.gitIdentities.editor.field.signCommits')}
|
||||
info={t('settings.gitIdentities.editor.section.commitSigning')}
|
||||
ariaLabel={t('settings.gitIdentities.editor.field.signCommits')}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
<label className="typography-ui-label text-foreground">
|
||||
<label className={SETTINGS_FIELD_LABEL_CLASS}>
|
||||
{t('settings.gitIdentities.editor.field.signingKey')}
|
||||
</label>
|
||||
</div>
|
||||
@@ -435,16 +412,11 @@ export const GitIdentityEditorDialog: React.FC<GitIdentityEditorDialogProps> = (
|
||||
{authType === 'token' && (
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-1.5">
|
||||
<label className="typography-ui-label text-foreground">{t('settings.gitIdentities.editor.field.host')}</label>
|
||||
<label className={SETTINGS_FIELD_LABEL_CLASS}>{t('settings.gitIdentities.editor.field.host')}</label>
|
||||
<span className="text-[var(--status-error)] text-xs">*</span>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Icon name="information" className="h-3.5 w-3.5 text-muted-foreground/60 cursor-help" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent sideOffset={8} className="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.hostTooltip')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<SettingsInfoHint contentClassName="max-w-xs">
|
||||
{t('settings.gitIdentities.editor.field.hostTooltip')}
|
||||
</SettingsInfoHint>
|
||||
</div>
|
||||
<Input
|
||||
value={host}
|
||||
|
||||
@@ -21,11 +21,12 @@ import { useShallow } from 'zustand/react/shallow';
|
||||
import { GitSettings } from '@/components/sections/openchamber/GitSettings';
|
||||
import { GitHubSettings } from '@/components/sections/openchamber/GitHubSettings';
|
||||
import { GitIdentityEditorDialog } from './GitIdentityEditorDialog';
|
||||
import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay';
|
||||
import { Icon } from "@/components/icon/Icon";
|
||||
import type { IconName } from "@/components/icon/icons";
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { SettingsPageLayout } from '@/components/sections/shared/SettingsPageLayout';
|
||||
import { SettingsSection } from '@/components/sections/shared/SettingsSection';
|
||||
|
||||
const ICON_MAP: Record<string, IconName> = {
|
||||
branch: 'git-branch',
|
||||
@@ -116,82 +117,79 @@ export const GitPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScrollableOverlay outerClassName="h-full" className="w-full bg-background">
|
||||
<div className="mx-auto w-full max-w-3xl space-y-6 p-3 sm:p-6 sm:pt-8">
|
||||
<div data-settings-item="git.github-account">
|
||||
<GitHubSettings />
|
||||
</div>
|
||||
<SettingsPageLayout
|
||||
title={t('settings.page.git.title')}
|
||||
showSaveStatus
|
||||
>
|
||||
<GitHubSettings />
|
||||
|
||||
{/* Identities Section */}
|
||||
<div data-settings-item="git.identities" className="border-t border-border/40 pt-6">
|
||||
<div className="mb-3 px-1 flex items-start justify-between gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="typography-ui-header font-semibold text-foreground">{t('settings.gitIdentities.page.section.title')}</h3>
|
||||
<SettingsSection
|
||||
title={t('settings.gitIdentities.page.section.title')}
|
||||
headerAction={(
|
||||
<Button size="sm" variant="outline" onClick={() => openEditor('new')}>
|
||||
<Icon name="add" className="w-3.5 h-3.5 mr-1" /> {t('settings.common.badge.new')}
|
||||
</Button>
|
||||
)}
|
||||
settingsItem="git.identities"
|
||||
>
|
||||
<div className="rounded-lg bg-[var(--surface-elevated)]/70 overflow-hidden flex flex-col">
|
||||
{/* Global identity */}
|
||||
{globalIdentity && (
|
||||
<IdentityRow
|
||||
profile={globalIdentity}
|
||||
isDefault={defaultGitIdentityId === 'global'}
|
||||
onEdit={() => openEditor('global')}
|
||||
onToggleDefault={() => handleToggleDefault('global')}
|
||||
isReadOnly
|
||||
hasBorder={profiles.length > 0 || unimportedCredentials.length > 0}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Custom profiles */}
|
||||
{profiles.map((profile, i) => (
|
||||
<IdentityRow
|
||||
key={profile.id}
|
||||
profile={profile}
|
||||
isDefault={defaultGitIdentityId === profile.id}
|
||||
onEdit={() => openEditor(profile.id)}
|
||||
onToggleDefault={() => handleToggleDefault(profile.id)}
|
||||
onDelete={() => setDeleteDialogProfile(profile)}
|
||||
hasBorder={i < profiles.length - 1 || unimportedCredentials.length > 0}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Empty state */}
|
||||
{!globalIdentity && profiles.length === 0 && unimportedCredentials.length === 0 && (
|
||||
<div className="py-8 px-4 text-center text-muted-foreground">
|
||||
<Icon name="shield-keyhole" className="mx-auto mb-2 h-8 w-8 opacity-40" />
|
||||
<p className="typography-ui-label">{t('settings.gitIdentities.page.empty.title')}</p>
|
||||
<p className="typography-meta mt-1 opacity-75">{t('settings.gitIdentities.page.empty.description')}</p>
|
||||
</div>
|
||||
<Button size="sm" variant="outline" onClick={() => openEditor('new')}>
|
||||
<Icon name="add" className="w-3.5 h-3.5 mr-1" /> {t('settings.common.badge.new')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="rounded-lg bg-[var(--surface-elevated)]/70 overflow-hidden flex flex-col">
|
||||
{/* Global identity */}
|
||||
{globalIdentity && (
|
||||
<IdentityRow
|
||||
profile={globalIdentity}
|
||||
isDefault={defaultGitIdentityId === 'global'}
|
||||
onEdit={() => openEditor('global')}
|
||||
onToggleDefault={() => handleToggleDefault('global')}
|
||||
isReadOnly
|
||||
hasBorder={profiles.length > 0 || unimportedCredentials.length > 0}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Custom profiles */}
|
||||
{profiles.map((profile, i) => (
|
||||
<IdentityRow
|
||||
key={profile.id}
|
||||
profile={profile}
|
||||
isDefault={defaultGitIdentityId === profile.id}
|
||||
onEdit={() => openEditor(profile.id)}
|
||||
onToggleDefault={() => handleToggleDefault(profile.id)}
|
||||
onDelete={() => setDeleteDialogProfile(profile)}
|
||||
hasBorder={i < profiles.length - 1 || unimportedCredentials.length > 0}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Empty state */}
|
||||
{!globalIdentity && profiles.length === 0 && unimportedCredentials.length === 0 && (
|
||||
<div className="py-8 px-4 text-center text-muted-foreground">
|
||||
<Icon name="shield-keyhole" className="mx-auto mb-2 h-8 w-8 opacity-40" />
|
||||
<p className="typography-ui-label">{t('settings.gitIdentities.page.empty.title')}</p>
|
||||
<p className="typography-meta mt-1 opacity-75">{t('settings.gitIdentities.page.empty.description')}</p>
|
||||
{/* Discovered credentials */}
|
||||
{unimportedCredentials.length > 0 && (
|
||||
<>
|
||||
<div className="px-4 py-2 border-t border-[var(--surface-subtle)]">
|
||||
<span className="typography-micro text-muted-foreground">
|
||||
{t('settings.gitIdentities.page.discoveredCredentials.title')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Discovered credentials */}
|
||||
{unimportedCredentials.length > 0 && (
|
||||
<>
|
||||
<div className="px-4 py-2 border-t border-[var(--surface-subtle)]">
|
||||
<span className="typography-micro text-muted-foreground">
|
||||
{t('settings.gitIdentities.page.discoveredCredentials.title')}
|
||||
</span>
|
||||
</div>
|
||||
{unimportedCredentials.map((cred, i) => (
|
||||
<DiscoveredRow
|
||||
key={`${cred.host}-${cred.username}`}
|
||||
credential={cred}
|
||||
onImport={() => openEditor('new', { host: cred.host, username: cred.username })}
|
||||
hasBorder={i < unimportedCredentials.length - 1}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{unimportedCredentials.map((cred, i) => (
|
||||
<DiscoveredRow
|
||||
key={`${cred.host}-${cred.username}`}
|
||||
credential={cred}
|
||||
onImport={() => openEditor('new', { host: cred.host, username: cred.username })}
|
||||
hasBorder={i < unimportedCredentials.length - 1}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</SettingsSection>
|
||||
|
||||
<GitSettings />
|
||||
</div>
|
||||
</ScrollableOverlay>
|
||||
<GitSettings />
|
||||
</SettingsPageLayout>
|
||||
|
||||
{/* Editor dialog */}
|
||||
<GitIdentityEditorDialog
|
||||
|
||||
Reference in New Issue
Block a user