From 8d5841b71f089e5605c4b03acf24ae25e43524ad Mon Sep 17 00:00:00 2001 From: RC-CHN <1051989940@qq.com> Date: Thu, 26 Feb 2026 14:48:20 +0800 Subject: [PATCH] feat(skills): add neo candidate and release deletion Add backend routes to delete neo candidates and releases with optional reason support and demo mode protection. Expose delete actions in the Skills dashboard for candidate and release rows, refresh data after success, and add localized success/failure messages in en-US and zh-CN. --- astrbot/dashboard/routes/skills.py | 52 +++++++ .../components/extension/SkillsSection.vue | 143 ++++++++++++++++-- .../locales/en-US/features/extension.json | 3 + .../locales/zh-CN/features/extension.json | 6 + 4 files changed, 191 insertions(+), 13 deletions(-) diff --git a/astrbot/dashboard/routes/skills.py b/astrbot/dashboard/routes/skills.py index fb8e71ab6..3c1682baf 100644 --- a/astrbot/dashboard/routes/skills.py +++ b/astrbot/dashboard/routes/skills.py @@ -53,6 +53,8 @@ class SkillsRoute(Route): "/skills/neo/promote": ("POST", self.promote_neo_candidate), "/skills/neo/rollback": ("POST", self.rollback_neo_release), "/skills/neo/sync": ("POST", self.sync_neo_release), + "/skills/neo/delete-candidate": ("POST", self.delete_neo_candidate), + "/skills/neo/delete-release": ("POST", self.delete_neo_release), } self.register_routes() @@ -76,6 +78,14 @@ class SkillsRoute(Route): ) return endpoint, access_token + async def _delete_neo_release(self, client: Any, release_id: str, reason: str | None): + return await client.skills.delete_release(release_id, reason=reason) + + async def _delete_neo_candidate( + self, client: Any, candidate_id: str, reason: str | None + ): + return await client.skills.delete_candidate(candidate_id, reason=reason) + async def _with_neo_client( self, operation: Callable[[Any], Awaitable[dict]], @@ -415,3 +425,45 @@ class SkillsRoute(Route): ) return await self._with_neo_client(_do) + + async def delete_neo_candidate(self): + if DEMO_MODE: + return ( + Response() + .error("You are not permitted to do this operation in demo mode") + .__dict__ + ) + logger.info("[Neo] POST /skills/neo/delete-candidate requested.") + data = await request.get_json() + candidate_id = data.get("candidate_id") + reason = data.get("reason") + if not candidate_id: + return Response().error("Missing candidate_id").__dict__ + + async def _do(client): + result = await self._delete_neo_candidate(client, candidate_id, reason) + logger.info(f"[Neo] Candidate deleted: id={candidate_id}") + return Response().ok(_to_jsonable(result)).__dict__ + + return await self._with_neo_client(_do) + + async def delete_neo_release(self): + if DEMO_MODE: + return ( + Response() + .error("You are not permitted to do this operation in demo mode") + .__dict__ + ) + logger.info("[Neo] POST /skills/neo/delete-release requested.") + data = await request.get_json() + release_id = data.get("release_id") + reason = data.get("reason") + if not release_id: + return Response().error("Missing release_id").__dict__ + + async def _do(client): + result = await self._delete_neo_release(client, release_id, reason) + logger.info(f"[Neo] Release deleted: id={release_id}") + return Response().ok(_to_jsonable(result)).__dict__ + + return await self._with_neo_client(_do) diff --git a/dashboard/src/components/extension/SkillsSection.vue b/dashboard/src/components/extension/SkillsSection.vue index 686890247..8ac2c6143 100644 --- a/dashboard/src/components/extension/SkillsSection.vue +++ b/dashboard/src/components/extension/SkillsSection.vue @@ -63,56 +63,73 @@