mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 05:29:44 +02:00
fix(editor): Lock the skill scope for users who cannot delete the skill (no-changelog) (#41221)
This commit is contained in:
parent
f553331100
commit
1ee29b2875
|
|
@ -3465,6 +3465,7 @@
|
|||
"settings.context.skills.empty.description": "Add a skill by hand or upload a SKILL.md file. Agents in the scope of the skill can then use it.",
|
||||
"settings.context.skills.modal.scope.label": "Where can this skill be added?",
|
||||
"settings.context.skills.modal.scope.tooltip": "A global skill can be added to any agent. A project skill can be added to the agents of that project. An agent skill belongs to one agent.",
|
||||
"settings.context.skills.modal.scope.noDelete": "You need permission to delete this skill to move it, because moving removes it from where it is now.",
|
||||
"settings.context.skills.modal.scope.inUse": "Used by {count} agent. Remove the skill from it to change where it is available. | Used by {count} agents. Remove the skill from them to change where it is available.",
|
||||
"settings.context.skills.delete.inUse": "Used by {count} agent. Remove the skill from the agent first. | Used by {count} agents. Remove the skill from each agent first.",
|
||||
"settings.context.skills.delete.confirm.title": "Delete skill?",
|
||||
|
|
|
|||
|
|
@ -335,6 +335,22 @@ describe('SettingsSkillsView', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('locks the scope when the user may edit but not delete the skill', async () => {
|
||||
skillsStore.skills = [skill()];
|
||||
skillsStore.count = 1;
|
||||
skillsStore.fetchSkill.mockResolvedValue(detail({ canEdit: true, canDelete: false }));
|
||||
const { getByText } = renderView();
|
||||
await new Promise(process.nextTick);
|
||||
|
||||
await userEvent.click(getByText('research-search'));
|
||||
await new Promise(process.nextTick);
|
||||
|
||||
expect(lastModalData().readOnly).toBe(false);
|
||||
expect(lastModalData().scopeLockedReason).toBe(
|
||||
'You need permission to delete this skill to move it, because moving removes it from where it is now.',
|
||||
);
|
||||
});
|
||||
|
||||
it('moves an unused skill to the scope the user picks', async () => {
|
||||
skillsStore.skills = [skill()];
|
||||
skillsStore.count = 1;
|
||||
|
|
|
|||
|
|
@ -245,6 +245,28 @@ function scopeValueOf(skill: Pick<SkillListItem, 'scope' | 'projectId'>): string
|
|||
return skill.scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Why the scope of a saved skill cannot change, if it cannot. The backend refuses a move
|
||||
* while an agent uses the skill, and a move needs the delete permission where the skill is,
|
||||
* because it takes the skill out of that scope.
|
||||
*/
|
||||
function scopeLock(
|
||||
detail: Pick<SkillListItem, 'usedByAgents' | 'canDelete'>,
|
||||
): Pick<AgentSkillModalData, 'scopeLockedReason'> {
|
||||
if (detail.usedByAgents > 0) {
|
||||
return {
|
||||
scopeLockedReason: i18n.baseText('settings.context.skills.modal.scope.inUse', {
|
||||
interpolate: { count: detail.usedByAgents },
|
||||
adjustToNumber: detail.usedByAgents,
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (!detail.canDelete) {
|
||||
return { scopeLockedReason: i18n.baseText('settings.context.skills.modal.scope.noDelete') };
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
async function openEditModal(item: Pick<SkillListItem, 'id'>) {
|
||||
try {
|
||||
const detail = await skillsStore.fetchSkill(item.id);
|
||||
|
|
@ -254,22 +276,13 @@ async function openEditModal(item: Pick<SkillListItem, 'id'>) {
|
|||
const options = scopeOptions.value.some((option) => option.value === currentValue)
|
||||
? scopeOptions.value
|
||||
: [{ value: currentValue, ...scopeDisplay(detail) }, ...scopeOptions.value];
|
||||
// The backend refuses to move a skill while an agent uses it.
|
||||
const inUse = detail.usedByAgents > 0;
|
||||
openModal({
|
||||
skill: detail.skill,
|
||||
skillId: detail.id,
|
||||
readOnly: !detail.canEdit,
|
||||
scopeOptions: options,
|
||||
initialScope: currentValue,
|
||||
...(inUse
|
||||
? {
|
||||
scopeLockedReason: i18n.baseText('settings.context.skills.modal.scope.inUse', {
|
||||
interpolate: { count: detail.usedByAgents },
|
||||
adjustToNumber: detail.usedByAgents,
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
...scopeLock(detail),
|
||||
existingSkillNames: [],
|
||||
onConfirm: async ({ skill, scope }) =>
|
||||
await onSave(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user