ibridgesgui 2.1.3__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/workflows/linter.yml +3 -3
  2. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/workflows/publish.yml +1 -1
  3. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/workflows/pypi_release.yml +3 -3
  4. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/workflows/tests.yml +5 -13
  5. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/PKG-INFO +4 -3
  6. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/coverage.svg +1 -1
  7. ibridgesgui-2.2.0/docs/screenshots/manage_tickets.png +0 -0
  8. ibridgesgui-2.2.0/docs/screenshots/supply_ticket.png +0 -0
  9. ibridgesgui-2.2.0/docs/userdoc.qmd +255 -0
  10. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/_version.py +3 -3
  11. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/browsertab/browser_controller.py +1 -3
  12. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/browsertab/irods_browser_service.py +3 -4
  13. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/info.py +13 -0
  14. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/login.py +6 -2
  15. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/mainmenu/main_window.py +35 -8
  16. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/mainmenu/session_manager.py +1 -1
  17. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/mainmenu/tab_manager.py +0 -1
  18. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/__init__.py +5 -1
  19. ibridgesgui-2.2.0/ibridgesgui/popup_widgets/manage_tickets.py +166 -0
  20. ibridgesgui-2.2.0/ibridgesgui/popup_widgets/supply_ticket.py +60 -0
  21. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/synctab/sync_controller.py +1 -1
  22. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/threads.py +6 -0
  23. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/MainMenu.py +41 -9
  24. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/MainMenu.ui +64 -4
  25. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabInfo.py +126 -114
  26. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabInfo.ui +153 -139
  27. ibridgesgui-2.2.0/ibridgesgui/ui_files/ticketEditor.py +211 -0
  28. ibridgesgui-2.2.0/ibridgesgui/ui_files/ticketEditor.ui +233 -0
  29. ibridgesgui-2.2.0/ibridgesgui/ui_files/ticketSupply.py +124 -0
  30. ibridgesgui-2.2.0/ibridgesgui/ui_files/ticketSupply.ui +159 -0
  31. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui.egg-info/PKG-INFO +4 -3
  32. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui.egg-info/SOURCES.txt +10 -0
  33. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui.egg-info/requires.txt +1 -1
  34. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui.egg-info/scm_file_list.json +10 -0
  35. ibridgesgui-2.2.0/ibridgesgui.egg-info/scm_version.json +8 -0
  36. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/pyproject.toml +3 -2
  37. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/gui/test_info_tab.py +2 -0
  38. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/main_window/test_main_window.py +2 -2
  39. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/main_window/test_session_manager.py +2 -2
  40. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/popup/conftest.py +16 -21
  41. ibridgesgui-2.2.0/tests/popup/test_manage_tickets.py +409 -0
  42. ibridgesgui-2.2.0/tests/popup/test_supply_ticket.py +180 -0
  43. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/threads/test_transfer_thread.py +1 -8
  44. ibridgesgui-2.1.3/docs/userdoc.qmd +0 -157
  45. ibridgesgui-2.1.3/ibridgesgui.egg-info/scm_version.json +0 -8
  46. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.flake8 +0 -0
  47. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  48. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  49. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/dependabot.yml +0 -0
  50. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.github/workflows/nuitka_release.yml +0 -0
  51. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/.gitignore +0 -0
  52. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/LICENSE +0 -0
  53. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/README.md +0 -0
  54. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_quarto.yml +0 -0
  55. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/callouts.css +0 -0
  56. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/code.css +0 -0
  57. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/hyperlinks.css +0 -0
  58. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/ibridges.css +0 -0
  59. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/navbar.css +0 -0
  60. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/search_icon.css +0 -0
  61. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/_styles/toc.css +0 -0
  62. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/build_tools/build_script.py +0 -0
  63. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/build_tools/ui_to_py.py +0 -0
  64. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/developers.qmd +0 -0
  65. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/faq.qmd +0 -0
  66. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/getting-started.qmd +0 -0
  67. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/info.qmd +0 -0
  68. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/add_check_config.png +0 -0
  69. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/add_new_config.png +0 -0
  70. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/browser.png +0 -0
  71. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/login.png +0 -0
  72. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/logo.png +0 -0
  73. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/metadata.png +0 -0
  74. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/permissions.png +0 -0
  75. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/replicas.png +0 -0
  76. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/search.png +0 -0
  77. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/start_ibridges.png +0 -0
  78. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/docs/screenshots/sync.png +0 -0
  79. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/__init__.py +0 -0
  80. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/__main__.py +0 -0
  81. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/browsertab/__init__.py +0 -0
  82. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/browsertab/browser.py +0 -0
  83. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/browsertab/browser_model.py +0 -0
  84. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/config.py +0 -0
  85. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/gui_utils.py +0 -0
  86. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/arrow-left.png +0 -0
  87. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/arrow-right.png +0 -0
  88. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/arrow-up.png +0 -0
  89. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/christmas-logo.png +0 -0
  90. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/home.png +0 -0
  91. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/iBridges.ico +0 -0
  92. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/loading_circle.gif +0 -0
  93. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/logo.png +0 -0
  94. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/nosync.png +0 -0
  95. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/refresh.png +0 -0
  96. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/icons/syncing.png +0 -0
  97. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/irods_tree_model.py +0 -0
  98. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/logviewer.py +0 -0
  99. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/mainmenu/__init__.py +0 -0
  100. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/mainmenu/config_manager.py +0 -0
  101. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/mainmenu/plugin_manager.py +0 -0
  102. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/md_schemas/ibridges_metadata_schema.json +0 -0
  103. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/base.py +0 -0
  104. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/check_config.py +0 -0
  105. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/create_collection.py +0 -0
  106. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/create_directory.py +0 -0
  107. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/download_data.py +0 -0
  108. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/rename_item.py +0 -0
  109. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/resc_tree.py +0 -0
  110. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/popup_widgets/upload_data.py +0 -0
  111. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/searchtab/__init__.py +0 -0
  112. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/searchtab/search.py +0 -0
  113. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/searchtab/search_controller.py +0 -0
  114. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/searchtab/search_model.py +0 -0
  115. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/synctab/__init__.py +0 -0
  116. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/synctab/sync.py +0 -0
  117. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/synctab/sync_model.py +0 -0
  118. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/__init__.py +0 -0
  119. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/configCheck.py +0 -0
  120. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/configCheck.ui +0 -0
  121. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/createCollection.py +0 -0
  122. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/createCollection.ui +0 -0
  123. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/downloadData.py +0 -0
  124. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/downloadData.ui +0 -0
  125. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/irodsLogin.py +0 -0
  126. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/irodsLogin.ui +0 -0
  127. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/renameItem.py +0 -0
  128. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/renameItem.ui +0 -0
  129. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/rescTree.py +0 -0
  130. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/rescTree.ui +0 -0
  131. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabBrowser.py +0 -0
  132. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabBrowser.ui +0 -0
  133. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabLogging.py +0 -0
  134. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabLogging.ui +0 -0
  135. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabSearch.py +0 -0
  136. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabSearch.ui +0 -0
  137. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabSync.py +0 -0
  138. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/tabSync.ui +0 -0
  139. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/transferData.py +0 -0
  140. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/transferData.ui +0 -0
  141. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/uploadData.py +0 -0
  142. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/uploadData.ui +0 -0
  143. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/welcome.py +0 -0
  144. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/ui_files/welcome.ui +0 -0
  145. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui/welcome.py +0 -0
  146. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui.egg-info/dependency_links.txt +0 -0
  147. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/ibridgesgui.egg-info/top_level.txt +0 -0
  148. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/index.qmd +0 -0
  149. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/setup.cfg +0 -0
  150. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/browser/conftest.py +0 -0
  151. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/browser/test_browser_controller.py +0 -0
  152. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/browser/test_browser_model.py +0 -0
  153. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/browser/test_irods_browser_service.py +0 -0
  154. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/conftest.py +0 -0
  155. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/gui/test_login.py +0 -0
  156. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/gui/test_main.py +0 -0
  157. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/main_window/conftest.py +0 -0
  158. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/main_window/test_config_manager.py +0 -0
  159. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/main_window/test_tab_manager.py +0 -0
  160. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/popup/test_check_config.py +0 -0
  161. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/popup/test_download_data.py +0 -0
  162. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/popup/test_simple_dialogs.py +0 -0
  163. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/popup/test_transfer_dialog_base.py +0 -0
  164. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/popup/test_upload_data.py +0 -0
  165. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/search/conftest.py +0 -0
  166. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/search/test_search_controller.py +0 -0
  167. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/search/test_search_model.py +0 -0
  168. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/sync/conftest.py +0 -0
  169. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/sync/test_sync_controller.py +0 -0
  170. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/sync/test_sync_model.py +0 -0
  171. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/threads/conftest.py +0 -0
  172. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/threads/test_search_thread.py +0 -0
  173. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/threads/test_sync_thread.py +0 -0
  174. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/unit/test_config.py +0 -0
  175. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/unit/test_gui_utils.py +0 -0
  176. {ibridgesgui-2.1.3 → ibridgesgui-2.2.0}/tests/unit/test_irods_tree_model.py +0 -0
@@ -29,7 +29,7 @@ jobs:
29
29
  fail-fast: false
30
30
  matrix:
31
31
  os: [ubuntu-latest]
32
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
32
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
33
33
  include:
34
34
  - os: windows-latest
35
35
  python-version: "3.12"
@@ -38,10 +38,10 @@ jobs:
38
38
  runs-on: ${{ matrix.os }}
39
39
 
40
40
  steps:
41
- - uses: actions/checkout@v4
41
+ - uses: actions/checkout@v5
42
42
 
43
43
  - name: Set up Python ${{ matrix.python-version }}
44
- uses: actions/setup-python@v4
44
+ uses: actions/setup-python@v5
45
45
  with:
46
46
  python-version: ${{ matrix.python-version }}
47
47
 
@@ -12,7 +12,7 @@ jobs:
12
12
  contents: write
13
13
  steps:
14
14
  - name: Check out repository
15
- uses: actions/checkout@v4
15
+ uses: actions/checkout@v5
16
16
 
17
17
  - name: Set up Quarto
18
18
  uses: quarto-dev/quarto-actions/setup@v2
@@ -24,9 +24,9 @@ jobs:
24
24
  runs-on: ubuntu-latest
25
25
 
26
26
  steps:
27
- - uses: actions/checkout@v4
27
+ - uses: actions/checkout@v5
28
28
  - name: Set up Python
