Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
4d6cbb4
feat: add stable plugin identities
PierreRaybaut Aug 8, 2026
af79523
Fixed various pylint warnings
PierreRaybaut Aug 8, 2026
ccb81ef
feat: add plugin-owned processing lifecycle
PierreRaybaut Aug 8, 2026
151f6f4
fix(pylint): add missing command palette action attribute initialization
PierreRaybaut Aug 8, 2026
5b29cb8
feat: add typed plugin capabilities
PierreRaybaut Aug 8, 2026
97f3971
feat: discover installed plugins by entry point
PierreRaybaut Aug 8, 2026
eea8458
feat: add headless plugin recipe contracts
PierreRaybaut Aug 8, 2026
bfae2be
feat: add transactional desktop recipe runner
PierreRaybaut Aug 8, 2026
1ca542a
feat: add local recipe run provenance
PierreRaybaut Aug 8, 2026
b7b8b9a
feat: add packaged plugin examples
PierreRaybaut Aug 8, 2026
a9ce4a4
feat: add minimal plugin project generator
PierreRaybaut Aug 8, 2026
5defdf6
feat: harden layered plugin project generator
PierreRaybaut Aug 9, 2026
3fca72c
fix: keep generated plugin metadata Ruff-compatible
PierreRaybaut Aug 9, 2026
ce8533a
feat: add Applications plugin catalog
PierreRaybaut Aug 9, 2026
9da44b7
feat: add Applications catalog actions
PierreRaybaut Aug 10, 2026
dda8165
fix: report plugin launcher failures in Applications catalog
PierreRaybaut Aug 10, 2026
2fc7153
fix: preserve rollback failure cause in RecipeCommitError
PierreRaybaut Aug 10, 2026
c422068
fix: reject blank plugin IDs at declaration
PierreRaybaut Aug 10, 2026
4033c9a
docs: document recipe provenance schema and plugin lifecycle hooks
PierreRaybaut Aug 10, 2026
d9fbd6b
feat: support generated plugin examples
PierreRaybaut Aug 11, 2026
ef38ef9
feat: improve Applications catalog readability
PierreRaybaut Aug 11, 2026
08def56
docs: plan business plugin architecture and lifecycle evolution
PierreRaybaut Aug 11, 2026
aae9388
fix: remove text from Applications menu action
PierreRaybaut Aug 11, 2026
eacfca1
feat: enhance color handling in CatalogItemDelegate for improved UI r…
PierreRaybaut Aug 11, 2026
9ad5e7a
refactor: remove unused assertions in application and plugin config d…
PierreRaybaut Aug 11, 2026
c6e20da
feat: open generated plugin examples on Desktop
PierreRaybaut Aug 11, 2026
399c854
fix: translate plugin recipe vocabulary as "méthodes" in French UI
PierreRaybaut Aug 11, 2026
0633d01
Enhance performance and functionality of object handling and plotting
PierreRaybaut Aug 11, 2026
51fde83
feat: implement non-modal applications dialog and enhance recipe outp…
PierreRaybaut Aug 11, 2026
55f300c
chore: remove plugin roadmap draft from repository
PierreRaybaut Oct 5, 2026
49a3835
Merge branch 'develop' into feat/plugin-sdk-implementation
PierreRaybaut Oct 5, 2026
e780634
fix: surface calc errors instead of retrying other panels
PierreRaybaut Oct 5, 2026
6cd66bb
feat: require <plugin_id>:<local_id> IDs for plugin-owned features
PierreRaybaut Oct 5, 2026
4cc84b6
fix: keep plugin feature IDs through result deletion and replay
PierreRaybaut Oct 5, 2026
d1fec3f
style: format plugin_examples with ruff
PierreRaybaut Oct 5, 2026
378ecf6
docs(i18n): update French catalogs for the plugin SDK
PierreRaybaut Oct 5, 2026
0d6b78e
fix: avoid importlib.abc.Traversable removed in Python 3.14
PierreRaybaut Oct 5, 2026
f728496
test: patch plugin settings by object, not via faked import_module
PierreRaybaut Oct 5, 2026
8786682
test: pass monkeypatch when running h5workspace test as a script
PierreRaybaut Oct 5, 2026
f783180
Merge branch 'develop' into feat/plugin-sdk-implementation
PierreRaybaut Oct 6, 2026
4d25fa9
feat(plugins): add application tiles to the welcome page
PierreRaybaut Oct 6, 2026
36a3f6a
fix(plugins): report missing zipped resources on Python 3.9
PierreRaybaut Oct 6, 2026
f3bb855
feat(plugins): show plugin icons in the catalog and configuration dialog
PierreRaybaut Oct 6, 2026
9d6ace0
Merge branch 'develop' into feat/plugin-sdk-implementation
PierreRaybaut Oct 6, 2026
546d455
feat(welcome): keep application tiles tidy with many plugins
PierreRaybaut Oct 6, 2026
2a73dad
feat(plugins): generic recipe launcher with live input readiness
PierreRaybaut Oct 7, 2026
52437e6
feat: collapsible application list, method accordion and welcome page…
PierreRaybaut Oct 7, 2026
0cbda5c
Merge remote-tracking branch 'origin/develop' into feat/plugin-sdk-im…
PierreRaybaut Oct 7, 2026
e9d9dd2
feat(applications): guide users to set the metadata methods expect (#…
PierreRaybaut Oct 7, 2026
c4e8494
feat(plugins): menu entries, selection gating and instruments for too…
PierreRaybaut Oct 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions datalab/aiassistant/tools/builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ def _tool_list_available_operations(
param_fields = [{"name": "?", "info": "introspection failed"}]
ops.append(
{
"feature_id": feature.feature_id,
"owner_plugin_id": feature.owner_plugin_id,
"name": feature.name,
"title": feature.title,
"pattern": feature.pattern,
Expand Down Expand Up @@ -449,8 +451,12 @@ def _tool_apply_operation(
f"Cannot set parameter {key!r} on "
f"{feature.paramclass.__name__}: {exc}"
) from exc
proxy.calc(name, param_obj)
return {"operation": name, "panel": proxy.get_current_panel()}
proxy.calc(feature.feature_id, param_obj)
return {
"operation": name,
"feature_id": feature.feature_id,
"panel": proxy.get_current_panel(),
}


# =============================================================================
Expand Down
42 changes: 41 additions & 1 deletion datalab/config/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def __init__(self) -> None:
"plugins_enabled_list",
category="main",
default=None,
description="Enabled plugin names (None = all, [] = none, or a list).",
description="Enabled plugin IDs (None = all, [] = none, or a list).",
)
self.plugins_path = TypedOptionField(
self,
Expand Down Expand Up @@ -158,6 +158,46 @@ def __init__(self) -> None:
"current signal or image panel is empty."
),
)
self.welcome_application_rows = TypedOptionField(
self,
"welcome_application_rows",
category="main",
default=2,
expected_type=int,
description="Maximum number of application tile rows on the welcome page.",
)
self.welcome_pinned_applications = TypedOptionField(
self,
"welcome_pinned_applications",
category="main",
default=[],
expected_type=list,
description="IDs of the applications pinned on the welcome page.",
)
self.welcome_hidden_applications = TypedOptionField(
self,
"welcome_hidden_applications",
category="main",
default=[],
expected_type=list,
description="IDs of the applications hidden from the welcome page.",
)
self.welcome_recent_applications = TypedOptionField(
self,
"welcome_recent_applications",
category="main",
default=[],
expected_type=list,
description="IDs of the recently used applications, most recent first.",
)
self.applications_list_collapsed = TypedOptionField(
self,
"applications_list_collapsed",
category="main",
default=False,
expected_type=bool,
description="If True, hide the application list of the catalog.",
)
self.v020_plugins_warning_ignore = TypedOptionField(
self,
"v020_plugins_warning_ignore",
Expand Down
26 changes: 24 additions & 2 deletions datalab/gui/actionhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@

from datalab.gui.panel.image import ImagePanel
from datalab.gui.panel.signal import SignalPanel
from datalab.gui.processor.base import ProcessingParameters
from datalab.objectmodel import ObjectGroup


Expand Down Expand Up @@ -375,7 +376,7 @@ def _delete_single_result(
analysis_params = extract_analysis_parameters(obj)
if (
analysis_params is not None
and analysis_params.func_name == adapter.func_name
and self.__get_analysis_function_name(analysis_params) == adapter.func_name
):
clear_analysis_parameters(obj)
adapter.remove_from(obj)
Expand All @@ -390,6 +391,27 @@ def _delete_single_result(
# Use the same refresh pattern as delete_results() method
self.panel.refresh_plot("selected", True, False)

def __get_analysis_function_name(self, params: ProcessingParameters) -> str:
"""Return the computation function name behind stored analysis parameters.

Results are named after their computation function, whereas analysis
parameters store the feature ID, which is namespaced for plugin features.

Args:
params: Stored analysis parameters

Returns:
Function name of the registered feature, or the local part of the
stored feature ID if the feature is not registered.
"""
try:
feature = self.panel.processor.get_feature(
params.func_name, plugin_origin=params.plugin_origin
)
except ValueError:
return params.func_name.rsplit(":", 1)[-1]
return feature.name

def clear_plugin_actions(self) -> None:
"""Clear plugin actions and submenus"""
self.feature_actions.pop(ActionCategory.PLUGINS, None)
Expand Down Expand Up @@ -646,7 +668,7 @@ def action_for(
feature.action_title,
position=position,
separator=separator,
triggered=lambda: self.panel.processor.run_feature(feature.function),
triggered=lambda: self.panel.processor.run_feature(feature.feature_id),
select_condition=condition,
icon_name=feature.icon_name,
tip=feature.comment,
Expand Down
Loading
Loading