Skip to content

fix: project list job stats not showing + uniform card height + clickable links#77

Open
wicky-zipstack wants to merge 1 commit intomainfrom
fix/project-list-job-stats
Open

fix: project list job stats not showing + uniform card height + clickable links#77
wicky-zipstack wants to merge 1 commit intomainfrom
fix/project-list-job-stats

Conversation

@wicky-zipstack
Copy link
Copy Markdown
Contributor

@wicky-zipstack wicky-zipstack commented May 1, 2026

What

  • Fix job stats (Scheduled/In Progress/Failed) not showing on project cards — always displayed "No jobs scheduled yet"
  • Add uniform card height so cards with and without jobs are the same size
  • Make job stats clickable — navigate to Jobs list or Run History

Why

  • apps.is_installed("job_scheduler") was returning False because it checks by app module path, not label. The scheduler app is registered as backend.core.scheduler with label job_scheduler, but is_installed() only matches by module path. The job count annotations were never running.
  • Cards without jobs were shorter than cards with jobs, causing uneven grid layout.
  • Users had no way to navigate from the project card to the job scheduler or run history.

How

  • Backend (base_context.py): Replaced apps.is_installed("job_scheduler") with apps.get_app_config("job_scheduler") wrapped in try/except — get_app_config resolves by label correctly.
  • CSS (ProjectListCard.css): Added min-height: 38px to .project-list-card-no-jobs with display: flex; align-items: center for uniform height.
  • JSX (ProjectListCard.jsx): Added onClick handlers with e.stopPropagation() — Scheduled navigates to /project/job/list, In Progress and Failed navigate to /project/job/history. Added cursor pointer + hover opacity via .project-list-card-job-link class.

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)

  • No breaking changes. The backend fix is a detection-method change — same logic runs, just the app lookup works correctly now. Frontend changes are additive — click handlers use stopPropagation so the card click still works. CSS adds min-height which only affects empty-state cards.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

  • N/A

Related Issues or PRs

  • N/A

Dependencies Versions

  • No new dependencies

Notes on Testing

  • Verify project cards show job stats (Scheduled/In Progress/Failed) for projects with jobs
  • Verify "No jobs scheduled yet" appears for projects without jobs
  • Verify card heights are uniform across all projects
  • Verify clicking "Scheduled" navigates to Jobs list page
  • Verify clicking "In Progress" or "Failed" navigates to Run History page
  • Verify card click still opens the project (not intercepted by job links)

Screenshots

image

Checklist

…able links

- Fix apps.is_installed("job_scheduler") returning False — use
  apps.get_app_config() instead (checks by label, not module path)
- Add min-height to "No jobs" section for uniform card height
- Make Scheduled/In Progress/Failed clickable — navigate to
  Jobs list or Run History page
@wicky-zipstack wicky-zipstack requested review from a team as code owners May 1, 2026 04:37
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 1, 2026

Greptile Summary

This PR fixes three related issues with project list cards: job stats never appearing (due to apps.is_installed matching by module path instead of app label), uneven card heights between cards with and without jobs, and the absence of clickable navigation on job stat badges. The backend fix is correct and minimal; the frontend changes are additive and follow existing patterns in the codebase.

Confidence Score: 4/5

Safe to merge — all findings are P2 style/UX suggestions with no runtime breakage.

Only P2 findings: the scheduler-installed check is recomputed on every request (trivial overhead), and job-stat links navigate to global routes without a project filter (consistent with existing NavigationTabs behaviour but potentially confusing UX).

No files require special attention; both P2 comments are enhancement suggestions, not blockers.

Important Files Changed

Filename Overview
backend/backend/application/context/base_context.py Replaces apps.is_installed (matched by module path) with apps.get_app_config in a try/except (matched by label), correctly fixing the always-false check; minor: result is recomputed on every request rather than cached at module level.
frontend/src/base/components/project-list/ProjectListCard.css Adds min-height: 38px + flex centering to .project-list-card-no-jobs for uniform card height, and introduces .project-list-card-job-link with cursor pointer and hover opacity — clean, additive changes with no issues.
frontend/src/base/components/project-list/ProjectListCard.jsx Adds onClick handlers with e.stopPropagation() to job-stat Typography elements; navigates to global /project/job/list and /project/job/history routes without a project-specific filter, which may confuse users expecting project-scoped results.

Sequence Diagram

sequenceDiagram
    participant Browser
    participant ProjectListCard
    participant Django as Django Backend
    participant AppRegistry as Django App Registry

    Browser->>Django: GET /api/projects/list
    Django->>AppRegistry: get_app_config("job_scheduler")
    AppRegistry-->>Django: AppConfig (or LookupError)
    Note over Django: _scheduler_installed = True/False
    Django->>Django: Annotate queryset with job counts (if installed)
    Django-->>Browser: Project list + job stats

    Browser->>ProjectListCard: Render cards with job stats
    Note over ProjectListCard: Show stats if any > 0, else "No jobs scheduled yet"

    ProjectListCard->>Browser: User clicks "Scheduled"
    Browser->>Browser: e.stopPropagation()
    Browser->>Browser: navigate("/project/job/list")

    ProjectListCard->>Browser: User clicks "In Progress" or "Failed"
    Browser->>Browser: e.stopPropagation()
    Browser->>Browser: navigate("/project/job/history")
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
backend/backend/application/context/base_context.py:184-189
**Scheduler check recomputed on every request**

`apps.get_app_config("job_scheduler")` is called inside the request handler on every project-list fetch. Since the Django app registry is fixed at startup, this result never changes at runtime. Consider hoisting the check to module level (or caching it as a module-level constant) to avoid the repeated try/except overhead on every request.

