fix(agent-assets): save rule markdown atomically
This commit is contained in:
@@ -405,6 +405,14 @@ export function createAgentAssetVersion(assetId, payload, options = {}) {
|
||||
})
|
||||
}
|
||||
|
||||
export function saveAgentAssetRuleMarkdown(assetId, payload, options = {}) {
|
||||
return apiRequest(`/agent-assets/${assetId}/rule-markdown`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
headers: buildWriteHeaders(options)
|
||||
})
|
||||
}
|
||||
|
||||
export function createAgentAssetReview(assetId, payload, options = {}) {
|
||||
return apiRequest(`/agent-assets/${assetId}/reviews`, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {
|
||||
activateAgentAsset,
|
||||
createAgentAssetVersion,
|
||||
restoreAgentAssetVersion,
|
||||
updateAgentAsset
|
||||
saveAgentAssetRuleMarkdown
|
||||
} from '../../services/agentAssets.js'
|
||||
import {
|
||||
buildRuleConfigPayload,
|
||||
@@ -26,16 +25,6 @@ export function useAuditRuleVersionActions({
|
||||
resolveActor,
|
||||
toast
|
||||
}) {
|
||||
async function persistRuleRuntimeConfig(asset, runtimeRule) {
|
||||
await updateAgentAsset(
|
||||
asset.id,
|
||||
{
|
||||
config_json: buildRuleConfigPayload(asset, runtimeRule)
|
||||
},
|
||||
{ actor: resolveActor() }
|
||||
)
|
||||
}
|
||||
|
||||
async function saveRuleVersion({ action, changeNote, successLabel }) {
|
||||
if (
|
||||
!selectedSkill.value ||
|
||||
@@ -62,18 +51,18 @@ export function useAuditRuleVersionActions({
|
||||
actionState.value = action
|
||||
|
||||
try {
|
||||
await createAgentAssetVersion(
|
||||
const actor = resolveActor()
|
||||
await saveAgentAssetRuleMarkdown(
|
||||
selectedSkill.value.id,
|
||||
{
|
||||
version: nextVersion,
|
||||
content: buildMarkdownVersionContent(selectedSkill.value.markdownContent, runtimeRule),
|
||||
content_type: 'markdown',
|
||||
config_json: buildRuleConfigPayload(selectedSkill.value, runtimeRule),
|
||||
change_note: changeNote,
|
||||
created_by: resolveActor()
|
||||
created_by: actor
|
||||
},
|
||||
{ actor: resolveActor() }
|
||||
{ actor }
|
||||
)
|
||||
await persistRuleRuntimeConfig(selectedSkill.value, runtimeRule)
|
||||
await refreshCurrentAssets()
|
||||
await loadSelectedAssetDetail(selectedSkill.value.id, { silent: true })
|
||||
toast(`${successLabel} ${nextVersion}。`)
|
||||
|
||||
73
web/tests/audit-rule-markdown-atomic-save.test.mjs
Normal file
73
web/tests/audit-rule-markdown-atomic-save.test.mjs
Normal file
@@ -0,0 +1,73 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { useAuditRuleVersionActions } from '../src/views/scripts/useAuditRuleVersionActions.js'
|
||||
|
||||
test('规则 Markdown 与运行时 JSON 通过单一原子接口保存', async (t) => {
|
||||
const requests = []
|
||||
const originalFetch = globalThis.fetch
|
||||
t.after(() => {
|
||||
globalThis.fetch = originalFetch
|
||||
})
|
||||
globalThis.fetch = async (url, options) => {
|
||||
requests.push({ url, options })
|
||||
return {
|
||||
ok: true,
|
||||
status: 201,
|
||||
json: async () => ({ version: 'v1.0.1' })
|
||||
}
|
||||
}
|
||||
|
||||
let refreshCount = 0
|
||||
let detailCount = 0
|
||||
const notices = []
|
||||
const actionState = ref('')
|
||||
const actions = useAuditRuleVersionActions({
|
||||
selectedSkill: ref({
|
||||
id: 'rule-id',
|
||||
currentVersion: 'v1.0.0',
|
||||
markdownContent: '# 差旅规则',
|
||||
runtimeRuleText: JSON.stringify({
|
||||
kind: 'policy_rule_draft',
|
||||
version: 2,
|
||||
template_key: 'general_policy_v1',
|
||||
rule_name: '差旅规则',
|
||||
scenario: 'travel',
|
||||
review_required: true
|
||||
}),
|
||||
config_json: { preserved: 'server-field' },
|
||||
usesSpreadsheetRule: false
|
||||
}),
|
||||
selectedSkillIsRule: ref(true),
|
||||
canEditMarkdown: ref(true),
|
||||
canManageSelected: ref(true),
|
||||
actionState,
|
||||
detailBusy: ref(false),
|
||||
refreshCurrentAssets: async () => {
|
||||
refreshCount += 1
|
||||
},
|
||||
loadSelectedAssetDetail: async () => {
|
||||
detailCount += 1
|
||||
},
|
||||
resolveActor: () => 'username:finance',
|
||||
toast: (message) => notices.push(message)
|
||||
})
|
||||
|
||||
await actions.saveRuleMarkdown()
|
||||
|
||||
assert.equal(requests.length, 1)
|
||||
assert.equal(requests[0].url, '/api/v1/agent-assets/rule-id/rule-markdown')
|
||||
assert.equal(requests[0].options.method, 'POST')
|
||||
const body = JSON.parse(requests[0].options.body)
|
||||
assert.equal(body.version, 'v1.0.1')
|
||||
assert.equal(body.created_by, 'username:finance')
|
||||
assert.equal(body.config_json.runtime_rule.version, 2)
|
||||
assert.equal(body.config_json.preserved, 'server-field')
|
||||
assert.match(body.content, /```expense-rule/)
|
||||
assert.equal('content_type' in body, false)
|
||||
assert.equal(refreshCount, 1)
|
||||
assert.equal(detailCount, 1)
|
||||
assert.equal(actionState.value, '')
|
||||
assert.deepEqual(notices, ['规则 Markdown 已保存为 v1.0.1。'])
|
||||
})
|
||||
Reference in New Issue
Block a user