Add Git credentials settings to frontend (#9956)

Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: Abubakar <abubakaran102025@gmail.com>
This commit is contained in:
Graham Neubig 2025-08-06 09:54:19 -04:00 committed by GitHub
parent dbba60356e
commit eba4294b08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 114 additions and 2 deletions

View File

@ -27,6 +27,10 @@ const saveSettingsMutationFn = async (settings: Partial<PostSettings>) => {
settings.ENABLE_PROACTIVE_CONVERSATION_STARTERS,
search_api_key: settings.SEARCH_API_KEY?.trim() || "",
max_budget_per_task: settings.MAX_BUDGET_PER_TASK,
git_user_name:
settings.GIT_USER_NAME?.trim() || DEFAULT_SETTINGS.GIT_USER_NAME,
git_user_email:
settings.GIT_USER_EMAIL?.trim() || DEFAULT_SETTINGS.GIT_USER_EMAIL,
};
await OpenHands.saveSettings(apiSettings);

View File

@ -31,6 +31,9 @@ const getSettingsQueryFn = async (): Promise<Settings> => {
EMAIL: apiSettings.email || "",
EMAIL_VERIFIED: apiSettings.email_verified,
MCP_CONFIG: apiSettings.mcp_config,
GIT_USER_NAME: apiSettings.git_user_name || DEFAULT_SETTINGS.GIT_USER_NAME,
GIT_USER_EMAIL:
apiSettings.git_user_email || DEFAULT_SETTINGS.GIT_USER_EMAIL,
IS_NEW_USER: false,
};
};

View File

