feat: replace AI provider modals with dedicated edit pages

This commit is contained in:
LTbinglingfeng
2026-01-30 01:30:36 +08:00
parent 34b6d114d3
commit 5c85df486e
23 changed files with 2536 additions and 645 deletions

View File

@@ -5,32 +5,21 @@ import type { AmpcodeConfig } from '@/types';
import { maskApiKey } from '@/utils/format';
import styles from '@/pages/AiProvidersPage.module.scss';
import { useTranslation } from 'react-i18next';
import { AmpcodeModal } from './AmpcodeModal';
interface AmpcodeSectionProps {
config: AmpcodeConfig | null | undefined;
loading: boolean;
disableControls: boolean;
isSaving: boolean;
isSwitching: boolean;
isBusy: boolean;
isModalOpen: boolean;
onOpen: () => void;
onCloseModal: () => void;
onBusyChange: (busy: boolean) => void;
onEdit: () => void;
}
export function AmpcodeSection({
config,
loading,
disableControls,
isSaving,
isSwitching,
isBusy,
isModalOpen,
onOpen,
onCloseModal,
onBusyChange,
onEdit,
}: AmpcodeSectionProps) {
const { t } = useTranslation();
@@ -46,8 +35,8 @@ export function AmpcodeSection({
extra={
<Button
size="sm"
onClick={onOpen}
disabled={disableControls || isSaving || isBusy || isSwitching}
onClick={onEdit}
disabled={disableControls || loading || isSwitching}
>
{t('common.edit')}
</Button>
@@ -99,13 +88,6 @@ export function AmpcodeSection({
</>
)}
</Card>
<AmpcodeModal
isOpen={isModalOpen}
disableControls={disableControls}
onClose={onCloseModal}
onBusyChange={onBusyChange}
/>
</>
);
}

View File

@@ -16,8 +16,6 @@ import styles from '@/pages/AiProvidersPage.module.scss';
import { ProviderList } from '../ProviderList';
import { ProviderStatusBar } from '../ProviderStatusBar';
import { getStatsBySource, hasDisableAllModelsRule } from '../utils';
import type { ProviderFormState } from '../types';
import { ClaudeModal } from './ClaudeModal';
interface ClaudeSectionProps {
configs: ProviderKeyConfig[];
@@ -25,16 +23,11 @@ interface ClaudeSectionProps {
usageDetails: UsageDetail[];
loading: boolean;
disableControls: boolean;
isSaving: boolean;
isSwitching: boolean;
isModalOpen: boolean;
modalIndex: number | null;
onAdd: () => void;
onEdit: (index: number) => void;
onDelete: (index: number) => void;
onToggle: (index: number, enabled: boolean) => void;
onCloseModal: () => void;
onSave: (data: ProviderFormState, index: number | null) => Promise<void>;
}
export function ClaudeSection({
@@ -43,20 +36,15 @@ export function ClaudeSection({
usageDetails,
loading,
disableControls,
isSaving,
isSwitching,
isModalOpen,
modalIndex,
onAdd,
onEdit,
onDelete,
onToggle,
onCloseModal,
onSave,
}: ClaudeSectionProps) {
const { t } = useTranslation();
const actionsDisabled = disableControls || isSaving || isSwitching;
const toggleDisabled = disableControls || loading || isSaving || isSwitching;
const actionsDisabled = disableControls || loading || isSwitching;
const toggleDisabled = disableControls || loading || isSwitching;
const statusBarCache = useMemo(() => {
const cache = new Map<string, ReturnType<typeof calculateStatusBarData>>();
@@ -76,8 +64,6 @@ export function ClaudeSection({
return cache;
}, [configs, usageDetails]);
const initialData = modalIndex !== null ? configs[modalIndex] : undefined;
return (
<>
<Card
@@ -200,15 +186,6 @@ export function ClaudeSection({
}}
/>
</Card>
<ClaudeModal
isOpen={isModalOpen}
editIndex={modalIndex}
initialData={initialData}
onClose={onCloseModal}
onSave={onSave}
isSaving={isSaving}
/>
</>
);
}

View File

@@ -17,8 +17,6 @@ import styles from '@/pages/AiProvidersPage.module.scss';
import { ProviderList } from '../ProviderList';
import { ProviderStatusBar } from '../ProviderStatusBar';
import { getStatsBySource, hasDisableAllModelsRule } from '../utils';
import type { ProviderFormState } from '../types';
import { CodexModal } from './CodexModal';
interface CodexSectionProps {
configs: ProviderKeyConfig[];
@@ -26,17 +24,12 @@ interface CodexSectionProps {
usageDetails: UsageDetail[];
loading: boolean;
disableControls: boolean;
isSaving: boolean;
isSwitching: boolean;
resolvedTheme: string;
isModalOpen: boolean;
modalIndex: number | null;
onAdd: () => void;
onEdit: (index: number) => void;
onDelete: (index: number) => void;
onToggle: (index: number, enabled: boolean) => void;
onCloseModal: () => void;
onSave: (data: ProviderFormState, index: number | null) => Promise<void>;
}
export function CodexSection({
@@ -45,21 +38,16 @@ export function CodexSection({
usageDetails,
loading,
disableControls,
isSaving,
isSwitching,
resolvedTheme,
isModalOpen,
modalIndex,
onAdd,
onEdit,
onDelete,
onToggle,
onCloseModal,
onSave,
}: CodexSectionProps) {
const { t } = useTranslation();
const actionsDisabled = disableControls || isSaving || isSwitching;
const toggleDisabled = disableControls || loading || isSaving || isSwitching;
const actionsDisabled = disableControls || loading || isSwitching;
const toggleDisabled = disableControls || loading || isSwitching;
const statusBarCache = useMemo(() => {
const cache = new Map<string, ReturnType<typeof calculateStatusBarData>>();
@@ -79,8 +67,6 @@ export function CodexSection({
return cache;
}, [configs, usageDetails]);
const initialData = modalIndex !== null ? configs[modalIndex] : undefined;
return (
<>
<Card
@@ -192,15 +178,6 @@ export function CodexSection({
}}
/>
</Card>
<CodexModal
isOpen={isModalOpen}
editIndex={modalIndex}
initialData={initialData}
onClose={onCloseModal}
onSave={onSave}
isSaving={isSaving}
/>
</>
);
}

View File

@@ -13,11 +13,9 @@ import {
type UsageDetail,
} from '@/utils/usage';
import styles from '@/pages/AiProvidersPage.module.scss';
import type { GeminiFormState } from '../types';
import { ProviderList } from '../ProviderList';
import { ProviderStatusBar } from '../ProviderStatusBar';
import { getStatsBySource, hasDisableAllModelsRule } from '../utils';
import { GeminiModal } from './GeminiModal';
interface GeminiSectionProps {
configs: GeminiKeyConfig[];
@@ -25,16 +23,11 @@ interface GeminiSectionProps {
usageDetails: UsageDetail[];
loading: boolean;
disableControls: boolean;
isSaving: boolean;
isSwitching: boolean;
isModalOpen: boolean;
modalIndex: number | null;
onAdd: () => void;
onEdit: (index: number) => void;
onDelete: (index: number) => void;
onToggle: (index: number, enabled: boolean) => void;
onCloseModal: () => void;
onSave: (data: GeminiFormState, index: number | null) => Promise<void>;
}
export function GeminiSection({
@@ -43,20 +36,15 @@ export function GeminiSection({
usageDetails,
loading,
disableControls,
isSaving,
isSwitching,
isModalOpen,
modalIndex,
onAdd,
onEdit,
onDelete,
onToggle,
onCloseModal,
onSave,
}: GeminiSectionProps) {
const { t } = useTranslation();
const actionsDisabled = disableControls || isSaving || isSwitching;
const toggleDisabled = disableControls || loading || isSaving || isSwitching;
const actionsDisabled = disableControls || loading || isSwitching;
const toggleDisabled = disableControls || loading || isSwitching;
const statusBarCache = useMemo(() => {
const cache = new Map<string, ReturnType<typeof calculateStatusBarData>>();
@@ -76,8 +64,6 @@ export function GeminiSection({
return cache;
}, [configs, usageDetails]);
const initialData = modalIndex !== null ? configs[modalIndex] : undefined;
return (
<>
<Card
@@ -181,15 +167,6 @@ export function GeminiSection({
}}
/>
</Card>
<GeminiModal
isOpen={isModalOpen}
editIndex={modalIndex}
initialData={initialData}
onClose={onCloseModal}
onSave={onSave}
isSaving={isSaving}
/>
</>
);
}

View File

@@ -17,8 +17,6 @@ import styles from '@/pages/AiProvidersPage.module.scss';
import { ProviderList } from '../ProviderList';
import { ProviderStatusBar } from '../ProviderStatusBar';
import { getOpenAIProviderStats, getStatsBySource } from '../utils';
import type { OpenAIFormState } from '../types';
import { OpenAIModal } from './OpenAIModal';
interface OpenAISectionProps {
configs: OpenAIProviderConfig[];
@@ -26,16 +24,11 @@ interface OpenAISectionProps {
usageDetails: UsageDetail[];
loading: boolean;
disableControls: boolean;
isSaving: boolean;
isSwitching: boolean;
resolvedTheme: string;
isModalOpen: boolean;
modalIndex: number | null;
onAdd: () => void;
onEdit: (index: number) => void;
onDelete: (index: number) => void;
onCloseModal: () => void;
onSave: (data: OpenAIFormState, index: number | null) => Promise<void>;
}
export function OpenAISection({
@@ -44,19 +37,14 @@ export function OpenAISection({
usageDetails,
loading,
disableControls,
isSaving,
isSwitching,
resolvedTheme,
isModalOpen,
modalIndex,
onAdd,
onEdit,
onDelete,
onCloseModal,
onSave,
}: OpenAISectionProps) {
const { t } = useTranslation();
const actionsDisabled = disableControls || isSaving || isSwitching;
const actionsDisabled = disableControls || loading || isSwitching;
const statusBarCache = useMemo(() => {
const cache = new Map<string, ReturnType<typeof calculateStatusBarData>>();
@@ -77,8 +65,6 @@ export function OpenAISection({
return cache;
}, [configs, usageDetails]);
const initialData = modalIndex !== null ? configs[modalIndex] : undefined;
return (
<>
<Card
@@ -204,15 +190,6 @@ export function OpenAISection({
}}
/>
</Card>
<OpenAIModal
isOpen={isModalOpen}
editIndex={modalIndex}
initialData={initialData}
onClose={onCloseModal}
onSave={onSave}
isSaving={isSaving}
/>
</>
);
}

View File

@@ -15,8 +15,6 @@ import styles from '@/pages/AiProvidersPage.module.scss';
import { ProviderList } from '../ProviderList';
import { ProviderStatusBar } from '../ProviderStatusBar';
import { getStatsBySource } from '../utils';
import type { VertexFormState } from '../types';
import { VertexModal } from './VertexModal';
interface VertexSectionProps {
configs: ProviderKeyConfig[];
@@ -24,15 +22,10 @@ interface VertexSectionProps {
usageDetails: UsageDetail[];
loading: boolean;
disableControls: boolean;
isSaving: boolean;
isSwitching: boolean;
isModalOpen: boolean;
modalIndex: number | null;
onAdd: () => void;
onEdit: (index: number) => void;
onDelete: (index: number) => void;
onCloseModal: () => void;
onSave: (data: VertexFormState, index: number | null) => Promise<void>;
}
export function VertexSection({
@@ -41,18 +34,13 @@ export function VertexSection({
usageDetails,
loading,
disableControls,
isSaving,
isSwitching,
isModalOpen,
modalIndex,
onAdd,
onEdit,
onDelete,
onCloseModal,
onSave,
}: VertexSectionProps) {
const { t } = useTranslation();
const actionsDisabled = disableControls || isSaving || isSwitching;
const actionsDisabled = disableControls || loading || isSwitching;
const statusBarCache = useMemo(() => {
const cache = new Map<string, ReturnType<typeof calculateStatusBarData>>();
@@ -72,8 +60,6 @@ export function VertexSection({
return cache;
}, [configs, usageDetails]);
const initialData = modalIndex !== null ? configs[modalIndex] : undefined;
return (
<>
<Card
@@ -168,15 +154,6 @@ export function VertexSection({
}}
/>
</Card>
<VertexModal
isOpen={isModalOpen}
editIndex={modalIndex}
initialData={initialData}
onClose={onCloseModal}
onSave={onSave}
isSaving={isSaving}
/>
</>
);
}