Skip to content

Commit b02d591

Browse files
committed
more CI fixes
1 parent 67ce854 commit b02d591

25 files changed

+189
-193
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ jobs:
1515
fail-fast: true
1616
max-parallel: 1
1717
matrix:
18-
os: [windows-latest]
1918
python-version: ["3.13", "3.14"]
2019

2120
steps:
@@ -51,10 +50,7 @@ jobs:
5150
- name: Install Core (No GUI)
5251
run: |
5352
python -m pip install --upgrade pip
54-
pip install .
55-
# pip install pytest <-- Included in .[test] or separate step if needed, but here we installed core only.
56-
# Assuming we need pytest for testing:
57-
pip install pytest
53+
pip install .[test]
5854
5955
- name: Run CLI Dynamic Tests
6056
run: |

src/switchcraft/assets/lang/de.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@
558558
"deploying_apps": "Bereitstellen",
559559
"deploy_stack_note": "Hinweis: Diese Funktion erfordert konfigurierte Intune-Integration.",
560560
"btn_deploy": "Bereitstellen",
561-
"deploy_stack_started": "Bereitstellung gestartet! Prüfen Sie Intune für den Fortschritt.",
561+
"deploy_stack_started": "Bereitstellung gestartet! Prüfe Intune auf den Fortschritt.",
562562
"stacks_saved": "Stacks gespeichert!",
563563
"save_failed": "Speichern fehlgeschlagen",
564564
"script_management_title": "Script Management Center",
@@ -621,7 +621,7 @@
621621
"wingetcreate_info": "Manifeste werden im SwitchCraft-Datenverzeichnis gespeichert",
622622
"create_new_manifest": "Neues Winget-Manifest erstellen",
623623
"update_existing_manifest": "Bestehendes Winget-Paket aktualisieren",
624-
"update_manifest_desc": "Aktualisieren Sie ein bestehendes Paket im winget-pkgs Repository mit einer neuen Version.",
624+
"update_manifest_desc": "Aktualisiere ein bestehendes Paket im winget-pkgs Repository mit einer neuen Version.",
625625
"installer_urls": "Installer-URLs",
626626
"new_installer_urls": "Neue Installer-URL(s)",
627627
"package_id": "Paket-ID",
@@ -808,7 +808,7 @@
808808
"notif_test_sent": "Test-Benachrichtigung gesendet!",
809809
"ai_addon_required_title": "AI-Addon Erforderlich",
810810
"entra_group_manager_title": "Entra Gruppenmanager",
811-
"entra_group_manager_desc": "Verwalten Sie Ihre Microsoft Entra ID (Azure AD) Gruppen.",
811+
"entra_group_manager_desc": "Verwalte deine Microsoft Entra ID (Azure AD) Gruppen.",
812812
"col_name": "Name",
813813
"col_description": "Beschreibung",
814814
"col_id": "ID",
@@ -833,5 +833,6 @@
833833
"no_members": "Keine Mitglieder gefunden.",
834834
"no_users_found": "Keine Benutzer gefunden.",
835835
"error_loading_members": "Fehler beim Laden der Mitglieder: {error}",
836-
"error_search_failed": "Suche fehlgeschlagen: {error}"
836+
"error_search_failed": "Suche fehlgeschlagen: {error}",
837+
"store_deploy_soon": "Deployment-Logik kommt bald in die Store-Ansicht!"
837838
}

src/switchcraft/assets/lang/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,5 +833,6 @@
833833
"no_members": "No members found.",
834834
"no_users_found": "No users found.",
835835
"error_loading_members": "Error loading members: {error}",
836-
"error_search_failed": "Search failed: {error}"
836+
"error_search_failed": "Search failed: {error}",
837+
"store_deploy_soon": "Deployment logic coming soon to Store view!"
837838
}

src/switchcraft/gui_modern/app.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,9 @@ def setup_page(self):
290290
import sys
291291
if "--wizard" in sys.argv:
292292
# We need to defer this until UI is built
293-
self._pending_nav_index = 2 # Wizard index
293+
self._pending_nav_index = NavIndex.PACKAGING_WIZARD
294294
elif "--analyzer" in sys.argv or "--all-in-one" in sys.argv:
295-
self._pending_nav_index = 3 # Analyzer index
295+
self._pending_nav_index = NavIndex.ANALYZER
296296
else:
297297
self._pending_nav_index = None
298298

@@ -1059,8 +1059,8 @@ def _f():
10591059
fade_container.opacity = 1
10601060
try:
10611061
fade_container.update()
1062-
except RuntimeError:
1063-
pass
1062+
except RuntimeError as re:
1063+
logger.debug(f"Fade container update failed: {re}")
10641064

10651065
def _on_notification_update(self):
10661066
"""Update notification icon based on unread count and trigger Windows toast."""
@@ -1082,8 +1082,8 @@ def _on_notification_update(self):
10821082
self.notif_btn.tooltip = "Notifications"
10831083
try:
10841084
self.notif_btn.update()
1085-
except RuntimeError:
1086-
pass
1085+
except RuntimeError as re:
1086+
logger.debug(f"Notification update failed (control likely detached): {re}")
10871087

10881088
# 2. Windows Toast Logic
10891089
if notifs and WINOTIFY_AVAILABLE:

src/switchcraft/gui_modern/utils/flet_compat.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ def create_tabs(tabs, **kwargs):
1212
Falls back to ft.Tabs(content=ft.TabBar(tabs=...), length=...) if needed.
1313
"""
1414
try:
15-
# Standard Flet
16-
return ft.Tabs(tabs=tabs, **kwargs)
15+
# Try with length (required by some versions/environments)
16+
try:
17+
return ft.Tabs(tabs=tabs, length=len(tabs) if tabs else 0, **kwargs)
18+
except TypeError:
19+
return ft.Tabs(tabs=tabs, **kwargs)
1720
except TypeError as te:
1821
# Fallback for environments where Tabs requires content/length (e.g. tests)
1922
logger.debug(f"Standard Tabs failed (likely compat mode needed): {te}")
@@ -46,12 +49,29 @@ def create_tabs(tabs, **kwargs):
4649
# If that failed above (TypeError), it implies signature mismatch.
4750

4851
# Re-try assuming it's the `content` argument issue or similar.
49-
# If we really need a fallback:
50-
52+
# Fallback: manually construct TabBar and use positional Tabs
53+
# Flet versions around 0.7.x/0.8.x might require this structure.
54+
tab_bar = ft.TabBar(tabs=tabs)
5155
length = len(tabs) if tabs else 0
52-
return ft.Tabs(content=ft.TabBar(tabs=tabs), length=length, **kwargs)
56+
57+
try:
58+
# Attempt positional Tabs wrapper - this supports on_change and selected_index
59+
return ft.Tabs(tab_bar, length, **kwargs)
60+
except (TypeError, ValueError):
61+
# Second Fallback: Column with TabBar and TabBarView
62+
# Note: Column does NOT support on_change, so this is a last resort.
63+
return ft.Column(
64+
controls=[
65+
tab_bar,
66+
ft.Container(
67+
content=ft.TabBarView(controls=tab_contents),
68+
expand=True
69+
)
70+
],
71+
**kwargs
72+
)
5373
else:
54-
# No TabBar, maybe properties assignment?
74+
# No TabBar available, try property assignment as last resort
5575
t = ft.Tabs(**kwargs)
5676
if tabs is not None:
5777
t.tabs = tabs
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import flet as ft
2+
import logging
3+
4+
logger = logging.getLogger(__name__)
5+
6+
class ViewMixin:
7+
"""Mixin for common view functionality."""
8+
9+
def _show_snack(self, msg, color="GREEN"):
10+
"""Show a snackbar message on the page."""
11+
try:
12+
# Check if self has app_page or page
13+
page = getattr(self, "app_page", getattr(self, "page", None))
14+
if not page:
15+
logger.debug("Cannot show snackbar: No page reference found")
16+
return
17+
18+
page.snack_bar = ft.SnackBar(ft.Text(msg), bgcolor=color)
19+
page.snack_bar.open = True
20+
page.update()
21+
except Exception as e:
22+
logger.debug(f"Failed to show snackbar: {e}")

src/switchcraft/gui_modern/views/addon_manager_view.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
from switchcraft.services.addon_service import AddonService
66
from switchcraft.gui_modern.utils.file_picker_helper import FilePickerHelper
7+
from switchcraft.gui_modern.utils.view_utils import ViewMixin
78

89
logger = logging.getLogger(__name__)
910

10-
class AddonManagerView(ft.Column):
11+
class AddonManagerView(ft.Column, ViewMixin):
1112
def __init__(self, page: ft.Page):
1213
super().__init__(expand=True)
1314
self.app_page = page
@@ -158,11 +159,3 @@ def _bg():
158159
self.app_page.dialog = dlg
159160
dlg.open = True
160161
self.app_page.update()
161-
162-
def _show_snack(self, msg, color="GREEN"):
163-
try:
164-
self.app_page.snack_bar = ft.SnackBar(ft.Text(msg), bgcolor=color)
165-
self.app_page.snack_bar.open = True
166-
self.app_page.update()
167-
except Exception:
168-
pass

src/switchcraft/gui_modern/views/analyzer_view.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from switchcraft.services.addon_service import AddonService
1919
from switchcraft.gui_modern.utils.file_picker_helper import FilePickerHelper
2020
from switchcraft.gui_modern.utils.flet_compat import create_tabs
21+
from switchcraft.gui_modern.utils.view_utils import ViewMixin
2122

2223
# Try to import flet_dropzone for native file DnD
2324
try:
@@ -29,7 +30,7 @@
2930

3031
logger = logging.getLogger(__name__)
3132

32-
class ModernAnalyzerView(ft.Column):
33+
class ModernAnalyzerView(ft.Column, ViewMixin):
3334
def __init__(self, page: ft.Page):
3435
super().__init__(expand=True)
3536
self.app_page = page
@@ -224,7 +225,7 @@ def _start_url_download(self, e):
224225
return
225226

226227
# Validate URL
227-
# Validate URL
228+
228229
if not url.startswith(("http://", "https://")):
229230
self._show_snack(i18n.get("invalid_url_format") or "Invalid URL format", "RED")
230231
return
@@ -240,8 +241,12 @@ def _bg():
240241
analysis_started = False
241242
try:
242243
# Get filename from URL
243-
filename = url.split("/")[-1].split("?")[0]
244-
if not filename.lower().endswith((".exe", ".msi")):
244+
raw_filename = url.split("/")[-1].split("?")[0]
245+
# Sanitize filename (basic)
246+
keep_chars = ("-", "_", ".")
247+
filename = "".join(c for c in raw_filename if c.isalnum() or c in keep_chars).strip()
248+
249+
if not filename or not filename.lower().endswith((".exe", ".msi")):
245250
filename = "installer.exe"
246251

247252
# Create temp directory
@@ -1047,13 +1052,7 @@ def _copy_to_clipboard(self, text: str):
10471052
except Exception:
10481053
self._show_snack("Failed to copy", "RED")
10491054

1050-
def _show_snack(self, msg, color="GREEN"):
1051-
try:
1052-
self.app_page.snack_bar = ft.SnackBar(ft.Text(msg), bgcolor=color)
1053-
self.app_page.snack_bar.open = True
1054-
self.app_page.update()
1055-
except Exception as e:
1056-
logger.debug(f"Failed to show snackbar: {e}")
1055+
10571056

10581057
def _add_history_entry(self, info, status):
10591058
try:

src/switchcraft/gui_modern/views/group_manager_view.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import requests
77
from switchcraft.services.intune_service import IntuneService
88
from switchcraft.utils.config import SwitchCraftConfig
9+
from switchcraft.gui_modern.utils.view_utils import ViewMixin
910

1011
logger = logging.getLogger(__name__)
1112

12-
class GroupManagerView(ft.Column):
13+
class GroupManagerView(ft.Column, ViewMixin):
1314
def __init__(self, page: ft.Page):
1415
super().__init__(expand=True)
1516
self.app_page = page
@@ -99,7 +100,7 @@ def _init_ui(self):
99100
ft.DataColumn(ft.Text(i18n.get("col_type") or "Type")),
100101
],
101102
rows=[],
102-
border=ft.border.all(1, "GREY_400"),
103+
border=ft.Border.all(1, "GREY_400"),
103104
vertical_lines=ft.border.BorderSide(1, "GREY_400"),
104105
horizontal_lines=ft.border.BorderSide(1, "GREY_400"),
105106
heading_row_color="BLACK12",
@@ -287,13 +288,7 @@ def _bg():
287288
self.app_page.open(dlg)
288289
self.app_page.update()
289290

290-
def _show_snack(self, msg, color="GREEN"):
291-
try:
292-
self.app_page.snack_bar = ft.SnackBar(ft.Text(msg), bgcolor=color)
293-
self.app_page.snack_bar.open = True
294-
self.app_page.update()
295-
except Exception:
296-
pass
291+
297292

298293
def _has_credentials(self):
299294
"""Check if Graph API credentials are configured."""
@@ -387,7 +382,7 @@ def show_add_dialog(e):
387382

388383
def search_users(e):
389384
query = search_box.value
390-
if not query: return
385+
if not query or not query.strip(): return
391386

392387
results_list.controls.clear()
393388
results_list.controls.append(ft.ProgressBar())

src/switchcraft/gui_modern/views/intune_store_view.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
from switchcraft.utils.config import SwitchCraftConfig
66
from switchcraft.utils.i18n import i18n
77
from switchcraft.gui_modern.nav_constants import NavIndex
8+
from switchcraft.gui_modern.utils.view_utils import ViewMixin
89

910
logger = logging.getLogger(__name__)
1011

11-
class ModernIntuneStoreView(ft.Column):
12+
class ModernIntuneStoreView(ft.Column, ViewMixin):
1213
def __init__(self, page: ft.Page):
1314
super().__init__(expand=True)
1415
self.app_page = page
@@ -196,17 +197,9 @@ def _show_details(self, app):
196197
icon=ft.Icons.CLOUD_UPLOAD,
197198
bgcolor="BLUE",
198199
color="WHITE",
199-
on_click=lambda _: self._show_snack("Deployment logic coming soon to Store view!", "BLUE")
200+
on_click=lambda _: self._show_snack(i18n.get("store_deploy_soon") or "Deployment logic coming soon to Store view!", "BLUE")
200201
)
201202
])
202203
)
203204

204205
self.update()
205-
206-
def _show_snack(self, msg, color="GREEN"):
207-
try:
208-
self.app_page.snack_bar = ft.SnackBar(ft.Text(msg), bgcolor=color)
209-
self.app_page.snack_bar.open = True
210-
self.app_page.update()
211-
except Exception as e:
212-
logger.debug(f"Failed to show snackbar: {e}")

0 commit comments

Comments
 (0)