Skip to content

feat: add status filter to projects table#1328

Closed
cabaucom376 wants to merge 17 commits intomainfrom
feat/inactive-project-sorting
Closed

feat: add status filter to projects table#1328
cabaucom376 wants to merge 17 commits intomainfrom
feat/inactive-project-sorting

Conversation

@cabaucom376
Copy link
Copy Markdown
Collaborator

@cabaucom376 cabaucom376 commented Jan 4, 2026

closes #1163

Disclaimer Greptiles Reviews use AI, make sure to check over its work

Greptile Overview

Greptile Summary

This PR adds a status filter to the projects table, allowing users to filter projects by their runtime status (running, stopped, partially running).

Implementation Overview

Backend Changes:

  • Added Status query parameter to the API endpoint (ListProjectsInput)
  • Refactored ListProjects service method to fetch all projects, enrich with live Docker status, then filter and paginate in-memory
  • Added filter accessors for both "status" and "projectStatus" keys to support frontend mapping

Frontend Changes:

  • Created statusFilters array with filter options (running, stopped, partially running)
  • Added status filter component to the table toolbar
  • Mapped column ID from "status" to "projectStatus" to avoid conflicts with the table library
  • Added filter key remapping in project-service.ts to transform "projectStatus" back to "status" for API calls
  • Added translation key for "Partially Running" status

Architecture

The implementation follows the existing pattern used for other table filters in the codebase. The filter supports comma-separated values for multi-select filtering, which is handled by the pagination utility's matchValue function.

The backend now uses a different approach than database-level filtering: it fetches all projects, enriches them with live Docker container status, then filters in-memory. This ensures the status filter always reflects the true runtime state rather than stale database values.

Issues Found

  1. Missing "unknown" status option - The filter only includes 3 of the 7 supported statuses. Projects can have "unknown" status when first discovered or when Docker status cannot be determined.

  2. Performance consideration - The new approach fetches and enriches all projects before filtering, which could impact performance with large project counts. This is a trade-off for accuracy.

Confidence Score: 4/5

  • This PR is safe to merge with minor improvements recommended
  • The implementation is solid and follows existing patterns in the codebase. The core functionality works correctly with proper filter handling, API mapping, and frontend-backend integration. Two issues identified: (1) missing "unknown" status in filter options is a minor feature gap that doesn't break functionality, and (2) the performance consideration around fetching all projects is a documented architectural trade-off for accuracy. The code is clean, well-structured, and maintains consistency with the rest of the codebase.
  • frontend/src/lib/components/arcane-table/data.ts requires adding the "unknown" status option; backend/internal/services/project_service.go may need performance optimization for deployments with many projects

Important Files Changed

File Analysis

Filename Score Overview
backend/internal/huma/handlers/projects.go 4/5 Added status filter query parameter to ListProjectsInput. Minor change, properly documented with example statuses.
backend/internal/services/project_service.go 3/5 Major refactor: Changed from DB-level filtering to in-memory filtering after enriching all projects with live status. This ensures accurate status filtering but may have performance implications with many projects.
frontend/src/lib/components/arcane-table/data.ts 3/5 Added statusFilters array with three status options (running, stopped, partially running). Missing "unknown" status which is supported by the backend.
frontend/src/lib/services/project-service.ts 5/5 Added mapping logic to transform 'projectStatus' filter key to 'status' for API compatibility. Correct implementation.
frontend/src/routes/(app)/projects/projects-table.svelte 5/5 Changed column ID from 'status' to 'projectStatus' for filter compatibility. Updated mobile field visibility references accordingly.

@cabaucom376 cabaucom376 requested a review from a team January 4, 2026 00:18
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 4, 2026

🔍 Deadcode Analysis

Found 1 unreachable functions in the backend.

View details
internal/utils/pagination/params.go:15:6: unreachable func: ExtractListModifiersQueryParams

Only remove deadcode that you know is 100% no longer used.

Analysis from commit 8b29b42

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

13 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Comment thread backend/internal/services/project_service.go Outdated
Comment thread frontend/src/routes/(app)/projects/projects-table.svelte Outdated
Comment thread frontend/src/routes/(app)/projects/projects-table.svelte Outdated
Comment thread backend/internal/huma/handlers/users.go Outdated
@cabaucom376 cabaucom376 force-pushed the feat/inactive-project-sorting branch from ce50317 to 42dbcf9 Compare January 4, 2026 00:25
@cabaucom376
Copy link
Copy Markdown
Collaborator Author