29
- uses: actions/setup-python@v4
29
+ uses: actions/setup-python@v5
30
30
  with:
31
31
  python-version: '3.x'
32
32
  - name: Install dependencies
@@ -36,7 +36,7 @@ jobs:
36
36
  - name: Build package
37
37
  run: python -m build
38
38
  - name: Publish package
39
- uses: pypa/gh-action-pypi-publish@v1.12.4
39
+ uses: pypa/gh-action-pypi-publish@release/v1
40
40
  with:
41
41
  user: __token__
42
42
  password: ${{ secrets.PYPI_API_TOKEN }}
@@ -26,23 +26,21 @@ jobs:
26
26
  fail-fast: true
27
27
  matrix:
28
28
  os: [ubuntu-latest]
29
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
29
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
30
30
  include:
31
31
  - os: macos-latest
32
32
  python-version: "3.13"
33
33
  runs-on: ${{ matrix.os }}
34
34
  steps:
35
35
  - name: Checkout
36
- uses: actions/checkout@v4
36
+ uses: actions/checkout@v6
37
37
 
38
38
  - name: Set up Python
39
- uses: actions/setup-python@v5
39
+ uses: actions/setup-python@v6
40
40
  with:
41
41
  python-version: ${{ matrix.python-version }}
42
42
 
43
- # -----------------------------
44
43
  # Linux-only Qt dependencies
45
- # -----------------------------
46
44
  - name: Install Qt system dependencies (Linux)
47
45
  if: runner.os == 'Linux'
48
46
  run: |
@@ -60,18 +58,14 @@ jobs:
60
58
  libxcb-xfixes0 \
61
59
  xvfb
62
60
 
63
- # -----------------------------
64
- # Install Python dependencies
65
- # -----------------------------
61
+
66
62
  - name: Install dependencies
67
63
  run: |
68
64
  python -m pip install --upgrade pip
69
65
  python -m pip install .[test]
70
66
  python -m pip install pytest pytest-cov
71
67
 
72
- # -----------------------------
73
68
  # Set Qt to offscreen mode
74
- # -----------------------------
75
69
  - name: Configure Qt for headless mode
76
70
  run: |
77
71
  echo "QT_QPA_PLATFORM=offscreen" >> $GITHUB_ENV
@@ -81,9 +75,7 @@ jobs:
81
75
  echo "QT_QPA_PLATFORM=offscreen" >> $GITHUB_ENV
82
76
  echo "QT_MAC_WANTS_LAYER=1" >> $GITHUB_ENV
83
77
 
84
- # -----------------------------
85
- # Run tests
86
- # -----------------------------
78
+
87
79
  - name: Run tests and coverage
88
80
  run: |
89
81
  python -m pytest --cov=ibridgesgui --cov-report=xml --cov-report=term-missing --cov-fail-under=70 tests
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ibridgesgui
3
- Version: 2.1.3
3
+ Version: 2.2.0
4
4
  Summary: Graphical user interface for accessing data and metadata on iRODS servers.
5
5
  Author-email: Christine Staiger <c.staiger@uu.nl>
6
6
  License: GNU LESSER GENERAL PUBLIC LICENSE
@@ -512,16 +512,17 @@ Project-URL: GitHub, https://github.com/chStaiger/iBridges-Gui
512
512
  Project-URL: documentation, https://github.com/chStaiger/iBridges-Gui
513
513
  Keywords: irods,data management,storage
514
514
  Classifier: Programming Language :: Python :: 3
515
- Classifier: Programming Language :: Python :: 3.9
516
515
  Classifier: Programming Language :: Python :: 3.10
