Coverage for aipyapp/gui/apimarket.py: 0%

374 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-11 12:02 +0200

1 

2import traceback 

3 

4import wx 

5from loguru import logger 

6from wx.lib.scrolledpanel import ScrolledPanel 

7 

8from .. import T 

9 

10class ApiItemPanel(wx.Panel): 

11 """单个API配置项面板""" 

12 def __init__(self, parent, api_name, api_config, on_edit=None, on_delete=None): 

13 super().__init__(parent, style=wx.BORDER_SIMPLE) 

14 self.api_name = api_name 

15 self.api_config = api_config 

16 self.on_edit = on_edit 

17 self.on_delete = on_delete 

18 

19 # 创建布局 

20 main_sizer = wx.BoxSizer(wx.VERTICAL) 

21 

22 # API名称 

23 name_sizer = wx.BoxSizer(wx.HORIZONTAL) 

24 name_label = wx.StaticText(self, label=f"{T('API Name')}: {api_name}") 

25 name_label.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) 

26 name_sizer.Add(name_label, 1, wx.EXPAND | wx.ALL, 5) 

27 

28 # 添加按钮 

29 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 

30 edit_button = wx.Button(self, label=T("Edit")) 

31 edit_button.Bind(wx.EVT_BUTTON, self.on_edit_click) 

32 delete_button = wx.Button(self, label=T("Delete")) 

33 delete_button.Bind(wx.EVT_BUTTON, self.on_delete_click) 

34 

35 button_sizer.Add(edit_button, 0, wx.ALL, 5) 

36 button_sizer.Add(delete_button, 0, wx.ALL, 5) 

37 name_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5) 

38 

39 main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 5) 

40 

41 # API详情 

42 details_sizer = wx.BoxSizer(wx.VERTICAL) 

43 

44 # 显示API KEY(s) 

45 envs = api_config.get('env', {}) 

46 for key_name in envs: 

47 key_value = envs[key_name] 

48 if isinstance(key_value, list) and len(key_value) > 0: 

49 masked_key = self.mask_api_key(key_value[0]) 

50 display_key = key_name 

51 key_text = wx.StaticText(self, label=f"{display_key}: {masked_key}") 

52 details_sizer.Add(key_text, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 10) 

53 

54 # 显示描述 

55 if 'desc' in api_config: 

56 desc_text = wx.StaticText(self, label=f"{T('Description')}: {api_config['desc']}") 

57 details_sizer.Add(desc_text, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10) 

58 

59 main_sizer.Add(details_sizer, 0, wx.EXPAND | wx.ALL, 5) 

60 

61 self.SetSizer(main_sizer) 

62 self.Layout() 

63 

64 def mask_api_key(self, key): 

65 """将API密钥进行掩码处理,只显示前3位和后3位""" 

66 if not key or len(key) < 8: 

67 return key 

68 return key[:3] + "..." + key[-3:] 

69 

70 def on_edit_click(self, event): 

71 if self.on_edit: 

72 self.on_edit(self.api_name, self.api_config) 

73 

74 def on_delete_click(self, event): 

75 if self.on_delete: 

76 dlg = wx.MessageDialog( 

77 self, 

78 f"{T('Are you sure to delete API')} '{self.api_name}'?", 

79 T("Confirm Delete"), 

80 wx.YES_NO | wx.ICON_QUESTION 

81 ) 

82 result = dlg.ShowModal() 

83 dlg.Destroy() 

84 

85 if result == wx.ID_YES and self.on_delete: 

86 self.on_delete(self.api_name) 

87 

88 

89class ApiEditDialog(wx.Dialog): 

90 """API编辑对话框""" 

91 def __init__(self, parent, api_name="", api_config=None, is_new=True): 

92 title = T("Add API") if is_new else T("Edit API") 

93 super().__init__(parent, title=title, size=(600, 500)) 

94 

95 self.is_new = is_new 

96 self.api_name = api_name 

97 self.api_config = api_config or {"desc": ""} 

98 

99 self._init_ui() 

100 

101 def _init_ui(self): 

102 """初始化UI界面""" 

103 main_sizer = wx.BoxSizer(wx.VERTICAL) 

104 

105 # API名称 

106 name_sizer = wx.BoxSizer(wx.HORIZONTAL) 

107 name_label = wx.StaticText(self, label=T("API Name")) 

