Say what a plugin settings tab can actually do, and catch a declaration that cannot work
Finding F12 of the architectural review, checked against the code and found worse than reported: the dynamic component import cannot be rewritten by the bundler, so the built file ships the unresolved path and a plugin tab answers 404 in every production build, staged or not. It works only under the dev server. Nothing shipping is affected, because the one plugin that declares a tab also registers the same page as an ordinary route, and that is the one sites reach. - The ADR draft now carries a "Constraints as implemented" section: only the model catalog hub registers plugin tabs, registration happens when that hub mounts so a tab is not deep-linkable and does not survive a refresh, and the build finding above with the bundler's own warning. The two ways out are stated as the open decision rather than taken. - The hook's docstring reads as instructions to a plugin author, and its example no longer names a path that does not exist at build time. - A route declared for a hub that cannot render it is dropped with an error naming the plugin, the hub and the hubs that do work, and the same is logged at startup. Enabling the plugin still succeeds: a tab nobody can reach is no reason to take a working backend offline. - Tests hold the two halves together: no bundled plugin may declare a hub the frontend does not implement, and the list in the server must equal the hubs that really register routes, so the two cannot drift apart again.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from flask import Blueprint, current_app, request
|
||||
from flask_jwt_extended import jwt_required
|
||||
|
||||
from shopdb.plugins.base import renderable_settings_routes
|
||||
from shopdb.utils.responses import success_response, error_response, ErrorCodes
|
||||
|
||||
from shopdb.utils.authz import require_role
|
||||
@@ -60,6 +61,13 @@ def get_plugin_settings_routes():
|
||||
component paths - free reconnaissance about which modules a site runs. The
|
||||
login page never calls this, so gating it costs nothing pre-login.
|
||||
|
||||
A route naming a hub that has no code to draw plugin tabs is DROPPED here,
|
||||
loudly. Returning it would put an entry in a response that nothing reads:
|
||||
the plugin author sees a correct declaration and an API that accepts it, and
|
||||
the tab never appears anywhere. Dropping it costs the same missing tab and
|
||||
leaves a line in the log that says which plugin, which hub, and what the
|
||||
supported set is. See SETTINGS_HUBS_WITH_PLUGIN_TABS in shopdb/plugins/base.
|
||||
|
||||
Returns: { routes: [{hub, path, name, tab, component}, ...] }
|
||||
"""
|
||||
pm = current_app.extensions.get('plugin_manager')
|
||||
@@ -81,8 +89,8 @@ def get_plugin_settings_routes():
|
||||
'get_settings_routes failed for plugin %s; skipping it',
|
||||
plugin_name)
|
||||
continue
|
||||
if plugin_routes:
|
||||
routes.extend(plugin_routes)
|
||||
routes.extend(renderable_settings_routes(plugin_name, plugin_routes,
|
||||
current_app.logger))
|
||||
|
||||
return success_response({'routes': routes})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user