diff --git a/weed/admin/dash/file_browser_data.go b/weed/admin/dash/file_browser_data.go index bd561e5ad..6e6e44c9d 100644 --- a/weed/admin/dash/file_browser_data.go +++ b/weed/admin/dash/file_browser_data.go @@ -3,7 +3,6 @@ package dash import ( "context" "path" - "sort" "strings" "time" @@ -34,34 +33,49 @@ type BreadcrumbItem struct { // FileBrowserData contains all data needed for the file browser view type FileBrowserData struct { - Username string `json:"username"` - CurrentPath string `json:"current_path"` - ParentPath string `json:"parent_path"` - Breadcrumbs []BreadcrumbItem `json:"breadcrumbs"` - Entries []FileEntry `json:"entries"` - TotalEntries int `json:"total_entries"` - TotalSize int64 `json:"total_size"` - LastUpdated time.Time `json:"last_updated"` - IsBucketPath bool `json:"is_bucket_path"` - BucketName string `json:"bucket_name"` + Username string `json:"username"` + CurrentPath string `json:"current_path"` + ParentPath string `json:"parent_path"` + Breadcrumbs []BreadcrumbItem `json:"breadcrumbs"` + Entries []FileEntry `json:"entries"` + + LastUpdated time.Time `json:"last_updated"` + IsBucketPath bool `json:"is_bucket_path"` + BucketName string `json:"bucket_name"` + // Pagination fields + PageSize int `json:"page_size"` + HasNextPage bool `json:"has_next_page"` + LastFileName string `json:"last_file_name"` // Cursor for next page + CurrentLastFileName string `json:"current_last_file_name"` // Cursor from current request (for page size changes) } -// GetFileBrowser retrieves file browser data for a given path -func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) { +// GetFileBrowser retrieves file browser data for a given path with cursor-based pagination +func (s *AdminServer) GetFileBrowser(dir string, lastFileName string, pageSize int) (*FileBrowserData, error) { if dir == "" { dir = "/" } - var entries []FileEntry - var totalSize int64 + // Set defaults for pagination + if pageSize < 1 { + pageSize = 20 // Default page size + } + + var entries []FileEntry + + // Fetch entries using cursor-based pagination + // We fetch pageSize+1 to determine if there's a next page + fetchLimit := pageSize + 1 + var fetchedCount int + var lastEntryName string - // Get directory listing from filer err := s.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error { + // Fetch entries starting from the cursor (lastFileName) stream, err := client.ListEntries(context.Background(), &filer_pb.ListEntriesRequest{ Directory: dir, Prefix: "", - Limit: 1000, - InclusiveStartFrom: false, + Limit: uint32(fetchLimit), + StartFromFileName: lastFileName, + InclusiveStartFrom: false, // Don't include the cursor file itself }) if err != nil { return err @@ -81,97 +95,102 @@ func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) { continue } - fullPath := path.Join(dir, entry.Name) + fetchedCount++ - var modTime time.Time - if entry.Attributes != nil && entry.Attributes.Mtime > 0 { - modTime = time.Unix(entry.Attributes.Mtime, 0) - } + // Only add entries up to pageSize (the +1 is just to check for next page) + if fetchedCount <= pageSize { + fullPath := path.Join(dir, entry.Name) - var mode string - var uid, gid uint32 - var size int64 - var replication, collection string - var ttlSec int32 - - if entry.Attributes != nil { - mode = FormatFileMode(entry.Attributes.FileMode) - uid = entry.Attributes.Uid - gid = entry.Attributes.Gid - size = int64(entry.Attributes.FileSize) - ttlSec = entry.Attributes.TtlSec - } - - // Get replication and collection from entry extended attributes or chunks - if entry.Extended != nil { - if repl, ok := entry.Extended["replication"]; ok { - replication = string(repl) + var modTime time.Time + if entry.Attributes != nil && entry.Attributes.Mtime > 0 { + modTime = time.Unix(entry.Attributes.Mtime, 0) } - if coll, ok := entry.Extended["collection"]; ok { - collection = string(coll) + + var mode string + var uid, gid uint32 + var size int64 + var replication, collection string + var ttlSec int32 + + if entry.Attributes != nil { + mode = FormatFileMode(entry.Attributes.FileMode) + uid = entry.Attributes.Uid + gid = entry.Attributes.Gid + size = int64(entry.Attributes.FileSize) + ttlSec = entry.Attributes.TtlSec } - } - // Determine MIME type based on file extension - mime := "application/octet-stream" - if entry.IsDirectory { - mime = "inode/directory" - } else { - ext := strings.ToLower(path.Ext(entry.Name)) - switch ext { - case ".txt", ".log": - mime = "text/plain" - case ".html", ".htm": - mime = "text/html" - case ".css": - mime = "text/css" - case ".js": - mime = "application/javascript" - case ".json": - mime = "application/json" - case ".xml": - mime = "application/xml" - case ".pdf": - mime = "application/pdf" - case ".jpg", ".jpeg": - mime = "image/jpeg" - case ".png": - mime = "image/png" - case ".gif": - mime = "image/gif" - case ".svg": - mime = "image/svg+xml" - case ".mp4": - mime = "video/mp4" - case ".mp3": - mime = "audio/mpeg" - case ".zip": - mime = "application/zip" - case ".tar": - mime = "application/x-tar" - case ".gz": - mime = "application/gzip" + // Get replication and collection from entry extended attributes + if entry.Extended != nil { + if repl, ok := entry.Extended["replication"]; ok { + replication = string(repl) + } + if coll, ok := entry.Extended["collection"]; ok { + collection = string(coll) + } } - } - fileEntry := FileEntry{ - Name: entry.Name, - FullPath: fullPath, - IsDirectory: entry.IsDirectory, - Size: size, - ModTime: modTime, - Mode: mode, - Uid: uid, - Gid: gid, - Mime: mime, - Replication: replication, - Collection: collection, - TtlSec: ttlSec, - } + // Determine MIME type based on file extension + mime := "application/octet-stream" + if entry.IsDirectory { + mime = "inode/directory" + } else { + ext := strings.ToLower(path.Ext(entry.Name)) + switch ext { + case ".txt", ".log": + mime = "text/plain" + case ".html", ".htm": + mime = "text/html" + case ".css": + mime = "text/css" + case ".js": + mime = "application/javascript" + case ".json": + mime = "application/json" + case ".xml": + mime = "application/xml" + case ".pdf": + mime = "application/pdf" + case ".jpg", ".jpeg": + mime = "image/jpeg" + case ".png": + mime = "image/png" + case ".gif": + mime = "image/gif" + case ".svg": + mime = "image/svg+xml" + case ".mp4": + mime = "video/mp4" + case ".mp3": + mime = "audio/mpeg" + case ".zip": + mime = "application/zip" + case ".tar": + mime = "application/x-tar" + case ".gz": + mime = "application/gzip" + } + } + + fileEntry := FileEntry{ + Name: entry.Name, + FullPath: fullPath, + IsDirectory: entry.IsDirectory, + Size: size, + ModTime: modTime, + Mode: mode, + Uid: uid, + Gid: gid, + Mime: mime, + Replication: replication, + Collection: collection, + TtlSec: ttlSec, + } + + entries = append(entries, fileEntry) + + lastEntryName = entry.Name - entries = append(entries, fileEntry) - if !entry.IsDirectory { - totalSize += size } } @@ -182,13 +201,8 @@ func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) { return nil, err } - // Sort entries: directories first, then files, both alphabetically - sort.Slice(entries, func(i, j int) bool { - if entries[i].IsDirectory != entries[j].IsDirectory { - return entries[i].IsDirectory - } - return strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name) - }) + // Determine if there's a next page + hasNextPage := fetchedCount > pageSize // Generate breadcrumbs breadcrumbs := s.generateBreadcrumbs(dir) @@ -214,15 +228,19 @@ func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) { } return &FileBrowserData{ - CurrentPath: dir, - ParentPath: parentPath, - Breadcrumbs: breadcrumbs, - Entries: entries, - TotalEntries: len(entries), - TotalSize: totalSize, + CurrentPath: dir, + ParentPath: parentPath, + Breadcrumbs: breadcrumbs, + Entries: entries, + LastUpdated: time.Now(), IsBucketPath: isBucketPath, BucketName: bucketName, + // Pagination metadata + PageSize: pageSize, + HasNextPage: hasNextPage, + LastFileName: lastEntryName, // Store for next page navigation + CurrentLastFileName: lastFileName, // Store input cursor for page size changes }, nil } diff --git a/weed/admin/handlers/file_browser_handlers.go b/weed/admin/handlers/file_browser_handlers.go index d8f79337d..b7c44a69d 100644 --- a/weed/admin/handlers/file_browser_handlers.go +++ b/weed/admin/handlers/file_browser_handlers.go @@ -63,8 +63,19 @@ func (h *FileBrowserHandlers) ShowFileBrowser(c *gin.Context) { // Normalize Windows-style paths for consistency path = util.CleanWindowsPath(path) - // Get file browser data - browserData, err := h.adminServer.GetFileBrowser(path) + // Get pagination parameters + lastFileName := c.DefaultQuery("lastFileName", "") + + pageSize, err := strconv.Atoi(c.DefaultQuery("limit", "20")) + if err != nil || pageSize < 1 { + pageSize = 20 + } + if pageSize > 200 { + pageSize = 200 + } + + // Get file browser data with cursor-based pagination + browserData, err := h.adminServer.GetFileBrowser(path, lastFileName, pageSize) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file browser data: " + err.Error()}) return diff --git a/weed/admin/view/app/file_browser.templ b/weed/admin/view/app/file_browser.templ index 83db7df0f..6ae00b81b 100644 --- a/weed/admin/view/app/file_browser.templ +++ b/weed/admin/view/app/file_browser.templ @@ -7,6 +7,10 @@ import ( "github.com/seaweedfs/seaweedfs/weed/admin/dash" ) +script changePageSize(path string, lastFileName string) { + window.location.href = '/files?path=' + encodeURIComponent(path) + '&lastFileName=' + encodeURIComponent(lastFileName) + '&limit=' + this.value +} + templ FileBrowser(data dash.FileBrowserData) {

@@ -45,15 +49,15 @@ templ FileBrowser(data dash.FileBrowserData) { for i, crumb := range data.Breadcrumbs { if i == len(data.Breadcrumbs)-1 { } else {
  • ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
  • ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" class=\"text-decoration-none\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
  • ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
  • ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
  • ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if crumb.Name == "Root" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, " ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - var templ_7745c5c3_Var5 string - templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.Name) + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 58, Col: 19} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 62, Col: 19} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -137,161 +155,211 @@ func FileBrowser(data dash.FileBrowserData) templ.Component { } } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
    Total Entries
    ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var6 string - templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalEntries)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 77, Col: 46} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "
    Directories
    ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var7 string - templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", countDirectories(data.Entries))) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 97, Col: 59} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
    Files
    ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var8 string - templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", countFiles(data.Entries))) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 117, Col: 53} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
    Total Size
    ") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var9 string - templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(data.TotalSize)) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 137, Col: 37} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if data.CurrentPath == "/" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "Root Directory") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "Root Directory") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else if data.CurrentPath == "/buckets" { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "Object Store Buckets Directory Manage Buckets") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "Object Store Buckets Directory Manage Buckets") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - var templ_7745c5c3_Var10 string - templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(filepath.Base(data.CurrentPath)) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(filepath.Base(data.CurrentPath)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 83, Col: 154} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, changePageSize(data.CurrentPath, data.CurrentLastFileName)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if data.HasNextPage { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "\" class=\"btn btn-outline-primary\" title=\"Next page\">Next ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } } if data.ParentPath != data.CurrentPath { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "Up") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "\" class=\"btn btn-outline-secondary\" title=\"Go up one directory\"> Up") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if len(data.Entries) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "
    NameSizeTypeModifiedPermissionsActions
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } for _, entry := range data.Entries { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "
    NameSizeTypeModifiedPermissionsActions
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "\">
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if entry.IsDirectory { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\" class=\"text-decoration-none\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 199, Col: 25} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 144, Col: 25} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -301,7 +369,7 @@ func FileBrowser(data dash.FileBrowserData) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var17 string templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 203, Col: 30} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 148, Col: 30} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if entry.IsDirectory { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -345,19 +413,19 @@ func FileBrowser(data dash.FileBrowserData) templ.Component { var templ_7745c5c3_Var18 string templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(formatBytes(entry.Size)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 211, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 156, Col: 36} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if entry.IsDirectory { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "Directory") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "Directory") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -365,14 +433,14 @@ func FileBrowser(data dash.FileBrowserData) templ.Component { var templ_7745c5c3_Var19 string templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(getMimeDisplayName(entry.Mime)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 219, Col: 44} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 164, Col: 44} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -380,174 +448,259 @@ func FileBrowser(data dash.FileBrowserData) templ.Component { var templ_7745c5c3_Var20 string templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(entry.ModTime.Format("2006-01-02 15:04")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 225, Col: 53} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 170, Col: 53} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\">") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var23 string templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Mode) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 231, Col: 146} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 176, Col: 146} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if !entry.IsDirectory { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, " ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\"> ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } else { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "
    Empty Directory

    This directory contains no files or subdirectories.

    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "
    Empty Directory

    This directory contains no files or subdirectories.

    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "
    Last updated: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var28 string - templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05")) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 271, Col: 66} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) + templ_7745c5c3_Err = templ.RenderScriptItems(ctx, templ_7745c5c3_Buffer, changePageSize(data.CurrentPath, data.CurrentLastFileName)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "
    Create New Folder
    Folder names cannot contain / or \\ characters.
    Upload Files
    Choose one or more files to upload to the current directory. You can select multiple files by holding Ctrl (Cmd on Mac) while clicking.
    entries per page
    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if data.HasNextPage { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "Next ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "
    Last updated: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var30 string - templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(data.CurrentPath) + templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(data.LastUpdated.Format("2006-01-02 15:04:05")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 328, Col: 79} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/file_browser.templ`, Line: 246, Col: 66} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "\">
    0%
    Preparing upload...
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "
  • Create New Folder
    Folder names cannot contain / or \\ characters.
    Upload Files
    Choose one or more files to upload to the current directory. You can select multiple files by holding Ctrl (Cmd on Mac) while clicking.
    0%
    Preparing upload...
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -555,26 +708,6 @@ func FileBrowser(data dash.FileBrowserData) templ.Component { }) } -func countDirectories(entries []dash.FileEntry) int { - count := 0 - for _, entry := range entries { - if entry.IsDirectory { - count++ - } - } - return count -} - -func countFiles(entries []dash.FileEntry) int { - count := 0 - for _, entry := range entries { - if !entry.IsDirectory { - count++ - } - } - return count -} - func getFileIcon(mime string) string { switch { case strings.HasPrefix(mime, "image/"): diff --git a/weed/admin/view/layout/layout.templ b/weed/admin/view/layout/layout.templ index cd192fa44..85eb8beed 100644 --- a/weed/admin/view/layout/layout.templ +++ b/weed/admin/view/layout/layout.templ @@ -218,6 +218,8 @@ templ Layout(c *gin.Context, content templ.Component) { } + +
    SYSTEM
    MAINTENANCE