fix(web): protect skill bindings in version view

This commit is contained in:
zxhlyh 2026-07-28 16:21:43 +08:00 committed by fatelei
parent 4cc89a054b
commit a6948b57e6
No known key found for this signature in database
GPG Key ID: 2F91DA05646F4EED
2 changed files with 58 additions and 10 deletions

View File

@ -1399,7 +1399,28 @@ describe('AgentSkills', () => {
)
})
it('should disable add and remove actions when viewing a version', () => {
it('should disable add and remove actions when viewing a version', async () => {
const user = userEvent.setup()
mocks.agentSkillBindingsQueryOptions.mockImplementation((options) => {
const { input } = options as { input: { params: { agent_id: string } } }
return {
queryKey: ['workspace-agent-skills', input],
queryFn: async () => ({
agent_id: input.params.agent_id,
skill_ids: ['workspace-skill-1'],
data: [
{
...createWorkspaceSkill(),
priority: 0,
status: 'published',
file_count: 1,
latest_published_at: 1,
},
],
}),
}
})
const { container } = renderAgentSkills({
apiContext: {
agentId: 'agent-1',
@ -1414,6 +1435,20 @@ describe('AgentSkills', () => {
screen.queryByRole('button', { name: /agentV2\.agentDetail\.configure\.skills\.add/i }),
).not.toBeInTheDocument()
expect(container.querySelector('[data-agent-skill-remove-button]')).toBeNull()
await user.click(
await screen.findByRole('button', {
name: 'agentV2.agentDetail.configure.skills.moreActions:{"name":"Refund approval"}',
}),
)
expect(
screen.getByText('agentV2.agentDetail.configure.skills.openInLibrary'),
).toBeInTheDocument()
expect(
screen.queryByText('agentV2.agentDetail.configure.skills.removeAction'),
).not.toBeInTheDocument()
expect(mocks.replaceAgentSkillBindingsMutationFn).not.toHaveBeenCalled()
})
it('should keep the add menu available for build draft skills', async () => {

View File

@ -304,9 +304,11 @@ function WorkspaceSkillSelector({
}
function WorkspaceAgentSkillItem({
canRemove,
skill,
onRemove,
}: {
canRemove: boolean
skill: AgentSkillBindingItemResponse
onRemove: (skillId: string) => void
}) {
@ -359,14 +361,16 @@ function WorkspaceAgentSkillItem({
<span aria-hidden className="i-ri-arrow-right-up-line size-4 shrink-0" />
<span>{t(($) => $['agentDetail.configure.skills.openInLibrary'])}</span>
</DropdownMenuItem>
<DropdownMenuItem
variant="destructive"
className="gap-2"
onClick={() => onRemove(skill.id)}
>
<span aria-hidden className="i-ri-delete-bin-line size-4 shrink-0" />
<span>{t(($) => $['agentDetail.configure.skills.removeAction'])}</span>
</DropdownMenuItem>
{canRemove && (
<DropdownMenuItem
variant="destructive"
className="gap-2"
onClick={() => onRemove(skill.id)}
>
<span aria-hidden className="i-ri-delete-bin-line size-4 shrink-0" />
<span>{t(($) => $['agentDetail.configure.skills.removeAction'])}</span>
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
@ -426,6 +430,8 @@ export function AgentSkills() {
const replaceWorkspaceSkillBindings = useCallback(
(skillIds: string[], onSuccess?: () => void) => {
if (isViewingVersion) return
replaceAgentSkillBindings(
{
params: {
@ -446,7 +452,13 @@ export function AgentSkills() {
},
)
},
[apiContext.agentId, invalidateAgentSkillBindings, replaceAgentSkillBindings, t],
[
apiContext.agentId,
invalidateAgentSkillBindings,
isViewingVersion,
replaceAgentSkillBindings,
t,
],
)
const handleOpenUpload = useCallback((options?: AgentOrchestrateAddActionOptions) => {
@ -634,6 +646,7 @@ export function AgentSkills() {
{workspaceSkills.map((skill) => (
<WorkspaceAgentSkillItem
key={skill.id}
canRemove={!isViewingVersion}
skill={skill}
onRemove={handleRemoveWorkspaceSkill}
/>