517
516
  Classifier: Programming Language :: Python :: 3.11
518
517
  Classifier: Programming Language :: Python :: 3.12
518
+ Classifier: Programming Language :: Python :: 3.13
519
+ Classifier: Programming Language :: Python :: 3.14
519
520
  Classifier: Development Status :: 3 - Alpha
520
521
  Requires-Python: >=3.9
521
522
  Description-Content-Type: text/markdown
522
523
  License-File: LICENSE
523
524
  Requires-Dist: PySide6>=6.8.1
524
- Requires-Dist: ibridges<2.2,>=2.1.0
525
+ Requires-Dist: ibridges<2.3,>=2.2.0
525
526
  Requires-Dist: setproctitle==1.3.8
526
527
  Requires-Dist: importlib-resources; python_version <= "3.10"
527
528
  Requires-Dist: jsonschema
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="114" height="20" role="img" aria-label="coverage: 83.05%"><title>coverage: 83.05%</title><filter id="blur"><feGaussianBlur stdDeviation="16"/></filter><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="114" height="20" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="53" height="20" fill="#67ac09"/><rect width="114" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="315" y="150" fill-opacity=".8" filter="url(#blur)" textLength="510">coverage</text><text x="315" y="150" fill-opacity=".3" textLength="510">coverage</text></g><text x="315" y="140" textLength="510">coverage</text></g><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="865" y="150" fill-opacity=".8" filter="url(#blur)" textLength="430">83.05%</text><text x="865" y="150" fill-opacity=".3" textLength="430">83.05%</text></g><text x="865" y="140" textLength="430">83.05%</text></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="114" height="20" role="img" aria-label="coverage: 84.04%"><title>coverage: 84.04%</title><filter id="blur"><feGaussianBlur stdDeviation="16"/></filter><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="114" height="20" rx="3"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="53" height="20" fill="#67ac09"/><rect width="114" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="315" y="150" fill-opacity=".8" filter="url(#blur)" textLength="510">coverage</text><text x="315" y="150" fill-opacity=".3" textLength="510">coverage</text></g><text x="315" y="140" textLength="510">coverage</text></g><g transform="scale(.1)"><g aria-hidden="true" fill="#010101"><text x="865" y="150" fill-opacity=".8" filter="url(#blur)" textLength="430">84.04%</text><text x="865" y="150" fill-opacity=".3" textLength="430">84.04%</text></g><text x="865" y="140" textLength="430">84.04%</text></g></g></svg>
@@ -0,0 +1,255 @@
1
+ ---
2
+ title: "User Documentation"
3
+ format:
4
+ html:
5
+ toc: true
6
+ ---
7
+
8
+ ## Synopsis
9
+
10
+ iBridges‑GUI is a graphical interface for any iRODS‑based data management platform.
11
+ It exposes core iRODS functionality through a set of focused views, each designed for a specific task.
12
+
13
+ Default views:
14
+
15
+ - `Browser` — explore collections, inspect data objects, edit metadata and permissions, upload/download, delete.
16
+ - `Data Synchronisation` — synchronise local directories with iRODS collections.
17
+ - `Search` — locate collections and data objects using name or metadata filters.
18
+ - `Info` — display user information, groups, and server resources (status, capacity).
19
+
20
+ ## Views and Plugins
21
+
22
+ The `Views and Plugins` menu (next to `Configure`) lets you show or hide tabs.
23
+ Checked views are restored automatically when you restart the application.
24
+
25
+ On first launch, the following tabs appear:
26
+ `Welcome`, `Browser`, `Synchronise Data`, `Search`, `Info`, and `Logs`.
27
+
28
+ ## Browser
29
+
30
+ After logging in, the *Browser* is the first view you see.
31
+ It consists of three parts:
32
+
33
+ 1. Navigation
34
+ 2. Listing
35
+ 3. Detailed inspection
36
+
37
+ ![](screenshots/browser.png)
38
+
39
+ ### Navigation
40
+
41
+ - The path field shows your current iRODS location.
42
+ Edit it and press `<Enter>` to jump anywhere in the tree.
43
+
44
+ - Buttons:
45
+ - *Refresh* — reload the listing
46
+ - *Up* — go one level up
47
+ - *Home* — jump to your home collection
48
+
49
+ - *Create Collection* — create a new collection at the current path.
50
+
51
+ - *Upload* — select files to upload.
52
+ Optional: include metadata files to extract and store as iRODS metadata.
53
+
54
+ - *Download* — choose a local destination.
55
+ Optional: export metadata alongside the download.
56
+ Select an item in the table to download it.
57
+ For downloading multiple items, use the *Search* view.
58
+
59
+ - *Delete* — permanently remove the selected item from iRODS.
60
+
61
+ ### Listing
62
+
63
+ The table lists all collections and data objects at the current path.
64
+
65
+ Columns:
66
+
67
+ - Status — `-C` for collections; replica status for data objects.
68
+ If a data object’s status is not `good`, the data is compromised. Contact your iRODS administrator.
69
+ - Name
70
+ - Size
71
+ - Checksum
72
+ - Created / Modified
73
+
74
+ Actions:
75
+
76
+ - *Single click* — load details below.
77
+ - *Double click* — open a collection.
78
+
79
+ ## Inspect collections and data objects
80
+
81
+ This section shows detailed information about the selected item.
82
+
83
+ ### Preview
84
+
85
+ Displays collection contents or the first lines of text/JSON/CSV files.
86
+
87
+ ### Metadata
88
+
89
+ Shows metadata as key–value–unit triples.
90
+
91
+ - *Single click* loads an entry into the editable fields.
92
+ - *Add* — create a new entry.
93
+ - *Update* — modify the selected entry.
94
+ - *Delete* — remove the entry matching the fields.
95
+
96
+ ![](screenshots/metadata.png)
97
+
98
+ ### Permissions
99
+
100
+ Shows access rights for the selected item.
101
+
102
+ ![](screenshots/permissions.png)
103
+
104
+ - The *Access name* dropdown lists available rights.
105
+ - Creator shows who created the item.
106
+ - Collections support `inherit` / `noinherit`.
107
+ `inherit` applies collection permissions to newly added items.
108
+ - Enable *Recursive* to apply changes to all existing members.
109
+
110
+ ### Replicas
111
+
112
+ Shows the storage resources where a data object is stored.
113
+ Collections do not have replicas.
114
+
115
+ ![](screenshots/replicas.png)
116
+
117
+ If a replica status is not `good`, contact your iRODS administrator.
118
+
119
+ ## Data Synchronisation
120
+
121
+ `Synchronise Data` lets you synchronise a local directory with an iRODS collection.
122
+
123
+ - Local → iRODS (*right arrow*)
124
+ - iRODS → Local (*left arrow*)
125
+
126
+ Before synchronising, differences are calculated and shown in the text field.
127
+ This may take some time for large directories.
128
+
129
+ ![](screenshots/sync.png)
130
+
131
+ Synchronisation works only for directories/collections, not individual files.
132
+
133
+
134
+ ## Search
135
+
136
+ The `Search` view allows you to filter by path, name, and metadata.
137
+
138
+ ![](screenshots/search.png)
139
+
140
+ ### Search fields
141
+
142
+ - `Path` — defines where the search is performed.
143
+ Must exist; defaults to your home collection.
144
+
145
+ - `Obj/Coll name` — filter by name.
146
+ Example: `demo` finds all items named *demo*.
147
+
148
+ - Wildcards use `%`.
149
+ Example: `my_books/%.txt` finds all `.txt` files in `my_books`.
150
+
151
+ - Metadata filters — narrow results further.
152
+ Example: key `author`, value `%Doyle%`.
153
+
154
+ ### Search results
155
+
156
+ - *Single click* or *Select all* → click *Download* to choose a destination.
157
+ - *Double click* → open the item in the `Browser` for inspection.
158
+
159
+ ## Data Sharing with iRODS tickets
160
+
161
+ ### What are iRODS tickets
162
+
163
+ An iRODS ticket is a short string, for example `kpIwGA1UZN0LFnM`, that gives
164
+ access to one collection or data object without changing any permissions
165
+ and without the need for an account. Anyone who has the ticket string and the
166
+ path it belongs to can read the shared data.
167
+
168
+ - A ticket is either a read ticket or a write ticket.
169
+ A write ticket also allows uploads and changes.
170
+ - A ticket can have an expiry date. After that date it no longer
171
+ gives access to the data.
172
+ - Tickets are stored on the iRODS server and belong to the user who created
173
+ them. The owner can delete a ticket at any time, which revokes the access.
174
+
175
+ Typical uses are sharing a dataset with external collaborators, publishing data
176
+ for download through an `anonymous` account, and giving temporary access.
177
+
178
+ **Always share the ticket string together with the iRODS path it was made for.**
179
+
180
+ ### Create tickets
181
+
182
+ ![](screenshots/manage_tickets.png)
183
+
184
+ Open the ticket manager from the menu bar `Data Access`. The view has two parts: the iRODS tree
185
+ and next to it the ticket settings to choose from, and below the table with your existing tickets.
186
+
187
+ To create a ticket:
188
+
189
+ 1. Select the collection or data object you want to share in the iRODS tree.
190
+ 2. Choose the access mode, *read* or *write*.
191
+ 3. Choose when the ticket expires. Pick a date in the calendar, or check the box to create a ticket that does not expire. The calendar is disabled while the box is checked.
192
+ 4. Click *Create ticket*. The new ticket appears in the table.
193
+ 5. Send the ticket string and the path to the person you want to share with.
194
+
195
+ The table lists all your tickets:
196
+
197
+ - Ticket — the ticket string to share.
198
+ - iRODS path — the shared collection or data object. Hover over the path
199
+ to see it in full.
200
+ - Expires — the expiry date, or `never`.
201
+ - ❌ — delete the ticket and revoke the access.
202
+
203
+ Good to know:
204
+
205
+ - A ticket stops working at the start of the selected day. If it should
206
+ still work during the whole day, select the following day.
207
+ - Share write tickets with care, since they allow changes to the shared
208
+ collection.
209
+ - Delete tickets that are no longer needed. Do not rely on the expiry date alone.
210
+
211
+ ### Use tickets
212
+
213
+ You can use tickets as user of the system or as anonymous user.
214
+
215
+ ![](screenshots/supply_ticket.png)
216
+
217
+ #### Supply a ticket
218
+
219
+ To use a ticket, open the *Supply Ticket* dialog and fill in:
220
+
221
+ - Ticket — the ticket string you received.
222
+ - iRODS path — the path of the collection or data object the ticket was
223
+ made for.
224
+
225
+ Click *OK*. If the ticket and the path match, the dialog closes and the
226
+ shared location becomes your current location in the `Browser`. You can then browse, view metadata and download data. With a write ticket you can also
227
+ upload.
228
+
229
+ #### As a user of the system
230
+
231
+ If you already have an account, log in as usual and supply the ticket. The
232
+ ticket gives you access to the shared data on top of your own permissions.
233
+
234
+ #### As an anonymous user
235
+
236
+ Collaborators without an account use the `anonymous` user of the iRODS server.
237
+ Create an iRODS environment file for it with the environment editor (*Configure*). The user name is `anonymous` and works without providing a password. Your iRODS administrator can provide you with the correct irods environment settings.
238
+
239
+ Once you log in with this environment you can supply the ticket as described above.
240
+ Without a ticket, an anonymous user cannot see any data.
241
+
242
+ #### Things to keep in mind
243
+
244
+ - A ticket lasts as long as your session. If you log out or restart the application, supply the ticket again.
245
+
246
+ - Use one ticket per session. To switch to another ticket, log in again first.
247
+
248
+ - A ticket on a data object only gives access to that object, not to the other items in its collection. The Browser opens the parent collection, where the listing may be empty. Type the full path of the object in the path field of the Browser to reach it.
249
+
250
+ - Expired tickets are still accepted by the dialog, and the shared path may still be visible, but downloading data fails with `CAT_TICKET_EXPIRED`. Ask the owner for a new ticket.
251
+
252
+ - Deleted tickets: if the owner deletes the ticket while you are using it, further actions fail with `CAT_TICKET_INVALID`.
253
+
254
+ The same functionality is available from the command line and in Python. See the
255
+ *Working with Tickets* tutorial in the [iBridges documentation](https://ibridges.readthedocs.io/en/latest/).
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.1.3'
22
- __version_tuple__ = version_tuple = (2, 1, 3)
21
+ __version__ = version = '2.2.0'
22
+ __version_tuple__ = version_tuple = (2, 2, 0)
23
23
 
24
- __commit_id__ = commit_id = 'gbfeb5d40a'
24
+ __commit_id__ = commit_id = 'g13809c1c4'
@@ -248,7 +248,7 @@ class BrowserController:
248
248
  label_to_acl = {
249
249
  "Newly added items to collection will inherit permissions": "inherit",
250
250
  "Remove inheritance.": "noinherit",
251
- "delete": "null",
251
+ #"delete": "null",
252
252
  }
253
253
  acl_value = label_to_acl.get(acc_label, acc_label)
254
254
 
@@ -265,7 +265,6 @@ class BrowserController:
265
265
  if not acc_label:
266
266
  self.ui.error_label.setText("Please provide an access level.")
267
267
  return
268
-
269
268
  try:
270
269
  self.service.set_acl(
271
270
  irods_path,
@@ -275,7 +274,6 @@ class BrowserController:
275
274
  recursive=recursive,
276
275
  )
277
276
 
278
- # NEW: use model helper instead of manual cache manipulation
279
277
  self.model.invalidate_acls(row)
280
278
 
281
279
  self._fill_current_info_tab()
@@ -27,7 +27,7 @@ class IrodsBrowserService:
27
27
 
28
28
  def home_path(self) -> IrodsPath:
29
29
  """Get home path."""
30
- return IrodsPath(self.session)
30
+ return IrodsPath(self.session, self.session.home)
31
31
 
32
32
  def parent_path(self, text: str) -> IrodsPath:
33
33
  """Determine parent."""
@@ -197,8 +197,7 @@ class IrodsBrowserService:
197
197
  PERM_MAP = {
198
198
  "read_object": "read",
199
199
  "modify_object": "write",
200
- "null": "delete permission",
201
- "delete_object": "delete",
200
+ "null": "delete",
202
201
  "create_object": "create"
203
202
  }
204
203
  REVERSE_PERM_MAP = {v: k for k, v in PERM_MAP.items()}
@@ -252,7 +251,7 @@ class IrodsBrowserService:
252
251
 
253
252
  obj = get_irods_item(path)
254
253
  perms = Permissions(self.session, obj)
255
- irods_access = self.REVERSE_PERM_MAP[access]
254
+ irods_access = self.REVERSE_PERM_MAP.get(access, access)
256
255
  perms.set(
257
256
  perm=irods_access,
258
257
  user=user_name,
@@ -1,6 +1,7 @@
1
1
  """Info tab."""
2
2
 
3
3
  import sys
4
+ from importlib.metadata import PackageNotFoundError, version
4
5
 
5
6
  from PySide6 import QtCore, QtWidgets
6
7
 
@@ -52,6 +53,10 @@ class Info(QtWidgets.QWidget, Ui_tabInfo):
52
53
  "default_resc": self.session.default_resc,
53
54
  "server": self.session.host,
54
55
  "version": ".".join(map(str, self.session.server_version)),
56
+ "client_version": (
57
+ f"iBridges GUI {self._get_version('ibridgesgui')} / "
58
+ f"iBridges API {self._get_version('ibridges')}"
59
+ ),
55
60
  "resources": Resources(self.session).root_resources,
56
61
  }
57
62
 
@@ -64,6 +69,7 @@ class Info(QtWidgets.QWidget, Ui_tabInfo):
64
69
  self.resc_label.setText(info["default_resc"])
65
70
  self.server_label.setText(info["server"])
66
71
  self.version_label.setText(info["version"])
72
+ self.client_version_label.setText(info["client_version"])
67
73
 
68
74
  resources = [
69
75
  tuple("" if v is None else v for v in row)
@@ -74,6 +80,13 @@ class Info(QtWidgets.QWidget, Ui_tabInfo):
74
80
 
75
81
  self._autosize_columns(self.resc_table)
76
82
 
83
+ def _get_version(self, dist_name):
84
+ """Return the installed version of a distribution, or 'unknown'."""
85
+ try:
86
+ return version(dist_name)
87
+ except PackageNotFoundError:
88
+ return "unknown"
89
+
77
90
  def _autosize_columns(self, table):
78
91
  header = table.horizontalHeader()
79
92
  for col in range(header.count()):
@@ -1,6 +1,7 @@
1
1
  """Login widget."""
2
2
  from __future__ import annotations
3
3
 
4
+ import json
4
5
  import os
5
6
  from pathlib import Path
6
7
  from typing import Any
@@ -149,12 +150,15 @@ class LoginDialog(QDialog, Ui_irodsLogin):
149
150
  # Resolve password
150
151
  typed_pw = self.password_field.text()
151
152
  password = self._resolve_password(entry, typed_pw)
152
- if password is None:
153
- return
154
153
 
155
154
  # Validate environment config
156
155
  if not self._validate_env_config(env_path):
157
156
  return
157
+ with open(env_path, encoding="utf-8") as f:
158
+ env_info = json.load(f)
159
+ is_anonymous = env_info.get("irods_user_name", "").lower() == "anonymous"
160
+ if password is None and not is_anonymous:
161
+ return
158
162
 
159
163
  try:
160
164
  session = self._create_session(env_path, typed_pw, password)
@@ -4,7 +4,8 @@ from __future__ import annotations
4
4
  import logging
5
5
  from pathlib import Path
6
6
 
7
- from PySide6.QtGui import QAction
7
+ from PySide6.QtCore import QUrl
8
+ from PySide6.QtGui import QAction, QDesktopServices
8
9
  from PySide6.QtWidgets import QApplication, QMainWindow, QMessageBox
9
10
 
10
11
  from ibridgesgui.gui_utils import UI_FILE_DIR, load_ui
@@ -13,10 +14,12 @@ from ibridgesgui.mainmenu import (
13
14
  SessionManager,
14
15
  TabManager,
15
16
  )
16
- from ibridgesgui.popup_widgets import CheckConfig
17
+ from ibridgesgui.popup_widgets import CheckConfig, SupplyTicket, TicketEditor
17
18
  from ibridgesgui.ui_files.MainMenu import Ui_MainWindow
18
19
  from ibridgesgui.welcome import Welcome
19
20
 
21
+ IBRIDGES_DOCS_URL = "https://ibridges.readthedocs.io"
22
+ GUI_DOCS_URL = "https://ibridges-for-irods.github.io/iBridges-GUI"
20
23
 
21
24
  class MainWindow(QMainWindow, Ui_MainWindow):
22
25
  """Main application window."""
@@ -43,8 +46,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
43
46
  self.action_connect.triggered.connect(self._on_connect)
44
47
  self.action_close_session.triggered.connect(self._on_disconnect)
45
48
  self.action_exit.triggered.connect(self._on_exit)
46
- self.action_add_configuration.triggered.connect(self._on_create_env)
47
- self.action_check_configuration.triggered.connect(self._on_check_env)
49
+ self.action_edit_configuration.triggered.connect(self._on_edit_env)
50
+ self.action_supply_ticket.triggered.connect(self._on_supply_ticket)
51
+ self.action_create_ticket.triggered.connect(self._on_edit_ticket)
52
+ self.action_gui_docs.triggered.connect(self._on_gui_docs)
53
+ self.action_ibridges_docs.triggered.connect(self._on_ibridges_docs)
48
54
 
49
55
  if session is not None:
50
56
  self.on_session_changed(session)
@@ -88,11 +94,20 @@ class MainWindow(QMainWindow, Ui_MainWindow):
88
94
 
89
95
  self.tab_manager.update_plugin_menu()
90
96
 
97
+ def _open_web_page(self, url):
98
+ if not QDesktopServices.openUrl(QUrl(url)):
99
+ self.logger.error("Could not open %s in a web browser.", url)
100
+
101
+ def _on_gui_docs(self) -> None:
102
+ self._open_web_page(GUI_DOCS_URL)
103
+ def _on_ibridges_docs(self) -> None:
104
+ self._open_web_page(IBRIDGES_DOCS_URL)
105
+
91
106
  def _on_connect(self) -> None:
92
107
  if self.session_manager.session is not None:
93
108
  QMessageBox.information(self, "Already connected", "You are already logged in.")
94
109
  return
95
- self.session_manager.connect(self)
110
+ self.session_manager.login(self)
96
111
 
97
112
  def _on_disconnect(self) -> None:
98
113
  self.session_manager.disconnect()
@@ -101,14 +116,19 @@ class MainWindow(QMainWindow, Ui_MainWindow):
101
116
  #self.close()
102
117
  QApplication.quit()
103
118
 
104
- def _on_create_env(self) -> None:
119
+ def _on_edit_env(self) -> None:
105
120
  widget = CheckConfig(self.logger, Path("~/.irods").expanduser())
106
121
  widget.exec()
107
122
 
108
- def _on_check_env(self) -> None:
109
- widget = CheckConfig(self.logger, Path("~/.irods").expanduser())
123
+ def _on_edit_ticket(self) -> None:
124
+ widget = TicketEditor(self.session_manager.session, self.logger)
110
125
  widget.exec()
111
126
 
127
+ def _on_supply_ticket(self) -> None:
128
+ widget = SupplyTicket(self.session_manager, self.logger)
129
+ widget.exec()
130
+
131
+
112
132
  def on_session_changed(self, session) -> None:
113
133
  """Reset when session changes."""
114
134
  self.tab_widget.clear()
@@ -116,10 +136,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
116
136
 
117
137
  if session is None:
118
138
  self.menuPlugins.setEnabled(False)
139
+ self.action_supply_ticket.setEnabled(False)
140
+ self.action_delete_ticket.setEnabled(False)
141
+ self.action_create_ticket.setEnabled(False)
119
142
  self._show_welcome_tab()
120
143
  return
121
144
 
122
145
  self.menuPlugins.setEnabled(True)
146
+ self.action_supply_ticket.setEnabled(True)
147
+ if session.irods_session.username != "anonymous":
148
+ self.action_delete_ticket.setEnabled(True)
149
+ self.action_create_ticket.setEnabled(True)
123
150
  self.tab_manager.restore_tabs(session, self.app_name, self.logger)
124
151
 
125
152
  def _show_welcome_tab(self) -> None:
@@ -21,7 +21,7 @@ class SessionManager(QObject):
21
21
  self.logger = logger
22
22
  self.session: Session | None = None
23
23
 
24
- def connect(self, parent=None):
24
+ def login(self, parent=None):
25
25
  """Get session from Login."""
26
26
  dialog = LoginDialog(parent, self.logger, self)
27
27
  if dialog.exec() != QDialog.Accepted:
@@ -94,7 +94,6 @@ class TabManager:
94
94
  for name in ordered_standard + third_party:
95
95
  self.load_tab(name, session, app_name, logger)
96
96
 
97
-
98
97
  def update_plugin_menu(self):
99
98
  """Check and uncheck tab names in main menu."""
100
99
  for name, action in self.main_window.plugin_actions.items():