```python
# module level, outside the class/method
from django.apps import apps as _django_apps
try:
    _django_apps.get_app_config("job_scheduler")
    _SCHEDULER_INSTALLED = True
except LookupError:
    _SCHEDULER_INSTALLED = False
```

Then replace the inline block with just:
```python
if _SCHEDULER_INSTALLED and hasattr(ProjectDetails, "user_tasks"):
```

### Issue 2 of 2
frontend/src/base/components/project-list/ProjectListCard.jsx:226-255
**Job link navigation missing project context**

Clicking any of the three job-stat links navigates to the global `/project/job/list` or `/project/job/history` route without carrying the current project's ID. A user clicking "3 Scheduled" on a specific project card will land on the full global jobs list with no filter applied, which can be disorienting. Other call sites (e.g. `no-code-model.jsx`) pass a `task=` or params query string; at minimum passing a project filter would make these links meaningfully project-scoped.

This matches the existing `NavigationTabs` behaviour, so it may be intentional, but it is worth confirming whether the Jobs/Run History pages support a project filter query param.

Reviews (1): Last reviewed commit: "fix: project list job stats not showing ..." | Re-trigger Greptile

Comment on lines 184 to +189
from django.apps import apps
if apps.is_installed("job_scheduler") and hasattr(ProjectDetails, "user_tasks"):
try:
apps.get_app_config("job_scheduler")
_scheduler_installed = True
except LookupError:
_scheduler_installed = False
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Scheduler check recomputed on every request

apps.get_app_config("job_scheduler") is called inside the request handler on every project-list fetch. Since the Django app registry is fixed at startup, this result never changes at runtime. Consider hoisting the check to module level (or caching it as a module-level constant) to avoid the repeated try/except overhead on every request.

# module level, outside the class/method
from django.apps import apps as _django_apps
try:
    _django_apps.get_app_config("job_scheduler")
    _SCHEDULER_INSTALLED = True
except LookupError:
    _SCHEDULER_INSTALLED = False

Then replace the inline block with just:

if _SCHEDULER_INSTALLED and hasattr(ProjectDetails, "user_tasks"):
Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/backend/application/context/base_context.py
Line: 184-189

Comment:
**Scheduler check recomputed on every request**

`apps.get_app_config("job_scheduler")` is called inside the request handler on every project-list fetch. Since the Django app registry is fixed at startup, this result never changes at runtime. Consider hoisting the check to module level (or caching it as a module-level constant) to avoid the repeated try/except overhead on every request.

```python
# module level, outside the class/method
from django.apps import apps as _django_apps
try:
    _django_apps.get_app_config("job_scheduler")
    _SCHEDULER_INSTALLED = True
except LookupError:
    _SCHEDULER_INSTALLED = False
```

Then replace the inline block with just:
```python
if _SCHEDULER_INSTALLED and hasattr(ProjectDetails, "user_tasks"):
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — apps.get_app_config() is a dict lookup internally (O(1), nanosecond overhead). Caching at module level would save the try/except but the gain is negligible for a page-load endpoint. Can optimize in a follow-up if profiling shows it matters.

Comment on lines +226 to 255
<Typography.Text
className="project-list-card-job-link"
onClick={(e) => {
e.stopPropagation();
navigate("/project/job/list");
}}
>
<ExclamationCircleFilled className="project-list-card-status-icon warning" />
{details?.total_scheduled_jobs} Scheduled
</Typography.Text>
<Typography.Text>
<Typography.Text
className="project-list-card-job-link"
onClick={(e) => {
e.stopPropagation();
navigate("/project/job/history");
}}
>
<InfoCircleFilled className="project-list-card-status-icon info" />
{details?.total_active_jobs} In&nbsp;Progress
</Typography.Text>
<Typography.Text>
<Typography.Text
className="project-list-card-job-link"
onClick={(e) => {
e.stopPropagation();
navigate("/project/job/history");
}}
>
<CheckCircleFilled className="project-list-card-status-icon failed" />
{details?.total_failed_job} Failed
</Typography.Text>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Job link navigation missing project context

Clicking any of the three job-stat links navigates to the global /project/job/list or /project/job/history route without carrying the current project's ID. A user clicking "3 Scheduled" on a specific project card will land on the full global jobs list with no filter applied, which can be disorienting. Other call sites (e.g. no-code-model.jsx) pass a task= or params query string; at minimum passing a project filter would make these links meaningfully project-scoped.

This matches the existing NavigationTabs behaviour, so it may be intentional, but it is worth confirming whether the Jobs/Run History pages support a project filter query param.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/base/components/project-list/ProjectListCard.jsx
Line: 226-255

Comment:
**Job link navigation missing project context**

Clicking any of the three job-stat links navigates to the global `/project/job/list` or `/project/job/history` route without carrying the current project's ID. A user clicking "3 Scheduled" on a specific project card will land on the full global jobs list with no filter applied, which can be disorienting. Other call sites (e.g. `no-code-model.jsx`) pass a `task=` or params query string; at minimum passing a project filter would make these links meaningfully project-scoped.

This matches the existing `NavigationTabs` behaviour, so it may be intentional, but it is worth confirming whether the Jobs/Run History pages support a project filter query param.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid point — currently navigates to the global Jobs/Run History pages, consistent with how the sidebar navigation works (same routes, no project filter). Filtering by project would need a query param (?project=<id>) which the Jobs page doesn't support yet. Will address when project-scoped filtering is added to the Jobs page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant