admin: add cursor-based pagination to file browser (#7891)
* adjust menu items * admin: add cursor-based pagination to file browser - Implement cursor-based pagination using lastFileName parameter - Add customizable page size selector (20/50/100/200 entries) - Add compact pagination controls in header and footer - Remove summary cards for cleaner UI - Make directory names clickable to return to first page - Support forward-only navigation (Next button) - Preserve cursor position when changing page size - Remove sorting to align with filer's storage order approach * Update file_browser_templ.go * admin: remove directory icons from breadcrumbs * Update file_browser_templ.go * admin: address PR comments - Fix fragile EOF check: use io.EOF instead of string comparison - Cap page size at 200 to prevent potential DoS - Remove unused helper functions from template - Use safer templ script for page size selector to prevent XSS * admin: cleanup redundant first button * Update file_browser_templ.go * admin: remove entry counting logic * admin: remove unused variables in file browser data * admin: remove unused logic for FirstFileName and HasPrevPage * admin: remove unused TotalEntries and TotalSize fields * Update file_browser_data.go
This commit is contained in:
@@ -3,7 +3,6 @@ package dash
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -34,34 +33,49 @@ type BreadcrumbItem struct {
|
|||||||
|
|
||||||
// FileBrowserData contains all data needed for the file browser view
|
// FileBrowserData contains all data needed for the file browser view
|
||||||
type FileBrowserData struct {
|
type FileBrowserData struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
CurrentPath string `json:"current_path"`
|
CurrentPath string `json:"current_path"`
|
||||||
ParentPath string `json:"parent_path"`
|
ParentPath string `json:"parent_path"`
|
||||||
Breadcrumbs []BreadcrumbItem `json:"breadcrumbs"`
|
Breadcrumbs []BreadcrumbItem `json:"breadcrumbs"`
|
||||||
Entries []FileEntry `json:"entries"`
|
Entries []FileEntry `json:"entries"`
|
||||||
TotalEntries int `json:"total_entries"`
|
|
||||||
TotalSize int64 `json:"total_size"`
|
LastUpdated time.Time `json:"last_updated"`
|
||||||
LastUpdated time.Time `json:"last_updated"`
|
IsBucketPath bool `json:"is_bucket_path"`
|
||||||
IsBucketPath bool `json:"is_bucket_path"`
|
BucketName string `json:"bucket_name"`
|
||||||
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
|
// GetFileBrowser retrieves file browser data for a given path with cursor-based pagination
|
||||||
func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) {
|
func (s *AdminServer) GetFileBrowser(dir string, lastFileName string, pageSize int) (*FileBrowserData, error) {
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
dir = "/"
|
dir = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
var entries []FileEntry
|
// Set defaults for pagination
|
||||||
var totalSize int64
|
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 {
|
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{
|
stream, err := client.ListEntries(context.Background(), &filer_pb.ListEntriesRequest{
|
||||||
Directory: dir,
|
Directory: dir,
|
||||||
Prefix: "",
|
Prefix: "",
|
||||||
Limit: 1000,
|
Limit: uint32(fetchLimit),
|
||||||
InclusiveStartFrom: false,
|
StartFromFileName: lastFileName,
|
||||||
|
InclusiveStartFrom: false, // Don't include the cursor file itself
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -81,97 +95,102 @@ func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fullPath := path.Join(dir, entry.Name)
|
fetchedCount++
|
||||||
|
|
||||||
var modTime time.Time
|
// Only add entries up to pageSize (the +1 is just to check for next page)
|
||||||
if entry.Attributes != nil && entry.Attributes.Mtime > 0 {
|
if fetchedCount <= pageSize {
|
||||||
modTime = time.Unix(entry.Attributes.Mtime, 0)
|
fullPath := path.Join(dir, entry.Name)
|
||||||
}
|
|
||||||
|
|
||||||
var mode string
|
var modTime time.Time
|
||||||
var uid, gid uint32
|
if entry.Attributes != nil && entry.Attributes.Mtime > 0 {
|
||||||
var size int64
|
modTime = time.Unix(entry.Attributes.Mtime, 0)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
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
|
// Get replication and collection from entry extended attributes
|
||||||
mime := "application/octet-stream"
|
if entry.Extended != nil {
|
||||||
if entry.IsDirectory {
|
if repl, ok := entry.Extended["replication"]; ok {
|
||||||
mime = "inode/directory"
|
replication = string(repl)
|
||||||
} else {
|
}
|
||||||
ext := strings.ToLower(path.Ext(entry.Name))
|
if coll, ok := entry.Extended["collection"]; ok {
|
||||||
switch ext {
|
collection = string(coll)
|
||||||
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{
|
// Determine MIME type based on file extension
|
||||||
Name: entry.Name,
|
mime := "application/octet-stream"
|
||||||
FullPath: fullPath,
|
if entry.IsDirectory {
|
||||||
IsDirectory: entry.IsDirectory,
|
mime = "inode/directory"
|
||||||
Size: size,
|
} else {
|
||||||
ModTime: modTime,
|
ext := strings.ToLower(path.Ext(entry.Name))
|
||||||
Mode: mode,
|
switch ext {
|
||||||
Uid: uid,
|
case ".txt", ".log":
|
||||||
Gid: gid,
|
mime = "text/plain"
|
||||||
Mime: mime,
|
case ".html", ".htm":
|
||||||
Replication: replication,
|
mime = "text/html"
|
||||||
Collection: collection,
|
case ".css":
|
||||||
TtlSec: ttlSec,
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort entries: directories first, then files, both alphabetically
|
// Determine if there's a next page
|
||||||
sort.Slice(entries, func(i, j int) bool {
|
hasNextPage := fetchedCount > pageSize
|
||||||
if entries[i].IsDirectory != entries[j].IsDirectory {
|
|
||||||
return entries[i].IsDirectory
|
|
||||||
}
|
|
||||||
return strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Generate breadcrumbs
|
// Generate breadcrumbs
|
||||||
breadcrumbs := s.generateBreadcrumbs(dir)
|
breadcrumbs := s.generateBreadcrumbs(dir)
|
||||||
@@ -214,15 +228,19 @@ func (s *AdminServer) GetFileBrowser(dir string) (*FileBrowserData, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &FileBrowserData{
|
return &FileBrowserData{
|
||||||
CurrentPath: dir,
|
CurrentPath: dir,
|
||||||
ParentPath: parentPath,
|
ParentPath: parentPath,
|
||||||
Breadcrumbs: breadcrumbs,
|
Breadcrumbs: breadcrumbs,
|
||||||
Entries: entries,
|
Entries: entries,
|
||||||
TotalEntries: len(entries),
|
|
||||||
TotalSize: totalSize,
|
|
||||||
LastUpdated: time.Now(),
|
LastUpdated: time.Now(),
|
||||||
IsBucketPath: isBucketPath,
|
IsBucketPath: isBucketPath,
|
||||||
BucketName: bucketName,
|
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
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,19 @@ func (h *FileBrowserHandlers) ShowFileBrowser(c *gin.Context) {
|
|||||||
// Normalize Windows-style paths for consistency
|
// Normalize Windows-style paths for consistency
|
||||||
path = util.CleanWindowsPath(path)
|
path = util.CleanWindowsPath(path)
|
||||||
|
|
||||||
// Get file browser data
|
// Get pagination parameters
|
||||||
browserData, err := h.adminServer.GetFileBrowser(path)
|
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 {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file browser data: " + err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get file browser data: " + err.Error()})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import (
|
|||||||
"github.com/seaweedfs/seaweedfs/weed/admin/dash"
|
"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) {
|
templ FileBrowser(data dash.FileBrowserData) {
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
<h1 class="h2">
|
<h1 class="h2">
|
||||||
@@ -45,15 +49,15 @@ templ FileBrowser(data dash.FileBrowserData) {
|
|||||||
for i, crumb := range data.Breadcrumbs {
|
for i, crumb := range data.Breadcrumbs {
|
||||||
if i == len(data.Breadcrumbs)-1 {
|
if i == len(data.Breadcrumbs)-1 {
|
||||||
<li class="breadcrumb-item active" aria-current="page">
|
<li class="breadcrumb-item active" aria-current="page">
|
||||||
<i class="fas fa-folder me-1"></i>{ crumb.Name }
|
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s", crumb.Path)) } class="text-decoration-none">
|
||||||
|
{ crumb.Name }
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
} else {
|
} else {
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s", crumb.Path)) } class="text-decoration-none">
|
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s", crumb.Path)) } class="text-decoration-none">
|
||||||
if crumb.Name == "Root" {
|
if crumb.Name == "Root" {
|
||||||
<i class="fas fa-home me-1"></i>
|
<i class="fas fa-home me-1"></i>
|
||||||
} else {
|
|
||||||
<i class="fas fa-folder me-1"></i>
|
|
||||||
}
|
}
|
||||||
{ crumb.Name }
|
{ crumb.Name }
|
||||||
</a>
|
</a>
|
||||||
@@ -63,110 +67,51 @@ templ FileBrowser(data dash.FileBrowserData) {
|
|||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Summary Cards -->
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-xl-3 col-md-6 mb-4">
|
|
||||||
<div class="card border-left-primary shadow h-100 py-2">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row no-gutters align-items-center">
|
|
||||||
<div class="col mr-2">
|
|
||||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
|
|
||||||
Total Entries
|
|
||||||
</div>
|
|
||||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
|
||||||
{ fmt.Sprintf("%d", data.TotalEntries) }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto">
|
|
||||||
<i class="fas fa-list fa-2x text-gray-300"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xl-3 col-md-6 mb-4">
|
|
||||||
<div class="card border-left-success shadow h-100 py-2">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row no-gutters align-items-center">
|
|
||||||
<div class="col mr-2">
|
|
||||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
|
|
||||||
Directories
|
|
||||||
</div>
|
|
||||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
|
||||||
{ fmt.Sprintf("%d", countDirectories(data.Entries)) }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto">
|
|
||||||
<i class="fas fa-folder fa-2x text-gray-300"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xl-3 col-md-6 mb-4">
|
|
||||||
<div class="card border-left-info shadow h-100 py-2">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row no-gutters align-items-center">
|
|
||||||
<div class="col mr-2">
|
|
||||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">
|
|
||||||
Files
|
|
||||||
</div>
|
|
||||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
|
||||||
{ fmt.Sprintf("%d", countFiles(data.Entries)) }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto">
|
|
||||||
<i class="fas fa-file fa-2x text-gray-300"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xl-3 col-md-6 mb-4">
|
|
||||||
<div class="card border-left-warning shadow h-100 py-2">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row no-gutters align-items-center">
|
|
||||||
<div class="col mr-2">
|
|
||||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
|
|
||||||
Total Size
|
|
||||||
</div>
|
|
||||||
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
|
||||||
{ formatBytes(data.TotalSize) }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto">
|
|
||||||
<i class="fas fa-hdd fa-2x text-gray-300"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- File Listing -->
|
<!-- File Listing -->
|
||||||
<div class="card shadow mb-4">
|
<div class="card shadow mb-4">
|
||||||
<div class="card-header py-3 d-flex justify-content-between align-items-center">
|
<div class="card-header py-3 d-flex justify-content-between align-items-center flex-wrap">
|
||||||
<h6 class="m-0 font-weight-bold text-primary">
|
<h6 class="m-0 font-weight-bold text-primary">
|
||||||
<i class="fas fa-folder-open me-2"></i>
|
<i class="fas fa-folder-open me-2"></i>
|
||||||
if data.CurrentPath == "/" {
|
if data.CurrentPath == "/" {
|
||||||
Root Directory
|
<a href="/files?path=/" class="text-decoration-none text-primary">Root Directory</a>
|
||||||
} else if data.CurrentPath == "/buckets" {
|
} else if data.CurrentPath == "/buckets" {
|
||||||
Object Store Buckets Directory
|
<a href="/files?path=/buckets" class="text-decoration-none text-primary">Object Store Buckets Directory</a>
|
||||||
<a href="/object-store/buckets" class="btn btn-sm btn-outline-primary ms-2">
|
<a href="/object-store/buckets" class="btn btn-sm btn-outline-primary ms-2">
|
||||||
<i class="fas fa-cube me-1"></i>Manage Buckets
|
<i class="fas fa-cube me-1"></i>Manage Buckets
|
||||||
</a>
|
</a>
|
||||||
} else {
|
} else {
|
||||||
{ filepath.Base(data.CurrentPath) }
|
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s", data.CurrentPath)) } class="text-decoration-none text-primary">{ filepath.Base(data.CurrentPath) }</a>
|
||||||
}
|
}
|
||||||
</h6>
|
</h6>
|
||||||
if data.ParentPath != data.CurrentPath {
|
|
||||||
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s", data.ParentPath)) } class="btn btn-sm btn-outline-secondary">
|
<!-- Compact pagination controls -->
|
||||||
<i class="fas fa-arrow-up me-1"></i>Up
|
<div class="d-flex align-items-center gap-2 ms-auto">
|
||||||
</a>
|
<div class="d-flex align-items-center">
|
||||||
}
|
<label class="me-1 mb-0 small text-muted">Show:</label>
|
||||||
|
<select class="form-select form-select-sm" style="width: 70px; font-size: 0.875rem;" onchange={ changePageSize(data.CurrentPath, data.CurrentLastFileName) }>
|
||||||
|
<option value="20" selected?={ data.PageSize == 20 }>20</option>
|
||||||
|
<option value="50" selected?={ data.PageSize == 50 }>50</option>
|
||||||
|
<option value="100" selected?={ data.PageSize == 100 }>100</option>
|
||||||
|
<option value="200" selected?={ data.PageSize == 200 }>200</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
if data.HasNextPage {
|
||||||
|
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s&lastFileName=%s&limit=%d", data.CurrentPath, data.LastFileName, data.PageSize)) } class="btn btn-outline-primary" title="Next page">
|
||||||
|
Next <i class="fas fa-angle-right"></i>
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
<button class="btn btn-outline-secondary" disabled title="Next page">
|
||||||
|
Next <i class="fas fa-angle-right"></i>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
if data.ParentPath != data.CurrentPath {
|
||||||
|
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s", data.ParentPath)) } class="btn btn-outline-secondary" title="Go up one directory">
|
||||||
|
<i class="fas fa-arrow-up"></i> Up
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
if len(data.Entries) > 0 {
|
if len(data.Entries) > 0 {
|
||||||
@@ -264,6 +209,36 @@ templ FileBrowser(data dash.FileBrowserData) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Last Updated -->
|
<!-- Last Updated -->
|
||||||
|
|
||||||
|
<!-- Pagination Controls (Bottom) -->
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<label class="me-2 mb-0">Show:</label>
|
||||||
|
<select class="form-select form-select-sm" style="width: auto;" onchange={ changePageSize(data.CurrentPath, data.CurrentLastFileName) }>
|
||||||
|
<option value="20" selected?={ data.PageSize == 20 }>20</option>
|
||||||
|
<option value="50" selected?={ data.PageSize == 50 }>50</option>
|
||||||
|
<option value="100" selected?={ data.PageSize == 100 }>100</option>
|
||||||
|
<option value="200" selected?={ data.PageSize == 200 }>200</option>
|
||||||
|
</select>
|
||||||
|
<span class="ms-2 text-muted">entries per page</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 text-end">
|
||||||
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
|
|
||||||
|
if data.HasNextPage {
|
||||||
|
<a href={ templ.SafeURL(fmt.Sprintf("/files?path=%s&lastFileName=%s&limit=%d", data.CurrentPath, data.LastFileName, data.PageSize)) } class="btn btn-outline-primary">
|
||||||
|
Next <i class="fas fa-angle-right ms-1"></i>
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
<button class="btn btn-outline-secondary" disabled>
|
||||||
|
Next <i class="fas fa-angle-right ms-1"></i>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
@@ -732,25 +707,7 @@ templ FileBrowser(data dash.FileBrowserData) {
|
|||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
func getFileIcon(mime string) string {
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -218,6 +218,8 @@ templ Layout(c *gin.Context, content templ.Component) {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</li>
|
</li>
|
||||||
|
<!-- Commented out for later -->
|
||||||
|
<!--
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/metrics">
|
<a class="nav-link" href="/metrics">
|
||||||
<i class="fas fa-chart-line me-2"></i>Metrics
|
<i class="fas fa-chart-line me-2"></i>Metrics
|
||||||
@@ -228,10 +230,11 @@ templ Layout(c *gin.Context, content templ.Component) {
|
|||||||
<i class="fas fa-file-alt me-2"></i>Logs
|
<i class="fas fa-file-alt me-2"></i>Logs
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
-->
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h6 class="sidebar-heading px-3 mt-4 mb-1 text-muted">
|
<h6 class="sidebar-heading px-3 mt-4 mb-1 text-muted">
|
||||||
<span>SYSTEM</span>
|
<span>MAINTENANCE</span>
|
||||||
</h6>
|
</h6>
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
@@ -284,22 +287,22 @@ templ Layout(c *gin.Context, content templ.Component) {
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
if currentPath == "/maintenance" {
|
if currentPath == "/maintenance" {
|
||||||
<a class="nav-link active" href="/maintenance">
|
<a class="nav-link active" href="/maintenance">
|
||||||
<i class="fas fa-list me-2"></i>Maintenance Queue
|
<i class="fas fa-list me-2"></i>Job Queue
|
||||||
</a>
|
</a>
|
||||||
} else {
|
} else {
|
||||||
<a class="nav-link" href="/maintenance">
|
<a class="nav-link" href="/maintenance">
|
||||||
<i class="fas fa-list me-2"></i>Maintenance Queue
|
<i class="fas fa-list me-2"></i>Job Queue
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
if currentPath == "/maintenance/workers" {
|
if currentPath == "/maintenance/workers" {
|
||||||
<a class="nav-link active" href="/maintenance/workers">
|
<a class="nav-link active" href="/maintenance/workers">
|
||||||
<i class="fas fa-user-cog me-2"></i>Maintenance Workers
|
<i class="fas fa-user-cog me-2"></i>Workers
|
||||||
</a>
|
</a>
|
||||||
} else {
|
} else {
|
||||||
<a class="nav-link" href="/maintenance/workers">
|
<a class="nav-link" href="/maintenance/workers">
|
||||||
<i class="fas fa-user-cog me-2"></i>Maintenance Workers
|
<i class="fas fa-user-cog me-2"></i>Workers
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</li><li class=\"nav-item\"><a class=\"nav-link\" href=\"/metrics\"><i class=\"fas fa-chart-line me-2\"></i>Metrics</a></li><li class=\"nav-item\"><a class=\"nav-link\" href=\"/logs\"><i class=\"fas fa-file-alt me-2\"></i>Logs</a></li></ul><h6 class=\"sidebar-heading px-3 mt-4 mb-1 text-muted\"><span>SYSTEM</span></h6><ul class=\"nav flex-column\"><li class=\"nav-item\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</li><!-- Commented out for later --><!--\n <li class=\"nav-item\">\n <a class=\"nav-link\" href=\"/metrics\">\n <i class=\"fas fa-chart-line me-2\"></i>Metrics\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" href=\"/logs\">\n <i class=\"fas fa-file-alt me-2\"></i>Logs\n </a>\n </li>\n --></ul><h6 class=\"sidebar-heading px-3 mt-4 mb-1 text-muted\"><span>MAINTENANCE</span></h6><ul class=\"nav flex-column\"><li class=\"nav-item\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var3 templ.SafeURL
|
var templ_7745c5c3_Var3 templ.SafeURL
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(menuItem.URL))
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(menuItem.URL))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 258, Col: 117}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 261, Col: 117}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -186,7 +186,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var6 string
|
var templ_7745c5c3_Var6 string
|
||||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(menuItem.Name)
|
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(menuItem.Name)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 259, Col: 109}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 262, Col: 109}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -204,7 +204,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var7 templ.SafeURL
|
var templ_7745c5c3_Var7 templ.SafeURL
|
||||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(menuItem.URL))
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(menuItem.URL))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 262, Col: 110}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 265, Col: 110}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -239,7 +239,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var10 string
|
var templ_7745c5c3_Var10 string
|
||||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(menuItem.Name)
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(menuItem.Name)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 263, Col: 109}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 266, Col: 109}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -272,7 +272,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var11 templ.SafeURL
|
var templ_7745c5c3_Var11 templ.SafeURL
|
||||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(menuItem.URL))
|
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(menuItem.URL))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 275, Col: 106}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 278, Col: 106}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -307,7 +307,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var14 string
|
var templ_7745c5c3_Var14 string
|
||||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(menuItem.Name)
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(menuItem.Name)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 276, Col: 105}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 279, Col: 105}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -328,12 +328,12 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if currentPath == "/maintenance" {
|
if currentPath == "/maintenance" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<a class=\"nav-link active\" href=\"/maintenance\"><i class=\"fas fa-list me-2\"></i>Maintenance Queue</a>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<a class=\"nav-link active\" href=\"/maintenance\"><i class=\"fas fa-list me-2\"></i>Job Queue</a>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<a class=\"nav-link\" href=\"/maintenance\"><i class=\"fas fa-list me-2\"></i>Maintenance Queue</a>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<a class=\"nav-link\" href=\"/maintenance\"><i class=\"fas fa-list me-2\"></i>Job Queue</a>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -343,12 +343,12 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if currentPath == "/maintenance/workers" {
|
if currentPath == "/maintenance/workers" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<a class=\"nav-link active\" href=\"/maintenance/workers\"><i class=\"fas fa-user-cog me-2\"></i>Maintenance Workers</a>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<a class=\"nav-link active\" href=\"/maintenance/workers\"><i class=\"fas fa-user-cog me-2\"></i>Workers</a>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<a class=\"nav-link\" href=\"/maintenance/workers\"><i class=\"fas fa-user-cog me-2\"></i>Maintenance Workers</a>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<a class=\"nav-link\" href=\"/maintenance/workers\"><i class=\"fas fa-user-cog me-2\"></i>Workers</a>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -368,7 +368,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var15 string
|
var templ_7745c5c3_Var15 string
|
||||||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", time.Now().Year()))
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", time.Now().Year()))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 323, Col: 60}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 326, Col: 60}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -381,7 +381,7 @@ func Layout(c *gin.Context, content templ.Component) templ.Component {
|
|||||||
var templ_7745c5c3_Var16 string
|
var templ_7745c5c3_Var16 string
|
||||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(version.VERSION_NUMBER)
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(version.VERSION_NUMBER)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 323, Col: 102}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 326, Col: 102}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -433,7 +433,7 @@ func LoginForm(c *gin.Context, title string, errorMessage string) templ.Componen
|
|||||||
var templ_7745c5c3_Var18 string
|
var templ_7745c5c3_Var18 string
|
||||||
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 347, Col: 17}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 350, Col: 17}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -446,7 +446,7 @@ func LoginForm(c *gin.Context, title string, errorMessage string) templ.Componen
|
|||||||
var templ_7745c5c3_Var19 string
|
var templ_7745c5c3_Var19 string
|
||||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 361, Col: 57}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 364, Col: 57}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
@@ -464,7 +464,7 @@ func LoginForm(c *gin.Context, title string, errorMessage string) templ.Componen
|
|||||||
var templ_7745c5c3_Var20 string
|
var templ_7745c5c3_Var20 string
|
||||||
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(errorMessage)
|
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(errorMessage)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 368, Col: 45}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/layout/layout.templ`, Line: 371, Col: 45}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user