Refactor site building workflow and context handling; update API response structure for improved clarity and consistency. Adjust frontend components to align with new data structure, including error handling and loading states.
This commit is contained in:
Binary file not shown.
@@ -35,11 +35,13 @@ class WizardContextService:
|
||||
|
||||
workflow_payload = self.workflow_service.serialize_state(workflow_state) if workflow_state else None
|
||||
|
||||
coverage_data = self._coverage_summary(site_blueprint)
|
||||
context = {
|
||||
'workflow': workflow_payload,
|
||||
'clusters': self._cluster_summary(site_blueprint),
|
||||
'taxonomies': self._taxonomy_summary(site_blueprint),
|
||||
'coverage': self._coverage_summary(site_blueprint),
|
||||
'cluster_summary': self._cluster_summary(site_blueprint),
|
||||
'taxonomy_summary': self._taxonomy_summary(site_blueprint),
|
||||
'sitemap_summary': coverage_data, # Frontend expects 'sitemap_summary' not 'coverage'
|
||||
'coverage': coverage_data, # Keep for backward compatibility
|
||||
}
|
||||
context['next_actions'] = self._next_actions(workflow_payload)
|
||||
return context
|
||||
|
||||
@@ -111,13 +111,21 @@ class WorkflowStateService:
|
||||
metadata: Optional[Dict[str, str]] = None,
|
||||
) -> Optional[WorkflowState]:
|
||||
"""Persist explicit step updates coming from the wizard."""
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
state = self.initialize(site_blueprint)
|
||||
if not state:
|
||||
return None
|
||||
|
||||
metadata = metadata or {}
|
||||
timestamp = timezone.now().isoformat()
|
||||
step_status = state.step_status or {}
|
||||
|
||||
# Ensure step_status is a dict (handle None case)
|
||||
if state.step_status is None:
|
||||
state.step_status = {}
|
||||
step_status = dict(state.step_status) # Create a copy to avoid mutation issues
|
||||
|
||||
entry = self._build_step_entry(
|
||||
step=step,
|
||||
status=status,
|
||||
@@ -132,8 +140,22 @@ class WorkflowStateService:
|
||||
|
||||
state.step_status = step_status
|
||||
state.blocking_reason = metadata.get('message')
|
||||
state.completed = all(value.get('status') == 'ready' for value in step_status.values())
|
||||
state.save(update_fields=['current_step', 'step_status', 'blocking_reason', 'completed', 'updated_at'])
|
||||
|
||||
# Calculate completed status - only true if all steps are ready and we have at least one step
|
||||
if step_status:
|
||||
state.completed = all(
|
||||
value.get('status') == 'ready' or value.get('status') == 'complete'
|
||||
for value in step_status.values()
|
||||
)
|
||||
else:
|
||||
state.completed = False
|
||||
|
||||
try:
|
||||
state.save(update_fields=['current_step', 'step_status', 'blocking_reason', 'completed', 'updated_at'])
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to save workflow state for blueprint {site_blueprint.id}: {str(e)}")
|
||||
raise
|
||||
|
||||
self._emit_event(site_blueprint, 'wizard_step_updated', {
|
||||
'step': step,
|
||||
'status': status,
|
||||
@@ -173,7 +195,7 @@ class WorkflowStateService:
|
||||
'completed': state.completed,
|
||||
'blocking_reason': state.blocking_reason,
|
||||
'steps': steps_payload,
|
||||
'updated_at': state.updated_at,
|
||||
'updated_at': state.updated_at.isoformat() if hasattr(state.updated_at, 'isoformat') else str(state.updated_at),
|
||||
}
|
||||
|
||||
def _build_step_entry(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from django.conf import settings
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import action
|
||||
@@ -6,6 +7,8 @@ from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from igny8_core.api.base import SiteSectorModelViewSet
|
||||
from igny8_core.api.permissions import IsAuthenticatedAndActive, IsEditorOrAbove
|
||||
from igny8_core.api.response import success_response, error_response
|
||||
@@ -308,8 +311,16 @@ class SiteBlueprintViewSet(SiteSectorModelViewSet):
|
||||
"""Return aggregated wizard context (steps, clusters, taxonomies, coverage)."""
|
||||
blueprint = self.get_object()
|
||||
if not self.workflow_service.enabled:
|
||||
# Return empty context structure matching frontend expectations
|
||||
return success_response(
|
||||
data={'workflow': None, 'clusters': {}, 'taxonomies': {}, 'coverage': {}},
|
||||
data={
|
||||
'workflow': None,
|
||||
'cluster_summary': {'attached_count': 0, 'coverage_counts': {}, 'clusters': []},
|
||||
'taxonomy_summary': {'total_taxonomies': 0, 'counts_by_type': {}, 'taxonomies': []},
|
||||
'sitemap_summary': {'pages_total': 0, 'pages_by_status': {}, 'pages_by_type': {}},
|
||||
'coverage': {'pages_total': 0, 'pages_by_status': {}, 'pages_by_type': {}},
|
||||
'next_actions': None,
|
||||
},
|
||||
request=request,
|
||||
)
|
||||
|
||||
@@ -362,27 +373,35 @@ class SiteBlueprintViewSet(SiteSectorModelViewSet):
|
||||
request
|
||||
)
|
||||
|
||||
updated_state = self.workflow_service.update_step(
|
||||
blueprint,
|
||||
step,
|
||||
status_value,
|
||||
metadata
|
||||
)
|
||||
|
||||
if not updated_state:
|
||||
try:
|
||||
updated_state = self.workflow_service.update_step(
|
||||
blueprint,
|
||||
step,
|
||||
status_value,
|
||||
metadata
|
||||
)
|
||||
|
||||
if not updated_state:
|
||||
return error_response(
|
||||
'Failed to update workflow step',
|
||||
status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
request
|
||||
)
|
||||
|
||||
# Serialize state
|
||||
serialized = self.workflow_service.serialize_state(updated_state)
|
||||
|
||||
return success_response(
|
||||
data=serialized,
|
||||
request=request
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(f"Error updating workflow step for blueprint {blueprint.id}: {str(e)}")
|
||||
return error_response(
|
||||
'Failed to update workflow step',
|
||||
f'Internal server error: {str(e)}',
|
||||
status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
request
|
||||
)
|
||||
|
||||
# Serialize state
|
||||
serialized = self.workflow_service.serialize_state(updated_state)
|
||||
|
||||
return success_response(
|
||||
data=serialized,
|
||||
request=request
|
||||
)
|
||||
|
||||
@action(detail=True, methods=['post'], url_path='clusters/attach')
|
||||
def attach_clusters(self, request, pk=None):
|
||||
|
||||
Reference in New Issue
Block a user