diff --git a/backend/src/api/routes/environments.py b/backend/src/api/routes/environments.py index a74d128..cff6847 100644 --- a/backend/src/api/routes/environments.py +++ b/backend/src/api/routes/environments.py @@ -23,7 +23,7 @@ router = APIRouter() # [DEF:ScheduleSchema:DataClass] class ScheduleSchema(BaseModel): enabled: bool = False - cron_expression: str = Field(..., pattern=r'^(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|((((\d+,)*\d+|(\d+(\/|-)\d+)|\d+|\*) ?){5,7})$') + cron_expression: str = Field(..., pattern=r'^(@(annually|yearly|monthly|weekly|daily|hourly|reboot))|((((\d+,)*\d+|(\d+(\/|-)\d+)|\d+|\*) ?){4,6})$') # [/DEF:ScheduleSchema:DataClass] # [DEF:EnvironmentResponse:DataClass] diff --git a/backend/src/core/plugin_base.py b/backend/src/core/plugin_base.py index 64a4d85..82e19fc 100755 --- a/backend/src/core/plugin_base.py +++ b/backend/src/core/plugin_base.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import Dict, Any +from typing import Dict, Any, Optional from .logger import belief_scope from pydantic import BaseModel, Field @@ -68,6 +68,21 @@ class PluginBase(ABC): pass # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the plugin's UI, if applicable. + # @PRE: Plugin instance exists. + # @POST: Returns string route or None. + # @RETURN: Optional[str] - Frontend route. + def ui_route(self) -> Optional[str]: + """ + The frontend route for the plugin's UI. + Returns None if the plugin does not have a dedicated UI page. + """ + with belief_scope("ui_route"): + return None + # [/DEF:ui_route:Function] + @abstractmethod # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for the plugin's input parameters. @@ -111,5 +126,6 @@ class PluginConfig(BaseModel): name: str = Field(..., description="Human-readable name for the plugin") description: str = Field(..., description="Brief description of what the plugin does") version: str = Field(..., description="Version of the plugin") + ui_route: Optional[str] = Field(None, description="Frontend route for the plugin UI") input_schema: Dict[str, Any] = Field(..., description="JSON schema for input parameters", alias="schema") # [/DEF:PluginConfig:Class] \ No newline at end of file diff --git a/backend/src/core/plugin_loader.py b/backend/src/core/plugin_loader.py index afcc21e..c786ad7 100755 --- a/backend/src/core/plugin_loader.py +++ b/backend/src/core/plugin_loader.py @@ -141,6 +141,7 @@ class PluginLoader: name=plugin_instance.name, description=plugin_instance.description, version=plugin_instance.version, + ui_route=plugin_instance.ui_route, schema=schema, ) # The following line is commented out because it requires a schema to be passed to validate against. diff --git a/backend/src/plugins/backup.py b/backend/src/plugins/backup.py index 1d68d8a..e6d221e 100755 --- a/backend/src/plugins/backup.py +++ b/backend/src/plugins/backup.py @@ -75,6 +75,15 @@ class BackupPlugin(PluginBase): return "1.0.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the backup plugin. + # @RETURN: str - "/tools/backups" + def ui_route(self) -> str: + with belief_scope("ui_route"): + return "/tools/backups" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for backup plugin parameters. # @PRE: Plugin instance exists. diff --git a/backend/src/plugins/debug.py b/backend/src/plugins/debug.py index 5394f2f..bbe8ba4 100644 --- a/backend/src/plugins/debug.py +++ b/backend/src/plugins/debug.py @@ -63,6 +63,15 @@ class DebugPlugin(PluginBase): return "1.0.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the debug plugin. + # @RETURN: str - "/tools/debug" + def ui_route(self) -> str: + with belief_scope("ui_route"): + return "/tools/debug" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for the debug plugin parameters. # @PRE: Plugin instance exists. diff --git a/backend/src/plugins/git_plugin.py b/backend/src/plugins/git_plugin.py index 0eeb7ff..8fb3e92 100644 --- a/backend/src/plugins/git_plugin.py +++ b/backend/src/plugins/git_plugin.py @@ -99,6 +99,15 @@ class GitPlugin(PluginBase): return "0.1.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the git plugin. + # @RETURN: str - "/git" + def ui_route(self) -> str: + with belief_scope("GitPlugin.ui_route"): + return "/git" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Возвращает JSON-схему параметров для выполнения задач плагина. # @PRE: GitPlugin is initialized. diff --git a/backend/src/plugins/mapper.py b/backend/src/plugins/mapper.py index c682004..92f136c 100644 --- a/backend/src/plugins/mapper.py +++ b/backend/src/plugins/mapper.py @@ -66,6 +66,15 @@ class MapperPlugin(PluginBase): return "1.0.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the mapper plugin. + # @RETURN: str - "/tools/mapper" + def ui_route(self) -> str: + with belief_scope("ui_route"): + return "/tools/mapper" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for the mapper plugin parameters. # @PRE: Plugin instance exists. diff --git a/backend/src/plugins/migration.py b/backend/src/plugins/migration.py index 40e6dc0..6270d8e 100755 --- a/backend/src/plugins/migration.py +++ b/backend/src/plugins/migration.py @@ -71,6 +71,15 @@ class MigrationPlugin(PluginBase): return "1.0.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the migration plugin. + # @RETURN: str - "/migration" + def ui_route(self) -> str: + with belief_scope("ui_route"): + return "/migration" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for migration plugin parameters. # @PRE: Config manager is available. diff --git a/backend/src/plugins/search.py b/backend/src/plugins/search.py index 9a39949..b29b7fe 100644 --- a/backend/src/plugins/search.py +++ b/backend/src/plugins/search.py @@ -64,6 +64,15 @@ class SearchPlugin(PluginBase): return "1.0.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the search plugin. + # @RETURN: str - "/tools/search" + def ui_route(self) -> str: + with belief_scope("ui_route"): + return "/tools/search" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for the search plugin parameters. # @PRE: Plugin instance exists. diff --git a/backend/src/plugins/storage/plugin.py b/backend/src/plugins/storage/plugin.py index 8fd20b4..459d381 100644 --- a/backend/src/plugins/storage/plugin.py +++ b/backend/src/plugins/storage/plugin.py @@ -82,6 +82,15 @@ class StoragePlugin(PluginBase): return "1.0.0" # [/DEF:version:Function] + @property + # [DEF:ui_route:Function] + # @PURPOSE: Returns the frontend route for the storage plugin. + # @RETURN: str - "/tools/storage" + def ui_route(self) -> str: + with belief_scope("StoragePlugin:ui_route"): + return "/tools/storage" + # [/DEF:ui_route:Function] + # [DEF:get_schema:Function] # @PURPOSE: Returns the JSON schema for storage plugin parameters. # @PRE: None. diff --git a/backend/tasks.db b/backend/tasks.db index 10e028d..bfa202c 100644 Binary files a/backend/tasks.db and b/backend/tasks.db differ diff --git a/frontend/src/components/EnvSelector.svelte b/frontend/src/components/EnvSelector.svelte new file mode 100644 index 0000000..78eda60 --- /dev/null +++ b/frontend/src/components/EnvSelector.svelte @@ -0,0 +1,60 @@ + + + + + + +
{$t.tasks.cron_hint}
+