Skip to content

Commit e82ccd5

Browse files
committed
✨ feat: feat: comprehensive UX, accessibility, security and code quality overhaul
Security & Critical Fixes: - Replace bare except clauses with explicit Exception types - Remove password persistence from config.json - Use subprocess.run() with lists instead of shell=True Accessibility (Orca/Screen Reader): - Add accessible labels on all interactive widgets (buttons, switches, entries) - Add accessible DESCRIPTION on IP entry row with format example - Add live region that mirrors installation status for screen readers - Add progress bar VALUE_NOW/VALUE_MIN/VALUE_MAX accessible properties - Announce scan results via update_property on devices group Code Quality: - Replace wildcard imports with explicit imports (168 → 0 lint errors) - Auto-fix 38 unused imports, add ruff.toml configuration - Format all 32 files with ruff (consistent style) - Replace deprecated Adw.MessageDialog with Adw.AlertDialog - Replace time.sleep() in async tests with threading.Event (7s → 4.5s) UX Improvements: - Theme-aware terminal colors (dark/light) with dynamic notify::dark listener - Dynamic status row prefix (spinner/icon) instead of visibility toggles - Progressive disclosure: sections hidden until developer mode enabled - Discovered Devices section hidden until scan completes - Manual Connection section shown only as fallback when scan finds nothing - IP field cleared on app start (no stale data from previous session) - Copy IP button highlighted with suggested-action style - IP inline validation with error class and descriptive title - Connect button requires both developer mode and non-empty IP - Docker install button and add-group button use flat style - Onboarding first-run banner with 4-step overview Docker Workflow: - Async Docker install via pkexec (single password prompt, no sudo) - Real-time docker pull progress with Popen line streaming - sg docker group wrapping for post-install usage without restart - Progress callback plumbing from docker service to UI Layout Polish: - Flat header bar (transparent background, no "Bem-vindo" title) - Reduced vertical spacing on installation page (compact layout) - Live region moved inside progress box to eliminate dead space Infrastructure: - Fix socket leak with context manager in local IP detection - Fix scan range to use NETWORK_IP_RANGE_END (254) - Thread-safe config manager access - Logger guard for missing handlers - Reusable header bar title label - setup.py version sync with constants
1 parent 5ea5794 commit e82ccd5

34 files changed

Lines changed: 2575 additions & 976 deletions

PLANNING.md

Lines changed: 278 additions & 0 deletions
Large diffs are not rendered by default.

ruff.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[lint]
2+
# E402: Module level import not at top of file
3+
# Expected in PyGObject apps due to gi.require_version() calls before imports
4+
ignore = ["E402"]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Success: no issues found in 32 source files

usr/share/jellytizen/.audit/radon.txt

Whitespace-only changes.

usr/share/jellytizen/.audit/radon_full.txt

