H-289: add Captain Skill management UI (#47)

* H-289: add Captain Skill management UI

* H-289: guard Captain Skill assistant switches

---------

Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Rogee
2026-08-18 15:34:26 +08:00
committed by GitHub
co-authored by rogee
parent 0f2b8d7857
commit f50eacdc92
17 changed files with 1725 additions and 0 deletions
@@ -0,0 +1,34 @@
/* global axios */
import ApiClient from '../ApiClient';
class CaptainSkills extends ApiClient {
constructor() {
super('captain/skills', { accountScoped: true });
}
get({ assistantId } = {}) {
return axios.get(this.url, { params: { assistant_id: assistantId } });
}
create(data) {
return axios.post(this.url, { skill: data });
}
update(id, data) {
return axios.put(`${this.url}/${id}`, { skill: data });
}
bind({ assistantId, skillId }) {
return axios.post(
`${this.baseUrl()}/captain/assistants/${assistantId}/skills/${skillId}`
);
}
unbind({ assistantId, skillId }) {
return axios.delete(
`${this.baseUrl()}/captain/assistants/${assistantId}/skills/${skillId}`
);
}
}
export default new CaptainSkills();
@@ -0,0 +1,56 @@
import CaptainSkillsAPI from '../skills';
import ApiClient from '../../ApiClient';
describe('#CaptainSkillsAPI', () => {
beforeEach(() => {
window.history.pushState({}, '', '/app/accounts/7/captain/2/skills');
global.axios = {
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
};
});
it('uses the account skill management endpoints', () => {
CaptainSkillsAPI.get({ assistantId: 2 });
CaptainSkillsAPI.show(3);
CaptainSkillsAPI.create({ name: 'Refunds' });
CaptainSkillsAPI.update(3, { expected_version: 1 });
CaptainSkillsAPI.delete(3);
expect(axios.get).toHaveBeenNthCalledWith(
1,
'/api/v1/accounts/7/captain/skills',
{ params: { assistant_id: 2 } }
);
expect(axios.get).toHaveBeenNthCalledWith(
2,
'/api/v1/accounts/7/captain/skills/3'
);
expect(axios.post).toHaveBeenCalledWith(
'/api/v1/accounts/7/captain/skills',
{ skill: { name: 'Refunds' } }
);
expect(axios.put).toHaveBeenCalledWith(
'/api/v1/accounts/7/captain/skills/3',
{ skill: { expected_version: 1 } }
);
expect(axios.delete).toHaveBeenCalledWith(
'/api/v1/accounts/7/captain/skills/3'
);
});
it('binds and unbinds a skill for one assistant', () => {
CaptainSkillsAPI.bind({ assistantId: 2, skillId: 3 });
CaptainSkillsAPI.unbind({ assistantId: 2, skillId: 3 });
const url = '/api/v1/accounts/7/captain/assistants/2/skills/3';
expect(axios.post).toHaveBeenCalledWith(url);
expect(axios.delete).toHaveBeenCalledWith(url);
});
it('is an account-scoped API client', () => {
expect(CaptainSkillsAPI).toBeInstanceOf(ApiClient);
});
});