feat: Frontend File Management and UI Enhancements#649
Open
Viyyy wants to merge 14 commits into
Open
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds richer file-management and clipboard-driven upload capabilities, plus several UI enhancements (resolution controls and a “web fullscreen” layout mode) to improve day-to-day remote desktop usage.
Changes:
- Added file deletion/rename support in the filetransfer plugin and exposed them via legacy HTTP proxy endpoints.
- Implemented frontend file filtering + preview modal, and added paste/drag-and-drop upload flows.
- Updated Chrome container policies and UI layout to better support downloads, clipboard, and fullscreen-like behavior.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| server/internal/plugins/filetransfer/manager.go | Adds DELETE/PATCH handlers for file deletion and rename. |
| server/internal/http/legacy/handler.go | Proxies new clipboard/upload-drop + file delete/rename endpoints to the v3 API. |
| server/internal/api/room/handler.go | Enables POST for clipboard image endpoint. |
| server/internal/api/room/clipboard.go | Re-enables clipboard image upload support and adjusts imports/commented code. |
| Dockerfile.dev | Adds a dev Dockerfile that builds server + client into a chrome runtime image. |
| docker-compose.yaml | Switches compose to a dev chrome image and enables filetransfer + higher FPS/bitrate. |
| config.yml | Enables upload-drop/file chooser dialog and changes implicit hosting default. |
| client/src/store/video.ts | Persists screen resolution settings to localStorage. |
| client/src/store/client.ts | Adds webFullscreen state + mutation. |
| client/src/neko/index.ts | Restores persisted resolution for admins on connect. |
| client/src/neko/base.ts | Prevents sending data over a non-open RTC data channel. |
| client/src/locale/zh-cn.ts | Adds file-management UI strings (but missing transfers). |
| client/src/locale/en-us.ts | Adds file-management UI strings including transfers. |
| client/src/components/video.vue | Adds paste + drag/drop handlers and a web-fullscreen toggle. |
| client/src/components/resolution.vue | Adds “fit to window” and custom resolution inputs. |
| client/src/components/files.vue | Adds filtering, preview modal, rename/delete actions, and collapsible transfers area. |
| client/src/app.vue | Hides header/sidebar/controls in web fullscreen and adds collapsible controls. |
| apps/google-chrome/supervisord.conf | Removes --disable-file-system flag. |
| apps/google-chrome/policies.json | Relaxes download restrictions and enables clipboard + file dialogs (broadly). |
| .gitignore | Ignores data/**. |
| .claude/skills/dev-guide/SKILL.md | Adds an internal development guide document. |
| .claude/settings.local.json | Adds local tool-permissions configuration (new file). |
Comments suppressed due to low confidence (3)
server/internal/http/legacy/handler.go:437
- The backend response body returned from s.req is an io.ReadCloser and is not closed here. Add a defer body.Close() after successful s.req to avoid leaking HTTP connections/resources on repeated drop uploads.
body, _, err := s.req(http.MethodPost, "/api/room/upload/drop", r.Header, r.Body)
if err != nil {
return utils.HttpInternalServerError().WithInternalErr(err)
}
_, err = io.Copy(w, body)
return err
})
server/internal/http/legacy/handler.go:489
- This handler proxies the backend response but doesn’t close the io.ReadCloser from s.req and doesn’t copy Content-Type from backend headers. Consider deferring body.Close() and forwarding Content-Type so clients receive the correct MIME type for JSON responses.
body, _, err := s.req(http.MethodPatch, "/api/filetransfer?filename="+url.QueryEscape(filename), r.Header, r.Body)
if err != nil {
return utils.HttpInternalServerError().WithInternalErr(err)
}
_, err = io.Copy(w, body)
return err
})
client/src/components/files.vue:553
download()creates an object URL for the downloaded blob but never revokes it. Consider revoking the URL after triggering the download to avoid accumulating blob URLs in long sessions.
const a = document.createElement('a')
a.href = URL.createObjectURL(new Blob([res.data]))
a.setAttribute('download', item.name)
document.body.appendChild(a); a.click(); document.body.removeChild(a)
transfer.progress = transfer.size; transfer.status = 'completed'
}).catch((error) => {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+366
to
+370
| if err := os.Remove(filePath); err != nil { | ||
| return utils.HttpInternalServerError(). | ||
| WithInternalErr(err). | ||
| Msg("error deleting file") | ||
| } |
Comment on lines
+422
to
+429
| oldPath := filepath.Join(m.config.RootDir, filename) | ||
| newPath := filepath.Join(m.config.RootDir, newName) | ||
|
|
||
| if err := os.Rename(oldPath, newPath); err != nil { | ||
| return utils.HttpInternalServerError(). | ||
| WithInternalErr(err). | ||
| Msg("error renaming file") | ||
| } |
Comment on lines
+406
to
+412
| body, _, err := s.req(http.MethodPost, "/api/room/clipboard/image.png", r.Header, r.Body) | ||
| if err != nil { | ||
| return utils.HttpInternalServerError().WithInternalErr(err) | ||
| } | ||
|
|
||
| _, err = io.Copy(w, body) | ||
| return err |
Comment on lines
+456
to
+463
| body, _, err := s.req(http.MethodDelete, "/api/filetransfer?filename="+url.QueryEscape(filename), r.Header, nil) | ||
| if err != nil { | ||
| return utils.HttpInternalServerError().WithInternalErr(err) | ||
| } | ||
|
|
||
| _, err = io.Copy(w, body) | ||
| return err | ||
| }) |
Comment on lines
123
to
133
| export const files = { | ||
| downloads: '下载', | ||
| uploads: '上传', | ||
| upload_here: '点击或拖动文件到此处上传', | ||
| download: '下载', | ||
| rename: '重命名', | ||
| delete: '删除', | ||
| preview: '预览', | ||
| no_files: '暂无文件', | ||
| preview_unsupported: '该文件类型不支持预览', | ||
| } |
| - NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD=admin | ||
| - NEKO_WEBRTC_EPR=52000-52100 | ||
| - NEKO_WEBRTC_ICELITE=1 | ||
| - NEKO_NAT1TO1=192.168.110.51 |
Comment on lines
+22
to
26
| "ClipboardAllowedForUrls": ["*"], | ||
| "URLAllowlist": [ | ||
| "file:///home/neko/Downloads" | ||
| ], | ||
| "URLBlocklist": [ |
| --disable-file-system | ||
| --disable-gpu | ||
| --disable-software-rasterizer | ||
| --disable-dev-shm-usage |
Comment on lines
+3
to
+17
| "allow": [ | ||
| "Skill(update-config)", | ||
| "Skill(update-config:*)", | ||
| "WebSearch", | ||
| "Bash(docker pull *)", | ||
| "Bash(docker build *)", | ||
| "Bash(docker run *)", | ||
| "Bash(docker rm *)", | ||
| "Bash(curl -s http://localhost:8080/api/stats)", | ||
| "Bash(docker exec *)", | ||
| "Bash(ipconfig)", | ||
| "Bash(docker compose *)", | ||
| "Bash(git add *)", | ||
| "Bash(git commit *)" | ||
| ] |
Comment on lines
22
to
25
| session: | ||
| merciful_reconnect: true | ||
| # default setting for legacy API | ||
| implicit_hosting: false | ||
| implicit_hosting: true | ||
| cookie: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New Features and Improvements
Impact