108 self.name_input = wx.TextCtrl(self) 

109 if not self.is_new: 

110 self.name_input.SetValue(self.api_name) 

111 self.name_input.Enable(False) # 编辑模式下不允许更改名称 

112 

113 name_sizer.Add(name_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

114 name_sizer.Add(self.name_input, 1, wx.ALL | wx.EXPAND, 5) 

115 

116 main_sizer.Add(name_sizer, 0, wx.EXPAND | wx.ALL, 10) 

117 

118 # API环境变量标题行 

119 env_header_sizer = wx.BoxSizer(wx.HORIZONTAL) 

120 env_label = wx.StaticText(self, label=T("API Key Settings")) 

121 add_env_button = wx.Button(self, label=T("Add Environment Variable")) 

122 add_env_button.Bind(wx.EVT_BUTTON, self.on_add_env) 

123 

124 env_header_sizer.Add(env_label, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 10) 

125 env_header_sizer.Add(add_env_button, 0, wx.ALIGN_CENTER_VERTICAL) 

126 main_sizer.Add(env_header_sizer, 0, wx.ALL, 10) 

127 

128 # 环境变量列表 

129 self.env_panel = wx.ScrolledWindow(self) 

130 self.env_panel.SetScrollRate(0, 20) 

131 self.env_sizer = wx.BoxSizer(wx.VERTICAL) 

132 self.env_panel.SetSizer(self.env_sizer) 

133 

134 # 添加已有的环境变量 

135 self.env_controls = [] 

136 

137 # 查找环境变量键 

138 env_vars = {} 

139 if 'env' in self.api_config and isinstance(self.api_config['env'], dict): 

140 for key, value in self.api_config['env'].items(): 

141 env_vars[key] = value 

142 

143 # 添加找到的环境变量 

144 for var_name, value in env_vars.items(): 

145 self.add_env_control(var_name, value) 

146 

147 # 如果是新建API且没有环境变量,则默认添加一个空的环境变量控件 

148 if self.is_new and not env_vars: 

149 self.add_env_control("api_key", [T("Enter your API key"), T("API key description")]) 

150 

151 main_sizer.Add(self.env_panel, 2, wx.EXPAND | wx.ALL, 10) # 增加比例权重到2 

152 

153 # 描述 

154 desc_sizer = wx.BoxSizer(wx.VERTICAL) 

155 desc_label = wx.StaticText(self, label=T("API Description")) 

156 

157 # 使用更大的多行文本框 

158 self.desc_input = wx.TextCtrl(self, style=wx.TE_MULTILINE) 

159 # 设置更大的字体和最小高度 

160 font = wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) 

161 self.desc_input.SetFont(font) 

162 self.desc_input.SetMinSize((-1, 100)) # 设置最小高度 

163 

164 if 'desc' in self.api_config: 

165 self.desc_input.SetValue(self.api_config['desc']) 

166 

167 # 添加提示文本 

168 desc_hint = wx.StaticText(self, label=T("Hint: Description supports multi-line text, will be saved in markdown format")) 

169 desc_hint.SetFont(wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 

170 

171 desc_sizer.Add(desc_label, 0, wx.ALL, 5) 

172 desc_sizer.Add(self.desc_input, 1, wx.EXPAND | wx.ALL, 5) 

173 desc_sizer.Add(desc_hint, 0, wx.LEFT | wx.BOTTOM, 5) 

174 

175 main_sizer.Add(desc_sizer, 1, wx.EXPAND | wx.ALL, 10) 

176 

177 # 按钮 

178 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 

179 save_button = wx.Button(self, wx.ID_OK, T("Save and Apply")) 

180 cancel_button = wx.Button(self, wx.ID_CANCEL, T("Cancel")) 

181 

182 button_sizer.Add(save_button, 0, wx.ALL, 5) 

183 button_sizer.Add(cancel_button, 0, wx.ALL, 5) 

184 

185 main_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 10) 

186 

187 self.SetSizer(main_sizer) 

188 self.Layout() 

189 

190 # 设置最小窗口大小 

191 self.SetMinSize((600, 500)) 

192 

193 def add_env_control(self, key_name="", key_value=None): 

194 """添加一个环境变量控制项""" 

195 if len(self.env_controls) >= 2: 

196 return 

197 

198 if key_value is None: 

199 key_value = ["", T("API key description")] 

200 

