feat(providers/codex): bulk add accounts via JSON
Add a "Bulk Add" button on /dashboard/providers/codex that imports
multiple OAuth accounts at once by pasting a JSON array, single object,
or { accounts: [...] } wrapper.
- New endpoint POST /api/oauth/codex/bulk-import (serial loop, no token echo)
- New BulkImportCodexModal component with JSON textarea + success/failure summary
- Persist idToken/lastRefreshAt on first insert via OPTIONAL_FIELDS
- Backfill email/chatgptAccountId/chatgptPlanType from JWT when missing
- Derive expiresAt from expiresIn when missing
- Gated to providerId === "codex" only; other providers unaffected
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
b2aa08ad16
commit
8962e466d6
4 files changed
+299
-1
No files matched your search
@@ -17,6 +17,7 @@ import ConnectionRow from "./ConnectionRow";
|
||||
import AddApiKeyModal from "./AddApiKeyModal";
|
||||
import EditCompatibleNodeModal from "./EditCompatibleNodeModal";
|
||||
import AddCustomModelModal from "./AddCustomModelModal";
|
||||
import BulkImportCodexModal from "./BulkImportCodexModal";
|
||||
|
||||
const ONE_BY_ONE_DELAY_MS = 1000;
|
||||
|
||||
@@ -36,6 +37,7 @@ export default function ProviderDetailPage() {
|
||||
const [showIFlowCookieModal, setShowIFlowCookieModal] = useState(false);
|
||||
const [showAddApiKeyModal, setShowAddApiKeyModal] = useState(false);
|
||||
const [addConnectionError, setAddConnectionError] = useState("");
|
||||
const [showBulkImportCodex, setShowBulkImportCodex] = useState(false);
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [showEditNodeModal, setShowEditNodeModal] = useState(false);
|
||||
const [showBulkProxyModal, setShowBulkProxyModal] = useState(false);
|
||||
@@ -1339,6 +1341,11 @@ export default function ProviderDetailPage() {
|
||||
Cookie
|
||||
</Button>
|
||||
)}
|
||||
{providerId === "codex" && (
|
||||
<Button size="sm" icon="playlist_add" variant="secondary" onClick={() => setShowBulkImportCodex(true)}>
|
||||
{translate("Bulk Add")}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="sm"
|
||||
icon="add"
|
||||
@@ -1383,6 +1390,18 @@ export default function ProviderDetailPage() {
|
||||
Cookie
|
||||
</Button>
|
||||
)}
|
||||
{providerId === "codex" && (
|
||||
<Button
|
||||
size="sm"
|
||||
icon="playlist_add"
|
||||
variant="secondary"
|
||||
onClick={() => setShowBulkImportCodex(true)}
|
||||
title={translate("Bulk import codex accounts from JSON")}
|
||||
className="w-full sm:w-auto"
|
||||
>
|
||||
{translate("Bulk Add")}
|
||||
</Button>
|
||||
)}
|
||||
{hasDualAuthModes ? (
|
||||
<>
|
||||
<Button
|
||||
@@ -1544,6 +1563,14 @@ export default function ProviderDetailPage() {
|
||||
/>
|
||||
)}
|
||||
|
||||
{providerId === "codex" && (
|
||||
<BulkImportCodexModal
|
||||
isOpen={showBulkImportCodex}
|
||||
onClose={() => setShowBulkImportCodex(false)}
|
||||
onSuccess={fetchConnections}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* AG Risk Confirmation Modal */}
|
||||
<ConfirmModal
|
||||
isOpen={showAgRiskModal}
|
||||
|
||||
Reference in new issue
Block a user