Skip to content

feat: connection-aware toolbar with state display and token refresh#2

Open
jeremi wants to merge 2 commits intomainfrom
feat/toolbar-ux-cleanup
Open

feat: connection-aware toolbar with state display and token refresh#2
jeremi wants to merge 2 commits intomainfrom
feat/toolbar-ux-cleanup

Conversation

@jeremi
Copy link
Member

@jeremi jeremi commented Mar 5, 2026

Summary

  • Replace the plain Connect button with a QToolButton with dropdown menu (DB Manager-style pattern): click opens connection dialog, dropdown shows server URL / Change / Disconnect
  • Disable action buttons (Stats, Proximity, Geofence, Export) when not connected; enable on connect
  • Show connection state in the toolbar: server hostname when connected, "Connect to OpenSPP" when not
  • Add disconnect flow (session-only, saved credentials persist for next QGIS launch)
  • OAPIF token refresh timer: keeps the Browser panel's APIHeader auth config alive so it doesn't silently break when the JWT expires
  • Extract shared update_oapif_auth_token() into auth.py (used by both connection dialog and refresh timer)
  • Rename menu "Settings" to "Connection Settings..." for clarity
  • Add token_expires_in property to OpenSppClient for accurate timer scheduling

Closes #1

Files changed

File Changes
openspp_plugin.py QToolButton, dropdown menu, _set_actions_enabled(), _update_connection_state(), _disconnect(), token refresh timer, cleanup in unload()
auth.py Extracted shared APIHeader auth config create/update logic
connection_dialog.py Delegates to auth.py instead of inline auth config logic
client.py token_expires_in property
test_plugin_ux.py 25 tests for all new functionality
test_connection_settings.py Updated to test extracted auth.py
test_batch_query.py Fixed pre-existing test failures (wrong client constructor args)

Test plan

  • All unit tests pass (python -m pytest tests/ -v)
  • Manual verification in QGIS: connect, disconnect, reconnect, button text updates
  • Verified QToolButton.MenuButtonPopup is the correct enum (not MenuButtonClick)
  • Verify token refresh keeps Browser panel working after token expiry (long-running test)

jeremi added 2 commits March 5, 2026 16:46
Replace the plain Connect QAction with a QToolButton dropdown that shows
connection state (server hostname when connected, "Connect to OpenSPP"
when disconnected). Action buttons (Stats, Proximity, Geofence, Export)
are now disabled when not connected.

Key changes:
- QToolButton with MenuButtonClick dropdown (connect/disconnect/change)
- _set_actions_enabled() grays out data actions when disconnected
- _update_connection_state() central method for all UI state updates
- _disconnect() clears session without deleting saved credentials
- OAPIF token refresh timer keeps Browser panel authenticated
- Extracted APIHeader auth logic into shared openspp_qgis/auth.py
- Added token_expires_in property to OpenSppClient
- Renamed "Settings" to "Connection Settings..." (menu-only)
- Fixed pre-existing test failures in test_batch_query.py
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience and stability of the OpenSPP QGIS plugin by revamping its connection management. It introduces a more intuitive toolbar for connecting and disconnecting, provides clear visual feedback on the connection status, and ensures continuous authentication for OAPIF services by automatically refreshing access tokens. These changes streamline interaction with the OpenSPP server and prevent common issues related to expired sessions.

Highlights

  • Enhanced Connection Toolbar: Replaced the simple 'Connect' button with a QToolButton featuring a dropdown menu, offering options to connect, change connection, or disconnect, and displaying the current server hostname when connected.
  • Dynamic Action Button States: Implemented logic to disable action buttons (Stats, Proximity, Geofence, Export) when the plugin is not connected to OpenSPP, enabling them automatically upon successful connection.
  • OAPIF Token Refresh Mechanism: Introduced an automatic token refresh timer for OAPIF connections to prevent silent authentication breaks in the QGIS Browser panel when JWT tokens expire.
  • Centralized Authentication Logic: Extracted the APIHeader authentication configuration logic into a new shared utility module (auth.py), allowing both the connection dialog and the token refresh timer to reuse it.
  • Improved Disconnect Flow: Added a clear disconnect function that clears the in-memory client and updates UI elements, while preserving saved credentials for future QGIS sessions.
  • Refined Connection Settings Menu: Renamed the 'Settings' menu item to 'Connection Settings...' for better clarity and updated its functionality to alias the connection dialog.
  • Token Expiry Tracking: Added a token_expires_in property to OpenSppClient to accurately determine the remaining time until a token expires, crucial for scheduling the refresh timer.