201 env_item = wx.Panel(self.env_panel) 

202 item_sizer = wx.BoxSizer(wx.HORIZONTAL) 

203 

204 # 变量名 

205 key_name_label = wx.StaticText(env_item, label=f"{T('Variable Name')}:") 

206 key_name_input = wx.TextCtrl(env_item, size=(150, -1)) 

207 key_name_input.SetValue(key_name) 

208 

209 # 值 

210 key_value_label = wx.StaticText(env_item, label=f"{T('Value')}:") 

211 key_value_input = wx.TextCtrl(env_item, size=(150, -1)) 

212 if isinstance(key_value, list) and len(key_value) > 0: 

213 key_value_input.SetValue(key_value[0]) 

214 

215 # 描述 

216 key_desc_label = wx.StaticText(env_item, label=f"{T('Description')}:") 

217 key_desc_input = wx.TextCtrl(env_item, size=(150, -1)) 

218 if isinstance(key_value, list) and len(key_value) > 1: 

219 key_desc_input.SetValue(key_value[1]) 

220 

221 # 删除按钮 

222 delete_button = wx.Button(env_item, label=T("Remove")) 

223 delete_button.Bind(wx.EVT_BUTTON, lambda evt, item=env_item: self.remove_env_item(item)) 

224 

225 # 添加到布局 