Lines changed: 380 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Would reformat: app.py
2+
Would reformat: conftest.py
3+
Would reformat: main.py
4+
Would reformat: pages/certificates.py
5+
Would reformat: pages/device.py
6+
Would reformat: pages/install.py
7+
Would reformat: pages/preferences.py
8+
Would reformat: pages/welcome.py
9+
Would reformat: services/certificates.py
10+
Would reformat: services/device.py
11+
Would reformat: services/docker.py
12+
Would reformat: setup.py
13+
Would reformat: tests/services/test_certificates.py
14+
Would reformat: tests/services/test_device.py
15+
Would reformat: tests/services/test_docker.py
16+
Would reformat: tests/unit/test_config.py
17+
Would reformat: tests/unit/test_exceptions.py
18+
Would reformat: tests/unit/test_validators.py
19+
Would reformat: utils/config.py
20+
Would reformat: utils/constants.py
21+
Would reformat: utils/exceptions.py
22+
Would reformat: utils/i18n.py
23+
Would reformat: utils/logger.py
24+
Would reformat: utils/ui_helpers.py
25+
Would reformat: utils/validators.py
26+
25 files would be reformatted, 7 files already formatted
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
F401 [*] `os` imported but unused
2+
--> app.py:3:8
3+
|
4+
1 | # app.py
5+
2 | import gi
6+
3 | import os
7+
| ^^
8+
4 | from pathlib import Path
9+
|
10+
help: Remove unused import: `os`
11+
12+
F401 [*] `pathlib.Path` imported but unused
13+
--> app.py:4:21
14+
|
15+
2 | import gi
16+
3 | import os
17+
4 | from pathlib import Path
18+
| ^^^^
19+
5 |
20+
6 | gi.require_version('Gtk', '4.0')
21+
|
22+
help: Remove unused import: `pathlib.Path`
23+
24+
E402 Module level import not at top of file
25+
--> app.py:9:1
26+
|
27+
7 | gi.require_version('Adw', '1')
28+
8 |
29+
9 | from gi.repository import Gtk, Adw, Gio
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
10 | from pages.welcome import WelcomePage
32+
11 | from pages.device import DevicePage
33+
|
34+
35+
E402 Module level import not at top of file
36+
--> app.py:10:1
37+
|
38+
9 | from gi.repository import Gtk, Adw, Gio
39+
10 | from pages.welcome import WelcomePage
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
11 | from pages.device import DevicePage
42+
12 | from pages.certificates import CertificatesPage
43+
|
44+
45+
E402 Module level import not at top of file
46+
--> app.py:11:1
47+
|
48+
9 | from gi.repository import Gtk, Adw, Gio
49+
10 | from pages.welcome import WelcomePage
50+
11 | from pages.device import DevicePage
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
12 | from pages.certificates import CertificatesPage
53+
13 | from pages.install import InstallPage
54+
|
55+
56+
E402 Module level import not at top of file
57+
--> app.py:12:1
58+
|
59+
10 | from pages.welcome import WelcomePage
60+
11 | from pages.device import DevicePage
61+
12 | from pages.certificates import CertificatesPage
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
63+
13 | from pages.install import InstallPage
64+
14 | from pages.preferences import PreferencesPage
65+
|
66+
67+
E402 Module level import not at top of file
68+
--> app.py:13:1
69+
|
70+
11 | from pages.device import DevicePage
71+
12 | from pages.certificates import CertificatesPage
72+
13 | from pages.install import InstallPage
73+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
74+
14 | from pages.preferences import PreferencesPage
75+
15 | from utils.config import ConfigManager
76+
|
77+
78+
E402 Module level import not at top of file
79+
--> app.py:14:1
80+
|
81+
12 | from pages.certificates import CertificatesPage
82+
13 | from pages.install import InstallPage
83+
14 | from pages.preferences import PreferencesPage
84+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
85+
15 | from utils.config import ConfigManager
86+
16 | from utils.logger import Logger
87+
|
88+
89+
E402 Module level import not at top of file
90+
--> app.py:15:1
91+
|
92+
13 | from pages.install import InstallPage
93+
14 | from pages.preferences import PreferencesPage
94+
15 | from utils.config import ConfigManager
95+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
96+
16 | from utils.logger import Logger
97+
17 | from utils.constants import *
98+
|
99+
100+
E402 Module level import not at top of file
101+
--> app.py:16:1
102+
|
103+
14 | from pages.preferences import PreferencesPage
104+
15 | from utils.config import ConfigManager
105+
16 | from utils.logger import Logger
106+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
107+
17 | from utils.constants import *
108+
18 | from utils.i18n import _
109+
|
110+
111+
E402 Module level import not at top of file
112+
--> app.py:17:1
113+
|
114+
15 | from utils.config import ConfigManager
115+
16 | from utils.logger import Logger
116+
17 | from utils.constants import *
117+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
118+
18 | from utils.i18n import _
119+
19 | from services.docker import DockerService
120+
|
121+
122+
F403 `from utils.constants import *` used; unable to detect undefined names
123+
--> app.py:17:1
124+
|
125+
15 | from utils.config import ConfigManager
126+
16 | from utils.logger import Logger
127+
17 | from utils.constants import *
128+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
129+
18 | from utils.i18n import _
130+
19 | from services.docker import DockerService
131+
|
132+
133+
E402 Module level import not at top of file
134+
--> app.py:18:1
135+
|
136+
16 | from utils.logger import Logger
137+
17 | from utils.constants import *
138+
18 | from utils.i18n import _
139+
| ^^^^^^^^^^^^^^^^^^^^^^^^
140+
19 | from services.docker import DockerService
141+
20 | from services.device import DeviceService
142+
|
143+
144+
E402 Module level import not at top of file
145+
--> app.py:19:1
146+
|
147+
17 | from utils.constants import *
148+
18 | from utils.i18n import _
149+
19 | from services.docker import DockerService
150+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
151+
20 | from services.device import DeviceService
152+
21 | from services.certificates import CertificateService
153+
|
154+
155+
E402 Module level import not at top of file
156+
--> app.py:20:1
157+
|
158+
18 | from utils.i18n import _
159+
19 | from services.docker import DockerService
160+
20 | from services.device import DeviceService
161+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
162+
21 | from services.certificates import CertificateService
163+
|
164+
165+
E402 Module level import not at top of file
166+
--> app.py:21:1
167+
|
168+
19 | from services.docker import DockerService
169+
20 | from services.device import DeviceService
170+
21 | from services.certificates import CertificateService
171+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
172+
22 |
173+
23 | class JellyTizenApplication(Adw.Application):
174+
|
175+
176+
F405 `APP_ID` may be undefined, or defined from star imports
177+
--> app.py:27:41
178+
|
179+
26 | def __init__(self):
180+
27 | super().__init__(application_id=APP_ID,
181+
| ^^^^^^
182+
28 | flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
183+
|
184+
185+
F405 `APP_NAME` may be undefined, or defined from star imports
186+
--> app.py:32:29
187+
|
188+
30 | self.config_manager = ConfigManager()
189+
31 | self.logger = Logger()
190+
32 | self.logger.info(f"{APP_NAME} {APP_VERSION} starting")
191+
| ^^^^^^^^
192+
33 | self.window = None
193+
|
194+
195+
F405 `APP_VERSION` may be undefined, or defined from star imports
196+
--> app.py:32:40
197+
|
198+
30 | self.config_manager = ConfigManager()
199+
31 | self.logger = Logger()
200+
32 | self.logger.info(f"{APP_NAME} {APP_VERSION} starting")
201+
| ^^^^^^^^^^^
202+
33 | self.window = None
203+
|
204+
205+
F405 `APP_NAME` may be undefined, or defined from star imports
206+
--> app.py:59:24
207+
|
208+
57 | self.logger.info("Initializing main window")
209+
58 |
210+
59 | self.set_title(APP_NAME)
211+
| ^^^^^^^^
212+
60 |
213+
61 | # Set window size from constants
214+
|
215+
216+
F405 `WINDOW_DEFAULT_WIDTH` may be undefined, or defined from star imports
217+
--> app.py:62:31
218+
|
219+
61 | # Set window size from constants
220+
62 | self.set_default_size(WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT)
221+
| ^^^^^^^^^^^^^^^^^^^^
222+
63 |
223+
64 | # Set minimum size
224+
|
225+
226+
F405 `WINDOW_DEFAULT_HEIGHT` may be undefined, or defined from star imports
227+
--> app.py:62:53
228+
|
229+
61 | # Set window size from constants
230+
62 | self.set_default_size(WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT)
231+
| ^^^^^^^^^^^^^^^^^^^^^
232+
63 |
233+
64 | # Set minimum size
234+
|
235+
236+
F405 `WINDOW_MIN_WIDTH` may be undefined, or defined from star imports
237+
--> app.py:66:31
238+
|
239+
64 | # Set minimum size
240+
65 | self.set_resizable(True)
241+
66 | self.set_size_request(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT)
242+
| ^^^^^^^^^^^^^^^^
243+
67 |
244+
68 | self._setup_ui()
245+
|
246+
247+
F405 `WINDOW_MIN_HEIGHT` may be undefined, or defined from star imports
248+
--> app.py:66:49
249+
|
250+
64 | # Set minimum size
251+
65 | self.set_resizable(True)
252+
66 | self.set_size_request(WINDOW_MIN_WIDTH, WINDOW_MIN_HEIGHT)
253+
| ^^^^^^^^^^^^^^^^^
254+
67 |
255+
68 | self._setup_ui()
256+
|
257+
258+
F405 `APP_NAME` may be undefined, or defined from star imports
259+
--> app.py:158:30
260+
|
261+
156 | """Show about dialog."""
262+
157 | about = Adw.AboutDialog(
263+
158 | application_name=APP_NAME,
264+
| ^^^^^^^^
265+
159 | application_icon="jellytizen",
266+
160 | version=APP_VERSION,
267+
|
268+

usr/share/jellytizen/.audit/techdebt_markers.txt

Whitespace-only changes.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
app.py:116: unused variable 'param' (100% confidence)
2+
app.py:150: unused variable 'action' (100% confidence)
3+
app.py:150: unused variable 'param' (100% confidence)
4+
app.py:155: unused variable 'action' (100% confidence)
5+
app.py:155: unused variable 'param' (100% confidence)
6+
pages/certificates.py:96: unused variable 'b' (100% confidence)
7+
pages/certificates.py:109: unused variable 'b' (100% confidence)
8+
pages/certificates.py:129: unused variable 'b' (100% confidence)
9+
pages/certificates.py:154: unused variable 'param' (100% confidence)
10+
pages/device.py:279: unused variable 'b' (100% confidence)
11+
pages/device.py:318: unused variable 'param' (100% confidence)
12+
pages/install.py:187: unused variable 'widget' (100% confidence)
13+
pages/preferences.py:46: unused variable 'p' (100% confidence)
14+
pages/preferences.py:109: unused variable 'p' (100% confidence)
15+
pages/preferences.py:129: unused variable 'p' (100% confidence)
16+
pages/preferences.py:150: unused variable 'param' (100% confidence)
17+
services/certificates.py:6: unused import 'serialization' (90% confidence)
18+
services/device.py:16: unused import 'DeviceNotReachableError' (90% confidence)
19+
services/device.py:16: unused import 'NetworkTimeoutError' (90% confidence)
20+
services/device.py:16: unused import 'SDBError' (90% confidence)
21+
services/docker.py:14: unused import 'AppBuildError' (90% confidence)
22+
services/docker.py:14: unused import 'AppInstallError' (90% confidence)
23+
services/docker.py:14: unused import 'DockerCommandError' (90% confidence)
24+
services/docker.py:14: unused import 'SDKInstallationError' (90% confidence)
25+
tests/services/test_device.py:150: unused variable 'mock_glib' (100% confidence)
26+
tests/services/test_device.py:162: unused variable 'mock_glib' (100% confidence)
27+
tests/services/test_docker.py:105: unused variable 'mock_glib' (100% confidence)
28+
tests/services/test_docker.py:122: unused variable 'mock_glib' (100% confidence)

0 commit comments

Comments
 (0)