@ -739,6 +739,8 @@ export enum I18nKey {
MICROAGENT_MANAGEMENT$WHAT_YOU_WOULD_LIKE_TO_KNOW_ABOUT_THIS_REPO = "MICROAGENT_MANAGEMENT$WHAT_YOU_WOULD_LIKE_TO_KNOW_ABOUT_THIS_REPO",
MICROAGENT_MANAGEMENT$DESCRIBE_WHAT_TO_KNOW_ABOUT_THIS_REPO = "MICROAGENT_MANAGEMENT$DESCRIBE_WHAT_TO_KNOW_ABOUT_THIS_REPO",
MICROAGENT_MANAGEMENT$UPDATE_MICROAGENT_MODAL_DESCRIPTION = "MICROAGENT_MANAGEMENT$UPDATE_MICROAGENT_MODAL_DESCRIPTION",
SETTINGS$GIT_USERNAME = "SETTINGS$GIT_USERNAME",
SETTINGS$GIT_EMAIL = "SETTINGS$GIT_EMAIL",
PROJECT_MANAGEMENT$TITLE = "PROJECT_MANAGEMENT$TITLE",
PROJECT_MANAGEMENT$VALIDATE_INTEGRATION_ERROR = "PROJECT_MANAGEMENT$VALIDATE_INTEGRATION_ERROR",
PROJECT_MANAGEMENT$LINK_BUTTON_LABEL = "PROJECT_MANAGEMENT$LINK_BUTTON_LABEL",

View File

@ -11823,6 +11823,38 @@
"de": "OpenHands aktualisiert den Microagenten basierend auf Ihren Anweisungen.",
"uk": "OpenHands оновить мікроагента відповідно до ваших інструкцій."
},
"SETTINGS$GIT_USERNAME": {
"en": "Git Username",
"ja": "Gitユーザー名",
"zh-CN": "Git用户名",
"zh-TW": "Git使用者名稱",
"ko-KR": "Git 사용자 이름",
"no": "Git-brukernavn",
"it": "Nome utente Git",
"pt": "Nome de usuário Git",
"es": "Nombre de usuario Git",
"ar": "اسم مستخدم Git",
"fr": "Nom d'utilisateur Git",
"tr": "Git Kullanıcı Adı",
"de": "Git-Benutzername",
"uk": "Ім'я користувача Git"
},
"SETTINGS$GIT_EMAIL": {
"en": "Git Email",
"ja": "Gitメールアドレス",
"zh-CN": "Git电子邮件",
"zh-TW": "Git電子郵件",
"ko-KR": "Git 이메일",
"no": "Git-e-post",
"it": "Email Git",
"pt": "Email Git",
"es": "Correo electrónico Git",
"ar": "بريد Git الإلكتروني",
"fr": "Email Git",
"tr": "Git E-posta",
"de": "Git-E-Mail",
"uk": "Електронна пошта Git"
},
"PROJECT_MANAGEMENT$TITLE": {
"en": "Project Management",
"ja": "プロジェクト管理",

View File

@ -40,6 +40,10 @@ function AppSettingsScreen() {
] = React.useState(false);
const [maxBudgetPerTaskHasChanged, setMaxBudgetPerTaskHasChanged] =
React.useState(false);
const [gitUserNameHasChanged, setGitUserNameHasChanged] =
React.useState(false);
const [gitUserEmailHasChanged, setGitUserEmailHasChanged] =
React.useState(false);
const formAction = (formData: FormData) => {
const languageLabel = formData.get("language-input")?.toString();
@ -62,6 +66,13 @@ function AppSettingsScreen() {
?.toString();
const maxBudgetPerTask = parseMaxBudgetPerTask(maxBudgetPerTaskValue || "");
const gitUserName =
formData.get("git-user-name-input")?.toString() ||
DEFAULT_SETTINGS.GIT_USER_NAME;
const gitUserEmail =
formData.get("git-user-email-input")?.toString() ||
DEFAULT_SETTINGS.GIT_USER_EMAIL;
saveSettings(
{
LANGUAGE: language,
@ -69,6 +80,8 @@ function AppSettingsScreen() {
ENABLE_SOUND_NOTIFICATIONS: enableSoundNotifications,
ENABLE_PROACTIVE_CONVERSATION_STARTERS: enableProactiveConversations,
MAX_BUDGET_PER_TASK: maxBudgetPerTask,
GIT_USER_NAME: gitUserName,
GIT_USER_EMAIL: gitUserEmail,
},
{
onSuccess: () => {
@ -85,6 +98,8 @@ function AppSettingsScreen() {
setSoundNotificationsSwitchHasChanged(false);
setProactiveConversationsSwitchHasChanged(false);
setMaxBudgetPerTaskHasChanged(false);
setGitUserNameHasChanged(false);
setGitUserEmailHasChanged(false);
},
},
);
@ -127,12 +142,24 @@ function AppSettingsScreen() {
setMaxBudgetPerTaskHasChanged(newValue !== currentValue);
};
const checkIfGitUserNameHasChanged = (value: string) => {
const currentValue = settings?.GIT_USER_NAME;
setGitUserNameHasChanged(value !== currentValue);
};
const checkIfGitUserEmailHasChanged = (value: string) => {
const currentValue = settings?.GIT_USER_EMAIL;
setGitUserEmailHasChanged(value !== currentValue);
};
const formIsClean =
!languageInputHasChanged &&
!analyticsSwitchHasChanged &&
!soundNotificationsSwitchHasChanged &&
!proactiveConversationsSwitchHasChanged &&
!maxBudgetPerTaskHasChanged;
!maxBudgetPerTaskHasChanged &&
!gitUserNameHasChanged &&
!gitUserEmailHasChanged;
const shouldBeLoading = !settings || isLoading || isPending;
@ -194,6 +221,34 @@ function AppSettingsScreen() {
step={1}
className="w-full max-w-[680px]" // Match the width of the language field
/>
<div className="border-t border-t-tertiary pt-6 mt-2">
<h3 className="text-lg font-medium mb-4">
{t(I18nKey.SETTINGS$GIT_SETTINGS)}
</h3>
<div className="flex flex-col gap-6">
<SettingsInput
testId="git-user-name-input"
name="git-user-name-input"
type="text"
label={t(I18nKey.SETTINGS$GIT_USERNAME)}
defaultValue={settings.GIT_USER_NAME || ""}
onChange={checkIfGitUserNameHasChanged}
placeholder="Username for git commits"
className="w-full max-w-[680px]"
/>
<SettingsInput
testId="git-user-email-input"
name="git-user-email-input"
type="email"
label={t(I18nKey.SETTINGS$GIT_EMAIL)}
defaultValue={settings.GIT_USER_EMAIL || ""}
onChange={checkIfGitUserEmailHasChanged}
placeholder="Email for git commits"
className="w-full max-w-[680px]"
/>
</div>
</div>
</div>
)}

View File

@ -26,6 +26,8 @@ export const DEFAULT_SETTINGS: Settings = {
sse_servers: [],
stdio_servers: [],
},
GIT_USER_NAME: "openhands",
GIT_USER_EMAIL: "openhands@all-hands.dev",
};
/**

View File

@ -50,6 +50,8 @@ export type Settings = {
MAX_BUDGET_PER_TASK: number | null;
EMAIL?: string;
EMAIL_VERIFIED?: boolean;
GIT_USER_NAME?: string;
GIT_USER_EMAIL?: string;
};
export type ApiSettings = {
@ -76,6 +78,8 @@ export type ApiSettings = {
};
email?: string;
email_verified?: boolean;
git_user_name?: string;
git_user_email?: string;
};
export type PostSettings = Settings & {

View File

@ -331,10 +331,12 @@ class StandaloneConversationManager(ConversationManager):
)
await self.close_session(oldest_conversation_id)
config = self.config.model_copy(deep=True)
session = Session(
sid=sid,
file_store=self.file_store,
config=self.config,
config=config,
sio=self.sio,
user_id=user_id,
)

View File

@ -122,6 +122,12 @@ class Session:
or settings.sandbox_runtime_container_image
else self.config.sandbox.runtime_container_image
)
# Set Git user configuration if provided in settings
if hasattr(settings, 'git_user_name') and settings.git_user_name:
self.config.git_user_name = settings.git_user_name
if hasattr(settings, 'git_user_email') and settings.git_user_email:
self.config.git_user_email = settings.git_user_email
max_iterations = settings.max_iterations or self.config.max_iterations
# Prioritize settings over config for max_budget_per_task

View File

@ -45,6 +45,8 @@ class Settings(BaseModel):
max_budget_per_task: float | None = None
email: str | None = None
email_verified: bool | None = None
git_user_name: str | None = None
git_user_email: str | None = None
model_config = ConfigDict(
validate_assignment=True,