Skip to content

Commit c8a6282

Browse files
committed
feat(providers): 请求头导入改为独立视图
导入按钮补上 ClipboardPaste 图标并在展开时进入选中态;点击后请求头 列表整块换成导入输入框(带入场动画与自动聚焦),解析成功后增量合并 并自动切回列表,失败则留在导入视图显示错误。 列表被顶掉期间:"添加"按钮禁用(新增行不可见,避免静默无响应),列表 级校验文案隐藏,保存命中非法请求头时先切回列表再聚焦。 "添加请求头"按钮文案缩短为"添加"/"Add",与相邻的"导入"对齐。 GUI 与 WebUI 两端同步。
1 parent 87a7922 commit c8a6282

4 files changed

Lines changed: 36 additions & 12 deletions

File tree

crates/agent-gateway/web/src/i18n/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,7 +1388,7 @@ export const translations: Record<Locale, Record<string, string>> = {
13881388
"settings.hideCustomHeaderValue": "隐藏请求头值",
13891389
"settings.manualAddModel": "手动添加",
13901390
"settings.customHeaderKeyPlaceholder": "请求头名称",
1391-
"settings.addCustomHeader": "添加请求头",
1391+
"settings.addCustomHeader": "添加",
13921392
"settings.importCustomHeaders": "导入",
13931393
"settings.customHeaderImportLabel": "JSON / cURL",
13941394
"settings.customHeaderImportPlaceholder": "粘贴 JSON 或 cURL",
@@ -3614,7 +3614,7 @@ export const translations: Record<Locale, Record<string, string>> = {
36143614
"settings.hideCustomHeaderValue": "Hide header value",
36153615
"settings.manualAddModel": "Add manually",
36163616
"settings.customHeaderKeyPlaceholder": "Header name",
3617-
"settings.addCustomHeader": "Add header",
3617+
"settings.addCustomHeader": "Add",
36183618
"settings.importCustomHeaders": "Import",
36193619
"settings.customHeaderImportLabel": "JSON / cURL",
36203620
"settings.customHeaderImportPlaceholder": "Paste JSON or cURL",

crates/agent-gateway/web/src/pages/settings/ProvidersSection.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createPortal } from "react-dom";
33
import {
44
Check,
55
ClaudeIcon,
6+
ClipboardPaste,
67
ExternalLink,
78
Eye,
89
EyeOff,
@@ -846,6 +847,8 @@ function ProviderModal({
846847
setHeaderValidationSubmitted(true);
847848
exitModelBulkMode();
848849
setActivePanel("request");
850+
// 导入视图会顶掉请求头列表,先切回列表再聚焦,否则目标输入框尚未挂载。
851+
setHeaderImportOpen(false);
849852
focusCustomHeader(
850853
invalidHeaderIndex,
851854
getCustomHeaderIssue(customHeaders[invalidHeaderIndex], true) === "invalid-value"
@@ -1691,21 +1694,28 @@ function ProviderModal({
16911694
type="button"
16921695
variant="outline"
16931696
size="sm"
1694-
className="h-8 shrink-0 max-[720px]:h-11 max-[720px]:flex-1"
1697+
className={cn(
1698+
"h-8 shrink-0 gap-1.5 max-[720px]:h-11 max-[720px]:flex-1",
1699+
headerImportOpen && "border-primary/50 bg-primary/10 text-primary",
1700+
)}
16951701
aria-expanded={headerImportOpen}
16961702
onClick={() => {
16971703
setHeaderImportOpen((open) => !open);
16981704
setHeaderImportError(null);
16991705
setHeaderImportSummary(null);
1706+
setHeaderSuggest(null);
17001707
}}
17011708
>
1709+
<ClipboardPaste className="h-3.5 w-3.5" />
17021710
{t("settings.importCustomHeaders")}
17031711
</Button>
17041712
<Button
17051713
type="button"
17061714
variant="outline"
17071715
size="sm"
17081716
className="h-8 shrink-0 gap-1.5 max-[720px]:h-11 max-[720px]:flex-1"
1717+
/* 导入视图占据了列表位置,此时新增行不可见,禁用避免静默无响应。 */
1718+
disabled={headerImportOpen}
17091719
onClick={() => addCustomHeader()}
17101720
>
17111721
<Plus className="h-3.5 w-3.5" />
@@ -1715,7 +1725,7 @@ function ProviderModal({
17151725
</div>
17161726

17171727
{headerImportOpen ? (
1718-
<div className="mt-3 min-w-0 rounded-xl border bg-card p-3">
1728+
<div className="provider-panel-enter mt-3 min-w-0 rounded-xl border bg-card p-3">
17191729
<Label
17201730
htmlFor="provider-custom-header-import"
17211731
className="mb-2 block text-xs font-medium"
@@ -1732,6 +1742,7 @@ function ProviderModal({
17321742
headerImportErrorMessage ? "provider-custom-header-import-error" : undefined
17331743
}
17341744
spellCheck={false}
1745+
autoFocus
17351746
onChange={(event) => {
17361747
setHeaderImportText(event.currentTarget.value);
17371748
setHeaderImportError(null);
@@ -1779,7 +1790,8 @@ function ProviderModal({
17791790
</p>
17801791
) : null}
17811792

1782-
{customHeaders.length === 0 ? (
1793+
{/* 导入视图与请求头列表互斥:解析成功后回到列表,直接看到增量导入的结果。 */}
1794+
{headerImportOpen ? null : customHeaders.length === 0 ? (
17831795
<button
17841796
type="button"
17851797
className="mt-3 flex w-full flex-col items-center gap-1 rounded-xl border border-dashed px-4 py-8 text-center transition-colors hover:border-primary/50 hover:bg-accent/20"
@@ -1949,7 +1961,7 @@ function ProviderModal({
19491961
</div>
19501962
)}
19511963

1952-
{headerIssueMessage ? (
1964+
{headerIssueMessage && !headerImportOpen ? (
19531965
<p className="mt-2 text-xs leading-relaxed text-destructive" role="alert">
19541966
{headerIssueMessage}
19551967
</p>

crates/agent-gui/src/i18n/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ export const translations: Record<Locale, Record<string, string>> = {
14581458
"settings.hideCustomHeaderValue": "隐藏请求头值",
14591459
"settings.manualAddModel": "手动添加",
14601460
"settings.customHeaderKeyPlaceholder": "请求头名称",
1461-
"settings.addCustomHeader": "添加请求头",
1461+
"settings.addCustomHeader": "添加",
14621462
"settings.importCustomHeaders": "导入",
14631463
"settings.customHeaderImportLabel": "JSON / cURL",
14641464
"settings.customHeaderImportPlaceholder": "粘贴 JSON 或 cURL",
@@ -3777,7 +3777,7 @@ export const translations: Record<Locale, Record<string, string>> = {
37773777
"settings.hideCustomHeaderValue": "Hide header value",
37783778
"settings.manualAddModel": "Add manually",
37793779
"settings.customHeaderKeyPlaceholder": "Header name",
3780-
"settings.addCustomHeader": "Add header",
3780+
"settings.addCustomHeader": "Add",
37813781
"settings.importCustomHeaders": "Import",
37823782
"settings.customHeaderImportLabel": "JSON / cURL",
37833783
"settings.customHeaderImportPlaceholder": "Paste JSON or cURL",

crates/agent-gui/src/pages/settings/ProvidersSection.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
CheckCircle2,
99
ChevronDown,
1010
ClaudeIcon,
11+
ClipboardPaste,
1112
Download,
1213
ExternalLink,
1314
Eye,
@@ -902,6 +903,8 @@ function ProviderModal({
902903
setHeaderValidationSubmitted(true);
903904
exitModelBulkMode();
904905
setActivePanel("request");
906+
// 导入视图会顶掉请求头列表,先切回列表再聚焦,否则目标输入框尚未挂载。
907+
setHeaderImportOpen(false);
905908
focusCustomHeader(
906909
invalidHeaderIndex,
907910
getCustomHeaderIssue(customHeaders[invalidHeaderIndex], true) === "invalid-value"
@@ -1743,21 +1746,28 @@ function ProviderModal({
17431746
type="button"
17441747
variant="outline"
17451748
size="sm"
1746-
className="h-8 shrink-0 max-[720px]:h-11 max-[720px]:flex-1"
1749+
className={cn(
1750+
"h-8 shrink-0 gap-1.5 max-[720px]:h-11 max-[720px]:flex-1",
1751+
headerImportOpen && "border-primary/50 bg-primary/10 text-primary",
1752+
)}
17471753
aria-expanded={headerImportOpen}
17481754
onClick={() => {
17491755
setHeaderImportOpen((open) => !open);
17501756
setHeaderImportError(null);
17511757
setHeaderImportSummary(null);
1758+
setHeaderSuggest(null);
17521759
}}
17531760
>
1761+
<ClipboardPaste className="h-3.5 w-3.5" />
17541762
{t("settings.importCustomHeaders")}
17551763
</Button>
17561764
<Button
17571765
type="button"
17581766
variant="outline"
17591767
size="sm"
17601768
className="h-8 shrink-0 gap-1.5 max-[720px]:h-11 max-[720px]:flex-1"
1769+
/* 导入视图占据了列表位置,此时新增行不可见,禁用避免静默无响应。 */
1770+
disabled={headerImportOpen}
17611771
onClick={() => addCustomHeader()}
17621772
>
17631773
<Plus className="h-3.5 w-3.5" />
@@ -1767,7 +1777,7 @@ function ProviderModal({
17671777
</div>
17681778

17691779
{headerImportOpen ? (
1770-
<div className="mt-3 min-w-0 rounded-xl border bg-card p-3">
1780+
<div className="provider-panel-enter mt-3 min-w-0 rounded-xl border bg-card p-3">
17711781
<Label
17721782
htmlFor="provider-custom-header-import"
17731783
className="mb-2 block text-xs font-medium"
@@ -1784,6 +1794,7 @@ function ProviderModal({
17841794
headerImportErrorMessage ? "provider-custom-header-import-error" : undefined
17851795
}
17861796
spellCheck={false}
1797+
autoFocus
17871798
onChange={(event) => {
17881799
setHeaderImportText(event.currentTarget.value);
17891800
setHeaderImportError(null);
@@ -1831,7 +1842,8 @@ function ProviderModal({
18311842
</p>
18321843
) : null}
18331844

1834-
{customHeaders.length === 0 ? (
1845+
{/* 导入视图与请求头列表互斥:解析成功后回到列表,直接看到增量导入的结果。 */}
1846+
{headerImportOpen ? null : customHeaders.length === 0 ? (
18351847
<button
18361848
type="button"
18371849
className="mt-3 flex w-full flex-col items-center gap-1 rounded-xl border border-dashed px-4 py-8 text-center transition-colors hover:border-primary/50 hover:bg-accent/20"
@@ -2001,7 +2013,7 @@ function ProviderModal({
20012013
</div>
20022014
)}
20032015

2004-
{headerIssueMessage ? (
2016+
{headerIssueMessage && !headerImportOpen ? (
20052017
<p className="mt-2 text-xs leading-relaxed text-destructive" role="alert">
20062018
{headerIssueMessage}
20072019
</p>

0 commit comments

Comments
 (0)