Changelog
  • openspp_qgis/api/client.py
    • Added token_expires_in property to calculate seconds until the current token expires.
  • openspp_qgis/auth.py
    • Added a new module to centralize the update_oapif_auth_token function for creating or updating APIHeader authentication configurations.
  • openspp_qgis/openspp_plugin.py
    • Replaced the 'Connect' action with a QToolButton featuring a dropdown menu for connection management.
    • Implemented _set_actions_enabled to dynamically enable/disable action buttons based on connection status.
    • Added _update_connection_state to manage UI elements reflecting the current connection.
    • Introduced _disconnect method for session-only disconnection.
    • Integrated _start_token_refresh_timer and _stop_token_refresh_timer for OAPIF token management.
    • Renamed the 'Settings' menu item to 'Connection Settings...' and updated its behavior.
    • Updated unload method to properly clean up new UI components and timers.
  • openspp_qgis/ui/connection_dialog.py
    • Modified _create_apiheader_auth_config to delegate to the new shared update_oapif_auth_token utility.
  • plans/toolbar-ux-cleanup.md
    • Added a detailed plan outlining the problem, goals, design decisions, and implementation steps for the toolbar UX cleanup.
  • tests/conftest.py
    • Added QToolButton to the mocked QGIS modules for testing purposes.
  • tests/test_batch_query.py
    • Updated OpenSppClient constructor arguments in test cases to match the new signature.
  • tests/test_connection_settings.py
    • Refactored tests for APIHeader auth configuration to target the new update_oapif_auth_token function in auth.py.
  • tests/test_plugin_ux.py
    • Added a new test file containing comprehensive unit tests for the plugin's toolbar UX, connection state, disconnect flow, and token refresh timer.
Activity
  • All unit tests have been run and passed, ensuring the reliability of the new features.
  • Manual verification in QGIS has confirmed the correct behavior of connect, disconnect, reconnect, and button text updates.
  • The QToolButton.MenuButtonPopup enum has been verified as the correct choice for the new toolbar button behavior.
  • The token_expires_in property has been added to OpenSppClient and tested for various token states.
  • The APIHeader authentication update logic has been extracted into a shared function and thoroughly tested.
  • The QToolButton with its dropdown menu has been implemented and verified for correct functionality.
  • Action buttons now correctly enable and disable based on the connection state.
  • The connection state display and menu updates are functioning as expected.
  • The disconnect flow has been implemented and tested, ensuring session-only disconnection.
  • The OAPIF token refresh timer has been integrated, with logic for scheduling, refreshing, and handling failures.
  • The 'Settings' menu item has been renamed and its cleanup process verified.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly improves the plugin's user experience by introducing a connection-aware toolbar, a token refresh mechanism, and a disconnect flow. No new security vulnerabilities were identified in the added or modified code. The implementation correctly utilizes the QGIS authentication manager for secure credential storage and follows standard Qt/QGIS patterns. The code is well-structured, with authentication logic refactored into a dedicated module and accompanied by a comprehensive suite of new tests. One opportunity exists to simplify the token refresh logic by removing some duplicated code.

Comment on lines +414 to +421
self._token_refresh_timer = QTimer()
self._token_refresh_timer.setSingleShot(True)
self._token_refresh_timer.timeout.connect(
self._on_token_refresh
)
self._token_refresh_timer.start(
self._TOKEN_REFRESH_RETRY_MS
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to create and start a retry timer in this except block is a duplication of what _start_token_refresh_timer() already does. When a token refresh fails, self.client.token_expires_in will return 0, causing _start_token_refresh_timer() to correctly schedule a retry with _TOKEN_REFRESH_RETRY_MS. You can simplify this by just calling self._start_token_refresh_timer() here.

Suggested change
self._token_refresh_timer = QTimer()
self._token_refresh_timer.setSingleShot(True)
self._token_refresh_timer.timeout.connect(
self._on_token_refresh
)
self._token_refresh_timer.start(
self._TOKEN_REFRESH_RETRY_MS
)
self._start_token_refresh_timer()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Track QGIS native OAuth2 limitations for future migration

1 participant