I'm not sure I like this current solution. The desired behavior is to just get rid of stopped projects from the view, so a filter like usage on the images table would be better.

@cabaucom376 cabaucom376 changed the title feat: customize sort order for stopped projects in table feat: add status filter to projects table Jan 5, 2026
@cabaucom376
Copy link
Copy Markdown
Collaborator Author

@greptileai

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jan 5, 2026

Greptile's behavior is changing!

From now on, if a review finishes with no comments, we will not post an additional "statistics" comment to confirm that our review found nothing to comment on. However, you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

@kmendell
Copy link
Copy Markdown
Member

kmendell commented Jan 5, 2026

I couldnt get this to work, which then got me thinking the existsing status field should be able to work for this id think

@cabaucom376
Copy link
Copy Markdown
Collaborator Author

cabaucom376 commented Jan 5, 2026

It is working for me but I'n all honesty I am now noticing it is janky starting it back up. If you stop a project externally it still shows the project under the running filter even though the status is correctly showing Stopped. I'll take another look.

On a side note, not related to this issue, but selecting multiple filters does not properly work, it seems to behave as a first selected basis. Try selecting both option under images usage filter for an example

@cabaucom376
Copy link
Copy Markdown
Collaborator Author

Check that out is that what you meant?

@getarcaneappbot
Copy link
Copy Markdown
Contributor

getarcaneappbot commented Jan 7, 2026

Docker images for this PR have been built successfully!

  • Manager: ghcr.io/getarcaneapp/arcane:pr-1328
  • Agent: ghcr.io/getarcaneapp/arcane-headless:pr-1328

Built from commit 1d69b38

@kmendell
Copy link
Copy Markdown
Member

kmendell commented Jan 8, 2026

@cabaucom376 See the filter fix i made in #1391, this is cleaner to me , and should fix every page as well.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 8, 2026

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

Copy link
Copy Markdown
Member

@cabaucom376 did you wanna try this again after my fixes ? or did you want me to try it?

@cabaucom376
Copy link
Copy Markdown
Collaborator Author

@kmendell I'll refactor it in like an hour 😃

@cabaucom376
Copy link
Copy Markdown
Collaborator Author

I just tried it and it still works just fine. Not sure if you would like to change anything else or what but I'll hand it off to you.

@kmendell
Copy link
Copy Markdown
Member

@greptileai

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +15 to +31
export const statusFilters = [
{
value: 'running',
label: m.common_running(),
icon: StartIcon
},
{
value: 'stopped',
label: m.common_stopped(),
icon: StopIcon
},
{
value: 'partially running',
label: m.common_partially_running(),
icon: AlertIcon
}
];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The statusFilters array is missing the "unknown" status, which is a valid project status supported by the backend (see ProjectStatusUnknown in backend/internal/models/project.go). The API handler documentation on line 44 of backend/internal/huma/handlers/projects.go lists "unknown" as one of the supported filter values.

Projects can have an "unknown" status when they're first discovered from the filesystem or when their Docker status cannot be determined. Users should be able to filter for these projects.

Consider adding the unknown status to maintain feature parity with the backend:

Suggested change
export const statusFilters = [
{
value: 'running',
label: m.common_running(),
icon: StartIcon
},
{
value: 'stopped',
label: m.common_stopped(),
icon: StopIcon
},
{
value: 'partially running',
label: m.common_partially_running(),
icon: AlertIcon
}
];
export const statusFilters = [
{
value: 'running',
label: m.common_running(),
icon: StartIcon
},
{
value: 'stopped',
label: m.common_stopped(),
icon: StopIcon
},
{
value: 'partially running',
label: m.common_partially_running(),
icon: AlertIcon
},
{
value: 'unknown',
label: m.common_unknown(),
icon: AlertIcon
}
];

Note: The common_unknown translation key already exists in all language files.

Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/lib/components/arcane-table/data.ts
Line: 15:31

Comment:
The statusFilters array is missing the "unknown" status, which is a valid project status supported by the backend (see `ProjectStatusUnknown` in `backend/internal/models/project.go`). The API handler documentation on line 44 of `backend/internal/huma/handlers/projects.go` lists "unknown" as one of the supported filter values.

