Clarify Hint pack save behavior
Keep manual editing while making save the only user action and applying changes immediately without a separate publish workflow.
This commit is contained in:
@@ -17,6 +17,7 @@ export type AdminAuditAction =
|
||||
| "CONTENT_SKILL_ENABLED"
|
||||
| "CONTENT_SKILL_DISABLED"
|
||||
| "CONTENT_HINT_PACK_PUBLISHED"
|
||||
| "CONTENT_HINT_PACK_SAVED"
|
||||
| "CONTENT_HINT_FEED_SETTINGS_UPDATED"
|
||||
| "CONTENT_HINT_FEED_GENERATED";
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ export function ContentPage() {
|
||||
const saved = await adminApi.updateContentHintPack(locale, payload);
|
||||
setHintVersion(saved.version);
|
||||
setHintText(formatHintPack(saved));
|
||||
toast.success(`${locale} Hint pack 已发布`);
|
||||
toast.success(`${locale} Hint pack 已保存并生效`);
|
||||
} catch (requestError) {
|
||||
toast.error(errorMessage(requestError, "Hint pack 保存失败"));
|
||||
} finally {
|
||||
@@ -129,7 +129,7 @@ export function ContentPage() {
|
||||
<PageHeader
|
||||
eyebrow="Official Content"
|
||||
title="内容管理"
|
||||
description="维护客户端官方 Skill、AI Hint 自动生成与 zh/en 手动发布包。所有变更都会写入审计。"
|
||||
description="维护客户端官方 Skill、AI Hint 自动生成与 zh/en 内容。所有变更都会写入审计。"
|
||||
actions={
|
||||
canEdit ? (
|
||||
<Button onClick={() => setEditingSkill("new")}>
|
||||
@@ -221,7 +221,7 @@ export function ContentPage() {
|
||||
AI Hint packs
|
||||
</h2>
|
||||
<p className="mt-1 text-sm text-muted">
|
||||
JSON 必须符合 AIHintPack 卡片字段;服务端自动递增 version。
|
||||
可查看并编辑当前生效的 AIHintPack;保存后立即生效,服务端自动递增 version。
|
||||
</p>
|
||||
</div>
|
||||
<Card className="overflow-hidden">
|
||||
@@ -263,7 +263,7 @@ export function ContentPage() {
|
||||
{canEdit ? (
|
||||
<div className="mt-4 flex justify-end">
|
||||
<Button loading={hintSaving} onClick={() => void saveHint()}>
|
||||
保存并立即发布
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -239,7 +239,7 @@ export function HintAutoSection({ canEdit }: HintAutoSectionProps) {
|
||||
|
||||
<p className="text-xs text-muted">
|
||||
TopHub API Key 仅从服务器环境变量读取,不会保存到数据库或返回浏览器。
|
||||
手动 JSON 发布仍保留;下一次自动生成会发布新的双语版本。
|
||||
手动 JSON 编辑与保存仍保留;下一次自动生成会更新双语版本。
|
||||
</p>
|
||||
|
||||
{canEdit ? (
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("内容管理", () => {
|
||||
expect(screen.queryByRole("button", { name: "新增 Skill" })).toBeNull();
|
||||
const editor = await screen.findByLabelText("zh JSON");
|
||||
expect(editor).toHaveProperty("readOnly", true);
|
||||
expect(screen.queryByRole("button", { name: "保存并立即发布" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "保存" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "立即生成" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "保存生成设置" })).toBeNull();
|
||||
});
|
||||
@@ -90,6 +90,25 @@ describe("内容管理", () => {
|
||||
|
||||
await waitFor(() => expect(regenerate).toHaveBeenCalledOnce());
|
||||
});
|
||||
|
||||
it("SUPER_ADMIN 可编辑并保存当前生效的 Hint pack", async () => {
|
||||
mockSession("SUPER_ADMIN");
|
||||
mockContent();
|
||||
const save = vi.spyOn(adminApi, "updateContentHintPack").mockResolvedValue({
|
||||
locale: "zh",
|
||||
generatedAt: "2026-08-21T06:00:00Z",
|
||||
intervalHours: 12,
|
||||
version: 3,
|
||||
cards: [],
|
||||
});
|
||||
window.location.hash = "#/content";
|
||||
render(<App />);
|
||||
|
||||
await userEvent.click(await screen.findByRole("button", { name: "保存" }));
|
||||
|
||||
await waitFor(() => expect(save).toHaveBeenCalledOnce());
|
||||
expect(await screen.findByText("version 3")).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
function mockSession(role: AdminRole) {
|
||||
|
||||
@@ -34,7 +34,7 @@ The migrated generator runs independently inside OSGAccountServer and publishes:
|
||||
## Rollback
|
||||
|
||||
Disable `HINT_FEED_ENABLED` to stop scheduled generation. Published packs remain
|
||||
available from MySQL and manual publishing remains available. No rollback step
|
||||
available from MySQL and manual editing/saving remains available. No rollback step
|
||||
depends on or modifies `key.osglab.com`.
|
||||
|
||||
Provider credentials such as `TOPHUB_API_KEY` stay in environment-backed secret
|
||||
|
||||
+3
-2
@@ -808,7 +808,7 @@ paths:
|
||||
security:
|
||||
- adminMtls: []
|
||||
adminSession: []
|
||||
summary: Immediately publish a locale Hint pack and increment its version
|
||||
summary: Save and immediately apply edits to a locale Hint pack
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/HintLocale"
|
||||
- $ref: "#/components/parameters/AdminCsrf"
|
||||
@@ -819,7 +819,7 @@ paths:
|
||||
schema: { $ref: "#/components/schemas/UpdateAIHintPackRequest" }
|
||||
responses:
|
||||
"200":
|
||||
description: Published pack
|
||||
description: Saved active pack
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/AdminAIHintPack" }
|
||||
@@ -1249,6 +1249,7 @@ paths:
|
||||
- CONTENT_SKILL_ENABLED
|
||||
- CONTENT_SKILL_DISABLED
|
||||
- CONTENT_HINT_PACK_PUBLISHED
|
||||
- CONTENT_HINT_PACK_SAVED
|
||||
- CONTENT_HINT_FEED_SETTINGS_UPDATED
|
||||
- CONTENT_HINT_FEED_GENERATED
|
||||
- name: result
|
||||
|
||||
@@ -116,6 +116,7 @@ enum class AdminAuditAction {
|
||||
CONTENT_SKILL_ENABLED,
|
||||
CONTENT_SKILL_DISABLED,
|
||||
CONTENT_HINT_PACK_PUBLISHED,
|
||||
CONTENT_HINT_PACK_SAVED,
|
||||
CONTENT_HINT_FEED_SETTINGS_UPDATED,
|
||||
CONTENT_HINT_FEED_GENERATED,
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ class ContentService(
|
||||
now,
|
||||
audit(
|
||||
actor,
|
||||
AdminAuditAction.CONTENT_HINT_PACK_PUBLISHED,
|
||||
AdminAuditAction.CONTENT_HINT_PACK_SAVED,
|
||||
"OFFICIAL_HINT_PACK",
|
||||
locale,
|
||||
requestId,
|
||||
|
||||
Reference in New Issue
Block a user