дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
fix(agents): tidy the Built-in agents settings page
- List rows are no longer text-selectable. Settings pages enable text selection for their content, and the shared List inherited it, so dragging or ⌘A highlighted every row. - An agent missing from PATH is shown as a muted row with a small "Not found" label instead of an orange warning badge; a custom executable gets an accent "Custom" label. - The details header puts the status (with a status dot) and the launch command on one line. - Reset only appears when a custom executable is set. - The sign-in hint gets its own "Sign in" heading. - The list/details frame sizes to its content instead of filling the page.
Цей коміт міститься в:
1 джерело
d54ef98a59
коміт
8c9ddb9879
4 files changed
+97
-34
No files matched your search
@@ -1,6 +1,6 @@
|
||||
.split {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex: none;
|
||||
min-height: 320px;
|
||||
border: 1px solid var(--border-strong);
|
||||
border-radius: var(--radius-control);
|
||||
@@ -19,6 +19,20 @@
|
||||
min-width: 0;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.agentMissing .agentName {
|
||||
color: var(--fg-muted);
|
||||
}
|
||||
.agentMissing svg {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.tag {
|
||||
flex: none;
|
||||
color: var(--fg-subtle);
|
||||
font-size: var(--fs-small);
|
||||
}
|
||||
.tagCustom {
|
||||
color: var(--accent);
|
||||
}
|
||||
.agentName {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
@@ -41,19 +55,43 @@
|
||||
margin: 0;
|
||||
font-size: var(--fs-input-large);
|
||||
}
|
||||
.launch {
|
||||
display: block;
|
||||
margin: 8px 0 0;
|
||||
.subtitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
margin: 6px 0 20px 28px;
|
||||
color: var(--fg-muted);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--fs-small);
|
||||
overflow-wrap: anywhere;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.status {
|
||||
margin: 6px 0 24px;
|
||||
color: var(--fg-muted);
|
||||
font-size: var(--fs-small);
|
||||
.dot {
|
||||
flex: none;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--fg-subtle);
|
||||
}
|
||||
.dotFound {
|
||||
background: var(--success);
|
||||
}
|
||||
.dotCustom {
|
||||
background: var(--accent);
|
||||
}
|
||||
.launch {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
.section {
|
||||
margin: 20px 0 6px;
|
||||
font-size: var(--fs-ui);
|
||||
font-weight: 600;
|
||||
color: var(--fg-strong);
|
||||
}
|
||||
.section + .hint {
|
||||
margin-top: 0;
|
||||
}
|
||||
.hint code {
|
||||
font-family: var(--font-mono);
|
||||
|
||||
@@ -2,19 +2,26 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import type { AgentProvider } from "@/bindings";
|
||||
import { tx, useTx } from "@/platform/i18n";
|
||||
import { Badge, Button, Icon, IconButton, Input, List, Spinner, T } from "@/ui";
|
||||
import clsx from "clsx";
|
||||
import { Button, Icon, IconButton, Input, List, Spinner, T } from "@/ui";
|
||||
import { useSettingsForm } from "@/workbench/contributions";
|
||||
import { providerIcon } from "./model";
|
||||
import type { CommandsBackend } from "./registry";
|
||||
import styles from "./BuiltinAgents.module.css";
|
||||
|
||||
/** Trailing list tag: a missing agent is a normal state, so it is muted rather than a warning. */
|
||||
function Status({ agent }: { agent: AgentProvider }) {
|
||||
const translate = useTx();
|
||||
if (!agent.commandOverridden && agent.installed) return null;
|
||||
if (agent.commandOverridden)
|
||||
return (
|
||||
<span className={clsx(styles.tag, styles.tagCustom)}>
|
||||
<T>Custom</T>
|
||||
</span>
|
||||
);
|
||||
if (agent.installed) return null;
|
||||
return (
|
||||
<Badge tone={agent.commandOverridden ? "accent" : "warning"}>
|
||||
{agent.commandOverridden ? translate("Custom") : translate("Not found")}
|
||||
</Badge>
|
||||
<span className={styles.tag}>
|
||||
<T>Not found</T>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,7 +62,7 @@ export function BuiltinAgents({ backend, onChanged }: { backend: CommandsBackend
|
||||
rowHeight={32}
|
||||
aria-label={tx("Built-in agents")}
|
||||
renderItem={(p) => (
|
||||
<div className={styles.agentRow}>
|
||||
<div className={clsx(styles.agentRow, !p.installed && !p.commandOverridden && styles.agentMissing)}>
|
||||
<Icon name={providerIcon(p.id)} size={16} />
|
||||
<span className={styles.agentName}>{p.name}</span> <Status agent={p} />
|
||||
</div>
|
||||
@@ -95,22 +102,28 @@ function Details({
|
||||
}
|
||||
}, [base, current, saving, refresh]);
|
||||
const launch = [agent.defaultProgram, ...agent.defaultArgs].join(" ");
|
||||
const status = agent.commandOverridden
|
||||
? tx("Custom executable")
|
||||
: agent.installed
|
||||
? tx("Found on PATH")
|
||||
: tx("Not found on PATH");
|
||||
return (
|
||||
<section className={styles.details} aria-label={tx`${agent.name} executable`}>
|
||||
<div className={styles.title}>
|
||||
<Icon name={providerIcon(agent.id)} size={20} />
|
||||
<h3>{agent.name}</h3>
|
||||
</div>
|
||||
<code className={styles.launch}>{launch}</code>
|
||||
<p className={styles.status}>
|
||||
{agent.commandOverridden ? (
|
||||
<T>Custom executable</T>
|
||||
) : agent.installed ? (
|
||||
<T>Found on PATH</T>
|
||||
) : (
|
||||
<T>Not found on PATH</T>
|
||||
)}
|
||||
</p>
|
||||
<div className={styles.subtitle}>
|
||||
<span
|
||||
aria-hidden
|
||||
className={clsx(styles.dot, agent.commandOverridden ? styles.dotCustom : agent.installed && styles.dotFound)}
|
||||
/>
|
||||
<span>{status}</span>
|
||||
<span aria-hidden>·</span>
|
||||
<code className={styles.launch} title={tx("Launch command")}>
|
||||
{launch}
|
||||
</code>
|
||||
</div>
|
||||
{agent.commandEditable ? (
|
||||
<>
|
||||
<label className={styles.label} htmlFor={`agent-executable-${agent.id}`}>
|
||||
@@ -140,9 +153,11 @@ function Details({
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button size="small" disabled={saving || !value} onClick={() => set("")}>
|
||||
<T>Reset</T>
|
||||
</Button>
|
||||
{value && (
|
||||
<Button size="small" disabled={saving} onClick={() => set("")}>
|
||||
<T>Reset</T>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<p className={styles.hint}>
|
||||
<T>Leave empty to find the executable on PATH. Changes apply to new sessions.</T>
|
||||
@@ -160,9 +175,14 @@ function Details({
|
||||
</p>
|
||||
)}
|
||||
{agent.loginHint && (
|
||||
<p className={styles.hint}>
|
||||
<LoginHint text={agent.loginHint} />
|
||||
</p>
|
||||
<>
|
||||
<h4 className={styles.section}>
|
||||
<T>Sign in</T>
|
||||
</h4>
|
||||
<p className={styles.hint}>
|
||||
<LoginHint text={agent.loginHint} />
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
{error && (
|
||||
<p className={styles.error} role="alert">
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
"Built-in agents": "内置智能体",
|
||||
"Custom executable": "自定义可执行文件",
|
||||
"Found on PATH": "已在 PATH 中找到",
|
||||
"Launch command": "启动命令",
|
||||
"Sign in": "登录",
|
||||
"Leave empty to find the executable on PATH. Changes apply to new sessions.": "留空以从 PATH 查找可执行文件。更改对新会话生效。",
|
||||
"Newer dependency version available": "有更新的依赖版本可用",
|
||||
"Not found": "未找到",
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
/* Rows are controls: a page that opts into text selection must not select them on drag / ⌘A. */
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.list::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
|
||||
Reference in new issue
Заблокувати користувача