226 item_sizer.Add(key_name_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

227 item_sizer.Add(key_name_input, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

228 item_sizer.Add(key_value_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

229 item_sizer.Add(key_value_input, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

230 item_sizer.Add(key_desc_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

231 item_sizer.Add(key_desc_input, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

232 item_sizer.Add(delete_button, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) 

233 

234 env_item.SetSizer(item_sizer) 

235 self.env_sizer.Add(env_item, 0, wx.EXPAND | wx.ALL, 5) 

236 

237 # 添加分隔线 

238 separator = wx.StaticLine(self.env_panel) 

239 self.env_sizer.Add(separator, 0, wx.EXPAND | wx.ALL, 5) 

240 

241 self.env_controls.append({ 

242 'panel': env_item, 

243 'name': key_name_input, 

244 'value': key_value_input, 

245 'desc': key_desc_input 

246 }) 

247 

248 self.env_panel.Layout() 

249 # 确保新添加的控件可见 

250 self.env_panel.Scroll(0, self.env_sizer.GetSize().GetHeight()) 

251 

252 def remove_env_item(self, item): 

253 """移除环境变量控制项""" 

254 for i, ctrl in enumerate(self.env_controls): 

255 if ctrl['panel'] == item: 

256 item.Destroy() 

257 self.env_controls.pop(i) 

258 break 

259 

260 self.env_panel.Layout() 

261 self.env_panel.SetupScrolling() 

262 

263 def on_add_env(self, event): 

264 """添加新的环境变量""" 

265 if len(self.env_controls) >= 2: 

266 wx.MessageBox(T("You can only add two environment variables at most"), T("Hint"), wx.OK | wx.ICON_INFORMATION) 

267 return 

268 self.add_env_control() 

269 

270 def get_api_config(self): 

271 """获取编辑后的API配置""" 

272 name = self.name_input.GetValue().strip() 

273 

274 config = { 

275 "desc": self.desc_input.GetValue() # 保留原始格式,包括换行 

276 } 

277 

278 env = {} 

279 for ctrl in self.env_controls: 

280 # 获取用户输入的键名 

281 key_name = ctrl['name'].GetValue().strip() 

282 

283 # 如果键名为空,则跳过 

284 if not key_name: 

285 continue 

286 

287 key_value = ctrl['value'].GetValue().strip() 

288 key_desc = ctrl['desc'].GetValue().strip() 

289 

290 env[key_name] = [key_value, key_desc] 

291 

292 if env: config['env'] = env 

293 return name, config 

294 

295 

296class ApiDetailsDialog(wx.Dialog): 

297 """API详情对话框""" 

298 def __init__(self, parent, api_name, api_config): 

299 super().__init__(parent, title=f"{T('API Details')}: {api_name}", size=(500, 400)) 

300 

301 self.api_name = api_name 

302 self.api_config = api_config 

303 self._init_ui() 

304 

305 def _init_ui(self): 

306 """初始化UI界面""" 

307 main_sizer = wx.BoxSizer(wx.VERTICAL) 

308 

309 # 创建滚动面板 

310 scroll_panel = ScrolledPanel(self) 

311 scroll_sizer = wx.BoxSizer(wx.VERTICAL) 

312 

313 # 描述 

314 if 'desc' in self.api_config and self.api_config['desc']: 

315 desc_group = wx.StaticBox(scroll_panel, label=T("Description")) 

316 desc_sizer = wx.StaticBoxSizer(desc_group, wx.VERTICAL) 

317 

318 desc_text = wx.StaticText(scroll_panel, label=self.api_config['desc']) 

319 desc_text.Wrap(450) # 设置自动换行宽度 

320 

321 desc_sizer.Add(desc_text, 0, wx.ALL | wx.EXPAND, 10) 

322 scroll_sizer.Add(desc_sizer, 0, wx.ALL | wx.EXPAND, 5) 

323 

324 # 查找环境变量键 

325 envs = self.api_config.get('env') 

326 if envs: 

327 env_group = wx.StaticBox(scroll_panel, label=T("Environment Variables")) 

328 env_sizer = wx.StaticBoxSizer(env_group, wx.VERTICAL) 

329 

330 for i, key_name in enumerate(envs.keys()): 

331 key_value = envs[key_name] 

332 display_key = key_name 

333 

334 env_panel = wx.Panel(scroll_panel) 

335 

336 env_box = wx.BoxSizer(wx.VERTICAL) 

337 

338 name_text = wx.StaticText(env_panel, label=f"{T('Variable Name')}: {display_key}") 

339 name_text.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) 

340 

341 if isinstance(key_value, list): 

342 if len(key_value) > 0: 

343 # 使用掩码显示API密钥 

344 masked_key = key_value[0] 

345 if len(masked_key) > 8: 

346 masked_key = masked_key[:3] + "..." + masked_key[-3:] 

347 value_text = wx.StaticText(env_panel, label=f"{T('Value')}: {masked_key}") 

348 

349 if len(key_value) > 1 and key_value[1]: 

350 desc_text = wx.StaticText(env_panel, label=f"{T('Description')}: {key_value[1]}") 

351 desc_text.Wrap(400) 

352 

353 env_box.Add(name_text, 0, wx.ALL, 5) 

354 env_box.Add(value_text, 0, wx.ALL, 5) 

355 if len(key_value) > 1 and key_value[1]: 

356 env_box.Add(desc_text, 0, wx.ALL, 5) 

357 

358 env_panel.SetSizer(env_box) 

359 env_sizer.Add(env_panel, 0, wx.ALL | wx.EXPAND, 5) 

360 

361 # 添加分隔线,除了最后一个 

362 if i < len(envs) - 1: 

363 env_sizer.Add(wx.StaticLine(scroll_panel), 0, wx.EXPAND | wx.ALL, 5) 

364 

365 scroll_sizer.Add(env_sizer, 0, wx.ALL | wx.EXPAND, 5) 

366 

367 scroll_panel.SetSizer(scroll_sizer) 

368 scroll_panel.SetupScrolling() 

369 

370 main_sizer.Add(scroll_panel, 1, wx.EXPAND | wx.ALL, 10) 

371 

372 # 关闭按钮 

373 close_button = wx.Button(self, wx.ID_OK, T("Close")) 

374 main_sizer.Add(close_button, 0, wx.ALIGN_CENTER | wx.ALL, 10) 

375 

376 self.SetSizer(main_sizer) 

377 self.Layout() 

378 

379 

380class ApiMarketDialog(wx.Dialog): 

381 """API市场对话框 - 列表视图""" 

382 def __init__(self, parent, config_manager): 

383 super().__init__(parent, title=T("API Market"), size=(800, 600)) 

384 

385 self.config_manager = config_manager 

386 self.log = logger.bind(src="apimarket") 

387 

388 # 确保获取最新配置 

389 self.config_manager.reload_config() 

390 self.settings = config_manager.get_config() 

391 

392 # 复制API配置 

393 self.api_configs = self.settings.get('api', {}) 

394 

395 # 创建界面 

396 self._init_ui() 

397 

398 def _init_ui(self): 

399 """初始化UI界面""" 

400 main_sizer = wx.BoxSizer(wx.VERTICAL) 

401 

402 # 标题 

403 title_text = wx.StaticText(self, label=T("API Market - Manage Your API Configurations")) 

404 title_text.SetFont(wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) 

405 main_sizer.Add(title_text, 0, wx.ALIGN_CENTER | wx.ALL, 10) 

406 

407 # 介绍说明 

408 desc_text = wx.StaticText(self, label=T("Manage your API configurations here, including adding new APIs, viewing and editing existing ones.")) 

409 main_sizer.Add(desc_text, 0, wx.ALIGN_CENTER | wx.BOTTOM, 10) 

410 

411 # 工具栏 

412 toolbar_sizer = wx.BoxSizer(wx.HORIZONTAL) 

413 

414 add_button = wx.Button(self, label=T("Add New API")) 

415 add_button.Bind(wx.EVT_BUTTON, self.on_add_api) 

416 refresh_button = wx.Button(self, label=T("Refresh List")) 

417 refresh_button.Bind(wx.EVT_BUTTON, self.on_refresh) 

418 

419 toolbar_sizer.Add(add_button, 0, wx.ALL, 5) 

420 toolbar_sizer.Add(refresh_button, 0, wx.ALL, 5) 

421 

422 main_sizer.Add(toolbar_sizer, 0, wx.LEFT, 10) 

423 

424 # 创建列表控件 

425 self.api_list = wx.ListCtrl(self, style=wx.LC_REPORT | wx.BORDER_SUNKEN) 

426 self.api_list.InsertColumn(0, T("API Name"), width=200) 

427 self.api_list.InsertColumn(1, T("Number of Keys"), width=100) 

428 self.api_list.InsertColumn(2, T("Description"), width=450) 

429 

430 # 添加操作提示 

431 help_text = wx.StaticText(self, label=T("Tip: Right-click on API item to view, edit and delete")) 

432 help_text.SetFont(wx.Font(9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_NORMAL)) 

433 

434 # 加载API配置到列表 

435 self.load_api_configs() 

436 

437 main_sizer.Add(self.api_list, 1, wx.EXPAND | wx.ALL, 10) 

438 main_sizer.Add(help_text, 0, wx.LEFT | wx.BOTTOM, 15) 

439 

440 # 右键菜单绑定 

441 self.api_list.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.on_right_click) 

442 

443 # 双击查看详情 

444 self.api_list.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_item_activated) 

445 

446 # 底部按钮 

447 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 

448 save_button = wx.Button(self, label=T("Save and Apply")) 

449 save_button.Bind(wx.EVT_BUTTON, self.on_save) 

450 cancel_button = wx.Button(self, wx.ID_CANCEL, T("Cancel")) 

451 

452 button_sizer.Add(save_button, 0, wx.ALL, 5) 

453 button_sizer.Add(cancel_button, 0, wx.ALL, 5) 

454 

455 main_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 10) 

456 

457 self.SetSizer(main_sizer) 

458 self.Layout() 

459 

460 def load_api_configs(self): 

461 """加载API配置到列表""" 

462 self.api_list.DeleteAllItems() 

463 if not self.api_configs: 

464 no_api_item = self.api_list.InsertItem(0, T("No API configured")) 

465 self.api_list.SetItem(no_api_item, 2, T("Click `Add New API` button to add API configuration")) 

466 return 

467 

468 idx = 0 

469 for api_name, api_config in self.api_configs.items(): 

470 item = self.api_list.InsertItem(idx, api_name) 

471 

472 env_count = len(api_config.get('env', {})) 

473 self.api_list.SetItem(item, 1, str(env_count)) 

474 

475 # 添加描述 

476 desc = api_config.get('desc', '') 

477 if len(desc) > 60: 

478 desc = desc[:57] + "..." 

479 self.api_list.SetItem(item, 2, desc) 

480 

481 idx += 1 

482 

483 def on_item_activated(self, event): 

484 """双击列表项查看详情""" 

485 idx = event.GetIndex() 

486 api_name = self.api_list.GetItemText(idx) 

487 

488 if api_name in self.api_configs: 

489 self.show_api_details(api_name) 

490 

491 def show_api_details(self, api_name): 

492 """显示API详情""" 

493 api_config = self.api_configs.get(api_name) 

494 if api_config: 

495 dialog = ApiDetailsDialog(self, api_name, api_config) 

496 dialog.ShowModal() 

497 dialog.Destroy() 

498 

499 def on_right_click(self, event): 

500 """右键菜单""" 

501 if not self.api_list.GetItemCount(): 

502 return 

503 

504 idx = event.GetIndex() 

505 if idx == -1: 

506 return 

507 

508 api_name = self.api_list.GetItemText(idx) 

509 

510 # 如果是"暂无API配置"提示项,不显示菜单 

511 if api_name == T("No API configured"): 

512 return 

513 

514 menu = wx.Menu() 

515 

516 view_item = menu.Append(wx.ID_VIEW_DETAILS, T("View Details")) 

517 edit_item = menu.Append(wx.ID_EDIT, T("Edit")) 

518 delete_item = menu.Append(wx.ID_DELETE, T("Delete")) 

519 

520 self.Bind(wx.EVT_MENU, lambda evt, name=api_name: self.show_api_details(name), view_item) 

521 self.Bind(wx.EVT_MENU, lambda evt, name=api_name: self.on_edit_api(name), edit_item) 

522 self.Bind(wx.EVT_MENU, lambda evt, name=api_name: self.on_delete_api(name), delete_item) 

523 

524 self.PopupMenu(menu) 

525 menu.Destroy() 

526 

527 def on_add_api(self, event=None): 

528 """添加新API""" 

529 dialog = ApiEditDialog(self, is_new=True) 

530 result = dialog.ShowModal() 

531 

532 if result == wx.ID_OK: 

533 api_name, api_config = dialog.get_api_config() 

534 

535 if not api_name: 

536 wx.MessageBox(T("API name cannot be empty"), T("Error"), wx.OK | wx.ICON_ERROR) 

537 return 

538 

539 if api_name in self.api_configs: 

540 wx.MessageBox(T("API name already exists"), T("Error"), wx.OK | wx.ICON_ERROR) 

541 return 

542 

543 self.api_configs[api_name] = api_config 

544 self.load_api_configs() 

545 

546 dialog.Destroy() 

547 

548 def on_edit_api(self, api_name): 

549 """编辑API配置""" 

550 if api_name not in self.api_configs: 

551 return 

552 

553 api_config = self.api_configs[api_name] 

554 dialog = ApiEditDialog(self, api_name, api_config, is_new=False) 

555 result = dialog.ShowModal() 

556 

557 if result == wx.ID_OK: 

558 _, updated_config = dialog.get_api_config() 

559 self.api_configs[api_name] = updated_config 

560 self.load_api_configs() 

561 

562 dialog.Destroy() 

563 

564 def on_delete_api(self, api_name): 

565 """删除API配置""" 

566 if api_name not in self.api_configs: 

567 return 

568 

569 dlg = wx.MessageDialog( 

570 self, 

571 f"{T('Are you sure to delete API')} '{api_name}'?", 

572 T("Confirm Delete"), 

573 wx.YES_NO | wx.ICON_QUESTION 

574 ) 

575 result = dlg.ShowModal() 

576 dlg.Destroy() 

577 

578 if result == wx.ID_YES: 

579 del self.api_configs[api_name] 

580 self.load_api_configs() 

581 

582 self.config_manager.update_api_config({'api': self.api_configs}) 

583 

584 def on_refresh(self, event): 

585 """刷新API列表""" 

586 # 重新加载配置 

587 self.config_manager.reload_config() 

588 self.settings = self.config_manager.get_config() 

589 

590 # 重新加载API配置 

591 self.api_configs = self.settings.get('api', {}) 

592 

593 # 更新列表 

594 self.load_api_configs() 

595 

596 def on_save(self, event): 

597 """保存API配置""" 

598 try: 

599 self.config_manager.update_sys_config({'api': self.api_configs}) 

600 self.settings = self.config_manager.reload_config() 

601 

602 # 更新父窗口的配置 

603 if hasattr(self.Parent, 'tm'): 

604 self.Parent.tm.settings = self.config_manager.get_config() 

605 if hasattr(self.Parent.tm, 'config'): 

606 self.Parent.tm.config = self.config_manager.get_config() 

607 

608 # 显示保存成功的消息 

609 wx.MessageBox(T("API configuration saved and applied"), T("Success"), wx.OK | wx.ICON_INFORMATION) 

610 self.EndModal(wx.ID_OK) 

611 except Exception as e: 

612 traceback.print_exc() 

613 wx.MessageBox(f"{T('Failed to save configuration')}: {str(e)}", T("Error"), wx.OK | wx.ICON_ERROR) 

614 traceback.print_exc()