Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ export function EditKeyForm({ keyData, user, isAdmin = false, onSuccess }: EditK
try {
const res = await editKey(keyData.id, {
name: data.name,
expiresAt: data.expiresAt || undefined,
// 重要:清除到期时间时用空字符串表达,避免 undefined 在 Server Action 序列化时被丢弃
expiresAt: data.expiresAt ?? "",
canLoginWebUi: data.canLoginWebUi,
cacheTtlPreference: data.cacheTtlPreference,
limit5hUsd: data.limit5hUsd,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,8 @@ function UnifiedEditDialogInner({
const keyRes = await addKey({
userId: user.id,
name: key.name,
expiresAt: key.expiresAt || undefined,
// 重要:清除到期时间时用空字符串表达,避免 undefined 在 Server Action 序列化时被丢弃
expiresAt: key.expiresAt ?? "",
isEnabled: key.isEnabled,
canLoginWebUi: key.canLoginWebUi,
providerGroup: normalizeProviderGroup(key.providerGroup),
Expand All @@ -466,7 +467,8 @@ function UnifiedEditDialogInner({
// Existing key - edit it
const keyRes = await editKey(key.id, {
name: key.name,
expiresAt: key.expiresAt || undefined,
// 重要:清除到期时间时用空字符串表达,避免 undefined 在 Server Action 序列化时被丢弃
expiresAt: key.expiresAt ?? "",
canLoginWebUi: key.canLoginWebUi,
isEnabled: key.isEnabled,
providerGroup: normalizeProviderGroup(key.providerGroup),
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/actions/keys-edit-key-expires-at-clear.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ describe("editKey: expiresAt 清除/不更新语义", () => {
);
});

test('携带 expiresAt="" 时应清除 expires_at(写入 null)', async () => {
const { editKey } = await import("@/actions/keys");

const res = await editKey(1, { name: "k2", expiresAt: "" });

expect(res.ok).toBe(true);
expect(updateKeyMock).toHaveBeenCalledTimes(1);
expect(updateKeyMock).toHaveBeenCalledWith(
1,
expect.objectContaining({
expires_at: null,
})
);
});

test("携带 expiresAt=YYYY-MM-DD 时应写入对应 Date", async () => {
const { editKey } = await import("@/actions/keys");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ describe("EditKeyForm: 清除 expiresAt 后应携带 expiresAt 字段提交(
expect(keysActionMocks.editKey).toHaveBeenCalledTimes(1);
const [, payload] = keysActionMocks.editKey.mock.calls[0] as [number, any];

// 关键点:必须显式携带 expiresAt 字段(即使为 undefined),后端才会识别为“清除”
// 关键点:必须显式携带 expiresAt 字段(清除时通常为 ""),后端才会识别为“清除”
expect(Object.hasOwn(payload, "expiresAt")).toBe(true);

unmount();
Expand Down
Loading