mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 21:43:05 +09:00
Introduce a plugin installation and management system. Backend: add InstalledPlugin model, plugin_service with download/install/enable/disable/uninstall, dynamic blueprint registration and frontend manifest generation, and plugins API endpoints (list/get/install/enable/disable/uninstall). Register plugins blueprint and attempt to hot-load installed plugin blueprints at app startup. Frontend: add PluginLoader component (Vite import.meta.glob) to render plugin widgets, extend Marketplace UI to install/manage plugins, add API client methods for plugins, and update styles for the marketplace plugin UI. This enables installing plugins from GitHub/repos/zips and managing them from the app.
90 lines
3.3 KiB
Python
90 lines
3.3 KiB
Python
"""Installed plugin tracking model."""
|
|
from datetime import datetime
|
|
from app import db
|
|
import json
|
|
|
|
|
|
class InstalledPlugin(db.Model):
|
|
"""Tracks plugins installed from external sources (zips/URLs)."""
|
|
__tablename__ = 'installed_plugins'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(128), nullable=False, unique=True)
|
|
display_name = db.Column(db.String(256), nullable=False)
|
|
slug = db.Column(db.String(128), nullable=False, unique=True)
|
|
version = db.Column(db.String(32), nullable=False)
|
|
description = db.Column(db.Text)
|
|
author = db.Column(db.String(128))
|
|
homepage = db.Column(db.String(512))
|
|
repository = db.Column(db.String(512))
|
|
license = db.Column(db.String(64))
|
|
category = db.Column(db.String(64))
|
|
|
|
# Where it came from
|
|
source_url = db.Column(db.String(1024))
|
|
source_type = db.Column(db.String(32), default='url') # url, local, marketplace
|
|
|
|
# Paths relative to ServerKit root
|
|
backend_path = db.Column(db.String(512)) # e.g. app/plugins/serverkit-ai
|
|
frontend_path = db.Column(db.String(512)) # e.g. src/plugins/serverkit-ai
|
|
|
|
# Blueprint registration info from manifest
|
|
entry_point = db.Column(db.String(256)) # e.g. blueprint:ai_assistant_bp
|
|
url_prefix = db.Column(db.String(256)) # e.g. /api/v1/ai-assistant
|
|
|
|
# Frontend entry from manifest
|
|
frontend_entry = db.Column(db.String(256)) # e.g. components/AiAssistant.jsx
|
|
|
|
# Full manifest stored as JSON
|
|
manifest_json = db.Column(db.Text)
|
|
|
|
# Status
|
|
STATUS_ACTIVE = 'active'
|
|
STATUS_DISABLED = 'disabled'
|
|
STATUS_ERROR = 'error'
|
|
STATUS_INSTALLING = 'installing'
|
|
status = db.Column(db.String(32), default=STATUS_INSTALLING)
|
|
error_message = db.Column(db.Text)
|
|
|
|
# Has frontend component that needs rebuild
|
|
has_frontend = db.Column(db.Boolean, default=False)
|
|
# Has backend blueprint
|
|
has_backend = db.Column(db.Boolean, default=False)
|
|
|
|
installed_by = db.Column(db.Integer, db.ForeignKey('users.id'))
|
|
installed_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
@property
|
|
def manifest(self):
|
|
return json.loads(self.manifest_json) if self.manifest_json else {}
|
|
|
|
@manifest.setter
|
|
def manifest(self, v):
|
|
self.manifest_json = json.dumps(v)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'id': self.id,
|
|
'name': self.name,
|
|
'display_name': self.display_name,
|
|
'slug': self.slug,
|
|
'version': self.version,
|
|
'description': self.description,
|
|
'author': self.author,
|
|
'homepage': self.homepage,
|
|
'repository': self.repository,
|
|
'license': self.license,
|
|
'category': self.category,
|
|
'source_url': self.source_url,
|
|
'source_type': self.source_type,
|
|
'entry_point': self.entry_point,
|
|
'url_prefix': self.url_prefix,
|
|
'has_frontend': self.has_frontend,
|
|
'has_backend': self.has_backend,
|
|
'status': self.status,
|
|
'error_message': self.error_message,
|
|
'installed_at': self.installed_at.isoformat() if self.installed_at else None,
|
|
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
|
|
}
|