Refactors the callsign/gridsquare search to support exact match toggling, partial/broad match fallback, and a recent searches history stored in localStorage. Search terms are now passed via GET parameters (bookmarkable URLs) instead of POST. The advanced filter panel gains result count badges, a clear button, and persists query rules across page loads. DataTable initialization is extracted into reusable helpers.
Add the `search` route to the shared Leaflet include checks in the main and mini headers plus the footer. This ensures search pages load the map CSS and scripts needed for Leaflet-based UI elements.
Add a persisted `force_amsat` OscarWatch user option, expose it on the user edit form, and keep the AMSAT upload setting in sync when OscarWatch status uploads are enabled. The controller now defaults unchecked values correctly and shows a notice when OscarWatch disables direct AMSAT uploads or when the override keeps both enabled.
Adds full user-setting support for OscarWatch SAT status uploads: new per-user `status_upload` option initialization, save/load wiring, and session hydration. The user edit page now includes an enable/disable selector plus a “Test Token” action that calls a new `validate_oscarwatch_token` controller endpoint to verify tokens against OscarWatch and return clear JSON status messages. Logbook SAT upload logic is updated so AMSAT and OscarWatch uploads are handled independently based on their respective user toggles.
This adds optional OscarWatch integration for SAT QSOs: users can store an OscarWatch API token in account settings, and Cloudlog now reports SAT status uploads to OscarWatch alongside AMSAT uploads when enabled. It includes payload building, mode remapping for common satellites/modes, timestamp/grid handling, and error logging for failed submissions. The edit flow was also updated to load/save these options for the correct edited user, and the account label was generalized from “AMSAT Status Upload” to “Satellite Status Upload.”
When Clublog returns HTTP 403 (access denied), automatically clear the stored credentials and optionally send the user an email notification with context about the failure. Also sets a session flash warning when the affected user is logged in. Adds an email view template for the notification.
Introduces a new `station_profile.clublogcron` flag (migration 276) and wires it into station create/edit save flows so users can explicitly enable locations for `/clublog/upload`. Clublog station selection now only includes enabled locations (with fallback to `clublogrealtime` if the new column is not present), and the dashboard shows a warning when Clublog credentials exist but no station is enabled. It also tightens Clublog upload-status query grouping and fixes `Clublog::uploadall` return flow so upload results are returned consistently.
- Fix returnStatus() to evaluate all band statuses before returning, so 'C' takes priority over 'W' across all bands instead of returning on first match
- Add band preset buttons (HF Only, VHF/UHF+, SAT Only, All, Clear) to the DXCC filter form
- Update map legend to show total worked count (confirmed + unconfirmed) alongside the unconfirmed breakdown
Replaces the single band dropdown on the DXCC awards page with a group of checkboxes allowing multiple bands to be selected simultaneously.
- Controller and model updated to accept `bands[]` array instead of a single `band` value
- `addBandToQuery()` in Dxcc model now handles array input, building appropriate IN clauses and SAT propagation mode logic
- `returnStatus()` priority fixed: Confirmed (C) now takes precedence over Worked (W); unworked entries now return 'x' instead of null
- JS updated to collect checked band values; map and filter reset functions updated accordingly
- Uninitialized `$newdxcc`/`$newiota` arrays now explicitly initialized before use
Enhances the eQSL mappings form to better support shared usernames by detecting existing usernames, guiding users with contextual hints, and automatically enabling password reuse behavior unless explicitly overridden. It also disables browser autofill/correction on sensitive fields and adds a visual “Reusable password” indicator in the mappings table.
Improves guidance for eQSL mappings by adding a shared-account tip, making the password field label/placeholder explicit about blank-password reuse, and clarifying that passwords are only required for new usernames. The eQSL wiki guide was updated to match this behavior and include a troubleshooting check for first-time username setup.
When editing or creating an eQSL mapping, the password field can now be left blank. Cloudlog will reuse an existing saved password for the same eQSL username. A password is only required when no saved password exists for that username. The mappings form hint text and docs are updated accordingly.
Adds a `qso_show_profile_image` JS flag from the user session and updates callbook panel rendering to honor it. The panel now omits the image column when profile images are disabled, keeps the empty-image message only when images are enabled, and applies a single-column layout class for no-image states.
Gate the QSO callbook tab on the configured callbook provider instead of the profile image setting. The controller now exposes a `show_callbook_tab` flag when the user's callbook type is `HAMQTH` or `QRZ`, and the view uses that flag for both the tab button and pane.
Canonicalize activator callsigns and combine results for variant forms such as portable suffixes and MM/MW prefixes. This updates activator listings, max-grid counts, and contact details to aggregate grids across matching calls while keeping the table output consistently sorted.
Extends Gridmap and Activated Gridmap to accept a new `sat_orbit` filter and applies it across worked/confirmed grid and VUCC queries, including SAT-specific SQL filtering for LEO, MEO (IO-117), and GEO (QO-100). Updates the gridmap UI to show/hide orbit controls with SAT selection, sends the new filter in AJAX requests, and adds activated-grid summary cards with worked/confirmed counts and satellite class breakdown data from new model methods.
Refactored the callsign profile display from a separate hidden card to an integrated tab-based interface. The new callbook tab includes a responsive grid layout with profile image, external links (QRZ and HamQTH), and metadata fields (name, QTH, locator, IOTA). Added proper HTML escaping for security and improved visual organization with Bootstrap 5 styling.
Add 'logbookadvanced' controller to the list of routes that require Leaflet map assets. Also conditionally load easyprint.js only when Leaflet is enabled to reduce unnecessary script loading.
#3453 Fixed
Add the `labeltable` class to the labels table and switch the checkbox handler to a delegated `change` event. The uncheck logic is now scoped to the current table so only labels in the same list are affected.
Leaflet CSS/JS assets are now loaded conditionally in shared headers/footers so map libraries are only included on pages that need them. For the QRB calculator dialog, Leaflet is loaded on demand in `common.js`, and the `newpath` map-rendering function was moved into the QRB view so the modal still works when global map scripts are skipped. Also adds a small HTMX updating indicator to the dashboard’s Today’s QSOs section.
Replace direct lang('prev')/lang('next') calls with localized labels using general_word_previous and general_word_next language lines (falling back to 'Previous'/'Next'). Adds $prev_label and $next_label and updates the pagination links/spans to use them, improving localization support for the previous-contacts pagination.
Introduce window.cloudlogLastCatData and window.cloudlogLastCatRadioId to cache the last CAT response and radio ID, set on successful CAT poll and cleared on UI reset. Add isSatelliteLookupContext() in qso.js to centralize logic for detecting satellite lookup context using UI fields or the cached CAT data, and replace scattered sat_name checks with this helper. This makes satellite lookups more reliable when CAT populates fields and avoids duplicated logic across handlers.
Introduce an advanced search status display and persist UI state for the Logbook Advanced view. Adds CSS and a status span to show result/selection counts and transient messages. Implements setAdvancedSearchStatus(), getVisibleColumnIndex(), restoreAdvancedSearchUiState() and persistAdvancedSearchUiState() to update status, handle visible columns dynamically, and save/restore collapsed sections and the QSO results selection via localStorage. Also adds client-side date range validation, sets status messages during load/search/failure, and updates status when rows are selected/unselected. Adjusts band/mode column lookups to respect visible columns.
Decode the PHP $options JSON into an object, ensure pota/operator/stationLocation keys exist (each with show:'true') when missing, and emit user_options via json_encode. Replace the previous string-based JS assembly with a robust PHP-side normalization and set $options for the view to the normalized object. Also add a defensive JS check around user_options.operator.show to avoid runtime errors when operator is absent.
Avoid double-processing of the Escape key by setting a timestamp (window.cloudlogQsoEscHandledAt) when handling the QSO-escape keydown and short-circuiting subsequent handlers within 500ms. Also broaden the SAT field restore logic in resetQsoEntryOnEscape to restore sat_name/sat_mode when preSatMode exists or when the previous propagation mode was SAT (not just when preSatName is present). These changes prevent accidental duplicate resets and ensure SAT fields are correctly restored.
Trim and store data.prop_mode into propModeFromCat and use it to decide how to update the propagation select. If the value is empty, clear #selectPropagation and remove its stored catValue to avoid carrying stale propagation settings; otherwise call cat2UI with the trimmed value. This prevents leftover propagation mode when CAT provides no prop_mode.
Prevent CAT polling from overwriting user-entered satellite fields by introducing lockSatelliteFieldsToUserInput and only updating #sat_name, #sat_mode and propagation when not locked. Clear stale sat fields if CAT returns empty values. Reset the lock on radio changes and when UI is reset, and set the lock dynamically on user input (or when propagation is SAT).
Also persist the selected radio as a post-save default: include radio in postSaveDefaults, restore it in reapplyPostSaveDefaults (update selects and localStorage), and trigger sat_name input after restore so the locking logic reacts to restored satellite fields.
Add a microphone mute control to the remote operation UI and wire it into the audio pipeline and settings. A new checkbox (remoteOperationMicMuteToggle) is added to the view. JavaScript gains a micMuted setting (default true), persistence to localStorage, UI syncing, and an applyMicMuteState() helper which enables/disables audio tracks on the media stream. The setting is applied when a stream is attached and updated immediately when the user toggles the checkbox.
Add server endpoints to store and retrieve the remote operation link password in the user's account and update the client to use them. Qso controller: added remoteoperationsecret_json and remoteoperationsecret_save which use user_options_model and CI encryption to get/set an encrypted link_password (save enforces a minimum 16-char password, empty value clears it). View and JS: default WebSocket URL changed to wss://relay.cloudlog.org/ws-webrtc; client no longer stores link password in localStorage and instead loads/saves it via the new endpoints (with error handling and UI feedback). Also clear the account secret on reset and stop exposing the password in browser storage.
Introduce an experimental browser-based remote audio feature: bump migration version to 270 and add a migration to add a remote_operation flag to the users table. Add server-side support to User and QSO controllers/models to read/save the remote_operation option (stored via user_options_model) and expose isRemoteOperationEnabled to views and session updates. Add UI: a Remote Operation card on the QSO page, a modal component for detailed settings, a toggle in the user edit page, and conditional loading of assets/js/remote-operation.js. Add a large client-side implementation (assets/js/remote-operation.js) implementing WebRTC signalling, device selection, level meters and diagnostics. Minor session/session-update and helper changes to keep UI state in sync.
Replace verbose stacked inputs with a compact, responsive grid for F1–F5 macros, add placeholder examples and a macro tokens note, and prefill values in the results view via a $macro_result variable. Also make the modal larger and scrollable and add a close button to improve usability.
Introduce server endpoints to get/save WinKey WebSocket relay settings and token (winkeyrelaysettings_json, winkeyrelaysettings_save, winkeyrelaytoken_json, winkeyrelaytoken_save) using the user_options_model. Add client-side changes to load settings from the account (with a localStorage fallback), save settings to the account, validate URL/token (ws:// or wss:// and token ≥ 8 chars), and clear legacy localStorage keys after a successful save. Defer WebSocket connect until account settings are loaded and update UI text to reflect that relay settings are stored in the user account and follow login across devices.
Introduce optional Winkey Relay transport for CW commands and a browser-based settings UI. Adds localStorage-backed relay config (enabled, url, token, room), a modal to edit/save settings, and validation for URL/token/room. WebSocket logic now switches between direct localhost connection and relay mode, handles relay protocol messages (join, frame, error), authenticates/join on open, and wraps sends via sendWinkeyCommand to support framed relay messages. Updates UI: new Relay button/modal, changed Settings button label/icon, socket status badge updates, and reconnect on save. Keeps compatibility with direct WebSocket server and retains logging and sidetone playback behavior.
Revamp CW sidetone UI and state handling: reorganize controls into responsive Bootstrap columns, switch the enable control to a form-switch, add a Volume range control and a status badge, and make frequency/volume labels responsive. Update cw-sidetone.js to persist and load a new volume setting, add updateVolumeLabel and updateStatusLabel helpers, and wire volume/status interactions in initControls. Persisted keys in localStorage now include cloudlog.cwSidetone.volume.
Add Enter key handling for the CW free-text input (sendText) so pressing Enter sends the message. Replaced the old 'message' keypress handler in footer.php with a DOMContentLoaded listener that binds keydown on #sendText and calls sendMyMessage() (preventing default). Also added matching keydown handling in assets/js/winkey.js to call clickSend() when Enter is pressed on the sendText element.
Introduce a client-side CW sidetone feature: add assets/js/cw-sidetone.js (AudioContext-based morse generator with persistence for enabled/frequency), and wire it into the UI and existing send flows. Include the new script in the footer and add speaker sidetone controls (enable checkbox + frequency slider) to the QSO view. Update winkey.js and websocket macro send handlers to compute a single textToSend, send it as before, and call window.cloudlogCwSidetone.playText(...) when available; also add defensive element existence checks. This provides audible sidetone feedback for CW macros and manual sends while preserving backwards compatibility when the sidetone module is not present.
Replace direct sendTextEl.focus() with setTimeout(..., 0) so the input is focused on the next tick. This avoids timing issues where an immediate focus call can be overridden by synchronous handlers (e.g. blur/submit) and ensures the message input reliably regains focus after sending.
When sending a WebSocket message, the input clearing logic now caches the sendText element, clears its value and calls focus() so the user can immediately start typing the next message. This improves UX by returning focus to the input and slightly refactors the DOM access into a local constant.
Add inline CSS to application/views/dashboard/index.php to forcibly hide the .htmx-indicator (display: none !important). This prevents the htmx loading spinner from appearing in the dashboard UI.
Add responsive styles and layout changes to improve usability on small screens: introduce CSS under @media (max-width:991.98px) to enable horizontal scrolling for tab bars, hide less-important table columns, adjust spacing and button widths, and remove scrollbars. Update column classes (col-sm -> col-lg and many inputs to col-6) so form fields stack better on mobile. Add a collapsible "More QSO Fields" button to surface optional fields on small devices and make the QSO map hidden on small screens (d-none d-md-block). Overall changes improve layout, readability and touch behavior for mobile users.
Add responsive styles and restructure header markup for better mobile layout (flex column on small, row on md+; full-width diary button on small). Update echo_table_header_col() and echo_table_col() to accept an optional CSS class and apply it to th/td elements. Apply Bootstrap responsive utility classes (d-none d-sm-/d-md-/d-lg-table-cell) to hide less-important columns on smaller screens and adjust time column visibility. These changes improve readability on narrow viewports while preserving existing tooltips and badges.
Move repeated table rendering helpers into a new application/helpers/dashboard_helper.php and load it from the Dashboard controller to remove duplication in views. Improve mobile/responsive dashboard behavior: detect mobile user agent to reduce recent-QSO rows, add mobile-specific quick links, collapse cards for compact display, and adjust HTMX polling intervals and targets. Add htmx loading indicators and last-updated timestamps with a small JS handler, and include minor CSS tweaks. Also add a session validation early-return in radio_display_component and load the user_agent library in the controller.
Advance the GMDX Summer Challenge event to 2026: update controller week end timestamps, and update view copy and table dates/entry link to reflect the new event window (11 May – 5 July 2026). In the model introduce START_DATE (2026-05-11), add validation to ignore empty/null COL_GRIDSQUARE values, and change combined-count logic to normalize gridsquares and group modes into CW / VOICE / DIGITAL so counts are consistent and case-insensitive.
Add a year filter to the DXCC awards UI and backend. Controller: populate worked_years for the view and read/sanitize a year POST value (default 'All'). Model: introduce addYearToQuery() to append a YEAR(col_time_on) clause to existing DXCC queries and call it in relevant query paths; add get_worked_years() to return distinct worked years for the active logbook locations. View: add a year select dropdown to the DXCC awards form. This enables narrowing DXCC results by year.
Replace the fixed 3s setInterval CAT updater with a scheduled poller that supports exponential backoff, failure counting, and UI warnings. Introduces consecutiveCatPollFailures, catPollTimer, lastSuccessfulCatUpdateAt, and constants for base/max intervals and warning threshold. Adds helper functions to compute delays, schedule polls, handle success/failure, show/clear warning banners, and only poll the currently selected radio. Clears warnings on login error/reset/selection changes and resets failure counters when selection changes to maintain responsive UI.
Add no-cache HTTP headers in Radio::json to prevent cached responses. Replace client-side $.getJSON with $.ajax(url, {dataType:'json', cache:false}) and preserve the stale-response checks while updating lastProcessedCatRequest only when a response is applied. Also ensure login errors return early. These changes ensure fresh CAT data and avoid stale or cached responses affecting the UI.
Add server-side read-only policy checks for plugins and surface security alerts to admins. Plugin_manager now validates plugin code (collects PHP files and scans for forbidden file/system/exec functions) during install and before enabling; installs are blocked or plugins auto-disabled on violation with a security alert returned. Plugins controller updated to use session validation for login, enforce admin (user_type 99) access, store/display security alerts via a flash session key, and pass a CSRF token to the view. The plugins index view now renders a warning banner for plugin security alerts. Documentation updated to link and include a new QSO Hooks plugin guide for third-party sync plugins.