feat: add Files tab backed by the managed-files endpoint (#727)
* feat: add Files tab backed by the managed-files endpoint Add a Hermes Mobile tab that browses the gateway's managed-files root via the existing /api/files* backend routes: list/navigate folders, breadcrumb path, create folder, upload (streaming multipart), delete, and open files via the authenticated GatewayFileClient download URL. - data/model/ManagedFile: entry + list/read/upload/mkdir/delete models - HermesApiService: list/read/upload(+stream)/mkdir/delete endpoints - FilesViewModel: state, navigation, per-row busy, transient-state cleanup - FilesScreen: folder list, breadcrumb, FAB new folder, upload picker, delete confirm, open via system viewer - NavigationKeys + ScreenRegistry + strings: register in Inspect drawer section * fix(files): open files in-app via FileProvider instead of browser URL The previous file-open path handed a ?token=-authenticated URL to the system browser, but /api/files/download only accepts the ephemeral in-process session token as ?token=, not the mobile's Bearer token — so the request failed and the browser rendered the JSON error body instead of the file. Fix: download the file in-app through the authenticated client (Bearer/ session-cookie, same path as the rest of the app), decode the base64 data_url, write it to cacheDir, and open it via FileProvider.getUriForFile + ACTION_VIEW (mirrors the existing ChatScreen/SystemViewModel open-from-cache pattern). Works on a remote phone since the file is materialized locally first. --------- Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
439ae9fcba
commit
6aee02c4da
8 files changed
+1024
No files matched your search
@@ -35,6 +35,12 @@ import com.m57.hermescontrol.data.model.KanbanBoardResponse
|
||||
import com.m57.hermescontrol.data.model.KanbanBoardsResponse
|
||||
import com.m57.hermescontrol.data.model.KanbanTask
|
||||
import com.m57.hermescontrol.data.model.LogResponse
|
||||
import com.m57.hermescontrol.data.model.ManagedDirectoryCreate
|
||||
import com.m57.hermescontrol.data.model.ManagedFileActionResponse
|
||||
import com.m57.hermescontrol.data.model.ManagedFileDelete
|
||||
import com.m57.hermescontrol.data.model.ManagedFileRead
|
||||
import com.m57.hermescontrol.data.model.ManagedFileUpload
|
||||
import com.m57.hermescontrol.data.model.ManagedFilesListResponse
|
||||
import com.m57.hermescontrol.data.model.McpCatalogInstallRequest
|
||||
import com.m57.hermescontrol.data.model.McpCatalogResponse
|
||||
import com.m57.hermescontrol.data.model.McpServer
|
||||
@@ -106,9 +112,11 @@ import retrofit2.http.Body
|
||||
import retrofit2.http.DELETE
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.HTTP
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.PATCH
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
import retrofit2.http.Part
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
@@ -757,4 +765,41 @@ interface HermesApiService {
|
||||
@Path("name") name: String,
|
||||
@Query("lines") lines: Int = 200,
|
||||
): Response<ActionStatusResponse>
|
||||
|
||||
// ── Managed Files ──────────────────────────────────────────────────
|
||||
// Backed by hermes_cli/web_server.py /api/files* endpoints. The mobile app
|
||||
// talks to the dashboard (9119) and authenticates with the standard
|
||||
// Bearer/session-cookie middleware, so no ?token= query param is needed.
|
||||
@GET("api/files")
|
||||
suspend fun listManagedFiles(
|
||||
@Query("path") path: String? = null,
|
||||
): Response<ManagedFilesListResponse>
|
||||
|
||||
@GET("api/files/read")
|
||||
suspend fun readManagedFile(
|
||||
@Query("path") path: String,
|
||||
): Response<ManagedFileRead>
|
||||
|
||||
@POST("api/files/upload")
|
||||
suspend fun uploadManagedFile(
|
||||
@Body body: ManagedFileUpload,
|
||||
): Response<ManagedFileActionResponse>
|
||||
|
||||
@Multipart
|
||||
@POST("api/files/upload-stream")
|
||||
suspend fun uploadManagedFileStream(
|
||||
@Part("path") path: okhttp3.RequestBody,
|
||||
@Part("overwrite") overwrite: okhttp3.RequestBody,
|
||||
@Part file: okhttp3.MultipartBody.Part,
|
||||
): Response<ManagedFileActionResponse>
|
||||
|
||||
@POST("api/files/mkdir")
|
||||
suspend fun createManagedDirectory(
|
||||
@Body body: ManagedDirectoryCreate,
|
||||
): Response<ManagedFileActionResponse>
|
||||
|
||||
@HTTP(method = "DELETE", path = "api/files", hasBody = true)
|
||||
suspend fun deleteManagedFile(
|
||||
@Body body: ManagedFileDelete,
|
||||
): Response<ManagedFileActionResponse>
|
||||
}
|
||||
Reference in new issue
Block a user