Skip to content

System libs build#1

Merged
NICourced merged 119 commits into
NICourced:masterfrom
mavlink:master
Mar 21, 2026
Merged

System libs build#1
NICourced merged 119 commits into
NICourced:masterfrom
mavlink:master

Conversation

@NICourced

Copy link
Copy Markdown
Owner

Description

Add corresponding CMake flags USE_SYSTEM_ before CPMAddPackage to let build with system build dependencies as brebuilt libs or source packages to make it easier to build without internet connection for distros that do so.
New build flags are:
USE_SYSTEM_MAVLINK
USE_SYSTEM_LIBEVENTS
USE_SYSTEM_ZLIB
USE_SYSTEM_XZ-EMBEDDED
USE_SYSTEM_ZSTD
USE_SYSTEM_LZ4
USE_SYSTEM_BZIP2
USE_SYSTEM_LIBARCHIVE
USE_SYSTEM_GEOGRAPHICLIB
USE_SYSTEM_SHAPE
USE_SYSTEM_SDL3
USE_SYSTEM_SDL_GAMECONTROLLERDB
USE_SYSTEM_QMDNSENGINE
USE_SYSTEM_LIBEXIF
USE_SYSTEM_ULOG_CPP
USE_SYSTEM_PX4-GPSDRIVERS
USE_SYSTEM_PARAMETERS
USE_SYSTEM_PROTOZERO
USE_SYSTEM_LIBOSMIUM
USE_SYSTEM_NANOBENCH
USE_SYSTEM_RAPIDCHECK
USE_SYSTEM_GSTQML6

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • CI/Build changes
  • Other

Testing

  • Tested locally
  • Added/updated unit tests
  • Tested with simulator (SITL)
  • Tested with hardware

Platforms Tested

  • Linux
  • Windows
  • macOS
  • Android
  • iOS

Flight Stacks Tested

  • PX4
  • ArduPilot

Screenshots

Checklist

  • I have read the Contribution Guidelines
  • I have read the Code of Conduct
  • My code follows the project's coding standards
  • I have added tests that prove my fix/feature works
  • New and existing unit tests pass locally

Related Issues

mavlink#13906

By submitting this pull request, I confirm that my contribution is made under the terms of the project's dual license (Apache 2.0 and GPL v3).

