diff --git a/selective-vpn-gui/traffic_mode_dialog.py b/selective-vpn-gui/traffic_mode_dialog.py index 7d72616..619c8a0 100644 --- a/selective-vpn-gui/traffic_mode_dialog.py +++ b/selective-vpn-gui/traffic_mode_dialog.py @@ -1236,6 +1236,27 @@ RU: Применяет policy-rules и проверяет health. При оши profs = list(self.ctrl.traffic_app_profiles_list() or []) self.lst_app_profiles.clear() + # Best-effort runtime context for UI flags (MARK/RUN). + try: + mark_items = list(self.ctrl.traffic_appmarks_items() or []) + except Exception: + mark_items = [] + marks_by_key: dict[tuple[str, str], list] = {} + unit_active: dict[str, bool] = {} + for it in mark_items: + tgt = (getattr(it, "target", "") or "").strip().lower() + key = (getattr(it, "app_key", "") or "").strip() + if tgt not in ("vpn", "direct") or not key: + continue + marks_by_key.setdefault((tgt, key), []).append(it) + unit = (getattr(it, "unit", "") or "").strip() + if unit and unit not in unit_active: + code, out = self._systemctl_user(["is-active", unit]) + unit_active[unit] = bool(code == 0 and (out or "").strip().lower() == "active") + + shortcuts = 0 + with_marks = 0 + running = 0 for p in profs: # p is a UI-friendly dataclass from ApiClient. name = (getattr(p, "name", "") or "").strip() @@ -1248,9 +1269,39 @@ RU: Применяет policy-rules и проверяет health. При оши label = name or pid or "(unnamed)" if target in ("vpn", "direct"): label += f" [{target}]" - it = QListWidgetItem(label) + + flags: list[str] = [] sc_path = self._profile_shortcut_path(pid) - sc_state = "yes" if (sc_path and os.path.isfile(sc_path)) else "no" + has_shortcut = bool(sc_path and os.path.isfile(sc_path)) + if has_shortcut: + flags.append("SC") + shortcuts += 1 + + mkey = (target, app_key) + items = marks_by_key.get(mkey) or [] + if items: + flags.append("MARK") + with_marks += 1 + + run_units: list[str] = [] + for it in items: + unit = (getattr(it, "unit", "") or "").strip() + if not unit: + continue + if unit_active.get(unit, False): + run_units.append(unit) + if run_units: + flags.append("RUN") + running += 1 + + if flags: + label += " [" + ",".join(flags) + "]" + + it = QListWidgetItem(label) + sc_state = "yes" if has_shortcut else "no" + unit_txt = ", ".join(run_units[:3]) + if len(run_units) > 3: + unit_txt += f", +{len(run_units) - 3}" it.setToolTip( ( f"id: {pid}\n" @@ -1259,13 +1310,18 @@ RU: Применяет policy-rules и проверяет health. При оши f"ttl: {ttl_sec}s\n\n" f"shortcut: {sc_state}\n" f"shortcut_path: {sc_path}\n\n" + f"runtime_marks: {len(items)}\n" + f"running_units: {len(run_units)}\n" + f"units: {unit_txt or '-'}\n\n" f"{cmd}" ).strip() ) it.setData(QtCore.Qt.UserRole, p) self.lst_app_profiles.addItem(it) - self.lbl_app_profiles.setText(f"Saved profiles: {len(profs)}") + self.lbl_app_profiles.setText( + f"Saved profiles: {len(profs)} (shortcut={shortcuts}, mark={with_marks}, run={running})" + ) self._update_profile_shortcut_ui() if quiet: