mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-22 11:17:04 +03:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f34eb18d1 | ||
|
|
3a822c02b2 | ||
|
|
84967d4c87 | ||
|
|
6981870554 | ||
|
|
7c06038072 | ||
|
|
86be15d474 | ||
|
|
2c64f83d05 | ||
|
|
6cc024ed91 | ||
|
|
607343292b | ||
|
|
03f74d77e4 | ||
|
|
1cf86ed4b5 | ||
|
|
c4570098a4 | ||
|
|
45fe2189f9 | ||
|
|
852ebddf3b | ||
|
|
7baf6af346 | ||
|
|
030c6a4d6d | ||
|
|
39759e2da0 | ||
|
|
9447f21de8 | ||
|
|
0fe25f61b3 | ||
|
|
96aa00f33b | ||
|
|
e5e9eb02bc | ||
|
|
898a03f676 |
2
.github/workflows/testing.yml
vendored
2
.github/workflows/testing.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Build and run Docker image
|
||||
run: |
|
||||
docker build -t gns3-gui-test .
|
||||
|
||||
11
CHANGELOG
11
CHANGELOG
@@ -1,5 +1,16 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.59 08/05/2026
|
||||
|
||||
* Remove psutil version check
|
||||
* Fix remaining PyQt6 compatibility issues. Fixes #3822
|
||||
* Add --title to remote-viewer console commands. Fixes #3783
|
||||
* Fix deleting drawings. Ref #3810
|
||||
|
||||
## 2.2.58.1 12/04/2026
|
||||
|
||||
* Fix callback issues in found in v2.2.58
|
||||
|
||||
## 2.2.58 10/04/2026
|
||||
|
||||
* Update snapshot date & time format
|
||||
|
||||
@@ -3,7 +3,7 @@ FROM ubuntu:latest
|
||||
MAINTAINER GNS3 Team
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y --force-yes python3 python3-pyqt5 python3-pip python3-pyqt5.qtsvg python3-pyqt5.qtwebsockets python3-dev xvfb
|
||||
RUN apt-get install -y --force-yes python3 python3-pyqt6 python3-pip python3-pyqt6.qtsvg python3-pyqt6.qtwebsockets python3-dev xvfb
|
||||
RUN apt-get clean
|
||||
|
||||
ADD dev-requirements.txt /dev-requirements.txt
|
||||
|
||||
@@ -217,7 +217,7 @@ class ComputeManager(QtCore.QObject):
|
||||
|
||||
if compute_id in self._computes:
|
||||
del self._computes[compute_id]
|
||||
self._controller.delete("/computes/{compute_id}".format(compute_id=compute_id))
|
||||
self._controller.delete("/computes/{compute_id}".format(compute_id=compute_id), None)
|
||||
self.deleted_signal.emit(compute_id)
|
||||
|
||||
def updateList(self, computes):
|
||||
|
||||
@@ -247,7 +247,7 @@ class Controller(QtCore.QObject):
|
||||
|
||||
def createHTTPQuery(self, method, path, *args, **kwargs):
|
||||
"""
|
||||
Forward the query to the HTTP client or controller depending of the path
|
||||
Forward the query to the HTTP client or controller depending on the path
|
||||
"""
|
||||
|
||||
if self._http_client:
|
||||
|
||||
@@ -50,7 +50,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://6eeccf4e06aaf1752e4244e27e81ffed@o19455.ingest.us.sentry.io/38506"
|
||||
DSN = "https://dd662ce99d7e4a04714a89939ec523c9@o19455.ingest.us.sentry.io/38506"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -580,7 +580,7 @@ class HTTPClient(QtCore.QObject):
|
||||
:param body: params to send (dictionary)
|
||||
:param callback: callback method to call when the server replies
|
||||
:param context: Pass a context to the response callback
|
||||
:param downloadProgressCallback: Callback called when received something, it can be an incomplete response
|
||||
:param downloadProgressCallback: callback called when received something, it can be an incomplete response
|
||||
:param showProgress: Display progress to the user
|
||||
:param networkManager: The network manager to use. If None use default
|
||||
:param progressText: Text display to user in progress dialog. None for auto generated
|
||||
@@ -606,7 +606,7 @@ class HTTPClient(QtCore.QObject):
|
||||
request = self._addAuth(request)
|
||||
request.setRawHeader(b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode())
|
||||
|
||||
# By default QT doesn't support GET with body even if it's in the RFC that's why we need to use sendCustomRequest
|
||||
# By default, QT doesn't support GET with body even if it's in the RFC that's why we need to use sendCustomRequest
|
||||
body = self._addBodyToRequest(body, request)
|
||||
|
||||
if not networkManager:
|
||||
@@ -616,12 +616,13 @@ class HTTPClient(QtCore.QObject):
|
||||
response = networkManager.sendCustomRequest(request, method.encode(), body)
|
||||
except SystemError as e:
|
||||
log.error("Can't send query: {}".format(str(e)))
|
||||
return
|
||||
return None
|
||||
|
||||
if context:
|
||||
context = copy.copy(context)
|
||||
else:
|
||||
context = {"query_id": str(uuid.uuid4())}
|
||||
context = dict()
|
||||
context["query_id"] = str(uuid.uuid4())
|
||||
|
||||
response.finished.connect(qpartial(self._processResponse, response, server, callback, context, body, ignoreErrors))
|
||||
response.errorOccurred.connect(qpartial(self._processError, response, server, callback, context, body, ignoreErrors))
|
||||
|
||||
@@ -106,6 +106,11 @@ class DrawingItem:
|
||||
"""
|
||||
|
||||
if error:
|
||||
if "doesn't exist" in result.get("message", ""):
|
||||
log.warning("Drawing not found on server, recreating: {}".format(self._id))
|
||||
self._id = None
|
||||
self.create()
|
||||
return True
|
||||
log.error("Error while updating drawing: {}".format(result["message"]))
|
||||
return False
|
||||
self.setPos(QtCore.QPointF(result["x"], result["y"]))
|
||||
@@ -214,7 +219,7 @@ class DrawingItem:
|
||||
"""
|
||||
Deletes this drawing.
|
||||
|
||||
:param skip_controller: Do not replicate change on the controller (usefull when it's already deleted on controller)
|
||||
:param skip_controller: Do not replicate change on the controller (useful when it's already deleted on controller)
|
||||
"""
|
||||
|
||||
self.setDeleting()
|
||||
@@ -222,7 +227,7 @@ class DrawingItem:
|
||||
from ..topology import Topology
|
||||
Topology.instance().removeDrawing(self)
|
||||
if self._id and not skip_controller:
|
||||
self._project.delete("/drawings/" + self._id, None, body=self.__json__())
|
||||
self._project.delete("/drawings/" + self._id, None)
|
||||
|
||||
def itemChange(self, change, value):
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ class TextItem(QtWidgets.QGraphicsTextItem, DrawingItem):
|
||||
text.set("text-decoration", "underline")
|
||||
text.set("fill", "#" + hex(self.defaultTextColor().rgba())[4:])
|
||||
text.set("fill-opacity", str(self.defaultTextColor().alphaF()))
|
||||
text.text = self.toPlainText()
|
||||
text.text = self.toPlainText() or " "
|
||||
|
||||
svg = ET.tostring(svg, encoding="utf-8").decode("utf-8")
|
||||
return svg
|
||||
|
||||
@@ -36,7 +36,6 @@ import time
|
||||
import locale
|
||||
import argparse
|
||||
import signal
|
||||
import psutil
|
||||
|
||||
try:
|
||||
from gns3.qt import QtCore, QtWidgets
|
||||
@@ -191,9 +190,6 @@ def main():
|
||||
if parse_version(QtCore.QT_VERSION_STR) < parse_version("6.3.1"):
|
||||
raise SystemExit("Requirement is PyQt6 version 6.3.1 or higher, got version {}".format(QtCore.QT_VERSION_STR))
|
||||
|
||||
if parse_version(psutil.__version__) < parse_version("2.2.1"):
|
||||
raise SystemExit("Requirement is psutil version 2.2.1 or higher, got version {}".format(psutil.__version__))
|
||||
|
||||
# check for the correct locale
|
||||
# (UNIX/Linux only)
|
||||
locale_check()
|
||||
|
||||
@@ -208,7 +208,7 @@ else:
|
||||
'TightVNC': 'vncviewer {host}:{port}',
|
||||
'Vinagre': 'vinagre {host}::{port}',
|
||||
'gvncviewer': 'gvncviewer {host}:{display}',
|
||||
'Remote Viewer': 'remote-viewer vnc://{host}:{port}',
|
||||
'Remote Viewer': 'remote-viewer --title "({name})" vnc://{host}:{port}',
|
||||
'KRDC': 'krdc vnc://{host}:{port}'
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ else:
|
||||
if sys.platform.startswith("win"):
|
||||
# Windows
|
||||
PRECONFIGURED_SPICE_CONSOLE_COMMANDS = {
|
||||
'Remote Viewer': r'"{}\VirtViewer v11.0-256\bin\remote-viewer.exe" spice://{{host}}:{{port}}'.format(program_files),
|
||||
'Remote Viewer': r'"{}\VirtViewer v11.0-256\bin\remote-viewer.exe" --title "({{name}})" spice://{{host}}:{{port}}'.format(program_files),
|
||||
}
|
||||
|
||||
# default Windows SPICE console command
|
||||
@@ -228,7 +228,7 @@ if sys.platform.startswith("win"):
|
||||
elif sys.platform.startswith("darwin"):
|
||||
# Mac OS X
|
||||
PRECONFIGURED_SPICE_CONSOLE_COMMANDS = {
|
||||
'Remote Viewer': '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer spice://{host}:{port}',
|
||||
'Remote Viewer': '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer --title "({name})" spice://{host}:{port}',
|
||||
}
|
||||
|
||||
# default Mac OS X SPICE console command
|
||||
@@ -236,7 +236,7 @@ elif sys.platform.startswith("darwin"):
|
||||
|
||||
else:
|
||||
PRECONFIGURED_SPICE_CONSOLE_COMMANDS = {
|
||||
'Remote Viewer': 'remote-viewer spice://{host}:{port}',
|
||||
'Remote Viewer': 'remote-viewer --title "({name})" spice://{host}:{port}',
|
||||
}
|
||||
|
||||
# default SPICE console command on other systems
|
||||
|
||||
@@ -81,7 +81,7 @@ class TemplateManager(QtCore.QObject):
|
||||
if template_id in self._templates and not self._templates[template_id].builtin():
|
||||
template = self._templates[template_id]
|
||||
log.debug("Delete template '{}' (ID={})".format(template.name(), template_id))
|
||||
self._controller.delete("/templates/{template_id}".format(template_id=template_id))
|
||||
self._controller.delete("/templates/{template_id}".format(template_id=template_id), None)
|
||||
|
||||
def deleteTemplateCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.58"
|
||||
__version_info__ = (2, 2, 58, 0)
|
||||
__version__ = "2.2.59"
|
||||
__version_info__ = (2, 2, 59, 0)
|
||||
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
jsonschema==4.25.1; python_version == '3.9' # version 4.25.1 is the last to support Python 3.9
|
||||
jsonschema>=4.26.0,<4.27; python_version >= '3.10'
|
||||
sentry-sdk>=2.52.0,<3 # optional dependency
|
||||
sentry-sdk>=2.59.0,<3 # optional dependency
|
||||
psutil>=7.2.2
|
||||
distro>=1.9.0
|
||||
truststore>=0.10.4; python_version >= '3.10'
|
||||
|
||||
2
setup.py
2
setup.py
@@ -79,7 +79,7 @@ setup(
|
||||
include_package_data=True,
|
||||
package_data={"gns3": ["configs/*.txt", "schemas/*.json"]},
|
||||
platforms="any",
|
||||
python_requires=">=3.8",
|
||||
python_requires=">=3.9",
|
||||
setup_requires=["setuptools>=45.2"],
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -66,7 +66,6 @@ def test_get_connected(http_client, http_request, network_manager, response):
|
||||
|
||||
http_client.createHTTPQuery("GET", "/test", callback)
|
||||
http_request.assert_called_with(QtCore.QUrl("http://127.0.0.1:3080/v2/test"))
|
||||
http_request.setRawHeader.assert_any_call(b"Content-Type", b"application/json")
|
||||
http_request.setRawHeader.assert_any_call(b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode())
|
||||
assert network_manager.sendCustomRequest.called
|
||||
args, kwargs = network_manager.sendCustomRequest.call_args
|
||||
@@ -80,7 +79,7 @@ def test_get_connected(http_client, http_request, network_manager, response):
|
||||
|
||||
|
||||
def test_paramsToQueryString(http_client):
|
||||
assert http_client._paramsToQueryString({}) == ""
|
||||
assert http_client._paramsToQueryString(None) == ""
|
||||
res = http_client._paramsToQueryString({"a": 1, "b": 2})
|
||||
assert res == "?a=1&b=2" or res == "?b=2&a=1"
|
||||
res = http_client._paramsToQueryString({"a": 1, "b": 2, "c": None})
|
||||
@@ -96,7 +95,6 @@ def test_get_connected_auth(http_client, http_request, network_manager, response
|
||||
|
||||
http_client.createHTTPQuery("GET", "/test", callback)
|
||||
http_request.assert_called_with(QtCore.QUrl("http://gns3@127.0.0.1:3080/v2/test"))
|
||||
http_request.setRawHeader.assert_any_call(b"Content-Type", b"application/json")
|
||||
http_request.setRawHeader.assert_any_call(b"Authorization", b"Basic Z25zMzozc25n")
|
||||
http_request.setRawHeader.assert_any_call(b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode())
|
||||
assert network_manager.sendCustomRequest.called
|
||||
|
||||
@@ -65,7 +65,7 @@ def link(devices, controller, project):
|
||||
{"node_id": devices[0].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": devices[1].node_id(), "adapter_number": 0, "port_number": 0}
|
||||
],
|
||||
"link_style": {},
|
||||
"link_style": {'color': '#000000', 'width': 2, 'type': 1},
|
||||
"filters": {},
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ def test_create_link(devices, project, controller):
|
||||
{"node_id": devices[0].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
{"node_id": devices[1].node_id(), "adapter_number": 0, "port_number": 0},
|
||||
],
|
||||
"link_style": {},
|
||||
"link_style": {'color': '#000000', 'width': 2, 'type': 1},
|
||||
"filters": {},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user