DonLakeFlyer and others added 30 commits February 27, 2026 07:41
Was causing too many problems in random places which would only be identified if you stumbled across a dusty corner of the QGC qml ui.
Bumps the npm_and_yarn group with 1 update in the / directory: [rollup](https://github.com/rollup/rollup).


Updates `rollup` from 4.34.4 to 4.59.0
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](rollup/rollup@v4.34.4...v4.59.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-version: 4.59.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
For PX4 vehicles, send a standalone PARAM_REQUEST_READ for _HASH_CHECK
before issuing PARAM_REQUEST_LIST. If the hash matches the local parameter
cache, parameters are loaded from disk and the full parameter stream is
skipped entirely, reducing reconnect time.

Split the single _initialRequestTimeoutTimer into two independent timers:
- _hashCheckTimer (1 s): guards the standalone _HASH_CHECK request
- _paramRequestListTimer (5 s): guards PARAM_REQUEST_LIST (unchanged timeout)

_hashCheckTimeout falls back to PARAM_REQUEST_LIST without consuming a
retry.  If _HASH_CHECK arrives later inside the PARAM_REQUEST_LIST stream
the cache path still works.

MockLink changes:
- Compute a real CRC-32 hash over the parameter map so _HASH_CHECK
  responses match the ParameterManager cache logic, enabling cache-hit
  and cache-miss scenarios in tests.
- Append _HASH_CHECK at the end of the PARAM_REQUEST_LIST stream (mirrors
  real PX4 firmware behaviour).
- Add setHashCheckNoResponse() and setMockParamValue() test helpers.

Co-Authored-By: Claude <noreply@anthropic.com>
Data-driven test matrix covering 12 scenarios:
- FirstConnect_NoCache, Reconnect_CacheHit, Reconnect_CacheMiss
- HashTimeout with and without cache, HashTimeout with stale cache
- BothTimersExhaust (params never ready)
- CacheDeleted_Between, ManualRefresh
- ArduPilot (FTP path, no _HASH_CHECK), HighLatency, LogReplay

Each row specifies MockLink configuration flags and expected outcomes
(hash-check sent, PARAM_REQUEST_LIST sent, parametersReady, missingParameters).

Co-Authored-By: Claude <noreply@anthropic.com>
Use qCCritical for offline/syncInProgress/flyView guard conditions in
loadFromVehicle, sendToVehicle, removeAllFromVehicle, and
showPlanFromManagerVehicle. Critical-level logs cause unit tests to
fail, ensuring these invalid call sequences are caught during testing.

Also converts bare qWarning() in PlanMasterController::removeAllFromVehicle
to categorized qCCritical for consistency.

Affected controllers:
- PlanMasterController
- MissionController
- GeoFenceController
- RallyPointController
Add _setDirtyStates() helper that atomically updates both dirtyForSave
and dirtyForUpload flags, emitting at most one signal per flag only when
the value actually changes. This eliminates the cascading issue where
_setDirtyForSave(true) would trigger _setDirtyForUpload(true), followed
immediately by _setDirtyForUpload(false), producing a transient incorrect
state and redundant signal emissions during load-from-vehicle completion.

Replace all paired _setDirtyForSave/_setDirtyForUpload call sites with
the new atomic helper.
…gle buttons for Waypoint and ROI

- Add checkable Waypoint toggle button (stays toggled on; each map click adds a waypoint)
- Add checkable ROI toggle button (toggles off after single click; shows insert/cancel dialog when ROI is active)
- Remove right-click/press-and-hold ROI insertion (_mapRightClicked)
- Make Waypoint and ROI toggles mutually exclusive
- Remove toolbar help text for waypoint/ROI click instructions (PlanToolBarIndicators)
- Clean up dead code: remove 18 unused property declarations (button indices, stale properties, unused QGCMapPalette)
- Fix dynamically created ROI DropPanel leak (onClosed: destroy())
- Add standard globals.parent explanatory comment
…screenshots

- Add missing indicator sections: GPS Resilience, ESC, Joystick, RTK GPS,
  Telemetry RSSI, RC RSSI, Gimbal, VTOL Transitions, Multi-Vehicle Selector,
  APM Support Forwarding
- Promote 'Other Indicators' items to top-level sections with descriptions
- Merge GPS and RTK GPS into single 'GPS / RTK GPS' section
- Add inline heading screenshots for all indicators that have assets
- Add new screenshot assets for all indicators
- Fix typos: acess, availble, give you, a multiple
- Add structured summary log per metadata type showing source (cache/FTP/HTTP),
  primary vs fallback, translation status, and URI
- Consolidate key diagnostic messages under ComponentInformationManagerLog category
- Add componentName parameter to translation warnings for context
- Skip translation download for English locales (metadata is authored in English)
- Log cache location on startup
- Log primary/fallback request attempts and download failures
- Demote intermediate CRC/cache messages to RequestMetaDataTypeStateMachineLog
- Replace pointer-identity metadata source tracking with explicit flag
- Track actual URI used (primary or fallback) for accurate failure reporting
- Remove unit-test-only restriction on FTP/HTTP failure logging
Change WheelHandler to zoom around the current mouse cursor position
instead of the map center. Uses alignCoordinateToPoint to keep the
coordinate under the cursor fixed, matching the existing PinchHandler
behavior.

Reset _lastRotation on WheelHandler deactivation to prevent zoom jumps
when rotation resets to 0 between wheel sequences.
The old /github/release/ endpoint is deprecated and returns 'invalid'.
Update to /github/v/release/ which correctly resolves the latest release.
Provide distinct error messages for joystick vs RC transmitter when
the channel count is below the minimum required:

- Joystick mode: show stick count vs required count
- RC transmitter mode: prompt to turn on transmitter when 0 channels,
  otherwise show required channel count
- Use clearer dialog titles for each case
Add setRequestMessageNoResponse() API that allows tests to silently drop
REQUEST_MESSAGE responses for specific MAVLink message IDs (no ACK, no
message). This enables precise timeout testing of individual
InitialConnectStateMachine states without affecting other message flows.

- New QSet<uint32_t> member tracks blocked message IDs
- Early return in _handleRequestMessage() when ID is in the blocked set
- Complements the existing RequestMessageFailureMode which is global
Add a thread-safe log capture system that records messages by category and
severity level during unit test execution. This enables tests to assert on
logged warnings, criticals, and uncategorized messages.

- CapturedLogMessage struct holds type, category, and raw message text
- Atomic bool gate + mutex-protected QList for minimal overhead when disabled
- captureIfEnabled() public static for external handler wrappers
- Query API: capturedMessages(), hasCapturedMessage(), hasCapturedWarning(),
  hasCapturedCritical(), hasCapturedUncategorizedMessage()
- Capture call placed inside the qt.quick filter in msgHandler
QTest::qExec() replaces the Qt message handler with its own, so
QGCLogging::msgHandler is NOT called during test runs. Work around this by
installing a thin wrapper (testCaptureHandler) on top of QTest's handler
in initTestCase(), restoring it in cleanupTestCase().

- testCaptureHandler calls QGCLogging::captureIfEnabled() then chains to
  QTest's handler for normal QWARN/QCRITICAL output
- init() enables capture and clears previous messages per-test
- cleanup() disables capture after each test finishes
Elevate qCWarning to qCCritical for conditions that indicate
programming or configuration errors in the state machine module:

- start() called on an already-running machine
- AsyncFunctionState with no completion connection and no timeout
- SubMachineState with null or broken factory
- SendMavlinkCommandState used before configuration
- resetToState() with null or foreign state

These are internal errors, not runtime conditions. Promoting them
ensures the test log capture infrastructure catches them as failures.
Add data-driven _stateTimeoutFallsThrough test that exercises timeout
fallthrough for each InitialConnectStateMachine state individually:

  - StandardModes: block AVAILABLE_MODES
  - CompInfo: block COMPONENT_METADATA
  - Parameters: no param response
  - Mission: block mission protocol from start
  - GeoFence: block mission protocol after mission loads

Each row verifies the state machine completes despite the timeout, and
checks parametersReady / initialPlanRequestComplete expectations.

Add cleanup() override that scans captured log messages and fails the
test if any uncategorized messages (raw qDebug/qWarning without a
category) or critical-level messages were logged during the test run.
This catches production code quality issues like missing logging
categories and unexpected error conditions.

Note: The CompInfo row currently exposes a real bug where
ComponentInformationManager::requestAllComponentInformation() calls
start() on an already-running state machine. That bug should be fixed
separately in production code.
When InitialConnectStateMachine's CompInfo state times out, the retry
callback re-invokes requestAllComponentInformation() while the CIM state
machine is still running, triggering a critical 'start() called but
already running' error.

Guard requestAllComponentInformation() with isRunning() so the retry
path updates the completion callback without restarting. Also add
setOnExit cleanup for the progress signal connection (consistent with
Parameters, Mission, GeoFence, and Rally states).
… log-capture race

- Guard _requestMessageNoResponseIds with QMutex in both setter and reader
- Check isInitialConnectComplete() before spy.wait() to avoid 60s stall
- Disable log capture before snapshotting in cleanup() for deterministic results
Filter RowLayout children to only include items with a 'checkable'
property (i.e. actual tab buttons) before assigning them to ButtonGroup.
This fixes ButtonGroup errors when Repeater or other non-button items
are among the RowLayout children.

- Build filtered _buttons array and assign to ButtonGroup
- Counter-rotate currentIndex logic to use _buttons instead of children
- Guard onCheckedButtonChanged against binding loops
- Re-select on children/visibility changes
Replace the plan view right panel's flat QmlObjectListModel-based editor
list with a QML TreeView backed by a new QmlObjectTreeModel. Mission Items,
GeoFence, and Rally Points are now presented as collapsible groups with
exclusive expand behavior (only one group open at a time). Clicking an
already-expanded group collapses it.

Structural changes:
- Extract ObjectItemModelBase from ObjectListModelBase to share dirty
  tracking, nested beginResetModel/endResetModel guards, count-changed
  signal suppression, and role definitions between list and tree models.
- Add QmlObjectTreeModel (QAbstractItemModel for trees) with cached
  node count, nodeType role, subtree insert/remove, and full dirty
  propagation from child QObjects.
- Add MissionController::visualItemsTree() which maintains a
  QmlObjectTreeModel shadow of visualItems with three top-level groups
  (missionGroup, fenceGroup, rallyGroup) and syncs on insert/remove.
- Rally point signal wiring lives in _initAllVisualItems so connections
  are refreshed on each plan reinit.
- insertRows/removeRows overrides log warnings instead of silently
  failing (prevents misuse from QML or proxy models).

QML changes:
- Add MissionItemTreeView.qml: TreeView delegate dispatches to
  MissionItemEditor, GeoFenceEditor, RallyPointEditorHeader, and
  RallyPointItemEditor based on nodeType. Group headers show
  expand/collapse indicators with highlight for the active group.
- Simplify PlanViewRightPanel.qml to host MissionItemTreeView directly
  instead of managing three separate editor views and a tab-like switcher.
- After collapse/expand, the view scrolls so the group header is visible
  (prevents blank view when expanding GeoFence/Rally after scrolling past
  many waypoints).
Unit test suites:
- QmlObjectTreeModelTest (48 tests): insert/remove/clear, tree navigation,
  data roles, dirty tracking, model signals, nested reset guards,
  persistent index stability, and null object edge cases.
- ObjectItemModelBaseTest (10 tests): nested beginResetModel/endResetModel
  at depths 1-3, count signal suppression during reset, sticky dirty
  tracking via _childDirtyChanged, and roleNames verification.
- ObjectListModelBaseTest (8 tests): validates QAbstractItemModel contract
  for flat lists — index bounds, column must be 0, parent always invalid,
  columnCount always 1, hasChildren correct for root vs non-root.
- MissionControllerTreeTest (6 integration tests): verifies tree model
  stays in sync with visualItems after init, insert, remove, removeAll;
  validates persistent group indexes survive mutations; exercises
  recalcChildItems without crash.
DonLakeFlyer and others added 18 commits March 14, 2026 20:19
Replace model-level beginResetModel/endResetModel in _syncTreeMissionItemsReset
and _syncTreeRallyPointsReset with row-level signals from removeChildren() and
appendItem(). This avoids unnecessarily invalidating all QPersistentModelIndex
instances (the 6 group indexes) when only children of a single group are being
manipulated.

Wrap _setupTreeModel() in beginResetModel/endResetModel and capture persistent
group indexes after endResetModel so they are not immediately invalidated.

Split _syncTreeRallyPointsAboutToBeRemoved into two handlers:
- aboutToBeRemoved: Only removes tree children (safe, indexes still valid)
- rowsRemoved: Re-adds the header marker after the source model finishes
  removing (final state available, safe to insert)

Rename all tree sync handlers from _on* prefix to _syncTree* prefix to
clearly indicate their purpose of propagating source model changes into
the _visualItemsTree secondary model.

Use targeted disconnect(visualItem, nullptr, this, nullptr) in
_deinitVisualItem instead of a full wildcard disconnect, preserving
internal Qt destroyed-signal connections that models rely on.
- Remove showSetPositionFromVehicle property; show Vehicle Position option
  whenever an active vehicle exists
- Consolidate four Set position/Move buttons into a single dispatch button
- Show vehicle lat/lon and altitude labels in Vehicle Position mode
- Add altitudeFact and altitudeFrame properties for optional altitude editing
- Show editable altitude field with frame label (Rel/AMSL/AGL) for
  Geographic, UTM, and MGRS modes when caller provides an altitude Fact
- Show frame-relevant vehicle altitude in Vehicle Position mode
- Add checkboxes to independently set position and/or altitude from
  vehicle (position defaults on, altitude defaults off)
- Wire MissionItemEditor to pass altitude info for SimpleMissionItems
- Remove unused showSetPositionFromVehicle parameter from FlyViewMap
Adds a left margin (_toolsMargin) to the MapScale widget so it has
proper spacing from the FlyViewToolStrip instead of being flush against it.

Also removes unused centerInset property from the pip-mode MapScale in
FlyViewMap.

Fixes #13526
The nested Repeaters in PIDTuning.qml had an index shadowing bug.
The inner Repeater's delegate used 'index' for the visibility check,
but inside the inner Repeater 'index' refers to the parameter index
rather than the outer axis index. This caused each axis tab to show
one wrong parameter from across all axes instead of all parameters
for the selected axis.

Store the outer axis index in a property on the inner Repeater and
reference that property in the visibility binding.

Fixes #13351
Rename the onboard log download feature from MAVLinkLog to OnboardLog
to better reflect its purpose. This affects the AnalyzeView log list
and download functionality, not the MAVLink telemetry log streaming
in Vehicle/MAVLinkLogManager.

- Rename directory: MAVLinkLogs -> OnboardLogs
- Rename classes: MAVLinkLogController -> OnboardLogController,
  QGCMAVLinkLogEntry -> QGCOnboardLogEntry,
  MAVLinkLogDownloadData -> OnboardLogDownloadData
- Update all user-facing strings
- Update test files and registration

Fixes #14137
ArduPilot 4.7 renames many parameters to new names with SI units.
This adds remap tables so QGC can work with both old and new firmware.

Key changes:
- Add 4.7 remap tables for Copter, Plane, Rover, and Sub
- Replace r. prefix system with noremap. bypass and always-on remap
- Use noremap. for version detection where old/new params have
  different units (speed, altitude, RTL defaults)
- Update all QML files to use new 4.7 parameter names
- Rename maximumHorizontalSpeedMultirotor to
  maximumHorizontalSpeedMultirotorMetersSecond for clarity
- Fix null dereference in APMFollowComponent.qml
- Handle removed PSC_ACCZ_FILT parameter gracefully

Fixes #14079
PX4 now centralizes handling of Joystick and RC controllers, so RC loss
applies to all configured manual controllers. Update labels accordingly.
- Fix qgc-lupdate-json.py to use 'src' instead of '../src' so it works
  when called from the repo root via qgc-lupdate.sh
- Add weekly cron schedule (Sunday 03:00 UTC) to lupdate.yml workflow
Camera Tracking Interface:
- Remove flawed TrackingStatus bitmask enum
- Separate point/rect tracking into distinct properties
- Rename signals to match property names (trackingImageIsActiveChanged, etc.)
- Add supportsTrackingPoint/supportsTrackingRect Q_PROPERTYs
- Split startTracking() overloads into startTrackingPoint()/startTrackingRect()
- Add capability guards with qCCritical to both methods
- setTrackingEnabled(false) now calls stopTracking() to notify vehicle
- Cache hasTrackingImageStatus to prevent redundant signal emissions
- Zero-initialize _trackingImageStatus struct

FlyView Mouse Handling:
- Extract camera tracking into OnScreenCameraTrackingController.qml
- Refactor OnScreenGimbalController to method-based API
- Clean 4-method API: mouseClicked/mouseDragStart/mouseDragPositionChanged/mouseDragEnd
- Add click vs drag separation with 10px threshold
- Remove hoverEnabled (unnecessary in full-screen mode)
- Fix operator precedence bug in tracking status overlay
- Fix mode guards bug in gimbal controller (was !value == 0)
- Fix ROI rectangle resize on drag direction reversal
- Declarative tracking status overlay (replaces imperative createObject/timer)
- Gimbal rate timer unconditionally stopped in mouseDragEnd

MockLink:
- Add tracking simulation with figure-8 drift animation
- Handle TRACK_POINT, TRACK_RECTANGLE, STOP_TRACKING commands
- Handle SET_MESSAGE_INTERVAL for CAMERA_TRACKING_IMAGE_STATUS
- Capability-gated commands (DENIED if flag not set)

Gimbal Settings:
- Rename ControlType to clickAndDrag boolean

Relates-to: #13363
Relates-to: #13957
Qt 6 TreeView delegates are destroyed asynchronously during a polish cycle,
not synchronously when rows are removed. When MissionController replaced
_visualItems, the old C++ VisualMissionItem objects were destroyed before
the TreeView polish cycle released delegates still holding QML bindings,
causing null-reference TypeErrors.

Fix takedown sequencing with stash-init-destroy pattern:
- Add _setupNewVisualItems() that stashes the old list, builds the new one,
  then destroys old items after a 1-second delay via QTimer::singleShot
- Refactor removeAll(), _newMissionItemsAvailableFromVehicle(), and
  _initLoadedVisualItems() to use _setupNewVisualItems()
- Make missionItemCount a computed property from _visualItems->count(),
  removing the _missionItemCount member variable
- Replace _updateContainsItems() with direct signal-to-signal connections
  from countChanged to containsItemsChanged and missionItemCountChanged
- Fix connect/disconnect mismatch in _deinitAllVisualItems (was
  disconnecting _recalcAll but _initAllVisualItems connected
  _recalcMissionFlightStatus)
- Fix PlanMasterController::_showPlanFromManagerVehicle() guard inversion
  that caused double-call of _newMissionItemsAvailableFromVehicle
Remove methods and constants that were only used for the old standalone
.mission JSON format (V1):

- _loadJsonMissionFileV1(): V1 format loader with separate complexItems array
- _loadJsonMissionFile(): dispatcher (declared but never implemented)
- _loadItemsFromJson(): wrapper that was never called
- _recalcROISpecialVisuals(): empty stub that was never effective
- _jsonFileTypeValue, _jsonComplexItemsKey, _jsonMavAutopilotKey constants

The current .plan format exclusively uses _loadJsonMissionFileV2() via
PlanMasterController::loadFromFile() -> MissionController::load(), which
remains unchanged. The .waypoints text import path is also unaffected.
…anged

All 10 properties (currentPlanViewSeqNum, currentPlanViewVIIndex,
currentPlanViewItem, previousCoordinate, onlyInsertTakeoffValid,
isInsertTakeoffValid, isInsertLandValid, isROIActive,
isROIBeginCurrentItem, flyThroughCommandsAllowed) are recomputed
together in setCurrentPlanViewSeqNum, so a single NOTIFY signal
suffices. QML bindings re-evaluate in one pass instead of 10
separate updates.

splitSegmentChanged is kept separate because PlanView.qml has an
explicit onSplitSegmentChanged handler.
Same pattern as _handleHeartbeat and _handleSysStatus (PR #13768):
ignore messages from non-autopilot components to prevent secondary
MAVLink components from overriding core vehicle state.

Handlers updated:
- _handleExtendedSysState (flying/landing/VTOL state)
- _handleGpsRawInt (GPS position and altitude)
- _handleGlobalPositionInt (fused position and altitude)
- _handleHomePosition (home/RTL location)
- _handleCurrentMode (displayed flight mode)

Relates-to: #13797
Implement MAVLink 2 message signing with named key management, per-vehicle
auto-detection from incoming signed packets, and toolbar indicator.

Key features:
- Named signing key storage (SHA-256 hashed passphrases) via MAVLinkSigningKeys
- Auto-detect signing key from incoming signed packets (no manual setup needed)
- Send SETUP_SIGNING to enable/disable signing on vehicles
- Toolbar indicator showing signing status with full key management UI
- Shared SigningKeyManager QML component for settings and indicator
- Track active key name per vehicle with proper signal emission

Includes unit tests (SigningTest: 5 tests) and integration tests
(MockLinkSigningTest: 3 tests) with QSignalSpy verification.

Also renames docs/settings_view/mavlink.md to telemetry.md to match
current UI naming.

Fixes #14160
@github-actions

github-actions Bot commented Mar 21, 2026

Copy link
Copy Markdown

Build Results

Platform Status

Platform Status Details
Linux Failed View
Windows Passed View
MacOS Passed View
Android Passed View

Some builds failed.

Pre-commit

Check Status Details
pre-commit Failed (non-blocking) View

Pre-commit hooks: 4 passed, 34 failed, 7 skipped.

Artifact Sizes

Artifact Size
QGroundControl 330.58 MB
QGroundControl 320.65 MB
QGroundControl-installer-AMD64 151.38 MB
QGroundControl-installer-AMD64-ARM64 77.64 MB
QGroundControl-installer-ARM64 78.58 MB
QGroundControl-mac 184.59 MB
QGroundControl-windows 184.63 MB

No baseline available for comparison


Updated: 2026-03-21 12:16:35 UTC • Triggered by: Android

@NICourced
NICourced merged commit a4fa53e into NICourced:master Mar 21, 2026
28 of 30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.