feat: track model execution status with failure icon in explorer#54
feat: track model execution status with failure icon in explorer#54abhizipstack merged 5 commits intomainfrom
Conversation
Implement model-level execution status tracking (NOT_STARTED, RUNNING, SUCCESS, FAILED) at DAG node level with visual indicators in the file explorer. Status is tracked per individual DAG node, ensuring accurate status for each model even when downstream dependencies fail. Backend changes: - Add RunStatus enum and 4 new fields to ConfigModels (run_status, failure_reason, last_run_at, run_duration) - Migration 0003_add_model_run_status - Update file_explorer.load_models to return status fields - Add _update_model_status to DAG executor — called before execution (RUNNING), after success (SUCCESS), and on exception (FAILED with reason) - Update execute/views.py to return 400 on DAG execution failures - Fix clear_cache decorator to re-raise exceptions instead of swallowing them silently Frontend changes: - Add getModelRunStatus helper to render colored dot badges next to model names in the explorer tree - Running: blue, Success: green, Failed: red - Show Popover on hover over failed status with full error message and last run timestamp - Trigger explorer refresh via setRefreshModels after runTransformation succeeds or fails Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
| Filename | Overview |
|---|---|
| backend/visitran/visitran.py | Adds _update_model_status() and per-node status tracking in execute_graph(); has two P1 bugs: datetime module shadowed in CLI fallback and non-executable nodes incorrectly marked FAILED |
| backend/backend/core/migrations/0003_add_model_run_status.py | Adds 4 nullable fields to configmodels and bumps project_schema max_length; safe additive migration with sensible defaults |
| backend/backend/core/models/config_models.py | Adds RunStatus TextChoices enum and 4 new execution-tracking fields; clean and well-structured |
| backend/backend/application/file_explorer/file_explorer.py | Builds a model lookup dict and adds run_status/failure_reason/last_run_at/run_duration to each node entry; correct and efficient |
| backend/backend/core/routers/execute/views.py | Wraps execution in try/except/finally, fixes the DB connection leak via finally, and returns 400 on DAG failures instead of crashing |
| backend/backend/utils/cache_service/decorators/cache_decorator.py | Adds raise to re-raise view-function exceptions instead of silently returning None; fixes pre-existing bug |
| frontend/src/ide/explorer/explorer-component.jsx | Adds getModelRunStatus() helper and renders colored dot badges + FAILED popover; getExplorer + setRefreshModels called together on success and failure |
| frontend/src/ide/editor/no-code-model/no-code-model.jsx | Calls setRefreshModels(true) after both success and error paths of runTransformation; simple additive change |
| backend/backend/core/models/project_details.py | Bumps project_schema max_length from 20 to 1024; safe change with matching migration |
Sequence Diagram
sequenceDiagram
participant FE as Frontend (Explorer)
participant API as execute/views.py
participant DAG as Visitran.execute_graph()
participant DB as ConfigModels (DB)
FE->>API: POST /execute/run {file_name}
API->>DAG: execute_visitran_run_command()
loop Each DAG node
DAG->>DB: UPDATE run_status=RUNNING, last_run_at=now()
alt Execution succeeds
DAG->>DB: UPDATE run_status=SUCCESS, run_duration=…
else VisitranBaseException
DAG->>DB: UPDATE run_status=FAILED, failure_reason=…
DAG-->>API: raise
else Generic Exception
DAG->>DB: UPDATE run_status=FAILED, failure_reason=repr(err)
end
end
alt All nodes succeeded
API-->>FE: 200 {status: success}
else Any exception raised
API-->>FE: 400 {status: failed}
end
Note over API: close_db_connection() always in finally
FE->>API: GET /file_explorer (run_status, failure_reason, last_run_at per model)
FE->>FE: Render status dot badge in explorer tree
Prompt To Fix All With AI
This is a comment left during a code review.
Path: backend/visitran/visitran.py
Line: 20-27
Comment:
**`datetime` module shadowed by the CLI fallback import**
`from datetime import datetime` inside the `except ImportError:` block rebinds the module-level name `datetime` (introduced at line 4 via `import datetime`) to the `datetime.datetime` class. In CLI mode every subsequent call to `datetime.datetime.now()` (e.g. in `BaseResult` construction) would raise `AttributeError: type object 'datetime' has no attribute 'datetime'`.
Use a private alias so the module reference is preserved:
```suggestion
except ImportError:
from datetime import datetime as _datetime, timezone as _tz
class timezone:
@staticmethod
def now():
return _datetime.now(_tz.utc)
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: backend/visitran/visitran.py
Line: 353-371
Comment:
**Non-executable dependency nodes incorrectly receive FAILED status**
The RUNNING update at line 300–301 is guarded by `if is_executable:`, but both `except` handlers call `_update_model_status(...FAILED...)` unconditionally. If `_apply_model_config_override()` or `node.materialize()` throws for a non-executable parent node (materialized only for DAG dependency resolution), that model gets written as FAILED in `ConfigModels` — showing a red dot in the explorer — even though it was never marked RUNNING and was not the model being executed.
Add the same `is_executable` guard to the FAILED paths:
```python
except VisitranBaseExceptions as visitran_err:
if is_executable:
self._update_model_status(
str(node_name),
ConfigModels.RunStatus.FAILED,
failure_reason=str(visitran_err),
run_duration=time.monotonic() - start_time,
)
raise visitran_err
except Exception as err:
...
if is_executable:
self._update_model_status(
str(node_name),
ConfigModels.RunStatus.FAILED,
failure_reason=err_trace,
run_duration=time.monotonic() - start_time,
)
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (5): Last reviewed commit: "fix: address Greptile P1s — CLI-safe tim..." | Re-trigger Greptile
- Remove unused .project-list-card-clickable-content CSS class - Reduce !important usage in schema select styles, increase specificity instead - Replace duplicate API call with explorerService.setProjectSchema - Replace message.success/error with useNotificationService for consistency - Show error InfoChip when schema list is empty instead of hiding dropdown - Revert project_schema max_length change (will be added to PR #54 with migration)
- Drop optional ConfigModels import; it's always present in the OSS build - Track run_duration via time.monotonic() and persist on SUCCESS/FAILED - Skip RUNNING update for non-executable parent nodes so they don't get stuck with a permanent blue badge in selective execution - Raise explicit errors when session/project_id missing instead of silent no-op - Stop returning raw exception strings from execute_run_command (CodeQL) - Refresh explorer tree on context-menu run failure so FAILED badge appears - Move getModelRunStatus to module scope and use antd theme tokens instead of hardcoded hex colors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Addressed all review feedback in 55332f7: Greptile P1s
Greptile P2
CodeQL
|
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Requested by @tahierhussain in PR #55 review — the project_schema field was too short for schemas with long names or multiple schemas. Bundled into migration 0003 alongside the model run-status fields since both target the core app and depend on 0002_seed_data. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
🔴 Blockers
🟠 Should split out
🟡 Minor
|
…leak
P1: `from django.utils import timezone` at module level crashes when
visitran is used as a standalone CLI without Django installed.
Wrapped in try/except with a minimal fallback that provides
timezone.now() via stdlib datetime.
P1: close_db_connection() was only called in the success path of
execute_run_command. On exception the connection leaked. Moved
to a finally block so it always runs regardless of outcome.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
What
RunStatusenum and 4 new fields toConfigModels:run_status,failure_reason,last_run_at,run_duration0003_add_model_run_status.pyfile_explorer.load_models()to return status fields for each model_update_model_status()to DAG executor invisitran.py— called before execution (RUNNING), after success (SUCCESS), and on exception (FAILED)execute/views.pyto return 400 on DAG execution failuresclear_cachedecorator to re-raise exceptions instead of silently swallowing themsetRefreshModelsafterrunTransformationsucceeds or failsWhy
After a model build/run, users had no visual indication of which models succeeded or failed. They had to manually open each model to check. This change shows failure icons directly in the explorer so users can quickly identify broken models and fix them via prompts or manual edits.
How
Status is tracked at the DAG node level (not API level). When the DAG executor processes each node, it updates the corresponding
ConfigModelsrow in the database with the current status. This ensures accurate per-model status even when Model A succeeds but downstream Model B fails — Model A is marked SUCCESS while Model B is marked FAILED.The frontend
file_explorerAPI already returns the full model tree — we just add the new status fields to each model entry. The explorer renders a small colored dot inline before the model name based onrun_status. Failed models show a Popover on hover with the fullfailure_reasonandlast_run_at.Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)
Low risk:
NOT_STARTED), so existing models continue to workclear_cachedecorator fix actually addresses a pre-existing silent bug where execution errors were being swallowed and returningNoneTypeto DRF (causing 500 errors instead of proper error responses)ConfigModelsimport is wrapped in try/except sovisitranCLI still works without DjangoDatabase Migrations
backend/backend/core/migrations/0003_add_model_run_status.py— adds 4 nullable fields toconfigmodelstable (run_status, failure_reason, last_run_at, run_duration)Env Config
None
Relevant Docs
None
Related Issues or PRs
None
Dependencies Versions
No changes
Notes on Testing
Tested locally with Python 3.11:
clear_cachefix verified —MultipleColumnDependencyexception now returns proper 400 error response instead of 500 NoneTypeScreenshots
TBD — will add after testing locally
Checklist
I have read and understood the Contribution Guidelines.
🤖 Generated with Claude Code