Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package tail-tray for openSUSE:Factory checked in at 2026-07-31 15:30:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tail-tray (Old) and /work/SRC/openSUSE:Factory/.tail-tray.new.2004 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tail-tray" Fri Jul 31 15:30:07 2026 rev:27 rq:1368474 version:0.2.34 Changes: -------- --- /work/SRC/openSUSE:Factory/tail-tray/tail-tray.changes 2026-06-02 16:09:32.803888960 +0200 +++ /work/SRC/openSUSE:Factory/.tail-tray.new.2004/tail-tray.changes 2026-07-31 16:10:36.603322577 +0200 @@ -1,0 +2,15 @@ +Thu Jul 30 05:41:38 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.2.34: + This is a maintenance release with mostly under the hood changes + and support for RPM builds directly in GitHub per commit and for + the tagged release flows. + * Notifications - Cleanup and improve ipn event handling for + messages/warnings/errors + * Cmake - QT6 only from now on + * Cmake - Minor fixes to not trigger warnings + * Replace QSharedMemory which is attachable after termination + with QLockFile (#117) + * Fix DATAROOTDIR #116 + +------------------------------------------------------------------- Old: ---- tail-tray-0.2.33.obscpio New: ---- tail-tray-0.2.34.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tail-tray.spec ++++++ --- /var/tmp/diff_new_pack.0Tpofc/_old 2026-07-31 16:10:37.151341640 +0200 +++ /var/tmp/diff_new_pack.0Tpofc/_new 2026-07-31 16:10:37.155341780 +0200 @@ -17,7 +17,7 @@ Name: tail-tray -Version: 0.2.33 +Version: 0.2.34 Release: 0 Summary: Tailscale tray menu and UI for the KDE Plasma Desktop License: GPL-3.0-only ++++++ _service ++++++ --- /var/tmp/diff_new_pack.0Tpofc/_old 2026-07-31 16:10:37.203343450 +0200 +++ /var/tmp/diff_new_pack.0Tpofc/_new 2026-07-31 16:10:37.207343589 +0200 @@ -1,9 +1,9 @@ <services> <service name="obs_scm" mode="manual"> - <param name="url">https://github.com/SneWs/tail-tray</param> + <param name="url">https://github.com/SneWs/tail-tray.git</param> <param name="scm">git</param> - <param name="revision">refs/tags/v0.2.33</param> - <param name="match-tag">v0.2.33</param> + <param name="revision">refs/tags/v0.2.34</param> + <param name="match-tag">v0.2.34</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.0Tpofc/_old 2026-07-31 16:10:37.231344424 +0200 +++ /var/tmp/diff_new_pack.0Tpofc/_new 2026-07-31 16:10:37.235344563 +0200 @@ -1,6 +1,8 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/SneWs/tail-tray</param> - <param name="changesrevision">5089d8a02763a01668fb90c0896fbf25b9b4d16c</param></service></servicedata> + <param name="changesrevision">5089d8a02763a01668fb90c0896fbf25b9b4d16c</param></service><service name="tar_scm"> + <param name="url">https://github.com/SneWs/tail-tray.git</param> + <param name="changesrevision">15aed130bcc8f1485fccd61b63f5452e4cf1cef1</param></service></servicedata> (No newline at EOF) ++++++ tail-tray-0.2.33.obscpio -> tail-tray-0.2.34.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/.github/workflows/fedora-latest-rpm-build.yml new/tail-tray-0.2.34/.github/workflows/fedora-latest-rpm-build.yml --- old/tail-tray-0.2.33/.github/workflows/fedora-latest-rpm-build.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/tail-tray-0.2.34/.github/workflows/fedora-latest-rpm-build.yml 2026-07-29 18:56:40.000000000 +0200 @@ -0,0 +1,91 @@ +name: Build Fedora Latest - RPM + +on: + push: + branches: ["master"] + pull_request: + branches: ["**"] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set reusable strings + id: strings + shell: bash + run: | + echo "rpm-output-dir=${{ github.workspace }}/build/rpm" >> "$GITHUB_OUTPUT" + + - name: Build RPMs in Fedora latest container + shell: bash + run: | + set -euo pipefail + mkdir -p "${{ steps.strings.outputs.rpm-output-dir }}" + + docker run --rm \ + -v "${GITHUB_WORKSPACE}:/workspace" \ + -w /workspace \ + fedora:latest \ + bash -lc ' + set -euo pipefail + dnf install -y \ + cmake \ + extra-cmake-modules \ + gcc-c++ \ + git \ + kf6-knotifications-devel \ + ninja-build \ + qt6-qtbase-devel \ + qt6-qtbase-private-devel \ + qt6-qttools-devel \ + rpm-build \ + rpmdevtools \ + tar + + VERSION=$(grep -oP "project\\(tail-tray VERSION \\K[0-9.]+" CMakeLists.txt) + + # Required for containerized builds on mounted GitHub workspaces. + git config --global --add safe.directory /workspace + + rpmdev-setuptree + git archive --format=tar.gz \ + --prefix="tail-tray-${VERSION}/" \ + --output="$HOME/rpmbuild/SOURCES/tail-tray-${VERSION}.tar.gz" \ + HEAD + + cp packaging/rpm/tail-tray.spec "$HOME/rpmbuild/SPECS/" + + rpmbuild -ba "$HOME/rpmbuild/SPECS/tail-tray.spec" \ + --define "_topdir $HOME/rpmbuild" \ + --define "version ${VERSION}" + + cp -v "$HOME"/rpmbuild/RPMS/*/*.rpm /workspace/build/rpm/ + cp -v "$HOME"/rpmbuild/SRPMS/*.src.rpm /workspace/build/rpm/ + ' + + - name: Upload RPM artifact for PR builds + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: Fedora-latest.rpm + path: ${{ steps.strings.outputs.rpm-output-dir }}/* + if-no-files-found: error + overwrite: true + + - name: Upload RPM files to latest release + if: github.ref == 'refs/heads/master' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + set -euo pipefail + mv "${{ steps.strings.outputs.rpm-output-dir }}"/tail-tray-[0-9]*.x86_64.rpm "${{ steps.strings.outputs.rpm-output-dir }}/tail-tray-fedora-latest.x86_64.rpm" + gh release upload latest "${{ steps.strings.outputs.rpm-output-dir }}"/*.rpm --clobber + + + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/.github/workflows/tagged-releases.yml new/tail-tray-0.2.34/.github/workflows/tagged-releases.yml --- old/tail-tray-0.2.33/.github/workflows/tagged-releases.yml 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/.github/workflows/tagged-releases.yml 2026-07-29 18:56:40.000000000 +0200 @@ -114,10 +114,57 @@ -G "Unix Makefiles" buildpackage-opts: --build=binary --no-sign + - name: Build Fedora latest RPMs + shell: bash + run: | + set -euo pipefail + + docker run --rm \ + -v "${GITHUB_WORKSPACE}:/workspace" \ + -w /workspace \ + fedora:latest \ + bash -lc ' + set -euo pipefail + dnf install -y \ + cmake \ + extra-cmake-modules \ + gcc-c++ \ + git \ + kf6-knotifications-devel \ + ninja-build \ + qt6-qtbase-devel \ + qt6-qtbase-private-devel \ + qt6-qttools-devel \ + rpm-build \ + rpmdevtools \ + tar + + git config --global --add safe.directory /workspace + + VERSION=$(grep -oP "project\\(tail-tray VERSION \\K[0-9.]+" CMakeLists.txt) + + rpmdev-setuptree + git archive --format=tar.gz \ + --prefix="tail-tray-${VERSION}/" \ + --output="$HOME/rpmbuild/SOURCES/tail-tray-${VERSION}.tar.gz" \ + HEAD + + cp packaging/rpm/tail-tray.spec "$HOME/rpmbuild/SPECS/" + + rpmbuild -ba "$HOME/rpmbuild/SPECS/tail-tray.spec" \ + --define "_topdir $HOME/rpmbuild" \ + --define "version ${VERSION}" + + cp -v "$HOME"/rpmbuild/RPMS/*/*.rpm /workspace/build/ + cp -v "$HOME"/rpmbuild/SRPMS/*.src.rpm /workspace/build/ + ' + - uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" prerelease: false files: | ${{ steps.strings.outputs.build-output-dir }}/*.deb + ${{ steps.strings.outputs.build-output-dir }}/*.rpm + ${{ steps.strings.outputs.build-output-dir }}/*.src.rpm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/.github/workflows/ubuntu-25_10-build.yml new/tail-tray-0.2.34/.github/workflows/ubuntu-25_10-build.yml --- old/tail-tray-0.2.33/.github/workflows/ubuntu-25_10-build.yml 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/.github/workflows/ubuntu-25_10-build.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,71 +0,0 @@ -name: Build Ubuntu 25.10 - Deb - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "**" ] - -jobs: - build: - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - build_type: [Release] - - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - - name: Set reusable strings - id: strings - shell: bash - run: | - echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" - - - name: Create structure - shell: bash - run: | - mkdir -p ${{ steps.strings.outputs.build-output-dir }} - echo "Build output directory: ${{ steps.strings.outputs.build-output-dir }}" - - - name: Package DEB file for Ubuntu 25.10 - uses: jtdor/build-deb-action@v1 - env: - DEB_BUILD_OPTIONS: noautodbgsym - with: - artifacts-dir: build - docker-image: ubuntu:25.10 - extra-build-deps: devscripts git libkf6notifications-dev extra-cmake-modules qt6-tools-dev qt6-tools-dev-tools davfs2 - buildpackage-opts: --build=binary --no-sign - before-build-hook: | - apt-get install libkf6notifications-dev - git checkout debian/changelog - cmake -B ${{ steps.strings.outputs.build-output-dir }} \ - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ - -DKNOTIFICATIONS_ENABLED=ON \ - -S /github/workspace \ - -G "Unix Makefiles" - - debchange --controlmaint --local="ubuntu-25.10-plucky~git$(git rev-parse --short HEAD)" "CI build" - - - name: Upload DEB for PR builds - if: github.event_name == 'pull_request' - uses: actions/upload-artifact@v7 - with: - name: Ubuntu-25.10.deb - path: ${{ steps.strings.outputs.build-output-dir }}/*.deb - overwrite: true - archive: false - - - name: Upload DEB files - if: github.ref == 'refs/heads/master' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: | - mv ${{ steps.strings.outputs.build-output-dir }}/*ubuntu-25.10*.deb ${{ steps.strings.outputs.build-output-dir }}/tail-tray-ubuntu-25.10.deb - gh release upload latest ${{ steps.strings.outputs.build-output-dir }}/*.deb --clobber diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/.gitignore new/tail-tray-0.2.34/.gitignore --- old/tail-tray-0.2.33/.gitignore 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/.gitignore 2026-07-29 18:56:40.000000000 +0200 @@ -16,7 +16,6 @@ cmake-build-release/ .cache/ -packaging/ .flatpak-builder/ tail-tray.desktop diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/CMakeLists.txt new/tail-tray-0.2.34/CMakeLists.txt --- old/tail-tray-0.2.33/CMakeLists.txt 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/CMakeLists.txt 2026-07-29 18:56:40.000000000 +0200 @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.21) -project(tail-tray VERSION 0.2.33 LANGUAGES CXX) +project(tail-tray VERSION 0.2.34 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) @@ -10,6 +10,21 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +option(BUILD_TESTS "Build tests" ON) +option(KNOTIFICATIONS_ENABLED "Enable KNotifications" OFF) + +if (UNIX AND NOT APPLE AND KNOTIFICATIONS_ENABLED) + # Use KNotifications + message("KNotifications has been enabled! This requires Plasma 6") + + find_package(ECM REQUIRED NO_MODULE) + set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + include(KDEInstallDirs) + include(KDECMakeSettings) + + add_definitions(-DKNOTIFICATIONS_ENABLED) +endif() + include(GNUInstallDirs) # Use Davfs or not @@ -30,28 +45,12 @@ message(STATUS "Full path of translations install path: ${FULL_LIBDIR_PATH}") -find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets Network LinguistTools) -find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network LinguistTools) - -option(BUILD_TESTS "Build tests" ON) -option(KNOTIFICATIONS_ENABLED "Enable KNotifications" OFF) - -if (UNIX AND NOT APPLE) - if (KNOTIFICATIONS_ENABLED) - # Use KNotifications - message("KNotifications has been enabled! This requires Plasma 6") +find_package(OpenGL REQUIRED) +find_package(Qt6 6.2 REQUIRED COMPONENTS Widgets Network Gui LinguistTools) - find_package(ECM REQUIRED NO_MODULE) - set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) - include(KDEInstallDirs) - include(KDECMakeSettings) - - add_definitions(-DKNOTIFICATIONS_ENABLED) - find_package(KF6Notifications) - else () - message("KNotifications has not been enabled!") - endif (KNOTIFICATIONS_ENABLED) -endif (UNIX AND NOT APPLE) +if (UNIX AND NOT APPLE AND KNOTIFICATIONS_ENABLED) + find_package(KF6Notifications REQUIRED) +endif() set(PROJECT_SOURCES src/main.cpp @@ -152,18 +151,13 @@ endif () -qt_add_translations(tail-tray TS_FILES - translations/tail_tray_en_US.ts - translations/tail_tray_sv_SE.ts - translations/tail_tray_de_DE.ts - translations/tail_tray_fr_FR.ts -) qt_standard_project_setup(I18N_TRANSLATED_LANGUAGES en_US sv_SE de_DE fr_FR) target_link_libraries( tail-tray PRIVATE - Qt${QT_VERSION_MAJOR}::Widgets - Qt${QT_VERSION_MAJOR}::Network + Qt6::Widgets + Qt6::Network + Qt6::Gui ) configure_file(src/Paths.h.in ${CMAKE_SOURCE_DIR}/src/Paths.h @ONLY) @@ -217,4 +211,4 @@ if (BUILD_TESTS) # Add the tests subdirectory so it is built with the main project add_subdirectory(tests) -endif () +endif () \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/debian/changelog new/tail-tray-0.2.34/debian/changelog --- old/tail-tray-0.2.33/debian/changelog 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/debian/changelog 2026-07-29 18:56:40.000000000 +0200 @@ -1,4 +1,4 @@ -tail-tray (0.2.33) UNRELEASED; urgency=medium +tail-tray (0.2.34) UNRELEASED; urgency=medium * New upstream release. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/packaging/rpm/tail-tray.spec new/tail-tray-0.2.34/packaging/rpm/tail-tray.spec --- old/tail-tray-0.2.33/packaging/rpm/tail-tray.spec 1970-01-01 01:00:00.000000000 +0100 +++ new/tail-tray-0.2.34/packaging/rpm/tail-tray.spec 2026-07-29 18:56:40.000000000 +0200 @@ -0,0 +1,52 @@ +%global app_version %{?version}%{!?version:0.2.34} + +Name: tail-tray +Version: %{app_version} +Release: 1%{?dist} +Summary: Tailscale tray application for Linux desktops + +License: GPL-3.0-or-later +URL: https://github.com/SneWs/tail-tray +Source0: %{name}-%{version}.tar.gz + +BuildRequires: cmake +BuildRequires: gcc-c++ +BuildRequires: ninja-build +BuildRequires: qt6-qtbase-devel +BuildRequires: qt6-qtbase-private-devel +BuildRequires: qt6-qttools-devel +BuildRequires: extra-cmake-modules +BuildRequires: kf6-knotifications-devel + +Requires: tailscale +Recommends: davfs2 + +%description +Tail Tray provides a system tray application and UI for Tailscale on Linux. + +%prep +%autosetup -n %{name}-%{version} + +%build +%cmake -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DKNOTIFICATIONS_ENABLED=ON \ + -DBUILD_TESTS=OFF +%cmake_build + +%install +%cmake_install + +%files +%license LICENSE +%{_bindir}/tail-tray +%{_datadir}/applications/tail-tray.desktop +%{_datadir}/knotifications5/tail-tray.notifyrc +%{_datadir}/icons/hicolor/scalable/apps/tail-tray-dark.svg +%{_datadir}/icons/hicolor/scalable/apps/tail-tray.svg + +%changelog +* Wed Jul 29 2026 Marcus Grenangen <[email protected]> - %{version}-1 +- Add Fedora RPM spec for GitHub CI builds + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/src/IpnWatcher.cpp new/tail-tray-0.2.34/src/IpnWatcher.cpp --- old/tail-tray-0.2.33/src/IpnWatcher.cpp 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/src/IpnWatcher.cpp 2026-07-29 18:56:40.000000000 +0200 @@ -74,10 +74,24 @@ IpnEventData eventData = IpnEventData::parse(obj); if (!eventData.Health.Warnings.networkStatus.Severity.isEmpty()) { - qDebug() << "Nw" << (eventData.Health.Warnings.networkStatus.ImpactsConnectivity ? "Connectivity Disruption" : "Connection OK"); - qDebug() << "Severity: " << eventData.Health.Warnings.networkStatus.Severity; - qDebug() << "Text: " << eventData.Health.Warnings.networkStatus.Text; - qDebug() << "Title: " << eventData.Health.Warnings.networkStatus.Title; + qDebug() << "IPN Health [network-status]" + << (eventData.Health.Warnings.networkStatus.ImpactsConnectivity + ? "- CONNECTIVITY IMPACTED" + : "- ok"); + qDebug() << " Severity:" << eventData.Health.Warnings.networkStatus.Severity + << " (high=error, medium/low=warning, info=info)"; + qDebug() << " Title:" << eventData.Health.Warnings.networkStatus.Title; + qDebug() << " Text: " << eventData.Health.Warnings.networkStatus.Text; + } + + // Log any additional warning codes present in this event + for (const auto& key : eventData.Health.Warnings.allWarnings.keys()) { + if (key == "network-status") + continue; // already logged above + const auto& w = eventData.Health.Warnings.allWarnings[key]; + qDebug() << "IPN Health [" << key << "] severity=" << w.Severity + << "impactsConnectivity=" << w.ImpactsConnectivity + << "title=" << w.Title; } emit eventReceived(eventData); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/src/MainWindow.cpp new/tail-tray-0.2.34/src/MainWindow.cpp --- old/tail-tray-0.2.33/src/MainWindow.cpp 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/src/MainWindow.cpp 2026-07-29 18:56:40.000000000 +0200 @@ -449,25 +449,55 @@ } void MainWindow::onIpnEvent(const IpnEventData& eventData) { - if (eventData.Health.Warnings.networkStatus.ImpactsConnectivity) { - if (eventData.Health.Warnings.networkStatus.WarnableCode == - "network-status") { - if (eCurrentState != TailState::Connected) { - if (!eventData.Health.Warnings.networkStatus.Text.isEmpty()) { - showWarningMessage(eventData.Health.Warnings.networkStatus.Title, - eventData.Health.Warnings.networkStatus.Text); - } - } + // Any non-empty ErrMessage from the IPN stream is always an error. + if (!eventData.ErrMessage.isEmpty()) { + showErrorMessage(tr("Tailscale Error"), eventData.ErrMessage); + } + + // Map well-known IPN states to an appropriate notification + if (!eventData.State.isEmpty()) { + if (eventData.State == "Starting") { + pNotificationsManager->showLevelNotification( + NotificationLevel::Info, + tr("Tailscale"), tr("Tailscale is starting…")); + } else if (eventData.State == "Stopped") { + pNotificationsManager->showLevelNotification( + NotificationLevel::Info, + tr("Tailscale"), tr("Tailscale has stopped.")); + } else if (eventData.State == "NeedsLogin") { + pNotificationsManager->showLevelNotification( + NotificationLevel::Warning, + tr("Tailscale"), tr("Tailscale needs you to log in.")); + } else if (eventData.State == "NeedsMachineAuth") { + pNotificationsManager->showLevelNotification( + NotificationLevel::Warning, + tr("Tailscale"), tr("This machine is waiting for authorization.")); } - } else { - if (eventData.Health.Warnings.networkStatus.Severity == "warning") { - if (!eventData.Health.Warnings.networkStatus.Text.isEmpty()) - showWarningMessage(eventData.Health.Warnings.networkStatus.Title, - eventData.Health.Warnings.networkStatus.Text); - } else if (eventData.Health.Warnings.networkStatus.Severity == "error") { - if (!eventData.Health.Warnings.networkStatus.Text.isEmpty()) - showErrorMessage(eventData.Health.Warnings.networkStatus.Title, - eventData.Health.Warnings.networkStatus.Text); + } + + for (const auto& warning : eventData.Health.Warnings.allWarnings) { + if (warning.Text.isEmpty()) + continue; + + auto level = NotificationLevel::Info; + if (warning.ImpactsConnectivity) { + // Connectivity-breaking → highest urgency, regardless of Severity string + level = NotificationLevel::Critical; + } else if (warning.Severity == "high") { + level = NotificationLevel::Error; + } else if (warning.Severity == "medium" || warning.Severity == "low") { + level = NotificationLevel::Warning; + } else if (warning.Severity == "info") { + level = NotificationLevel::Info; + } + + // Use de-dup helper for warning/error/critical to avoid spam + if (level == NotificationLevel::Critical || level == NotificationLevel::Error) { + showErrorMessage(warning.Title, warning.Text); + } else if (level == NotificationLevel::Warning) { + showWarningMessage(warning.Title, warning.Text); + } else { + pNotificationsManager->showLevelNotification(level, warning.Title, warning.Text); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/src/NotificationsManager.cpp new/tail-tray-0.2.34/src/NotificationsManager.cpp --- old/tail-tray-0.2.33/src/NotificationsManager.cpp 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/src/NotificationsManager.cpp 2026-07-29 18:56:40.000000000 +0200 @@ -15,13 +15,8 @@ notification->setTitle(title); notification->setText(message); - notification->setUrgency(KNotification::Urgency::DefaultUrgency); - if (!iconName.isEmpty()) { - notification->setIconName(iconName); - } - else { - notification->setIconName("notification-active"); - } + notification->setUrgency(KNotification::Urgency::LowUrgency); + notification->setIconName(iconName.isEmpty() ? QStringLiteral("notification-active") : iconName); notification->sendEvent(); #else @@ -63,17 +58,12 @@ notification->setTitle(title); notification->setText(message); - notification->setUrgency(KNotification::Urgency::DefaultUrgency); - if (!iconName.isEmpty()) { - notification->setIconName(iconName); - } - else { - notification->setIconName("dialog-warning"); - } + notification->setUrgency(KNotification::Urgency::NormalUrgency); + notification->setIconName(iconName.isEmpty() ? QStringLiteral("dialog-warning") : iconName); notification->sendEvent(); #else - m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Warning, 5000); + m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Warning, 7000); #endif } @@ -83,17 +73,28 @@ notification->setTitle(title); notification->setText(message); - notification->setUrgency(KNotification::Urgency::DefaultUrgency); - if (!iconName.isEmpty()) { - notification->setIconName(iconName); - } - else { - notification->setIconName("dialog-error"); - } + notification->setUrgency(KNotification::Urgency::HighUrgency); + notification->setIconName(iconName.isEmpty() ? QStringLiteral("dialog-error") : iconName); + + notification->sendEvent(); +#else + m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Critical, 8000); +#endif +} + +void NotificationsManager::showCriticalNotification(const QString& title, const QString& message, const QString& iconName) { +#if defined(KNOTIFICATIONS_ENABLED) + // Persistent + CriticalUrgency: stays on screen until dismissed + auto* notification = new KNotification("BasicNotification", KNotification::NotificationFlag::Persistent, this); + notification->setTitle(title); + notification->setText(message); + + notification->setUrgency(KNotification::Urgency::CriticalUrgency); + notification->setIconName(iconName.isEmpty() ? QStringLiteral("dialog-error") : iconName); notification->sendEvent(); #else - m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Critical, 5000); + m_pTrayMgr->trayIcon()->showMessage(title, message, QSystemTrayIcon::Critical, 0 /* no timeout */); #endif } @@ -129,4 +130,23 @@ tr("A device have been removed from your tailnet!\n\nDevice: %1 (%2) - %3") .arg(nodeName, ipAddress, os), QSystemTrayIcon::Information, 8000); #endif -} \ No newline at end of file +} + +void NotificationsManager::showLevelNotification(NotificationLevel level, + const QString& title, const QString& message) +{ + switch (level) { + case NotificationLevel::Info: + showNotification(title, message); + break; + case NotificationLevel::Warning: + showWarningNotification(title, message); + break; + case NotificationLevel::Error: + showErrorNotification(title, message); + break; + case NotificationLevel::Critical: + showCriticalNotification(title, message); + break; + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/src/NotificationsManager.h new/tail-tray-0.2.34/src/NotificationsManager.h --- old/tail-tray-0.2.33/src/NotificationsManager.h 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/src/NotificationsManager.h 2026-07-29 18:56:40.000000000 +0200 @@ -9,6 +9,13 @@ #include "TrayMenuManager.h" +enum class NotificationLevel { + Info, + Warning, + Error, + Critical, +}; + class NotificationsManager : public QObject { Q_OBJECT @@ -16,16 +23,21 @@ explicit NotificationsManager(TrayMenuManager const* pTrayMgr, QObject* parent = nullptr); ~NotificationsManager() override; + // --- typed helpers (preferred call sites) --- void showNotification(const QString &title, const QString& message, const QString& iconName = QString()); void showFileNotification(const QString& title, const QString& message, const QFileInfo& fileInfo, const QString& iconName = QString()); void showWarningNotification(const QString& title, const QString& message, const QString& iconName = QString("dialog-warning")); void showErrorNotification(const QString& title, const QString& message, const QString& iconName = QString("dialog-error")); + void showCriticalNotification(const QString& title, const QString& message, const QString& iconName = QString("dialog-error")); void showNodeConnectedNotification(const QString& nodeName, const QString& ipAddress, const QString& os); void showNodeDisconnectedNotification(const QString& nodeName, const QString& ipAddress, const QString& os); + // --- generic entry-point driven by a NotificationLevel flag --- + void showLevelNotification(NotificationLevel level, const QString& title, const QString& message); + private: TrayMenuManager const* m_pTrayMgr; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/src/Version.h new/tail-tray-0.2.34/src/Version.h --- old/tail-tray-0.2.33/src/Version.h 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/src/Version.h 2026-07-29 18:56:40.000000000 +0200 @@ -1,6 +1,6 @@ #pragma once -#define TAIL_TRAY_VERSION "0.2.33" +#define TAIL_TRAY_VERSION "0.2.34" #define TAIL_TRAY_VERSION_MAJOR 0 #define TAIL_TRAY_VERSION_MINOR 2 -#define TAIL_TRAY_VERSION_PATCH 33 +#define TAIL_TRAY_VERSION_PATCH 34 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tail-tray-0.2.33/src/models/IpnEvents.h new/tail-tray-0.2.34/src/models/IpnEvents.h --- old/tail-tray-0.2.33/src/models/IpnEvents.h 2026-06-01 20:32:32.000000000 +0200 +++ new/tail-tray-0.2.34/src/models/IpnEvents.h 2026-07-29 18:56:40.000000000 +0200 @@ -46,15 +46,26 @@ }; struct IpnHealthWarningsModel { + /* + * The well-known "network-status" warning, kept as a named field for + * backwards compatibility. All other warning codes are available via + * the generic `allWarnings` map. + */ IpnHealthWarningsNetworkStatusModel networkStatus{}; + // All health warnings keyed by their WarnableCode string + QMap<QString, IpnHealthWarningsNetworkStatusModel> allWarnings{}; + static IpnHealthWarningsModel parse(const QJsonObject& json) { IpnHealthWarningsModel model; - if (json.contains("network-status") && !json["network-status"].isNull()) { - model.networkStatus = IpnHealthWarningsNetworkStatusModel::parse(json["network-status"].toObject()); - } - else { - model.networkStatus = IpnHealthWarningsNetworkStatusModel{}; + for (const auto& key : json.keys()) { + if (json[key].isNull() || !json[key].isObject()) + continue; + auto warning = IpnHealthWarningsNetworkStatusModel::parse(json[key].toObject()); + model.allWarnings.insert(key, warning); + if (key == "network-status") { + model.networkStatus = warning; + } } return model; } ++++++ tail-tray.obsinfo ++++++ --- /var/tmp/diff_new_pack.0Tpofc/_old 2026-07-31 16:10:37.699360704 +0200 +++ /var/tmp/diff_new_pack.0Tpofc/_new 2026-07-31 16:10:37.707360983 +0200 @@ -1,5 +1,5 @@ name: tail-tray -version: 0.2.33 -mtime: 1780338752 -commit: 5089d8a02763a01668fb90c0896fbf25b9b4d16c +version: 0.2.34 +mtime: 1785344200 +commit: 15aed130bcc8f1485fccd61b63f5452e4cf1cef1
