feat(servers-ui): Add new UI for server list#6610
Conversation
js is unavoidable. pure css accordion with proper animations can be made but it cant be accessible so i had to use the inert prop so might as well ditch <summary> and just use normal div
Confidence Score: 2/5Not safe to merge — several dialogs (AppsDialog, AddSiteDialog) and the pipeline socket wiring in BenchRow have confirmed broken flows that were identified in earlier review rounds and are still unresolved. Multiple interactive paths in the new UI have open defects: the pipeline socket listener accumulates on every re-deploy without ever calling socket.off, onBeforeUnmount is registered inside a conditional (Vue 3 antipattern that leaks the cleanup for benches that later go active), app.title.toLowerCase() crashes the apps dialog when any app has no title, and the async onSuccess in AppsDialog swallows deploy errors silently. These are not theoretical — each one breaks a primary user journey (deploy bench, search apps, error feedback). BenchRow.vue (pipeline socket lifecycle), AppsDialog.vue (null title crash + unhandled async error), AddSiteDialog.vue (silent site-creation errors)
|
| Filename | Overview |
|---|---|
| dashboard/src/pages/servers/list/Page.vue | Main list page with filtering and pagination; refresh button now functional and cluster.title filter key corrected, but breadcrumb still links to /ser and stray w attribute on Status Select remain (tracked in prior threads). |
| dashboard/src/pages/servers/list/BenchRow.vue | Pipeline socket listener is not removed on Success/Failure (tracked), onBeforeUnmount is called inside a conditional (tracked), and the site socket cleanup is correct; dropBench is now properly imported. |
| dashboard/src/pages/servers/list/ServerCard.vue | Server status dot and text are now dynamic; active_benches and site_count are properly fetched; onSuccess callback is now passed correctly to AddBenchDialog. |
| dashboard/src/pages/servers/list/utils.ts | onDropServer message now uses list-prop fields directly (null-dereference fixed); route name matches router.js; error.messages.length still lacks optional chaining in the drop-server error handler (tracked). |
| dashboard/src/pages/servers/list/AppsDialog.vue | apiRes, checkboxes, and submit handler are now wired; filteredApps still calls app.title.toLowerCase() without optional chaining (tracked), and async onSuccess has no try/catch (tracked). |
| dashboard/src/pages/servers/list/AddSiteDialog.vue | apiRes crash and debug leaks are fixed; search now uses filteredApps computed; newSite still has no onError handler (tracked). |
| dashboard/src/pages/servers/list/AddBenchDialog.vue | Correctly passes server.name and server.cluster to the API; onSuccess prop is required and now always supplied by the caller; version selection and form validation look correct. |
| press/api/bench.py | Single-field addition (description) to the all_apps marketplace query — safe, no logic change. |
Reviews (46): Last reviewed commit: "fix(servers-ui): make server name a link" | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #6610 +/- ##
============================================
- Coverage 62.90% 50.65% -12.25%
============================================
Files 117 993 +876
Lines 18093 83596 +65503
Branches 526 526
============================================
+ Hits 11381 42345 +30964
- Misses 6680 41219 +34539
Partials 32 32
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@greptile-apps re-review. I have changed many files, now show the new fix suggestions |
|
@greptile-apps rereview |
|
@greptile-apps rereview |
| const benches = createListResource({ | ||
| doctype: 'Release Group', | ||
| pageLength: 5, | ||
| auto: true, | ||
| fields: ['name', 'title', 'version', 'active_benches', "site_count"], | ||
| filters: { server: props.data.name }, | ||
| cache: ['benchesRes', props.data.name], | ||
| orderBy: 'creation desc', | ||
| }) |
There was a problem hiding this comment.
Hard
pageLength: 5 with no "Load more" button silently truncates benches. A server with 6+ benches will always show only 5 with no indication that more exist. The same problem affects sites in BenchRow.vue (also pageLength: 5). Add a conditional "Load more" link below the bench list and below the site list.
| const benches = createListResource({ | |
| doctype: 'Release Group', | |
| pageLength: 5, | |
| auto: true, | |
| fields: ['name', 'title', 'version', 'active_benches', "site_count"], | |
| filters: { server: props.data.name }, | |
| cache: ['benchesRes', props.data.name], | |
| orderBy: 'creation desc', | |
| }) | |
| const benches = createListResource({ | |
| doctype: 'Release Group', | |
| pageLength: 10, | |
| auto: true, | |
| fields: ['name', 'title', 'version', 'active_benches', "site_count"], | |
| filters: { server: props.data.name }, | |
| cache: ['benchesRes', props.data.name], | |
| orderBy: 'creation desc', | |
| }) |
Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/pages/servers/list/ServerCard.vue
Line: 17-25
Comment:
Hard `pageLength: 5` with no "Load more" button silently truncates benches. A server with 6+ benches will always show only 5 with no indication that more exist. The same problem affects `sites` in `BenchRow.vue` (also `pageLength: 5`). Add a conditional "Load more" link below the bench list and below the site list.
```suggestion
const benches = createListResource({
doctype: 'Release Group',
pageLength: 10,
auto: true,
fields: ['name', 'title', 'version', 'active_benches', "site_count"],
filters: { server: props.data.name },
cache: ['benchesRes', props.data.name],
orderBy: 'creation desc',
})
```
How can I resolve this? If you propose a fix, please make it concise.| const newSite = createResource({ | ||
| url: 'press.api.client.insert', | ||
| onSuccess() { | ||
| emit('siteCreated') | ||
| show.value = false | ||
| }, | ||
| }) |
There was a problem hiding this comment.
Silent failure on site-creation error.
newSite has no onError handler. If press.api.client.insert fails (invalid subdomain, plan limits, etc.), the error is swallowed: the dialog stays open, nothing is shown to the user, and loading clears. Add an onError that writes to an err ref or shows a toast, consistent with apiRes.onError in AppsDialog.vue.
Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/pages/servers/list/AddSiteDialog.vue
Line: 66-72
Comment:
**Silent failure on site-creation error.** `newSite` has no `onError` handler. If `press.api.client.insert` fails (invalid subdomain, plan limits, etc.), the error is swallowed: the dialog stays open, nothing is shown to the user, and `loading` clears. Add an `onError` that writes to an `err` ref or shows a toast, consistent with `apiRes.onError` in `AppsDialog.vue`.
How can I resolve this? If you propose a fix, please make it concise.| async onSuccess() { | ||
| const info = await deployInfoRes.submit({ name: props.bench.name }) | ||
|
|
||
| const apps = info.apps | ||
| .filter((a) => addedApps.find((x) => x.name === a.name)) | ||
| .map((a) => ({ | ||
| app: a.name, | ||
| source: a.source, | ||
| release: | ||
| a.releases?.find((r) => r.name === a.next_release && !r.is_yanked) | ||
| ?.name ?? a.next_release, | ||
| hash: | ||
| a.releases?.find((r) => r.name === a.next_release && !r.is_yanked) | ||
| ?.hash ?? a.next_release_hash, | ||
| })) | ||
|
|
||
| deployRes.submit({ | ||
| name: props.bench.name, | ||
| apps, | ||
| sites: [], | ||
| run_will_fail_check: true, | ||
| }) | ||
| }, |
There was a problem hiding this comment.
Unhandled rejection in
apiRes.onSuccess swallows deploy errors. The async onSuccess awaits deployInfoRes.submit(...) but has no try/catch. If deploy_information fails (network error, server-side exception), the rejected promise is uncaught: deployRes.submit never runs, err is not set, and the dialog stays open with no feedback. Wrap the body in a try/catch and set err.value on failure, or add onError to deployInfoRes.
Prompt To Fix With AI
This is a comment left during a code review.
Path: dashboard/src/pages/servers/list/AppsDialog.vue
Line: 45-67
Comment:
**Unhandled rejection in `apiRes.onSuccess` swallows deploy errors.** The `async onSuccess` `await`s `deployInfoRes.submit(...)` but has no `try/catch`. If `deploy_information` fails (network error, server-side exception), the rejected promise is uncaught: `deployRes.submit` never runs, `err` is not set, and the dialog stays open with no feedback. Wrap the body in a `try/catch` and set `err.value` on failure, or add `onError` to `deployInfoRes`.
How can I resolve this? If you propose a fix, please make it concise.
Issue: #6438
Note: Dialogs are async components so a lil delay while opening
New UI for servers list
Screen.Recording.2026-06-10.at.8.30.02.PM.mov
Add Bench & deploy
Screen.Recording.2026-06-10.at.8.31.30.PM.mov
Add Site
Screen.Recording.2026-06-10.at.8.40.21.PM.mov