Projects can have an "unknown" status when they're first discovered from the filesystem or when their Docker status cannot be determined. Users should be able to filter for these projects.

Consider adding the unknown status to maintain feature parity with the backend:

```suggestion
export const statusFilters = [
	{
		value: 'running',
		label: m.common_running(),
		icon: StartIcon
	},
	{
		value: 'stopped',
		label: m.common_stopped(),
		icon: StopIcon
	},
	{
		value: 'partially running',
		label: m.common_partially_running(),
		icon: AlertIcon
	},
	{
		value: 'unknown',
		label: m.common_unknown(),
		icon: AlertIcon
	}
];
```

Note: The `common_unknown` translation key already exists in all language files.

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

Comment on lines 1226 to 1234
func (s *ProjectService) ListProjects(ctx context.Context, params pagination.QueryParams) ([]project.Details, pagination.Response, error) {
var projectsArray []models.Project
query := s.db.WithContext(ctx).Model(&models.Project{})

if term := strings.TrimSpace(params.Search); term != "" {
searchPattern := "%" + term + "%"
query = query.Where(
"name LIKE ? OR path LIKE ? OR status LIKE ? OR COALESCE(dir_name, '') LIKE ?",
searchPattern, searchPattern, searchPattern, searchPattern,
)
// We fetch all projects from the database first, then enrich with live status,
// and finally filter and paginate in memory. This ensures the status filter
// always works against the true live status.
if err := s.db.WithContext(ctx).Find(&projectsArray).Error; err != nil {
return nil, pagination.Response{}, fmt.Errorf("failed to fetch projects: %w", err)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change from database-level filtering to fetching all projects and filtering in-memory could cause performance issues as the number of projects grows. The previous implementation used pagination.PaginateAndSortDB which applied filters at the database level, allowing the DB to efficiently handle large datasets.

The current approach:

  1. Fetches ALL projects from database (Find(&projectsArray))
  2. Enriches all of them with live Docker status
  3. Then filters and paginates in memory

This means that with 1000 projects, you're:

  • Loading 1000 database records
  • Making Docker API calls for all 1000 projects
  • Then filtering down to potentially just 10 results

While the comment justifies this as ensuring "the status filter always works against the true live status," this could be optimized by:

  1. Applying non-status filters at the DB level first
  2. Only enriching the filtered subset with live status
  3. Then applying the status filter in memory

Consider implementing a hybrid approach that filters on database fields first, then enriches and filters on runtime status. Alternatively, document this performance trade-off in the code comments and consider implementing pagination limits or caching strategies for deployments with many projects.

Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/internal/services/project_service.go
Line: 1226:1234

Comment:
This change from database-level filtering to fetching all projects and filtering in-memory could cause performance issues as the number of projects grows. The previous implementation used `pagination.PaginateAndSortDB` which applied filters at the database level, allowing the DB to efficiently handle large datasets.

The current approach:
1. Fetches ALL projects from database (`Find(&projectsArray)`)
2. Enriches all of them with live Docker status
3. Then filters and paginates in memory

This means that with 1000 projects, you're:
- Loading 1000 database records
- Making Docker API calls for all 1000 projects
- Then filtering down to potentially just 10 results

While the comment justifies this as ensuring "the status filter always works against the true live status," this could be optimized by:
1. Applying non-status filters at the DB level first
2. Only enriching the filtered subset with live status
3. Then applying the status filter in memory

Consider implementing a hybrid approach that filters on database fields first, then enriches and filters on runtime status. Alternatively, document this performance trade-off in the code comments and consider implementing pagination limits or caching strategies for deployments with many projects.

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

@github-actions
Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve the conflicts so the PR can stay up-to-date and reviewed.

@kmendell
Copy link
Copy Markdown
Member

Git screwed up locally and corrupted this branch, and would not let me pull it again, so i repushed it to a new branch feat/kyles-project-status, closign this in favor of that PR so i can finish work on it.

@kmendell kmendell closed this Jan 15, 2026
@cabaucom376 cabaucom376 deleted the feat/inactive-project-sorting branch January 15, 2026 01:14
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.

🐞 Bug: Eventlog severity filter does not work ⚡️ Feature: Keep Stopped Projects at the bottom

3 participants