Show max 500 files per folder #364
No infinite scrolling in this case... Maybe we add it later. Waiting for user feedback. Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
06b43da8c2
commit
f7fbc6e0de
@ -136,6 +136,8 @@ export class Folder extends RestModel {
|
||||
}
|
||||
|
||||
response.models = [];
|
||||
response.files = files.length;
|
||||
response.folders = folders.length;
|
||||
response.count = count;
|
||||
response.limit = limit;
|
||||
response.offset = offset;
|
||||
|
@ -163,8 +163,8 @@
|
||||
dirty: false,
|
||||
results: [],
|
||||
loading: true,
|
||||
pageSize: 24,
|
||||
offset: 0,
|
||||
filesLimit: 500,
|
||||
filesOffset: 0,
|
||||
page: 0,
|
||||
selection: [],
|
||||
settings: settings,
|
||||
@ -360,6 +360,8 @@
|
||||
const params = {
|
||||
files: true,
|
||||
uncached: true,
|
||||
count: this.filesLimit,
|
||||
offset: this.filesOffset,
|
||||
};
|
||||
|
||||
Object.assign(params, this.filter);
|
||||
@ -387,7 +389,7 @@
|
||||
|
||||
Object.assign(this.lastFilter, this.filter);
|
||||
|
||||
this.offset = 0;
|
||||
this.filesOffset = 0;
|
||||
this.page = 0;
|
||||
this.loading = true;
|
||||
this.listen = false;
|
||||
@ -395,7 +397,7 @@
|
||||
const params = this.searchParams();
|
||||
|
||||
Folder.originals(this.path, params).then(response => {
|
||||
this.offset = this.pageSize;
|
||||
this.filesOffset = this.filesLimit;
|
||||
|
||||
this.results = response.models;
|
||||
this.breadcrumbs = this.getBreadcrumbs();
|
||||
@ -404,8 +406,10 @@
|
||||
this.$notify.warn(this.$gettext('Directory is empty'));
|
||||
} else if (response.count === 1) {
|
||||
this.$notify.info(this.$gettext('One entry found'));
|
||||
} else {
|
||||
} else if (response.files < this.filesLimit) {
|
||||
this.$notify.info(response.count + this.$gettext(' entries found'));
|
||||
} else {
|
||||
this.$notify.warn(this.$gettext('Too many files in folder, showing first') + ` ${response.files}`);
|
||||
}
|
||||
}).finally(() => {
|
||||
this.dirty = false;
|
||||
|
@ -9,10 +9,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
type FoldersResponse struct {
|
||||
@ -31,11 +34,20 @@ func GetFolders(router *gin.RouterGroup, conf *config.Config, urlPath, rootName,
|
||||
return
|
||||
}
|
||||
|
||||
var f form.FolderSearch
|
||||
|
||||
start := time.Now()
|
||||
err := c.MustBindWith(&f, binding.Form)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
recursive := c.Query("recursive") != ""
|
||||
listFiles := c.Query("files") != ""
|
||||
uncached := listFiles || c.Query("uncached") != ""
|
||||
recursive := f.Recursive
|
||||
listFiles := f.Files
|
||||
uncached := listFiles || f.Uncached
|
||||
resp := FoldersResponse{Root: rootName, Recursive: recursive, Cached: !uncached}
|
||||
path := c.Param("path")
|
||||
|
||||
@ -64,7 +76,7 @@ func GetFolders(router *gin.RouterGroup, conf *config.Config, urlPath, rootName,
|
||||
}
|
||||
|
||||
if listFiles {
|
||||
if files, err := query.FilesByPath(rootName, path); err != nil {
|
||||
if files, err := query.FilesByPath(f.Count, f.Offset, rootName, path); err != nil {
|
||||
log.Errorf("folders: %s", err)
|
||||
} else {
|
||||
resp.Files = files
|
||||
@ -78,8 +90,11 @@ func GetFolders(router *gin.RouterGroup, conf *config.Config, urlPath, rootName,
|
||||
}
|
||||
}
|
||||
|
||||
c.Header("X-Files", strconv.Itoa(len(resp.Files)))
|
||||
c.Header("X-Folders", strconv.Itoa(len(resp.Folders)))
|
||||
c.Header("X-Count", strconv.Itoa(len(resp.Files)+len(resp.Folders)))
|
||||
c.Header("X-Offset", "0")
|
||||
c.Header("X-Limit", strconv.Itoa(f.Count))
|
||||
c.Header("X-Offset", strconv.Itoa(f.Offset))
|
||||
|
||||
c.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
33
internal/form/folder_search.go
Normal file
33
internal/form/folder_search.go
Normal file
@ -0,0 +1,33 @@
|
||||
package form
|
||||
|
||||
// FolderSearch represents search form fields for "/api/v1/folders".
|
||||
type FolderSearch struct {
|
||||
Query string `form:"q"`
|
||||
Recursive bool `form:"recursive"`
|
||||
Files bool `form:"files"`
|
||||
Uncached bool `form:"uncached"`
|
||||
Count int `form:"count" serialize:"-"`
|
||||
Offset int `form:"offset" serialize:"-"`
|
||||
}
|
||||
|
||||
func (f *FolderSearch) GetQuery() string {
|
||||
return f.Query
|
||||
}
|
||||
|
||||
func (f *FolderSearch) SetQuery(q string) {
|
||||
f.Query = q
|
||||
}
|
||||
|
||||
func (f *FolderSearch) ParseQueryString() error {
|
||||
return ParseQueryString(f)
|
||||
}
|
||||
|
||||
// Serialize returns a string containing non-empty fields and values of a struct.
|
||||
func (f *FolderSearch) Serialize() string {
|
||||
return Serialize(f, false)
|
||||
}
|
||||
|
||||
// SerializeAll returns a string containing all non-empty fields and values of a struct.
|
||||
func (f *FolderSearch) SerializeAll() string {
|
||||
return Serialize(f, true)
|
||||
}
|
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
// FilesByPath returns a slice of files in a given originals folder.
|
||||
func FilesByPath(rootName, pathName string) (files entity.Files, err error) {
|
||||
func FilesByPath(limit, offset int, rootName, pathName string) (files entity.Files, err error) {
|
||||
if strings.HasPrefix(pathName, "/") {
|
||||
pathName = pathName[1:]
|
||||
}
|
||||
@ -18,13 +18,14 @@ func FilesByPath(rootName, pathName string) (files entity.Files, err error) {
|
||||
Where("files.file_missing = 0").
|
||||
Where("files.file_root = ? AND photos.photo_path = ?", rootName, pathName).
|
||||
Order("files.file_name").
|
||||
Limit(limit).Offset(offset).
|
||||
Find(&files).Error
|
||||
|
||||
return files, err
|
||||
}
|
||||
|
||||
// Files returns not-missing and not-deleted file entities in the range of limit and offset sorted by id.
|
||||
func Files(limit int, offset int, pathName string, includeMissing bool) (files entity.Files, err error) {
|
||||
func Files(limit, offset int, pathName string, includeMissing bool) (files entity.Files, err error) {
|
||||
if strings.HasPrefix(pathName, "/") {
|
||||
pathName = pathName[1:]
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
func TestFilesByPath(t *testing.T) {
|
||||
t.Run("files found", func(t *testing.T) {
|
||||
files, err := FilesByPath(entity.RootOriginals, "2016/11")
|
||||
files, err := FilesByPath(10, 0, entity.RootOriginals, "2016/11")
|
||||
|
||||
t.Logf("files: %+v", files)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user