Employees + USB default-disabled with an enable-time provisioning note
Both plugins provision extra tables, so they now install disabled and explain
themselves before a site opts in.
- Plugin contract gains get_provisioning_note() -> {tables, note, docs}.
Employees and USB implement it (what tables get created in shopdb, how they
are referenced, link to the schema README; USB references the captured
DLP/reminder plans).
- Manifest default_enabled=false for employees + usb; the plugins list API
returns provisioning_note + default_enabled; install now registers a plugin
disabled when default_enabled is false.
- Setup wizard Features step renders the provisioning note the moment a plugin
with one is enabled.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -147,6 +147,11 @@ class PluginManager:
|
||||
config_schema = temp.get_config_schema()
|
||||
except Exception:
|
||||
config_schema = []
|
||||
try:
|
||||
provisioning_note = temp.get_provisioning_note()
|
||||
except Exception:
|
||||
provisioning_note = None
|
||||
manifest = self.loader.load_manifest(name)
|
||||
available.append({
|
||||
'name': meta.name,
|
||||
'version': meta.version,
|
||||
@@ -157,6 +162,8 @@ class PluginManager:
|
||||
'enabled': state.enabled if state else False,
|
||||
'installedat': state.installed_at if state else None,
|
||||
'config_schema': config_schema,
|
||||
'provisioning_note': provisioning_note,
|
||||
'default_enabled': manifest.get('default_enabled', True),
|
||||
})
|
||||
except Exception as e:
|
||||
logger.warning(f"Error inspecting plugin {name}: {e}")
|
||||
@@ -203,7 +210,10 @@ class PluginManager:
|
||||
return False
|
||||
|
||||
# Register plugin
|
||||
self.registry.register(name, manifest_version)
|
||||
# Plugins that provision extra tables install disabled until a site
|
||||
# opts in (manifest default_enabled=false).
|
||||
self.registry.register(name, manifest_version,
|
||||
enabled=manifest.get('default_enabled', True))
|
||||
|
||||
# Load the plugin
|
||||
plugin = self.loader.load_plugin(name, self._app, self._db)
|
||||
|
||||
@@ -74,6 +74,20 @@ class BasePlugin(ABC):
|
||||
"""Return dict of service name -> service class."""
|
||||
return {}
|
||||
|
||||
def get_provisioning_note(self) -> Optional[Dict]:
|
||||
"""Transparency note shown when a site enables this plugin.
|
||||
|
||||
Return None for plugins that need no special setup. For plugins that
|
||||
create extra tables (e.g. a self-hosted directory or USB tables), return:
|
||||
{
|
||||
'tables': ['directoryemployees', ...], # created in the shopdb DB
|
||||
'note': 'Plain-language what/why.',
|
||||
'docs': 'plugins/<name>/README.md', # where the schema lives
|
||||
}
|
||||
The setup wizard shows this the moment the plugin is checked.
|
||||
"""
|
||||
return None
|
||||
|
||||
def get_config_schema(self) -> List[Dict]:
|
||||
"""Declare the config fields this plugin needs, for the setup wizard.
|
||||
|
||||
|
||||
@@ -53,13 +53,14 @@ class PluginRegistry:
|
||||
}
|
||||
}, f, indent=2)
|
||||
|
||||
def register(self, name: str, version: str) -> PluginState:
|
||||
"""Register a newly installed plugin."""
|
||||
def register(self, name: str, version: str, enabled: bool = True) -> PluginState:
|
||||
"""Register a newly installed plugin. enabled=False leaves it off until a
|
||||
site opts in (used for plugins that provision extra tables)."""
|
||||
state = PluginState(
|
||||
name=name,
|
||||
version=version,
|
||||
installed_at=datetime.utcnow().isoformat(),
|
||||
enabled=True
|
||||
enabled=enabled
|
||||
)
|
||||
self._plugins[name] = state
|
||||
self._save()
|
||||
|
||||
Reference in New Issue
Block a user