feat(gui): add task deletion menus
This commit is contained in:
@@ -9026,6 +9026,192 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_generate_tab_context_menu_soft_deletes_only_clicked_task(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": row,
|
||||
"account_name": "主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": item_id,
|
||||
}
|
||||
for row, item_id in ((2, "51100639510"), (3, "51100639511"))
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
first, second = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
for task in (first, second):
|
||||
db.set_collected(task.id, "旧标题", "old.jpg", path=cfg["db_path"])
|
||||
db.set_generated(task.id, "新标题", "new.jpg", path=cfg["db_path"])
|
||||
db.set_applied(first.id, True, path=cfg["db_path"])
|
||||
statuses = []
|
||||
refresh_calls = []
|
||||
tab = GenerateTab(
|
||||
config=cfg,
|
||||
status_callback=statuses.append,
|
||||
refresh_workflow_callback=lambda: refresh_calls.append(True),
|
||||
)
|
||||
self.addCleanup(tab.close)
|
||||
tab.resize(1000, 600)
|
||||
tab.show()
|
||||
QApplication.processEvents()
|
||||
first_rect = tab.task_table.visualRect(tab.model.index(0, 0))
|
||||
self.assertTrue(first_rect.isValid())
|
||||
|
||||
class FakeMenu:
|
||||
instances = []
|
||||
|
||||
def __init__(self, parent=None):
|
||||
self.actions = []
|
||||
FakeMenu.instances.append(self)
|
||||
|
||||
def addAction(self, text):
|
||||
action = SimpleNamespace(
|
||||
text=text,
|
||||
enabled=True,
|
||||
triggered=DummySignal(),
|
||||
)
|
||||
action.setEnabled = lambda enabled: setattr(action, "enabled", bool(enabled))
|
||||
self.actions.append(action)
|
||||
return action
|
||||
|
||||
def exec(self, position):
|
||||
return None
|
||||
|
||||
with mock.patch("app.gui.tabs.generate.QMenu", FakeMenu):
|
||||
tab.show_task_context_menu(first_rect.center())
|
||||
self.assertEqual(0, tab.task_table.currentIndex().row())
|
||||
self.assertEqual(["删除本条记录"], [action.text for action in FakeMenu.instances[0].actions])
|
||||
self.assertTrue(FakeMenu.instances[0].actions[0].enabled)
|
||||
|
||||
with mock.patch(
|
||||
"app.gui.tabs.generate.QMessageBox.question",
|
||||
return_value=gui.QMessageBox.No,
|
||||
) as question:
|
||||
tab.delete_selected_task()
|
||||
self.assertIsNotNone(db.get_task(first.id, path=cfg["db_path"]))
|
||||
self.assertIn("不会回滚蝦皮线上商品", question.call_args[0][2])
|
||||
self.assertIn("已取消删除本条记录", statuses[-1])
|
||||
|
||||
with mock.patch(
|
||||
"app.gui.tabs.generate.QMessageBox.question",
|
||||
return_value=gui.QMessageBox.Yes,
|
||||
), mock.patch("app.gui.tabs.generate.QMessageBox.information") as information:
|
||||
tab.delete_selected_task()
|
||||
self.assertIsNone(db.get_task(first.id, path=cfg["db_path"]))
|
||||
self.assertEqual([second.id], [task.id for task in tab.model.tasks])
|
||||
self.assertEqual([True], refresh_calls)
|
||||
self.assertIn("已删除本地记录:商品 51100639510", information.call_args[0][2])
|
||||
|
||||
tab.generate_thread = object()
|
||||
tab.delete_selected_task()
|
||||
self.assertIn("AI 生成正在进行,不能删除记录", statuses[-1])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_apply_tab_context_menu_keeps_reset_and_soft_deletes_clicked_task(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": row,
|
||||
"account_name": "主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": item_id,
|
||||
}
|
||||
for row, item_id in ((2, "51100639510"), (3, "51100639511"))
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
first, second = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
for task in (first, second):
|
||||
db.set_collected(task.id, "旧标题", "old.jpg", path=cfg["db_path"])
|
||||
db.set_generated(task.id, "新标题", "new.jpg", path=cfg["db_path"])
|
||||
db.set_applied(first.id, True, path=cfg["db_path"])
|
||||
statuses = []
|
||||
refresh_calls = []
|
||||
tab = ApplyTab(
|
||||
config=cfg,
|
||||
status_callback=statuses.append,
|
||||
refresh_workflow_callback=lambda: refresh_calls.append(True),
|
||||
)
|
||||
self.addCleanup(tab.close)
|
||||
tab.status_filter.setCurrentIndex(tab.status_filter.findData("all"))
|
||||
tab.resize(1000, 600)
|
||||
tab.show()
|
||||
QApplication.processEvents()
|
||||
first_rect = tab.task_table.visualRect(tab.model.index(0, 0))
|
||||
self.assertTrue(first_rect.isValid())
|
||||
|
||||
class FakeMenu:
|
||||
instances = []
|
||||
|
||||
def __init__(self, parent=None):
|
||||
self.actions = []
|
||||
self.separator_count = 0
|
||||
FakeMenu.instances.append(self)
|
||||
|
||||
def addAction(self, text):
|
||||
action = SimpleNamespace(
|
||||
text=text,
|
||||
enabled=True,
|
||||
triggered=DummySignal(),
|
||||
)
|
||||
action.setEnabled = lambda enabled: setattr(action, "enabled", bool(enabled))
|
||||
self.actions.append(action)
|
||||
return action
|
||||
|
||||
def addSeparator(self):
|
||||
self.separator_count += 1
|
||||
|
||||
def exec(self, position):
|
||||
return None
|
||||
|
||||
with mock.patch("app.gui.tabs.apply.QMenu", FakeMenu):
|
||||
tab.show_task_context_menu(first_rect.center())
|
||||
self.assertEqual(0, tab.task_table.currentIndex().row())
|
||||
menu = FakeMenu.instances[0]
|
||||
self.assertEqual(["重置更新状态", "删除本条记录"], [action.text for action in menu.actions])
|
||||
self.assertEqual(1, menu.separator_count)
|
||||
self.assertTrue(all(action.enabled for action in menu.actions))
|
||||
|
||||
with mock.patch(
|
||||
"app.gui.tabs.apply.QMessageBox.question",
|
||||
return_value=gui.QMessageBox.No,
|
||||
) as question:
|
||||
tab.delete_selected_task()
|
||||
self.assertIsNotNone(db.get_task(first.id, path=cfg["db_path"]))
|
||||
self.assertIn("不会回滚蝦皮线上商品", question.call_args[0][2])
|
||||
|
||||
with mock.patch(
|
||||
"app.gui.tabs.apply.QMessageBox.question",
|
||||
return_value=gui.QMessageBox.Yes,
|
||||
), mock.patch("app.gui.tabs.apply.QMessageBox.information") as information:
|
||||
tab.delete_selected_task()
|
||||
self.assertIsNone(db.get_task(first.id, path=cfg["db_path"]))
|
||||
self.assertEqual([second.id], [task.id for task in tab.model.tasks])
|
||||
self.assertEqual([True], refresh_calls)
|
||||
self.assertIn("已删除本地记录:商品 51100639510", information.call_args[0][2])
|
||||
|
||||
tab.apply_thread = object()
|
||||
tab.delete_selected_task()
|
||||
self.assertIn("更新或回写正在进行,不能删除记录", statuses[-1])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_collect_tab_can_filter_unmatched_tasks_from_summary_bar(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
|
||||
Reference in New Issue
Block a user