chore(semantics): checkpoint orphan-reduction hub normalization batch
This commit is contained in:
@@ -4,9 +4,9 @@
|
||||
# @SEMANTICS: api, dashboards, resources, hub
|
||||
# @PURPOSE: API endpoints for the Dashboard Hub - listing dashboards with Git and task status
|
||||
# @LAYER: API
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.dependencies:Dependencies]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.services.resource_service:ResourceService]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.core.superset_client:SupersetClient]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.dependencies]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.services.resource_service.ResourceService]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.core.superset_client.SupersetClient]
|
||||
#
|
||||
# @INVARIANT: All dashboard responses include git_status and last_task metadata
|
||||
#
|
||||
@@ -533,7 +533,7 @@ def _matches_dashboard_actor_aliases(
|
||||
# @PARAM: page (Optional[int]) - Page number (default: 1)
|
||||
# @PARAM: page_size (Optional[int]) - Items per page (default: 10, max: 100)
|
||||
# @RETURN: DashboardsResponse - List of dashboards with status metadata
|
||||
# @RELATION: CALLS ->[ResourceService:get_dashboards_with_status]
|
||||
# @RELATION: CALLS ->[get_dashboards_with_status]
|
||||
@router.get("", response_model=DashboardsResponse)
|
||||
async def get_dashboards(
|
||||
env_id: str,
|
||||
@@ -883,7 +883,7 @@ async def get_database_mappings(
|
||||
# @PURPOSE: Fetch detailed dashboard info with related charts and datasets
|
||||
# @PRE: env_id must be valid and dashboard ref (slug or id) must exist
|
||||
# @POST: Returns dashboard detail payload for overview page
|
||||
# @RELATION: CALLS ->[AsyncSupersetClient:get_dashboard_detail_async]
|
||||
# @RELATION: CALLS ->[backend.src.core.async_superset_client.AsyncSupersetClient.get_dashboard_detail_async]
|
||||
@router.get("/{dashboard_ref}", response_model=DashboardDetailResponse)
|
||||
async def get_dashboard_detail(
|
||||
dashboard_ref: str,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
# @PURPOSE: API endpoints for the Dataset Hub - listing datasets with mapping progress
|
||||
# @LAYER: API
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.dependencies]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.services.resource_service]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.core.superset_client]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.services.resource_service.ResourceService]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.core.superset_client.SupersetClient]
|
||||
#
|
||||
# @INVARIANT: All dataset responses include last_task metadata
|
||||
|
||||
@@ -121,7 +121,7 @@ class TaskResponse(BaseModel):
|
||||
# @PARAM: env_id (str) - The environment ID to fetch datasets from
|
||||
# @PARAM: search (Optional[str]) - Filter by table name
|
||||
# @RETURN: List[int] - List of dataset IDs
|
||||
# @RELATION: CALLS ->[backend.src.services.resource_service.ResourceService:get_datasets_with_status]
|
||||
# @RELATION: CALLS ->[get_datasets_with_status]
|
||||
@router.get("/ids")
|
||||
async def get_dataset_ids(
|
||||
env_id: str,
|
||||
@@ -178,7 +178,7 @@ async def get_dataset_ids(
|
||||
# @PARAM: page (Optional[int]) - Page number (default: 1)
|
||||
# @PARAM: page_size (Optional[int]) - Items per page (default: 10, max: 100)
|
||||
# @RETURN: DatasetsResponse - List of datasets with status metadata
|
||||
# @RELATION: CALLS ->[backend.src.services.resource_service.ResourceService:get_datasets_with_status]
|
||||
# @RELATION: CALLS ->[backend.src.services.resource_service.ResourceService.get_datasets_with_status]
|
||||
@router.get("", response_model=DatasetsResponse)
|
||||
async def get_datasets(
|
||||
env_id: str,
|
||||
|
||||
@@ -25,14 +25,14 @@ from .utils.async_network import AsyncAPIClient
|
||||
# [/SECTION]
|
||||
|
||||
|
||||
# [DEF:AsyncSupersetClient:Class]
|
||||
# [DEF:backend.src.core.async_superset_client.AsyncSupersetClient:Class]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Async sibling of SupersetClient for dashboard read paths.
|
||||
# @RELATION: [INHERITS] ->[backend.src.core.superset_client.SupersetClient]
|
||||
# @RELATION: [DEPENDS_ON] ->[backend.src.core.utils.async_network.AsyncAPIClient]
|
||||
# @RELATION: [CALLS] ->[backend.src.core.utils.async_network.AsyncAPIClient.request]
|
||||
class AsyncSupersetClient(SupersetClient):
|
||||
# [DEF:__init__:Function]
|
||||
# [DEF:backend.src.core.async_superset_client.AsyncSupersetClient.__init__:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Initialize async Superset client with AsyncAPIClient transport.
|
||||
# @PRE: env is valid Environment instance.
|
||||
@@ -52,18 +52,18 @@ class AsyncSupersetClient(SupersetClient):
|
||||
timeout=env.timeout,
|
||||
)
|
||||
self.delete_before_reimport = False
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:backend.src.core.async_superset_client.AsyncSupersetClient.__init__:Function]
|
||||
|
||||
# [DEF:aclose:Function]
|
||||
# [DEF:backend.src.core.async_superset_client.AsyncSupersetClient.aclose:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Close async transport resources.
|
||||
# @POST: Underlying AsyncAPIClient is closed.
|
||||
# @SIDE_EFFECT: Closes network sockets.
|
||||
async def aclose(self) -> None:
|
||||
await self.network.aclose()
|
||||
# [/DEF:aclose:Function]
|
||||
# [/DEF:backend.src.core.async_superset_client.AsyncSupersetClient.aclose:Function]
|
||||
|
||||
# [DEF:get_dashboards_page_async:Function]
|
||||
# [DEF:backend.src.core.async_superset_client.AsyncSupersetClient.get_dashboards_page_async:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetch one dashboards page asynchronously.
|
||||
# @POST: Returns total count and page result list.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# [DEF:backend.src.core.superset_client:Module]
|
||||
#
|
||||
# @TIER: STANDARD
|
||||
# @SEMANTICS: superset, api, client, rest, http, dashboard, dataset, import, export
|
||||
# @PURPOSE: Предоставляет высокоуровневый клиент для взаимодействия с Superset REST API, инкапсулируя логику запросов, обработку ошибок и пагинацию.
|
||||
# @LAYER: Core
|
||||
@@ -23,13 +24,13 @@ from .utils.fileio import get_filename_from_headers
|
||||
from .config_models import Environment
|
||||
# [/SECTION]
|
||||
|
||||
# [DEF:SupersetClient:Class]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient:Class]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Класс-обёртка над Superset REST API, предоставляющий методы для работы с дашбордами и датасетами.
|
||||
# @RELATION: [DEPENDS_ON] ->[backend.src.core.utils.network.APIClient]
|
||||
# @RELATION: [DEPENDS_ON] ->[backend.src.core.config_models.Environment]
|
||||
class SupersetClient:
|
||||
# [DEF:__init__:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.__init__:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Инициализирует клиент, проверяет конфигурацию и создает сетевой клиент.
|
||||
# @PRE: `env` должен быть валидным объектом Environment.
|
||||
@@ -58,7 +59,7 @@ class SupersetClient:
|
||||
app_logger.info("[SupersetClient.__init__][Exit] SupersetClient initialized.")
|
||||
# [/DEF:__init__:Function]
|
||||
|
||||
# [DEF:authenticate:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.authenticate:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Authenticates the client using the configured credentials.
|
||||
# @PRE: self.network must be initialized with valid auth configuration.
|
||||
@@ -71,7 +72,7 @@ class SupersetClient:
|
||||
# [/DEF:authenticate:Function]
|
||||
|
||||
@property
|
||||
# [DEF:headers:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.headers:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Возвращает базовые HTTP-заголовки, используемые сетевым клиентом.
|
||||
# @PRE: APIClient is initialized and authenticated.
|
||||
@@ -83,7 +84,7 @@ class SupersetClient:
|
||||
|
||||
# [SECTION: DASHBOARD OPERATIONS]
|
||||
|
||||
# [DEF:get_dashboards:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Получает полный список дашбордов, автоматически обрабатывая пагинацию.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -117,7 +118,7 @@ class SupersetClient:
|
||||
return total_count, paginated_data
|
||||
# [/DEF:get_dashboards:Function]
|
||||
|
||||
# [DEF:get_dashboards_page:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_page:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches a single dashboards page from Superset without iterating all pages.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -154,7 +155,7 @@ class SupersetClient:
|
||||
return total_count, result
|
||||
# [/DEF:get_dashboards_page:Function]
|
||||
|
||||
# [DEF:get_dashboards_summary:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_summary:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches dashboard metadata optimized for the grid.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -239,7 +240,7 @@ class SupersetClient:
|
||||
return result
|
||||
# [/DEF:get_dashboards_summary:Function]
|
||||
|
||||
# [DEF:get_dashboards_summary_page:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboards_summary_page:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches one page of dashboard metadata optimized for the grid.
|
||||
# @PRE: page >= 1 and page_size > 0.
|
||||
@@ -312,7 +313,7 @@ class SupersetClient:
|
||||
return total_count, result
|
||||
# [/DEF:get_dashboards_summary_page:Function]
|
||||
|
||||
# [DEF:_extract_owner_labels:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._extract_owner_labels:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Normalize dashboard owners payload to stable display labels.
|
||||
# @PRE: owners payload can be scalar, object or list.
|
||||
@@ -340,7 +341,7 @@ class SupersetClient:
|
||||
return normalized
|
||||
# [/DEF:_extract_owner_labels:Function]
|
||||
|
||||
# [DEF:_extract_user_display:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._extract_user_display:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Normalize user payload to a stable display name.
|
||||
# @PRE: user payload can be string, dict or None.
|
||||
@@ -369,7 +370,7 @@ class SupersetClient:
|
||||
return None
|
||||
# [/DEF:_extract_user_display:Function]
|
||||
|
||||
# [DEF:_sanitize_user_text:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._sanitize_user_text:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Convert scalar value to non-empty user-facing text.
|
||||
# @PRE: value can be any scalar type.
|
||||
@@ -383,7 +384,7 @@ class SupersetClient:
|
||||
return normalized
|
||||
# [/DEF:_sanitize_user_text:Function]
|
||||
|
||||
# [DEF:get_dashboard:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboard:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches a single dashboard by ID.
|
||||
# @PRE: Client is authenticated and dashboard_id exists.
|
||||
@@ -396,7 +397,7 @@ class SupersetClient:
|
||||
return cast(Dict, response)
|
||||
# [/DEF:get_dashboard:Function]
|
||||
|
||||
# [DEF:get_chart:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_chart:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches a single chart by ID.
|
||||
# @PRE: Client is authenticated and chart_id exists.
|
||||
@@ -409,7 +410,7 @@ class SupersetClient:
|
||||
return cast(Dict, response)
|
||||
# [/DEF:get_chart:Function]
|
||||
|
||||
# [DEF:get_dashboard_detail:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dashboard_detail:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches detailed dashboard information including related charts and datasets.
|
||||
# @PRE: Client is authenticated and dashboard_id exists.
|
||||
@@ -604,7 +605,7 @@ class SupersetClient:
|
||||
}
|
||||
# [/DEF:get_dashboard_detail:Function]
|
||||
|
||||
# [DEF:get_charts:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_charts:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches all charts with pagination support.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -624,7 +625,8 @@ class SupersetClient:
|
||||
return len(paginated_data), paginated_data
|
||||
# [/DEF:get_charts:Function]
|
||||
|
||||
# [DEF:_extract_chart_ids_from_layout:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._extract_chart_ids_from_layout:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Traverses dashboard layout metadata and extracts chart IDs from common keys.
|
||||
# @PRE: payload can be dict/list/scalar.
|
||||
# @POST: Returns a set of chart IDs found in nested structures.
|
||||
@@ -656,7 +658,7 @@ class SupersetClient:
|
||||
return found
|
||||
# [/DEF:_extract_chart_ids_from_layout:Function]
|
||||
|
||||
# [DEF:export_dashboard:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.export_dashboard:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Экспортирует дашборд в виде ZIP-архива.
|
||||
# @PRE: dashboard_id must exist in Superset.
|
||||
@@ -681,7 +683,7 @@ class SupersetClient:
|
||||
return response.content, filename
|
||||
# [/DEF:export_dashboard:Function]
|
||||
|
||||
# [DEF:import_dashboard:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.import_dashboard:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Импортирует дашборд из ZIP-файла.
|
||||
# @PRE: file_name must be a valid ZIP dashboard export.
|
||||
@@ -713,7 +715,7 @@ class SupersetClient:
|
||||
return self._do_import(file_path)
|
||||
# [/DEF:import_dashboard:Function]
|
||||
|
||||
# [DEF:delete_dashboard:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.delete_dashboard:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Удаляет дашборд по его ID или slug.
|
||||
# @PRE: dashboard_id must exist.
|
||||
@@ -735,7 +737,7 @@ class SupersetClient:
|
||||
|
||||
# [SECTION: DATASET OPERATIONS]
|
||||
|
||||
# [DEF:get_datasets:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_datasets:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Получает полный список датасетов, автоматически обрабатывая пагинацию.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -756,7 +758,8 @@ class SupersetClient:
|
||||
return total_count, paginated_data
|
||||
# [/DEF:get_datasets:Function]
|
||||
|
||||
# [DEF:get_datasets_summary:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_datasets_summary:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches dataset metadata optimized for the Dataset Hub grid.
|
||||
# @PRE: Client is authenticated.
|
||||
# @POST: Returns a list of dataset metadata summaries.
|
||||
@@ -780,7 +783,8 @@ class SupersetClient:
|
||||
return result
|
||||
# [/DEF:get_datasets_summary:Function]
|
||||
|
||||
# [DEF:get_dataset_detail:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dataset_detail:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches detailed dataset information including columns and linked dashboards
|
||||
# @PRE: Client is authenticated and dataset_id exists.
|
||||
# @POST: Returns detailed dataset info with columns and linked dashboards.
|
||||
@@ -892,7 +896,7 @@ class SupersetClient:
|
||||
return result
|
||||
# [/DEF:get_dataset_detail:Function]
|
||||
|
||||
# [DEF:get_dataset:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_dataset:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Получает информацию о конкретном датасете по его ID.
|
||||
# @PRE: dataset_id must exist.
|
||||
@@ -908,7 +912,7 @@ class SupersetClient:
|
||||
return response
|
||||
# [/DEF:get_dataset:Function]
|
||||
|
||||
# [DEF:update_dataset:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.update_dataset:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Обновляет данные датасета по его ID.
|
||||
# @PRE: dataset_id must exist.
|
||||
@@ -934,7 +938,7 @@ class SupersetClient:
|
||||
|
||||
# [SECTION: DATABASE OPERATIONS]
|
||||
|
||||
# [DEF:get_databases:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_databases:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Получает полный список баз данных.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -957,7 +961,7 @@ class SupersetClient:
|
||||
return total_count, paginated_data
|
||||
# [/DEF:get_databases:Function]
|
||||
|
||||
# [DEF:get_database:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_database:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Получает информацию о конкретной базе данных по её ID.
|
||||
# @PRE: database_id must exist.
|
||||
@@ -973,7 +977,7 @@ class SupersetClient:
|
||||
return response
|
||||
# [/DEF:get_database:Function]
|
||||
|
||||
# [DEF:get_databases_summary:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_databases_summary:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetch a summary of databases including uuid, name, and engine.
|
||||
# @PRE: Client is authenticated.
|
||||
@@ -994,7 +998,7 @@ class SupersetClient:
|
||||
return databases
|
||||
# [/DEF:get_databases_summary:Function]
|
||||
|
||||
# [DEF:get_database_by_uuid:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_database_by_uuid:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Find a database by its UUID.
|
||||
# @PRE: db_uuid must be a valid UUID string.
|
||||
@@ -1014,7 +1018,7 @@ class SupersetClient:
|
||||
|
||||
# [SECTION: HELPERS]
|
||||
|
||||
# [DEF:_resolve_target_id_for_delete:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._resolve_target_id_for_delete:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Resolves a dashboard ID from either an ID or a slug.
|
||||
# @PRE: Either dash_id or dash_slug should be provided.
|
||||
@@ -1037,7 +1041,7 @@ class SupersetClient:
|
||||
return None
|
||||
# [/DEF:_resolve_target_id_for_delete:Function]
|
||||
|
||||
# [DEF:_do_import:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._do_import:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Performs the actual multipart upload for import.
|
||||
# @PRE: file_name must be a path to an existing ZIP file.
|
||||
@@ -1059,7 +1063,7 @@ class SupersetClient:
|
||||
)
|
||||
# [/DEF:_do_import:Function]
|
||||
|
||||
# [DEF:_validate_export_response:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._validate_export_response:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Validates that the export response is a non-empty ZIP archive.
|
||||
# @PRE: response must be a valid requests.Response object.
|
||||
@@ -1073,7 +1077,7 @@ class SupersetClient:
|
||||
raise SupersetAPIError("Получены пустые данные при экспорте")
|
||||
# [/DEF:_validate_export_response:Function]
|
||||
|
||||
# [DEF:_resolve_export_filename:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._resolve_export_filename:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Determines the filename for an exported dashboard.
|
||||
# @PRE: response must contain Content-Disposition header or dashboard_id must be provided.
|
||||
@@ -1089,7 +1093,7 @@ class SupersetClient:
|
||||
return filename
|
||||
# [/DEF:_resolve_export_filename:Function]
|
||||
|
||||
# [DEF:_validate_query_params:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._validate_query_params:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Ensures query parameters have default page and page_size.
|
||||
# @PRE: query can be None or a dictionary.
|
||||
@@ -1102,7 +1106,7 @@ class SupersetClient:
|
||||
return {**base_query, **(query or {})}
|
||||
# [/DEF:_validate_query_params:Function]
|
||||
|
||||
# [DEF:_fetch_total_object_count:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._fetch_total_object_count:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Fetches the total number of items for a given endpoint.
|
||||
# @PRE: endpoint must be a valid Superset API path.
|
||||
@@ -1117,7 +1121,8 @@ class SupersetClient:
|
||||
)
|
||||
# [/DEF:_fetch_total_object_count:Function]
|
||||
|
||||
# [DEF:_fetch_all_pages:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._fetch_all_pages:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Iterates through all pages to collect all data items.
|
||||
# @PRE: pagination_options must contain base_query, total_count, and results_field.
|
||||
# @POST: Returns a combined list of all items.
|
||||
@@ -1126,7 +1131,8 @@ class SupersetClient:
|
||||
return self.network.fetch_paginated_data(endpoint=endpoint, pagination_options=pagination_options)
|
||||
# [/DEF:_fetch_all_pages:Function]
|
||||
|
||||
# [DEF:_validate_import_file:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient._validate_import_file:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Validates that the file to be imported is a valid ZIP with metadata.yaml.
|
||||
# @PRE: zip_path must be a path to a file.
|
||||
# @POST: Raises error if file is missing, not a ZIP, or missing metadata.
|
||||
@@ -1142,7 +1148,8 @@ class SupersetClient:
|
||||
raise SupersetAPIError(f"Архив {zip_path} не содержит 'metadata.yaml'")
|
||||
# [/DEF:_validate_import_file:Function]
|
||||
|
||||
# [DEF:get_all_resources:Function]
|
||||
# [DEF:backend.src.core.superset_client.SupersetClient.get_all_resources:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetches all resources of a given type with id, uuid, and name columns.
|
||||
# @PARAM: resource_type (str) - One of "chart", "dataset", "dashboard".
|
||||
# @PRE: Client is authenticated. resource_type is valid.
|
||||
@@ -1191,6 +1198,6 @@ class SupersetClient:
|
||||
|
||||
# [/SECTION]
|
||||
|
||||
# [/DEF:SupersetClient:Class]
|
||||
# [/DEF:backend.src.core.superset_client.SupersetClient:Class]
|
||||
|
||||
# [/DEF:backend.src.core.superset_client:Module]
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
# @SEMANTICS: git, service, gitpython, repository, version_control
|
||||
# @PURPOSE: Core Git logic using GitPython to manage dashboard repositories.
|
||||
# @LAYER: Service
|
||||
# @RELATION: INHERITS_FROM -> None
|
||||
# @RELATION: USED_BY -> src.api.routes.git
|
||||
# @RELATION: USED_BY -> src.plugins.git_plugin
|
||||
# @RELATION: DEPENDS_ON -> src.core.database.SessionLocal
|
||||
# @RELATION: DEPENDS_ON -> src.models.config.AppConfigRecord
|
||||
# @RELATION: DEPENDS_ON -> src.models.git.GitRepository
|
||||
# @RELATION: USED_BY -> backend.src.api.routes.git
|
||||
# @RELATION: USED_BY -> backend.src.plugins.git_plugin
|
||||
# @RELATION: DEPENDS_ON -> backend.src.core.database.SessionLocal
|
||||
# @RELATION: DEPENDS_ON -> backend.src.models.config.AppConfigRecord
|
||||
# @RELATION: DEPENDS_ON -> backend.src.models.git.GitRepository
|
||||
#
|
||||
# @INVARIANT: All Git operations must be performed on a valid local directory.
|
||||
|
||||
@@ -32,14 +31,15 @@ from src.models.git import GitRepository, GitServerConfig
|
||||
from src.models.config import AppConfigRecord
|
||||
from src.core.database import SessionLocal
|
||||
|
||||
# [DEF:GitService:Class]
|
||||
# [DEF:backend.src.services.git_service.GitService:Class]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Wrapper for GitPython operations with semantic logging and error handling.
|
||||
class GitService:
|
||||
"""
|
||||
Wrapper for GitPython operations.
|
||||
"""
|
||||
|
||||
# [DEF:__init__:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService.__init__:Function]
|
||||
# @PURPOSE: Initializes the GitService with a base path for repositories.
|
||||
# @PARAM: base_path (str) - Root directory for all Git clones.
|
||||
# @PRE: base_path is a valid string path.
|
||||
@@ -64,7 +64,7 @@ class GitService:
|
||||
base.mkdir(parents=True, exist_ok=True)
|
||||
# [/DEF:_ensure_base_path_exists:Function]
|
||||
|
||||
# [DEF:_resolve_base_path:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService._resolve_base_path:Function]
|
||||
# @PURPOSE: Resolve base repository directory from explicit argument or global storage settings.
|
||||
# @PRE: base_path is a string path.
|
||||
# @POST: Returns absolute path for Git repositories root.
|
||||
@@ -254,7 +254,7 @@ class GitService:
|
||||
)
|
||||
# [/DEF:_ensure_gitflow_branches:Function]
|
||||
|
||||
# [DEF:_get_repo_path:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService._get_repo_path:Function]
|
||||
# @PURPOSE: Resolves the local filesystem path for a dashboard's repository.
|
||||
# @PARAM: dashboard_id (int)
|
||||
# @PARAM: repo_key (Optional[str]) - Slug-like key used when DB local_path is absent.
|
||||
@@ -394,7 +394,7 @@ class GitService:
|
||||
session.close()
|
||||
# [/DEF:delete_repo:Function]
|
||||
|
||||
# [DEF:get_repo:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService.get_repo:Function]
|
||||
# @PURPOSE: Get Repo object for a dashboard.
|
||||
# @PRE: Repository must exist on disk for the given dashboard_id.
|
||||
# @POST: Returns a GitPython Repo instance for the dashboard.
|
||||
@@ -1112,7 +1112,7 @@ class GitService:
|
||||
raise HTTPException(status_code=500, detail=f"Git pull failed: {str(e)}")
|
||||
# [/DEF:pull_changes:Function]
|
||||
|
||||
# [DEF:get_status:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService.get_status:Function]
|
||||
# @PURPOSE: Get current repository status (dirty files, untracked, etc.)
|
||||
# @PRE: Repository for dashboard_id exists.
|
||||
# @POST: Returns a dictionary representing the Git status.
|
||||
@@ -1657,7 +1657,7 @@ class GitService:
|
||||
}
|
||||
# [/DEF:_parse_remote_repo_identity:Function]
|
||||
|
||||
# [DEF:_derive_server_url_from_remote:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService._derive_server_url_from_remote:Function]
|
||||
# @PURPOSE: Build API base URL from remote repository URL without credentials.
|
||||
# @PRE: remote_url may be any git URL.
|
||||
# @POST: Returns normalized http(s) base URL or None when derivation is impossible.
|
||||
@@ -1744,7 +1744,7 @@ class GitService:
|
||||
}
|
||||
# [/DEF:promote_direct_merge:Function]
|
||||
|
||||
# [DEF:create_gitea_pull_request:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService.create_gitea_pull_request:Function]
|
||||
# @PURPOSE: Create pull request in Gitea.
|
||||
# @PRE: Config and remote URL are valid.
|
||||
# @POST: Returns normalized PR metadata.
|
||||
@@ -1832,7 +1832,7 @@ class GitService:
|
||||
}
|
||||
# [/DEF:create_gitea_pull_request:Function]
|
||||
|
||||
# [DEF:create_github_pull_request:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService.create_github_pull_request:Function]
|
||||
# @PURPOSE: Create pull request in GitHub or GitHub Enterprise.
|
||||
# @PRE: Config and remote URL are valid.
|
||||
# @POST: Returns normalized PR metadata.
|
||||
@@ -1886,7 +1886,7 @@ class GitService:
|
||||
}
|
||||
# [/DEF:create_github_pull_request:Function]
|
||||
|
||||
# [DEF:create_gitlab_merge_request:Function]
|
||||
# [DEF:backend.src.services.git_service.GitService.create_gitlab_merge_request:Function]
|
||||
# @PURPOSE: Create merge request in GitLab.
|
||||
# @PRE: Config and remote URL are valid.
|
||||
# @POST: Returns normalized MR metadata.
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
# @SEMANTICS: service, resources, dashboards, datasets, tasks, git
|
||||
# @PURPOSE: Shared service for fetching resource data with Git status and task status
|
||||
# @LAYER: Service
|
||||
# @RELATION: DEPENDS_ON -> backend.src.core.superset_client
|
||||
# @RELATION: DEPENDS_ON -> backend.src.core.task_manager
|
||||
# @RELATION: DEPENDS_ON -> backend.src.services.git_service
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.core.superset_client.SupersetClient]
|
||||
# @RELATION: DEPENDS_ON ->[TaskManagerPackage]
|
||||
# @RELATION: DEPENDS_ON ->[TaskManagerModels]
|
||||
# @RELATION: DEPENDS_ON ->[backend.src.services.git_service.GitService]
|
||||
# @INVARIANT: All resources include metadata about their current state
|
||||
|
||||
# [SECTION: IMPORTS]
|
||||
@@ -17,12 +18,12 @@ from ..services.git_service import GitService
|
||||
from ..core.logger import logger, belief_scope
|
||||
# [/SECTION]
|
||||
|
||||
# [DEF:ResourceService:Class]
|
||||
# [DEF:backend.src.services.resource_service.ResourceService:Class]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Provides centralized access to resource data with enhanced metadata
|
||||
class ResourceService:
|
||||
|
||||
# [DEF:__init__:Function]
|
||||
# [DEF:backend.src.services.resource_service.ResourceService.__init__:Function]
|
||||
# @TIER: TRIVIAL
|
||||
# @PURPOSE: Initialize the resource service with dependencies
|
||||
# @PRE: None
|
||||
@@ -31,9 +32,9 @@ class ResourceService:
|
||||
with belief_scope("ResourceService.__init__"):
|
||||
self.git_service = GitService()
|
||||
logger.info("[ResourceService][Action] Initialized ResourceService")
|
||||
# [/DEF:__init__:Function]
|
||||
# [/DEF:backend.src.services.resource_service.ResourceService.__init__:Function]
|
||||
|
||||
# [DEF:get_dashboards_with_status:Function]
|
||||
# [DEF:backend.src.services.resource_service.ResourceService.get_dashboards_with_status:Function]
|
||||
# @TIER: STANDARD
|
||||
# @PURPOSE: Fetch dashboards from environment with Git status and last task status
|
||||
# @PRE: env is a valid Environment object
|
||||
@@ -41,9 +42,9 @@ class ResourceService:
|
||||
# @PARAM: env (Environment) - The environment to fetch from
|
||||
# @PARAM: tasks (List[Task]) - List of tasks to check for status
|
||||
# @RETURN: List[Dict] - Dashboards with git_status and last_task fields
|
||||
# @RELATION: CALLS ->[SupersetClient:get_dashboards_summary]
|
||||
# @RELATION: CALLS ->[self:_get_git_status_for_dashboard]
|
||||
# @RELATION: CALLS ->[self:_get_last_llm_task_for_dashboard]
|
||||
# @RELATION: CALLS ->[backend.src.core.superset_client.SupersetClient.get_dashboards_summary]
|
||||
# @RELATION: CALLS ->[backend.src.services.resource_service.ResourceService._get_git_status_for_dashboard]
|
||||
# @RELATION: CALLS ->[backend.src.services.resource_service.ResourceService._get_last_llm_task_for_dashboard]
|
||||
async def get_dashboards_with_status(
|
||||
self,
|
||||
env: Any,
|
||||
|
||||
Reference in New Issue
Block a user