ibridgesgui 0.2.0__tar.gz → 0.2.2__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.
- ibridgesgui-0.2.2/.github/workflows/pypi_release.yml +39 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/PKG-INFO +15 -9
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/README.md +13 -7
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/docs/getting-started.qmd +4 -5
- ibridgesgui-0.2.2/docs/screenshots/add_check_config.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/add_new_config.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/browser.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/delete.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/login.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/metadata.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/permissions.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/replicas.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/search.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/start_ibridges.png +0 -0
- ibridgesgui-0.2.2/docs/screenshots/sync.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/docs/userdoc.qmd +1 -1
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/__main__.py +31 -12
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/_version.py +2 -2
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/browser.py +3 -9
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/gui_utils.py +3 -0
- ibridgesgui-0.2.2/ibridgesgui/icons/logo.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/irods_tree_model.py +4 -1
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/login.py +35 -3
- ibridgesgui-0.2.2/ibridgesgui/logviewer.py +50 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/popup_widgets.py +29 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/search.py +2 -1
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/sync.py +7 -3
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/threads.py +2 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/MainMenu.py +17 -13
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/MainMenu.ui +29 -12
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/configCheck.py +47 -30
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/configCheck.ui +38 -9
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/createCollection.py +42 -36
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/createCollection.ui +25 -28
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/irodsLogin.py +41 -52
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/irodsLogin.ui +25 -17
- ibridgesgui-0.2.2/ibridgesgui/ui_files/renameItem.py +94 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/renameItem.ui +24 -7
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabBrowser.py +104 -145
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabBrowser.ui +53 -46
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabInfo.py +40 -57
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabInfo.ui +15 -10
- ibridgesgui-0.2.2/ibridgesgui/ui_files/tabLogging.py +49 -0
- ibridgesgui-0.2.2/ibridgesgui/ui_files/tabLogging.ui +51 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabSearch.py +46 -67
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabSearch.ui +18 -17
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabSync.py +30 -15
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/tabSync.ui +29 -14
- ibridgesgui-0.2.2/ibridgesgui/ui_files/welcome.py +48 -0
- ibridgesgui-0.2.2/ibridgesgui/ui_files/welcome.ui +47 -0
- ibridgesgui-0.2.2/ibridgesgui/welcome.py +43 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui.egg-info/PKG-INFO +15 -9
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui.egg-info/SOURCES.txt +8 -4
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui.egg-info/requires.txt +1 -1
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/pyproject.toml +2 -3
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/requirements.txt +1 -1
- ibridgesgui-0.2.2/requirements_dev.txt +4 -0
- ibridgesgui-0.2.0/docs/screenshots/add_check_config.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/add_new_config.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/browser.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/delete.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/login.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/metadata.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/permissions.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/replicas.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/search.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/start_ibridges.png +0 -0
- ibridgesgui-0.2.0/docs/screenshots/sync.png +0 -0
- ibridgesgui-0.2.0/ibridgesgui/ui_files/dataTransferState.py +0 -114
- ibridgesgui-0.2.0/ibridgesgui/ui_files/dataTransferState.ui +0 -187
- ibridgesgui-0.2.0/ibridgesgui/ui_files/renameItem.py +0 -77
- ibridgesgui-0.2.0/ibridgesgui/ui_files/tabUpDownload.py +0 -303
- ibridgesgui-0.2.0/ibridgesgui/ui_files/tabUpDownload.ui +0 -460
- ibridgesgui-0.2.0/requirements_dev.txt +0 -4
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.flake8 +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.github/dependabot.yml +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.github/workflows/linter.yml +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.github/workflows/publish.yml +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/.gitignore +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/LICENSE +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/_quarto.yml +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/docs/info.qmd +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/__init__.py +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/config.py +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/arrow-left.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/arrow-right.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/arrow-up.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/home.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/iBridges.ico +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/loading_circle.gif +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/nosync.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/refresh.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/icons/syncing.png +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/info.py +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/.py +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/ExampleTab.py +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/ExampleTab.ui +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui/ui_files/__init__.py +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui.egg-info/dependency_links.txt +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui.egg-info/entry_points.txt +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/ibridgesgui.egg-info/top_level.txt +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/index.qmd +0 -0
- {ibridgesgui-0.2.0 → ibridgesgui-0.2.2}/setup.cfg +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# This workflow will upload a Python Package using Twine when a release is created
|
|
2
|
+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
|
|
3
|
+
|
|
4
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
5
|
+
# They are provided by a third-party and are governed by
|
|
6
|
+
# separate terms of service, privacy policy, and support
|
|
7
|
+
# documentation.
|
|
8
|
+
|
|
9
|
+
name: Upload Python Package
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
release:
|
|
13
|
+
types: [published]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
deploy:
|
|
20
|
+
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v4
|
|
27
|
+
with:
|
|
28
|
+
python-version: '3.x'
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
pip install build
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: python -m build
|
|
35
|
+
- name: Publish package
|
|
36
|
+
uses: pypa/gh-action-pypi-publish@7eb3b701d11256e583f5b49899c5e7203deab573
|
|
37
|
+
with:
|
|
38
|
+
user: __token__
|
|
39
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ibridgesgui
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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 GENERAL PUBLIC LICENSE
|
|
@@ -690,7 +690,7 @@ Requires-Python: >=3.9
|
|
|
690
690
|
Description-Content-Type: text/markdown
|
|
691
691
|
License-File: LICENSE
|
|
692
692
|
Requires-Dist: PyQt6>=6.4.2
|
|
693
|
-
Requires-Dist: ibridges==0.2.
|
|
693
|
+
Requires-Dist: ibridges==0.2.2
|
|
694
694
|
Requires-Dist: setproctitle==1.3.3
|
|
695
695
|
Requires-Dist: importlib-resources; python_version <= "3.10"
|
|
696
696
|
Provides-Extra: test
|
|
@@ -700,10 +700,7 @@ Requires-Dist: pytest-cov; extra == "test"
|
|
|
700
700
|
Requires-Dist: ruff; extra == "test"
|
|
701
701
|
Requires-Dist: mypy; extra == "test"
|
|
702
702
|
|
|
703
|
-
# iBridges
|
|
704
|
-
|
|
705
|
-
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/linter.yml)
|
|
706
|
-
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/publish.yml)
|
|
703
|
+
# iBridges <img src="ibridgesgui/icons/logo.png" width="150" align="right">
|
|
707
704
|
|
|
708
705
|
<p align="center">
|
|
709
706
|
<p align="center">
|
|
@@ -713,6 +710,9 @@ Requires-Dist: mypy; extra == "test"
|
|
|
713
710
|
</p>
|
|
714
711
|
</p>
|
|
715
712
|
|
|
713
|
+
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/linter.yml)
|
|
714
|
+
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/publish.yml)
|
|
715
|
+
|
|
716
716
|
## About
|
|
717
717
|
|
|
718
718
|
The git repository contains a generic *iRODS* graphical user interface. The iRODS functionality is based on [ibridges](https://github.com/UtrechtUniversity/iBridges) and works with any *iRODS* instance.
|
|
@@ -732,12 +732,18 @@ The git repository contains a generic *iRODS* graphical user interface. The iRO
|
|
|
732
732
|
- Safe default options when working with your data.
|
|
733
733
|
|
|
734
734
|
## Installation
|
|
735
|
-
-
|
|
735
|
+
- The python package
|
|
736
736
|
|
|
737
737
|
```bash
|
|
738
|
-
pip install
|
|
739
|
-
pip install git+https://github.com/chStaiger/iBridges-Gui.git@main
|
|
738
|
+
pip install ibridgesgui
|
|
740
739
|
```
|
|
740
|
+
|
|
741
|
+
- A specific branch of the git repository (testers, developers)
|
|
742
|
+
|
|
743
|
+
```bash
|
|
744
|
+
pip install git+https://github.com/chStaiger/iBridges-Gui.git@branch-name
|
|
745
|
+
```
|
|
746
|
+
|
|
741
747
|
- Locally from code (for developers)
|
|
742
748
|
|
|
743
749
|
```bash
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
# iBridges
|
|
2
|
-
|
|
3
|
-
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/linter.yml)
|
|
4
|
-
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/publish.yml)
|
|
1
|
+
# iBridges <img src="ibridgesgui/icons/logo.png" width="150" align="right">
|
|
5
2
|
|
|
6
3
|
<p align="center">
|
|
7
4
|
<p align="center">
|
|
@@ -11,6 +8,9 @@
|
|
|
11
8
|
</p>
|
|
12
9
|
</p>
|
|
13
10
|
|
|
11
|
+
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/linter.yml)
|
|
12
|
+
[](https://github.com/chStaiger/iBridges-Gui/actions/workflows/publish.yml)
|
|
13
|
+
|
|
14
14
|
## About
|
|
15
15
|
|
|
16
16
|
The git repository contains a generic *iRODS* graphical user interface. The iRODS functionality is based on [ibridges](https://github.com/UtrechtUniversity/iBridges) and works with any *iRODS* instance.
|
|
@@ -30,12 +30,18 @@ The git repository contains a generic *iRODS* graphical user interface. The iRO
|
|
|
30
30
|
- Safe default options when working with your data.
|
|
31
31
|
|
|
32
32
|
## Installation
|
|
33
|
-
-
|
|
33
|
+
- The python package
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
pip install
|
|
37
|
-
pip install git+https://github.com/chStaiger/iBridges-Gui.git@main
|
|
36
|
+
pip install ibridgesgui
|
|
38
37
|
```
|
|
38
|
+
|
|
39
|
+
- A specific branch of the git repository (testers, developers)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install git+https://github.com/chStaiger/iBridges-Gui.git@branch-name
|
|
43
|
+
```
|
|
44
|
+
|
|
39
45
|
- Locally from code (for developers)
|
|
40
46
|
|
|
41
47
|
```bash
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
## Install iBridges-gui
|
|
5
5
|
|
|
6
6
|
```
|
|
7
|
-
pip install
|
|
8
|
-
pip install pip install git+https://github.com/chStaiger/iBridges-Gui.git@main
|
|
7
|
+
pip install ibridgesgui
|
|
9
8
|
```
|
|
10
9
|
|
|
11
10
|
## Start the program
|
|
@@ -20,7 +19,7 @@ When you start iBridges you will find in the upper drop-down menu `Connect` and
|
|
|
20
19
|
|
|
21
20
|
Before we start iBridges for the first time let us check and create a valid configuration file; Click on `Configure -> Add Configuration`.
|
|
22
21
|
|
|
23
|
-
{width=
|
|
22
|
+
{width=75% fig-align="center"}
|
|
24
23
|
|
|
25
24
|
If you already stored an `irods_environment.json` in the directory `~/.irods` (Windows `C:\Users\<username>\.irods`) then you can use the drop-down menu (little downward arrow) to load the configuration.
|
|
26
25
|
|
|
@@ -28,7 +27,7 @@ If you do not have an iRODS configuration yet, click on the button `New Config`.
|
|
|
28
27
|
|
|
29
28
|
You should see now something like:
|
|
30
29
|
|
|
31
|
-
{width=
|
|
30
|
+
{width=75% fig-align="center"}
|
|
32
31
|
|
|
33
32
|
Click the `Check` button to find out whether you can make a connection to the iRODS server. If you get error messages, adjust the contents accordingly. If you are unsure, please contact your iRODS service provider.
|
|
34
33
|
|
|
@@ -38,7 +37,7 @@ Once the check runs through fine click the `Save` or `Save as` button. This will
|
|
|
38
37
|
|
|
39
38
|
To start working with data in iRODS select `Connect -> Connect to iRODS`. This will open the pop-up window
|
|
40
39
|
|
|
41
|
-
{width=
|
|
40
|
+
{width=75% fig-align="center"}
|
|
42
41
|
|
|
43
42
|
Select the file we edited above from the drop-down menu and provide your password. If you already logged into iRODS with this or another iRODS client your password might still be cached. This is indicated by the `******`. Hit `<Enter>` or press the `Connect` button.
|
|
44
43
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -110,7 +110,7 @@ In the case you want to download a large collection from iRODS, create the desti
|
|
|
110
110
|
|
|
111
111
|
**Note that the wild card is `%`**!
|
|
112
112
|
|
|
113
|
-
In the example search we are looking for data in a collection called *my_books* which can be located anywhere in the iRODS tree. This is denoted by
|
|
113
|
+
In the example search we are looking for data in a collection called *my_books* which can be located anywhere in the iRODS tree. This is denoted by `%` and we specify that we want to retrieve data which carries the metadata key *author* where the value ends with *Carroll*.
|
|
114
114
|
|
|
115
115
|
*Single click* on items in the list and click the `Download` button to open a dialog to select the destination for the data and start the download
|
|
116
116
|
|
|
@@ -5,19 +5,21 @@ import logging
|
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
+
import PyQt6.QtGui
|
|
8
9
|
import PyQt6.QtWidgets
|
|
9
10
|
import PyQt6.uic
|
|
10
11
|
import setproctitle
|
|
11
12
|
|
|
12
13
|
from ibridgesgui.browser import Browser
|
|
13
14
|
from ibridgesgui.config import get_log_level, init_logger, set_log_level
|
|
14
|
-
from ibridgesgui.gui_utils import UI_FILE_DIR
|
|
15
15
|
from ibridgesgui.info import Info
|
|
16
16
|
from ibridgesgui.login import Login
|
|
17
|
+
from ibridgesgui.logviewer import LogViewer
|
|
17
18
|
from ibridgesgui.popup_widgets import CheckConfig
|
|
18
19
|
from ibridgesgui.search import Search
|
|
19
20
|
from ibridgesgui.sync import Sync
|
|
20
21
|
from ibridgesgui.ui_files.MainMenu import Ui_MainWindow
|
|
22
|
+
from ibridgesgui.welcome import Welcome
|
|
21
23
|
|
|
22
24
|
# Global constants
|
|
23
25
|
THIS_APPLICATION = "ibridges-gui"
|
|
@@ -32,24 +34,21 @@ class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow):
|
|
|
32
34
|
def __init__(self, app_name):
|
|
33
35
|
"""Initialise the main window."""
|
|
34
36
|
super().__init__()
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
PyQt6.uic.loadUi(UI_FILE_DIR / "MainMenu.ui", self)
|
|
37
|
+
super().setupUi(self)
|
|
38
|
+
|
|
39
|
+
app.aboutToQuit.connect(self.close_event)
|
|
39
40
|
|
|
40
41
|
self.logger = logging.getLogger(app_name)
|
|
42
|
+
|
|
41
43
|
self.irods_path = Path("~", ".irods").expanduser()
|
|
42
44
|
self.app_name = app_name
|
|
45
|
+
self.welcome_tab()
|
|
43
46
|
self.ui_tabs_lookup = {
|
|
44
47
|
"tabBrowser": self.init_browser_tab,
|
|
45
48
|
"tabSync": self.init_sync_tab,
|
|
46
49
|
"tabSearch": self.init_search_tab,
|
|
47
|
-
#'tabDataBundle': self.setupTabDataBundle,
|
|
48
|
-
#'tabCreateTicket': self.setupTabCreateTicket,
|
|
49
|
-
#'tabELNData': self.setupTabELNData,
|
|
50
|
-
#'tabAmberWorkflow': self.setupTabAmberWorkflow,
|
|
51
50
|
"tabInfo": self.init_info_tab,
|
|
52
|
-
|
|
51
|
+
"tabLog": self.init_log_tab
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
self.session = None
|
|
@@ -62,6 +61,7 @@ class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow):
|
|
|
62
61
|
self.action_check_configuration.triggered.connect(self.inspect_env_file)
|
|
63
62
|
self.tab_widget.setCurrentIndex(0)
|
|
64
63
|
|
|
64
|
+
|
|
65
65
|
def disconnect(self):
|
|
66
66
|
"""Close iRODS session."""
|
|
67
67
|
self.error_label.clear()
|
|
@@ -71,6 +71,7 @@ class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow):
|
|
|
71
71
|
self.session = None
|
|
72
72
|
self.session_dict.clear()
|
|
73
73
|
self.tab_widget.clear()
|
|
74
|
+
self.welcome_tab()
|
|
74
75
|
|
|
75
76
|
def connect(self):
|
|
76
77
|
"""Create iRODS session."""
|
|
@@ -82,6 +83,7 @@ class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow):
|
|
|
82
83
|
login_window = Login(self.session_dict, self.app_name)
|
|
83
84
|
login_window.exec()
|
|
84
85
|
# Trick to get the session object from the QDialog
|
|
86
|
+
|
|
85
87
|
if "session" in self.session_dict:
|
|
86
88
|
self.session = self.session_dict["session"]
|
|
87
89
|
try:
|
|
@@ -89,6 +91,8 @@ class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow):
|
|
|
89
91
|
except:
|
|
90
92
|
self.session = None
|
|
91
93
|
raise
|
|
94
|
+
else:
|
|
95
|
+
self.logger.exception("No session created. %s", self.session_dict)
|
|
92
96
|
|
|
93
97
|
def exit(self):
|
|
94
98
|
"""Quit program."""
|
|
@@ -106,17 +110,32 @@ class MainMenu(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow):
|
|
|
106
110
|
else:
|
|
107
111
|
pass
|
|
108
112
|
|
|
113
|
+
def close_event(self):
|
|
114
|
+
"""Close program properly if main window is closed."""
|
|
115
|
+
self.disconnect()
|
|
116
|
+
sys.exit()
|
|
117
|
+
|
|
109
118
|
def setup_tabs(self):
|
|
110
119
|
"""Init tab view."""
|
|
111
120
|
for tab_fun in self.ui_tabs_lookup.values():
|
|
112
121
|
tab_fun()
|
|
113
122
|
# self.ui_tabs_lookup[tab_name]()
|
|
114
123
|
|
|
124
|
+
def welcome_tab(self):
|
|
125
|
+
"""Create first tab."""
|
|
126
|
+
welcome = Welcome()
|
|
127
|
+
self.tab_widget.addTab(welcome, "iBridges")
|
|
128
|
+
|
|
115
129
|
def init_info_tab(self):
|
|
116
130
|
"""Create info."""
|
|
117
131
|
irods_info = Info(self.session)
|
|
118
132
|
self.tab_widget.addTab(irods_info, "Info")
|
|
119
133
|
|
|
134
|
+
def init_log_tab(self):
|
|
135
|
+
"""Create log tab."""
|
|
136
|
+
ibridges_log = LogViewer(self.logger)
|
|
137
|
+
self.tab_widget.addTab(ibridges_log, "Logs")
|
|
138
|
+
|
|
120
139
|
def init_browser_tab(self):
|
|
121
140
|
"""Create browser."""
|
|
122
141
|
self.irods_browser = Browser(self.session, self.app_name)
|
|
@@ -151,8 +170,8 @@ def main():
|
|
|
151
170
|
if log_level is not None:
|
|
152
171
|
init_logger(THIS_APPLICATION, log_level)
|
|
153
172
|
else:
|
|
154
|
-
set_log_level("
|
|
155
|
-
init_logger(THIS_APPLICATION, "
|
|
173
|
+
set_log_level("debug")
|
|
174
|
+
init_logger(THIS_APPLICATION, "debug")
|
|
156
175
|
main_widget = PyQt6.QtWidgets.QStackedWidget()
|
|
157
176
|
main_app = MainMenu(THIS_APPLICATION)
|
|
158
177
|
main_widget.addWidget(main_app)
|
|
@@ -12,5 +12,5 @@ __version__: str
|
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
|
13
13
|
version_tuple: VERSION_TUPLE
|
|
14
14
|
|
|
15
|
-
__version__ = version = '0.
|
|
16
|
-
__version_tuple__ = version_tuple = (0,
|
|
15
|
+
__version__ = version = '0.2.2'
|
|
16
|
+
__version_tuple__ = version_tuple = (0, 2, 2)
|
|
@@ -48,14 +48,7 @@ class Browser(PyQt6.QtWidgets.QWidget, Ui_tabBrowser):
|
|
|
48
48
|
self.session, f"/{self.session.zone}/home/{self.session.username}"
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
self.root_coll = IrodsPath(self.session, root_path).collection
|
|
53
|
-
elif IrodsPath(self.session, f"/{self.session.zone}/home").collection_exists():
|
|
54
|
-
self.root_coll = IrodsPath(self.session, f"/{self.session.zone}/home").collection
|
|
55
|
-
else:
|
|
56
|
-
self.error_label.setText(
|
|
57
|
-
'Cannot set root collection. Set "irods_home" in your environment.json'
|
|
58
|
-
)
|
|
51
|
+
self.root_coll = IrodsPath(self.session, root_path).collection
|
|
59
52
|
self.reset_path()
|
|
60
53
|
self.browse()
|
|
61
54
|
|
|
@@ -231,7 +224,6 @@ class Browser(PyQt6.QtWidgets.QWidget, Ui_tabBrowser):
|
|
|
231
224
|
len(coll.data_objects) + len(coll.subcollections),
|
|
232
225
|
coll_data + obj_data,
|
|
233
226
|
)
|
|
234
|
-
self.browser_table.resizeColumnsToContents()
|
|
235
227
|
except Exception:
|
|
236
228
|
self.browser_table.setRowCount(0)
|
|
237
229
|
self.logger.exception("Cannot load browser.")
|
|
@@ -523,6 +515,8 @@ class Browser(PyQt6.QtWidgets.QWidget, Ui_tabBrowser):
|
|
|
523
515
|
]
|
|
524
516
|
else:
|
|
525
517
|
content = [f"No Preview for: {irods_path}"]
|
|
518
|
+
else:
|
|
519
|
+
content = [f"No Preview for: {irods_path}"]
|
|
526
520
|
populate_textfield(self.preview_browser, content)
|
|
527
521
|
|
|
528
522
|
def _get_item_path(self, row):
|
|
@@ -16,12 +16,15 @@ except ImportError:
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
UI_FILE_DIR = files(__package__) / "ui_files"
|
|
19
|
+
LOGO_DIR = files(__package__) / "icons"
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
# Widget utils
|
|
22
23
|
def populate_table(table_widget, rows: int, data_by_row: list):
|
|
23
24
|
"""Populate a table-like pyqt widget with data."""
|
|
25
|
+
table_widget.setRowCount(0)
|
|
24
26
|
table_widget.setRowCount(rows)
|
|
27
|
+
|
|
25
28
|
for row, data in enumerate(data_by_row):
|
|
26
29
|
for col, item in enumerate(data):
|
|
27
30
|
table_widget.setItem(row, col, PyQt6.QtWidgets.QTableWidgetItem(str(item)))
|
|
Binary file
|
|
@@ -105,9 +105,12 @@ class IrodsTreeModel(PyQt6.QtGui.QStandardItemModel):
|
|
|
105
105
|
_, level, _, _, _, abs_irods_path = tree_item_data
|
|
106
106
|
parent_coll = IrodsPath(self.session, abs_irods_path).collection
|
|
107
107
|
|
|
108
|
+
# the irods root also contains the irods root as subcollection
|
|
109
|
+
subcolls = [c for c in parent_coll.subcollections if c.path != "/"]
|
|
110
|
+
dataobjs = parent_coll.data_objects
|
|
108
111
|
# we assume that tree_item has no children yet.
|
|
109
112
|
new_nodes = {}
|
|
110
|
-
for item in
|
|
113
|
+
for item in subcolls + dataobjs:
|
|
111
114
|
row = self._tree_row_from_irods_item(item, parent_coll.id, int(level))
|
|
112
115
|
tree_item.appendRow(row)
|
|
113
116
|
new_nodes[item.id] = tree_item.child(tree_item.rowCount() - 1)
|
|
@@ -4,8 +4,10 @@ import logging
|
|
|
4
4
|
import sys
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
-
from ibridges import Session
|
|
7
|
+
from ibridges import IrodsPath, Session
|
|
8
|
+
from ibridges.resources import Resources
|
|
8
9
|
from ibridges.session import LoginError, PasswordError
|
|
10
|
+
from irods.exception import ResourceDoesNotExist
|
|
9
11
|
from PyQt6.QtWidgets import QDialog, QLineEdit
|
|
10
12
|
from PyQt6.uic import loadUi
|
|
11
13
|
|
|
@@ -77,7 +79,6 @@ class Login(QDialog, Ui_irodsLogin):
|
|
|
77
79
|
else:
|
|
78
80
|
session = Session(irods_env=env_file, password=self.password_field.text())
|
|
79
81
|
self.logger.debug("Login with %s and password from prompt.", env_file)
|
|
80
|
-
self.session_dict["session"] = session
|
|
81
82
|
self.logger.info(
|
|
82
83
|
"Logged in as %s to %s; working coll %s",
|
|
83
84
|
session.username,
|
|
@@ -85,17 +86,48 @@ class Login(QDialog, Ui_irodsLogin):
|
|
|
85
86
|
session.home,
|
|
86
87
|
)
|
|
87
88
|
session.write_pam_password()
|
|
89
|
+
self.session_dict["session"] = session
|
|
88
90
|
set_last_ienv_path(env_file.name)
|
|
89
|
-
self.close()
|
|
90
91
|
except LoginError:
|
|
91
92
|
self.error_label.setText("irods_environment.json not setup correctly.")
|
|
93
|
+
self.logger.error("irods_environment.json not setup correctly.")
|
|
92
94
|
except PasswordError:
|
|
93
95
|
self.error_label.setText("Wrong password!")
|
|
96
|
+
self.logger.error("Wrong password provided.")
|
|
94
97
|
except ConnectionError:
|
|
95
98
|
self.error_label.setText(
|
|
96
99
|
"Cannot connect to server. Check Internet, host name and port."
|
|
97
100
|
)
|
|
101
|
+
self.logger.exception("Network error.")
|
|
98
102
|
except Exception as err:
|
|
99
103
|
log_path = Path("~/.ibridges")
|
|
100
104
|
self.logger.exception("Failed to login: %s", repr(err))
|
|
101
105
|
self.error_label.setText(f"Login failed, consult the log file(s) in {log_path}")
|
|
106
|
+
|
|
107
|
+
#check irods_home
|
|
108
|
+
fail_home = True
|
|
109
|
+
if not IrodsPath(self.session_dict["session"]).collection_exists():
|
|
110
|
+
self.error_label.setText(f'"irods_home": "{session.home}" does not exist.')
|
|
111
|
+
self.logger.error("irods_home does not exist.")
|
|
112
|
+
else:
|
|
113
|
+
fail_home = False
|
|
114
|
+
|
|
115
|
+
#check existance of default resource
|
|
116
|
+
fail_resc = True
|
|
117
|
+
try:
|
|
118
|
+
resc = Resources(self.session_dict["session"]).get_resource(session.default_resc)
|
|
119
|
+
if resc.parent is None:
|
|
120
|
+
fail_resc = False
|
|
121
|
+
else:
|
|
122
|
+
self.error_label.setText(f'"default_resource": "{session.default_resc}" not valid.')
|
|
123
|
+
except ResourceDoesNotExist:
|
|
124
|
+
self.error_label.setText(
|
|
125
|
+
f'"default_resource": "{session.default_resc}" does not exist.')
|
|
126
|
+
self.logger.error("Default resource does not exist.")
|
|
127
|
+
except AttributeError:
|
|
128
|
+
self.error_label.setText(f'"default_resource": "{session.default_resc}" not valid.')
|
|
129
|
+
|
|
130
|
+
if fail_resc or fail_home:
|
|
131
|
+
del self.session_dict["session"]
|
|
132
|
+
else:
|
|
133
|
+
self.close()
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Logging tab."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import PyQt6
|
|
7
|
+
|
|
8
|
+
from ibridgesgui.config import CONFIG_DIR
|
|
9
|
+
from ibridgesgui.gui_utils import UI_FILE_DIR
|
|
10
|
+
from ibridgesgui.ui_files.tabLogging import Ui_tabLogging
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class QTextEditLogger(logging.Handler, PyQt6.QtCore.QObject):
|
|
14
|
+
"""Logging in a Qt text browser."""
|
|
15
|
+
|
|
16
|
+
append_plain_text = PyQt6.QtCore.pyqtSignal(str)
|
|
17
|
+
|
|
18
|
+
def __init__(self, text_browser):
|
|
19
|
+
"""Initialise."""
|
|
20
|
+
super().__init__()
|
|
21
|
+
PyQt6.QtCore.QObject.__init__(self)
|
|
22
|
+
self.widget = text_browser
|
|
23
|
+
self.widget.setReadOnly(True)
|
|
24
|
+
self.append_plain_text.connect(self.widget.insertPlainText)
|
|
25
|
+
|
|
26
|
+
def emit(self, record):
|
|
27
|
+
"""Emit when new logging accurs."""
|
|
28
|
+
msg = self.format(record)+"\n"
|
|
29
|
+
self.append_plain_text.emit(msg)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class LogViewer(PyQt6.QtWidgets.QWidget, Ui_tabLogging):
|
|
33
|
+
"""Set iBridges logging in GUI."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, logger):
|
|
36
|
+
"""Initialise the tab."""
|
|
37
|
+
super().__init__()
|
|
38
|
+
if getattr(sys, "frozen", False):
|
|
39
|
+
super().setupUi(self)
|
|
40
|
+
else:
|
|
41
|
+
PyQt6.uic.loadUi(UI_FILE_DIR / "tabLogging.ui", self)
|
|
42
|
+
|
|
43
|
+
self.logger = logger
|
|
44
|
+
self.log_label.setText(str(CONFIG_DIR))
|
|
45
|
+
self.log_text = QTextEditLogger(self.log_browser)
|
|
46
|
+
self.log_text.setFormatter(
|
|
47
|
+
logging.Formatter(
|
|
48
|
+
'%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s'))
|
|
49
|
+
self.logger.addHandler(self.log_text)
|
|
50
|
+
self.logger.setLevel(logging.DEBUG)
|
|
@@ -6,6 +6,7 @@ import sys
|
|
|
6
6
|
|
|
7
7
|
import irods
|
|
8
8
|
from ibridges import IrodsPath
|
|
9
|
+
from ibridges.util import find_environment_provider, get_environment_providers
|
|
9
10
|
from PyQt6 import QtCore
|
|
10
11
|
from PyQt6.QtWidgets import QDialog, QFileDialog
|
|
11
12
|
from PyQt6.uic import loadUi
|
|
@@ -79,6 +80,8 @@ class CreateDirectory(QDialog, Ui_createCollection):
|
|
|
79
80
|
try:
|
|
80
81
|
os.makedirs(new_dir_path)
|
|
81
82
|
self.done(1)
|
|
83
|
+
except FileExistsError:
|
|
84
|
+
self.error_label.setText("ERROR: Folder already exists.")
|
|
82
85
|
except Exception as error:
|
|
83
86
|
if hasattr(error, "message"):
|
|
84
87
|
self.error_label.setText(error.message)
|
|
@@ -138,8 +141,10 @@ class CheckConfig(QDialog, Ui_configCheck):
|
|
|
138
141
|
self.env_path = env_path
|
|
139
142
|
self.setWindowTitle("Create, edit and inspect iRODS environment")
|
|
140
143
|
self._init_env_box()
|
|
144
|
+
self._init_template_box()
|
|
141
145
|
|
|
142
146
|
self.envbox.activated.connect(self.load_env)
|
|
147
|
+
self.template_box.activated.connect(self.load_template)
|
|
143
148
|
self.new_button.clicked.connect(self.create_env)
|
|
144
149
|
self.check_button.clicked.connect(self.check_env)
|
|
145
150
|
self.save_button.clicked.connect(self.save_env)
|
|
@@ -153,6 +158,30 @@ class CheckConfig(QDialog, Ui_configCheck):
|
|
|
153
158
|
self.envbox.addItems(env_jsons)
|
|
154
159
|
self.envbox.setCurrentIndex(0)
|
|
155
160
|
|
|
161
|
+
def _init_template_box(self):
|
|
162
|
+
self.template_box.clear()
|
|
163
|
+
providers = get_environment_providers()
|
|
164
|
+
|
|
165
|
+
if len(providers) == 0:
|
|
166
|
+
self.template_box.hide()
|
|
167
|
+
return
|
|
168
|
+
|
|
169
|
+
templates = [key+": "+descr for p in providers
|
|
170
|
+
for key, descr in p.descriptions.items()]
|
|
171
|
+
if len(templates) > 0:
|
|
172
|
+
self.template_box.addItems(templates)
|
|
173
|
+
self.template_box.setCurrentIndex(0)
|
|
174
|
+
|
|
175
|
+
def load_template(self):
|
|
176
|
+
"""Load environment template into text field."""
|
|
177
|
+
self.error_label.clear()
|
|
178
|
+
template = self.template_box.currentText()
|
|
179
|
+
key = template.split(": ")[0]
|
|
180
|
+
env_json = find_environment_provider(get_environment_providers(), key).\
|
|
181
|
+
environment_json(key, "USERNAME").split("\n")
|
|
182
|
+
populate_textfield(self.env_field, env_json)
|
|
183
|
+
self.error_label.setText("Please fill in your user name.")
|
|
184
|
+
|
|
156
185
|
def load_env(self):
|
|
157
186
|
"""Load json into text field."""
|
|
158
187
|
self.error_label.clear()
|
|
@@ -184,7 +184,8 @@ class Search(PyQt6.QtWidgets.QWidget, Ui_tabSearch):
|
|
|
184
184
|
key.text(): "%" if val.text() == "" else val.text()
|
|
185
185
|
for key, val in zip(self.keys, self.vals)
|
|
186
186
|
}
|
|
187
|
-
|
|
187
|
+
if "" in key_vals:
|
|
188
|
+
del key_vals[""]
|
|
188
189
|
|
|
189
190
|
path = self.path_field.text() if self.path_field.text() != "" else None
|
|
190
191
|
checksum = self.checksum_field.text() if self.checksum_field.text() != "" else None
|
|
@@ -89,7 +89,7 @@ class Sync(PyQt6.QtWidgets.QWidget, Ui_tabSync):
|
|
|
89
89
|
def irods_root(self):
|
|
90
90
|
"""Retrieve lowest visible level in the iRODS tree for the user."""
|
|
91
91
|
lowest = IrodsPath(self.session).absolute()
|
|
92
|
-
while lowest.parent.exists():
|
|
92
|
+
while lowest.parent.exists() and str(lowest) != "/":
|
|
93
93
|
lowest = lowest.parent
|
|
94
94
|
return lowest
|
|
95
95
|
|
|
@@ -276,8 +276,12 @@ class Sync(PyQt6.QtWidgets.QWidget, Ui_tabSync):
|
|
|
276
276
|
return
|
|
277
277
|
|
|
278
278
|
self.error_label.clear()
|
|
279
|
-
table_data =
|
|
280
|
-
|
|
279
|
+
table_data = [
|
|
280
|
+
(ipath, lpath, ipath.size) for ipath, lpath in thread_output["result"]["download"]
|
|
281
|
+
] + [
|
|
282
|
+
(lpath, ipath, lpath.stat().st_size)
|
|
283
|
+
for lpath, ipath in thread_output["result"]["upload"]
|
|
284
|
+
]
|
|
281
285
|
populate_table(self.diff_table, len(table_data), table_data)
|
|
282
286
|
if len(table_data) == 0:
|
|
283
287
|
self.error_label.setText("Data is already synchronised.")
|
|
@@ -89,6 +89,7 @@ class TransferDataThread(QThread):
|
|
|
89
89
|
transfer_out = {}
|
|
90
90
|
transfer_out["error"] = ""
|
|
91
91
|
|
|
92
|
+
emit_string = "Create collections."
|
|
92
93
|
for coll in self.diffs["create_collection"]:
|
|
93
94
|
try:
|
|
94
95
|
IrodsPath.create_collection(self.thread_session, coll)
|
|
@@ -101,6 +102,7 @@ class TransferDataThread(QThread):
|
|
|
101
102
|
transfer_out["error"] + f"\nTransfer failed Cannot create {coll}: {repr(error)}"
|
|
102
103
|
)
|
|
103
104
|
|
|
105
|
+
emit_string = "Create folders."
|
|
104
106
|
for folder in self.diffs["create_dir"]:
|
|
105
107
|
print(f"create {folder}")
|
|
106
108
|
try:
|