synodic-client 0.0.1.dev55__tar.gz → 0.0.1.dev57__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/PKG-INFO +2 -2
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/pyproject.toml +3 -3
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/data.py +21 -1
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/plugin_row.py +68 -36
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/schema.py +30 -6
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/screen.py +353 -54
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/settings.py +39 -17
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/spinner.py +1 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/tool_update_controller.py +99 -11
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/tray.py +2 -1
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/theme.py +26 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/update_controller.py +38 -19
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/workers.py +48 -1
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/resolution.py +4 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_gather_packages.py +507 -12
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_settings.py +16 -8
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_update_controller.py +104 -141
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_update_feedback.py +106 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_resolution.py +18 -0
- synodic_client-0.0.1.dev57/tests/unit/test_workers.py +163 -0
- synodic_client-0.0.1.dev55/tests/unit/test_workers.py +0 -55
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/LICENSE.md +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/README.md +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/__main__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/bootstrap.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/icon.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/init.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/instance.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/qt.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/schema.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/action_card.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/card.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/install.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/install_workers.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/log_panel.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/projects.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/sidebar.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/screen/update_banner.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/uri.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/cli.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/client.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/config.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/logging.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/protocol.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/py.typed +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/schema.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/startup.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/updater.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/conftest.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/conftest.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_action_card.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_install_preview.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_log_panel.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_logging.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_preview_model.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_sidebar.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_tray_window_show.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/qt/test_update_banner.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_cli.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_client_updater.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_client_version.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_config.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_examples.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_init.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_install.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_updater.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/test_uri.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/windows/__init__.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/windows/conftest.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/windows/test_protocol.py +0 -0
- {synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/tests/unit/windows/test_startup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: synodic_client
|
|
3
|
-
Version: 0.0.1.
|
|
3
|
+
Version: 0.0.1.dev57
|
|
4
4
|
Author-Email: Synodic Software <contact@synodic.software>
|
|
5
5
|
License: LGPL-3.0-or-later
|
|
6
6
|
Project-URL: homepage, https://github.com/synodic/synodic-client
|
|
@@ -8,7 +8,7 @@ Project-URL: repository, https://github.com/synodic/synodic-client
|
|
|
8
8
|
Requires-Python: <3.15,>=3.14
|
|
9
9
|
Requires-Dist: pyside6>=6.10.2
|
|
10
10
|
Requires-Dist: packaging>=26.0
|
|
11
|
-
Requires-Dist: porringer>=0.2.1.
|
|
11
|
+
Requires-Dist: porringer>=0.2.1.dev77
|
|
12
12
|
Requires-Dist: qasync>=0.28.0
|
|
13
13
|
Requires-Dist: velopack>=0.0.1444.dev49733
|
|
14
14
|
Requires-Dist: typer>=0.24.1
|
|
@@ -10,12 +10,12 @@ requires-python = ">=3.14, <3.15"
|
|
|
10
10
|
dependencies = [
|
|
11
11
|
"pyside6>=6.10.2",
|
|
12
12
|
"packaging>=26.0",
|
|
13
|
-
"porringer>=0.2.1.
|
|
13
|
+
"porringer>=0.2.1.dev77",
|
|
14
14
|
"qasync>=0.28.0",
|
|
15
15
|
"velopack>=0.0.1444.dev49733",
|
|
16
16
|
"typer>=0.24.1",
|
|
17
17
|
]
|
|
18
|
-
version = "0.0.1.
|
|
18
|
+
version = "0.0.1.dev57"
|
|
19
19
|
|
|
20
20
|
[project.license]
|
|
21
21
|
text = "LGPL-3.0-or-later"
|
|
@@ -35,7 +35,7 @@ build = [
|
|
|
35
35
|
"pyinstaller>=6.19.0",
|
|
36
36
|
]
|
|
37
37
|
lint = [
|
|
38
|
-
"ruff>=0.15.
|
|
38
|
+
"ruff>=0.15.5",
|
|
39
39
|
"pyrefly>=0.55.0",
|
|
40
40
|
]
|
|
41
41
|
test = [
|
{synodic_client-0.0.1.dev55 → synodic_client-0.0.1.dev57}/synodic_client/application/data.py
RENAMED
|
@@ -22,6 +22,7 @@ from porringer.schema import (
|
|
|
22
22
|
CheckParameters,
|
|
23
23
|
CheckResult,
|
|
24
24
|
)
|
|
25
|
+
from porringer.schema.check import RuntimeCheckResult
|
|
25
26
|
|
|
26
27
|
from synodic_client.application.schema import Snapshot
|
|
27
28
|
|
|
@@ -107,7 +108,26 @@ class DataCoordinator:
|
|
|
107
108
|
A list of :class:`CheckResult` per plugin.
|
|
108
109
|
"""
|
|
109
110
|
params = CheckParameters(plugins=plugins)
|
|
110
|
-
return await self._porringer.
|
|
111
|
+
return await self._porringer.package.check_updates(
|
|
112
|
+
params,
|
|
113
|
+
plugins=self._snapshot.discovered,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
async def check_updates_by_runtime(
|
|
117
|
+
self,
|
|
118
|
+
plugins: list[str] | None = None,
|
|
119
|
+
) -> list[RuntimeCheckResult]:
|
|
120
|
+
"""Run per-runtime update detection using cached ``DiscoveredPlugins``.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
plugins: Optional include-set of plugin names. ``None``
|
|
124
|
+
means all plugins.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
A list of :class:`RuntimeCheckResult` per runtime.
|
|
128
|
+
"""
|
|
129
|
+
params = CheckParameters(plugins=plugins)
|
|
130
|
+
return await self._porringer.package.check_updates_by_runtime(
|
|
111
131
|
params,
|
|
112
132
|
plugins=self._snapshot.discovered,
|
|
113
133
|
)
|
|
@@ -25,6 +25,8 @@ from synodic_client.application.theme import (
|
|
|
25
25
|
FILTER_CHIP_STYLE,
|
|
26
26
|
PLUGIN_KIND_HEADER_STYLE,
|
|
27
27
|
PLUGIN_PROVIDER_NAME_STYLE,
|
|
28
|
+
PLUGIN_PROVIDER_RUNTIME_TAG_DEFAULT_STYLE,
|
|
29
|
+
PLUGIN_PROVIDER_RUNTIME_TAG_STYLE,
|
|
28
30
|
PLUGIN_PROVIDER_STATUS_INSTALLED_STYLE,
|
|
29
31
|
PLUGIN_PROVIDER_STATUS_MISSING_STYLE,
|
|
30
32
|
PLUGIN_PROVIDER_STYLE,
|
|
@@ -140,17 +142,19 @@ class PluginProviderHeader(QFrame):
|
|
|
140
142
|
self.setObjectName('pluginProvider')
|
|
141
143
|
self.setStyleSheet(PLUGIN_PROVIDER_STYLE)
|
|
142
144
|
self._plugin_name = plugin.name
|
|
145
|
+
self._runtime_tag = ''
|
|
146
|
+
self._signal_key = plugin.name
|
|
143
147
|
self._update_btn: QPushButton | None = None
|
|
144
148
|
self._checking_spinner: _RowSpinner | None = None
|
|
145
149
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
self._layout = QHBoxLayout(self)
|
|
151
|
+
self._layout.setContentsMargins(0, 0, 0, 0)
|
|
152
|
+
self._layout.setSpacing(6)
|
|
149
153
|
|
|
150
154
|
# Plugin name
|
|
151
155
|
name_label = QLabel(plugin.name)
|
|
152
156
|
name_label.setStyleSheet(PLUGIN_PROVIDER_NAME_STYLE)
|
|
153
|
-
|
|
157
|
+
self._layout.addWidget(name_label)
|
|
154
158
|
|
|
155
159
|
# Version
|
|
156
160
|
version_text = (
|
|
@@ -162,7 +166,7 @@ class PluginProviderHeader(QFrame):
|
|
|
162
166
|
)
|
|
163
167
|
version_label = QLabel(version_text)
|
|
164
168
|
version_label.setStyleSheet(PLUGIN_PROVIDER_VERSION_STYLE)
|
|
165
|
-
|
|
169
|
+
self._layout.addWidget(version_label)
|
|
166
170
|
|
|
167
171
|
# Installed indicator
|
|
168
172
|
status_label = QLabel('\u25cf' if plugin.installed else '\u25cb')
|
|
@@ -170,47 +174,73 @@ class PluginProviderHeader(QFrame):
|
|
|
170
174
|
PLUGIN_PROVIDER_STATUS_INSTALLED_STYLE if plugin.installed else PLUGIN_PROVIDER_STATUS_MISSING_STYLE
|
|
171
175
|
)
|
|
172
176
|
status_label.setToolTip('Installed' if plugin.installed else 'Not installed')
|
|
173
|
-
|
|
177
|
+
self._layout.addWidget(status_label)
|
|
174
178
|
|
|
175
|
-
|
|
179
|
+
self._layout.addStretch()
|
|
176
180
|
|
|
177
181
|
# Transient inline error label (hidden by default)
|
|
178
182
|
self._status_label = QLabel()
|
|
179
183
|
self._status_label.setStyleSheet(PLUGIN_ROW_ERROR_STYLE)
|
|
180
184
|
self._status_label.hide()
|
|
181
|
-
|
|
185
|
+
self._layout.addWidget(self._status_label)
|
|
182
186
|
|
|
183
187
|
# Auto / Update controls (only for updatable kinds)
|
|
184
188
|
if show_controls:
|
|
185
|
-
|
|
186
|
-
toggle_btn.setCheckable(True)
|
|
187
|
-
toggle_btn.setChecked(auto_update)
|
|
188
|
-
toggle_btn.setStyleSheet(PLUGIN_TOGGLE_STYLE)
|
|
189
|
-
toggle_btn.setToolTip('Enable automatic updates for this plugin')
|
|
190
|
-
toggle_btn.clicked.connect(
|
|
191
|
-
lambda checked: self.auto_update_toggled.emit(self._plugin_name, checked),
|
|
192
|
-
)
|
|
193
|
-
layout.addWidget(toggle_btn)
|
|
189
|
+
self._build_controls(self._layout, plugin, auto_update, has_updates)
|
|
194
190
|
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
def set_runtime(self, tag: str, label: str = '') -> None:
|
|
192
|
+
"""Set runtime identity and optionally insert a runtime tag pill.
|
|
197
193
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
Must be called before the widget is added to a visible layout.
|
|
195
|
+
"""
|
|
196
|
+
self._runtime_tag = tag
|
|
197
|
+
self._signal_key = f'{self._plugin_name}:{tag}' if tag else self._plugin_name
|
|
198
|
+
if label:
|
|
199
|
+
is_default = '(default)' in label
|
|
200
|
+
pill = QLabel(label)
|
|
201
|
+
pill.setStyleSheet(
|
|
202
|
+
PLUGIN_PROVIDER_RUNTIME_TAG_DEFAULT_STYLE if is_default else PLUGIN_PROVIDER_RUNTIME_TAG_STYLE
|
|
203
203
|
)
|
|
204
|
-
|
|
205
|
-
self.
|
|
206
|
-
|
|
204
|
+
# Insert after the name label (index 1)
|
|
205
|
+
self._layout.insertWidget(1, pill)
|
|
206
|
+
|
|
207
|
+
def _build_controls(
|
|
208
|
+
self,
|
|
209
|
+
layout: QHBoxLayout,
|
|
210
|
+
plugin: PluginInfo,
|
|
211
|
+
auto_update: bool,
|
|
212
|
+
has_updates: bool,
|
|
213
|
+
) -> None:
|
|
214
|
+
"""Build Auto/Update control buttons."""
|
|
215
|
+
toggle_btn = QPushButton('Auto')
|
|
216
|
+
toggle_btn.setCheckable(True)
|
|
217
|
+
toggle_btn.setChecked(auto_update)
|
|
218
|
+
toggle_btn.setStyleSheet(PLUGIN_TOGGLE_STYLE)
|
|
219
|
+
toggle_btn.setToolTip('Enable automatic updates for this plugin')
|
|
220
|
+
toggle_btn.clicked.connect(
|
|
221
|
+
lambda checked: self.auto_update_toggled.emit(self._signal_key, checked),
|
|
222
|
+
)
|
|
223
|
+
layout.addWidget(toggle_btn)
|
|
224
|
+
|
|
225
|
+
self._checking_spinner = _RowSpinner(self)
|
|
226
|
+
layout.addWidget(self._checking_spinner)
|
|
227
|
+
|
|
228
|
+
update_btn = QPushButton('Update')
|
|
229
|
+
update_btn.setStyleSheet(PLUGIN_UPDATE_STYLE)
|
|
230
|
+
update_btn.setToolTip(f'Upgrade packages via {plugin.name} now')
|
|
231
|
+
update_btn.clicked.connect(
|
|
232
|
+
lambda: self.update_requested.emit(self._signal_key),
|
|
233
|
+
)
|
|
234
|
+
update_btn.setVisible(has_updates)
|
|
235
|
+
self._update_btn = update_btn
|
|
236
|
+
layout.addWidget(update_btn)
|
|
207
237
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
238
|
+
if not plugin.installed:
|
|
239
|
+
toggle_btn.setEnabled(False)
|
|
240
|
+
toggle_btn.setChecked(False)
|
|
241
|
+
toggle_btn.setToolTip('Not installed \u2014 cannot auto-update')
|
|
242
|
+
update_btn.setEnabled(False)
|
|
243
|
+
update_btn.setToolTip('Not installed \u2014 cannot update')
|
|
214
244
|
|
|
215
245
|
def set_updating(self, updating: bool) -> None:
|
|
216
246
|
"""Toggle the button between *Updating…* and *Update* states."""
|
|
@@ -291,6 +321,8 @@ class PluginRow(QFrame):
|
|
|
291
321
|
self.setStyleSheet(PLUGIN_ROW_STYLE)
|
|
292
322
|
self._plugin_name = data.plugin_name
|
|
293
323
|
self._package_name = data.name
|
|
324
|
+
self._runtime_tag = data.runtime_tag
|
|
325
|
+
self._signal_key = f'{data.plugin_name}:{data.runtime_tag}' if data.runtime_tag else data.plugin_name
|
|
294
326
|
self._update_btn: QPushButton | None = None
|
|
295
327
|
self._remove_btn: QPushButton | None = None
|
|
296
328
|
self._checking_spinner: _RowSpinner | None = None
|
|
@@ -391,7 +423,7 @@ class PluginRow(QFrame):
|
|
|
391
423
|
toggle_btn.setToolTip('Auto-update this package')
|
|
392
424
|
toggle_btn.clicked.connect(
|
|
393
425
|
lambda checked: self.auto_update_toggled.emit(
|
|
394
|
-
self.
|
|
426
|
+
self._signal_key,
|
|
395
427
|
self._package_name,
|
|
396
428
|
checked,
|
|
397
429
|
),
|
|
@@ -408,7 +440,7 @@ class PluginRow(QFrame):
|
|
|
408
440
|
update_btn.setFixedWidth(PLUGIN_ROW_UPDATE_WIDTH)
|
|
409
441
|
update_btn.setToolTip(f'Update {data.name}')
|
|
410
442
|
update_btn.clicked.connect(
|
|
411
|
-
lambda: self.update_requested.emit(self.
|
|
443
|
+
lambda: self.update_requested.emit(self._signal_key, self._package_name),
|
|
412
444
|
)
|
|
413
445
|
update_btn.setVisible(data.has_update)
|
|
414
446
|
self._update_btn = update_btn
|
|
@@ -435,7 +467,7 @@ class PluginRow(QFrame):
|
|
|
435
467
|
if data.is_global:
|
|
436
468
|
remove_btn.setToolTip(f'Remove {data.name}')
|
|
437
469
|
remove_btn.clicked.connect(
|
|
438
|
-
lambda: self.remove_requested.emit(self.
|
|
470
|
+
lambda: self.remove_requested.emit(self._signal_key, self._package_name),
|
|
439
471
|
)
|
|
440
472
|
else:
|
|
441
473
|
remove_btn.setEnabled(False)
|
|
@@ -23,6 +23,7 @@ from porringer.schema import (
|
|
|
23
23
|
SubActionProgress,
|
|
24
24
|
SyncStrategy,
|
|
25
25
|
)
|
|
26
|
+
from porringer.schema.plugin import RuntimePackageResult
|
|
26
27
|
|
|
27
28
|
from synodic_client.application.screen.action_card import action_key
|
|
28
29
|
from synodic_client.application.uri import normalize_manifest_key
|
|
@@ -139,6 +140,9 @@ class PluginRowData:
|
|
|
139
140
|
host_tool: str = ''
|
|
140
141
|
"""Host-tool name for injected packages."""
|
|
141
142
|
|
|
143
|
+
runtime_tag: str = ''
|
|
144
|
+
"""Runtime tag for per-runtime packages (e.g. ``\"3.12\"``)."""
|
|
145
|
+
|
|
142
146
|
project_paths: list[str] = field(default_factory=list)
|
|
143
147
|
"""Filesystem paths for project-scoped packages."""
|
|
144
148
|
|
|
@@ -150,7 +154,7 @@ class PluginRowData:
|
|
|
150
154
|
|
|
151
155
|
|
|
152
156
|
@dataclass(slots=True)
|
|
153
|
-
class
|
|
157
|
+
class RefreshData:
|
|
154
158
|
"""Internal data bundle returned by ``ToolsView._gather_refresh_data``."""
|
|
155
159
|
|
|
156
160
|
plugins: list[PluginInfo]
|
|
@@ -162,6 +166,12 @@ class _RefreshData:
|
|
|
162
166
|
manifest_packages: dict[str, set[str]]
|
|
163
167
|
"""Mapping of plugin name → manifest-referenced package names."""
|
|
164
168
|
|
|
169
|
+
runtime_packages: dict[str, list[RuntimePackageResult]] = field(default_factory=dict)
|
|
170
|
+
"""Mapping of plugin name → per-runtime package results (RuntimeConsumer plugins only)."""
|
|
171
|
+
|
|
172
|
+
default_runtime_executable: Path | None = None
|
|
173
|
+
"""Executable path of the resolved default runtime, if any."""
|
|
174
|
+
|
|
165
175
|
|
|
166
176
|
# ---------------------------------------------------------------------------
|
|
167
177
|
# Install preview data models (from install.py)
|
|
@@ -351,11 +361,25 @@ class UpdateView(Protocol):
|
|
|
351
361
|
status stays in sync.
|
|
352
362
|
"""
|
|
353
363
|
|
|
354
|
-
def show_downloading(self, version: str) -> None:
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def
|
|
364
|
+
def show_downloading(self, version: str) -> None:
|
|
365
|
+
"""Indicate that *version* is being downloaded."""
|
|
366
|
+
...
|
|
367
|
+
|
|
368
|
+
def show_downloading_progress(self, percentage: int) -> None:
|
|
369
|
+
"""Update the download progress indicator."""
|
|
370
|
+
...
|
|
371
|
+
|
|
372
|
+
def show_ready(self, version: str) -> None:
|
|
373
|
+
"""Indicate that *version* is downloaded and ready to install."""
|
|
374
|
+
...
|
|
375
|
+
|
|
376
|
+
def show_error(self, message: str) -> None:
|
|
377
|
+
"""Display an error *message* in the update area."""
|
|
378
|
+
...
|
|
379
|
+
|
|
380
|
+
def hide_banner(self) -> None:
|
|
381
|
+
"""Hide the update banner."""
|
|
382
|
+
...
|
|
359
383
|
|
|
360
384
|
|
|
361
385
|
class UpdateBannerState(Enum):
|