feat(persona): add batch sort order update endpoint for personas and folders
Add new API endpoint POST /persona/reorder to batch update sort_order for both personas and folders. This enables drag-and-drop reordering in the dashboard UI. Changes: - Add abstract batch_update_sort_order method to BaseDatabase - Implement batch_update_sort_order in SQLiteDatabase - Add batch_update_sort_order to PersonaManager with cache refresh - Add reorder_items route handler with input validation
This commit is contained in:
@@ -345,6 +345,21 @@ class BaseDatabase(abc.ABC):
|
||||
"""Get all personas in a specific folder."""
|
||||
...
|
||||
|
||||
@abc.abstractmethod
|
||||
async def batch_update_sort_order(
|
||||
self,
|
||||
items: list[dict],
|
||||
) -> None:
|
||||
"""Batch update sort_order for personas and/or folders.
|
||||
|
||||
Args:
|
||||
items: List of dicts with keys:
|
||||
- id: The persona_id or folder_id
|
||||
- type: Either "persona" or "folder"
|
||||
- sort_order: The new sort_order value
|
||||
"""
|
||||
...
|
||||
|
||||
@abc.abstractmethod
|
||||
async def insert_preference_or_update(
|
||||
self,
|
||||
|
||||
@@ -776,6 +776,45 @@ class SQLiteDatabase(BaseDatabase):
|
||||
result = await session.execute(query)
|
||||
return list(result.scalars().all())
|
||||
|
||||
async def batch_update_sort_order(
|
||||
self,
|
||||
items: list[dict],
|
||||
) -> None:
|
||||
"""Batch update sort_order for personas and/or folders.
|
||||
|
||||
Args:
|
||||
items: List of dicts with keys:
|
||||
- id: The persona_id or folder_id
|
||||
- type: Either "persona" or "folder"
|
||||
- sort_order: The new sort_order value
|
||||
"""
|
||||
if not items:
|
||||
return
|
||||
|
||||
async with self.get_db() as session:
|
||||
session: AsyncSession
|
||||
async with session.begin():
|
||||
for item in items:
|
||||
item_id = item.get("id")
|
||||
item_type = item.get("type")
|
||||
sort_order = item.get("sort_order")
|
||||
|
||||
if item_id is None or item_type is None or sort_order is None:
|
||||
continue
|
||||
|
||||
if item_type == "persona":
|
||||
await session.execute(
|
||||
update(Persona)
|
||||
.where(col(Persona.persona_id) == item_id)
|
||||
.values(sort_order=sort_order)
|
||||
)
|
||||
elif item_type == "folder":
|
||||
await session.execute(
|
||||
update(PersonaFolder)
|
||||
.where(col(PersonaFolder.folder_id) == item_id)
|
||||
.values(sort_order=sort_order)
|
||||
)
|
||||
|
||||
async def insert_preference_or_update(self, scope, scope_id, key, value):
|
||||
"""Insert a new preference record or update if it exists."""
|
||||
async with self.get_db() as session:
|
||||
|
||||
@@ -180,6 +180,20 @@ class PersonaManager:
|
||||
"""
|
||||
await self.db.delete_persona_folder(folder_id)
|
||||
|
||||
async def batch_update_sort_order(self, items: list[dict]) -> None:
|
||||
"""批量更新 personas 和/或 folders 的排序顺序
|
||||
|
||||
Args:
|
||||
items: 包含以下键的字典列表:
|
||||
- id: persona_id 或 folder_id
|
||||
- type: "persona" 或 "folder"
|
||||
- sort_order: 新的排序顺序值
|
||||
"""
|
||||
await self.db.batch_update_sort_order(items)
|
||||
# 刷新缓存
|
||||
self.personas = await self.get_all_personas()
|
||||
self.get_v3_persona_data()
|
||||
|
||||
async def get_folder_tree(self) -> list[dict]:
|
||||
"""获取文件夹树形结构
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ class PersonaRoute(Route):
|
||||
"/persona/update": ("POST", self.update_persona),
|
||||
"/persona/delete": ("POST", self.delete_persona),
|
||||
"/persona/move": ("POST", self.move_persona),
|
||||
"/persona/reorder": ("POST", self.reorder_items),
|
||||
# Folder routes
|
||||
"/persona/folder/list": ("GET", self.list_folders),
|
||||
"/persona/folder/tree": ("GET", self.get_folder_tree),
|
||||
@@ -368,3 +369,41 @@ class PersonaRoute(Route):
|
||||
except Exception as e:
|
||||
logger.error(f"删除文件夹失败: {e!s}\n{traceback.format_exc()}")
|
||||
return Response().error(f"删除文件夹失败: {e!s}").__dict__
|
||||
|
||||
async def reorder_items(self):
|
||||
"""批量更新排序顺序
|
||||
|
||||
请求体格式:
|
||||
{
|
||||
"items": [
|
||||
{"id": "persona_id_1", "type": "persona", "sort_order": 0},
|
||||
{"id": "persona_id_2", "type": "persona", "sort_order": 1},
|
||||
{"id": "folder_id_1", "type": "folder", "sort_order": 0},
|
||||
...
|
||||
]
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = await request.get_json()
|
||||
items = data.get("items", [])
|
||||
|
||||
if not items:
|
||||
return Response().error("items 不能为空").__dict__
|
||||
|
||||
# 验证每个 item 的格式
|
||||
for item in items:
|
||||
if not all(k in item for k in ("id", "type", "sort_order")):
|
||||
return Response().error(
|
||||
"每个 item 必须包含 id, type, sort_order 字段"
|
||||
).__dict__
|
||||
if item["type"] not in ("persona", "folder"):
|
||||
return Response().error(
|
||||
"type 字段必须是 'persona' 或 'folder'"
|
||||
).__dict__
|
||||
|
||||
await self.persona_mgr.batch_update_sort_order(items)
|
||||
|
||||
return Response().ok({"message": "排序更新成功"}).__dict__
|
||||
except Exception as e:
|
||||
logger.error(f"更新排序失败: {e!s}\n{traceback.format_exc()}")
|
||||
return Response().error(f"更新排序失败: {e!s}").__dict__
|
||||
|
||||
Reference in New Issue
Block a user