Steffag/refactor slices (#38)
Co-authored-by: Graham Steffaniak <graham.steffaniak@autodesk.com>
This commit is contained in:
parent
d6e9ed6272
commit
65159848c2
|
@ -5,33 +5,33 @@
|
|||
? github.com/gtsteffaniak/filebrowser/auth [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/cmd [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/diskcache 0.003s
|
||||
ok github.com/gtsteffaniak/filebrowser/diskcache 0.011s
|
||||
? github.com/gtsteffaniak/filebrowser/errors [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/files [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/fileutils 0.003s
|
||||
2023/09/24 12:52:05 h: 401 <nil>
|
||||
2023/09/24 12:52:05 h: 401 <nil>
|
||||
2023/09/24 12:52:05 h: 401 <nil>
|
||||
2023/09/24 12:52:05 h: 401 <nil>
|
||||
2023/09/24 12:52:05 h: 401 <nil>
|
||||
2023/09/24 12:52:05 h: 401 <nil>
|
||||
2023/09/29 19:48:56 h: 401 <nil>
|
||||
2023/09/29 19:48:56 h: 401 <nil>
|
||||
2023/09/29 19:48:56 h: 401 <nil>
|
||||
2023/09/29 19:48:56 h: 401 <nil>
|
||||
2023/09/29 19:48:56 h: 401 <nil>
|
||||
2023/09/29 19:48:56 h: 401 <nil>
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/http 0.094s
|
||||
ok github.com/gtsteffaniak/filebrowser/http 0.095s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/img 0.144s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/rules 0.002s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/runner 0.003s
|
||||
ok github.com/gtsteffaniak/filebrowser/img 0.141s
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/gtsteffaniak/filebrowser/search
|
||||
pkg: github.com/gtsteffaniak/filebrowser/index
|
||||
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
|
||||
BenchmarkSearchAllIndexes-8 10 5912685 ns/op 3003976 B/op 46139 allocs/op
|
||||
BenchmarkFillIndex-8 10 3157995 ns/op 18370 B/op 449 allocs/op
|
||||
BenchmarkFillIndex-8 10 3232060 ns/op 12384 B/op 451 allocs/op
|
||||
BenchmarkSearchAllIndexes-8 10 5611219 ns/op 3262723 B/op 42857 allocs/op
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/search 0.116s
|
||||
ok github.com/gtsteffaniak/filebrowser/index 0.124s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/rules 0.003s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/runner 0.005s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/settings 0.005s
|
||||
? github.com/gtsteffaniak/filebrowser/share [no test files]
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/gtsteffaniak/filebrowser/diskcache"
|
||||
fbhttp "github.com/gtsteffaniak/filebrowser/http"
|
||||
"github.com/gtsteffaniak/filebrowser/img"
|
||||
"github.com/gtsteffaniak/filebrowser/search"
|
||||
"github.com/gtsteffaniak/filebrowser/index"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
@ -67,7 +67,7 @@ var rootCmd = &cobra.Command{
|
|||
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
||||
}
|
||||
// initialize indexing and schedule indexing ever n minutes (default 5)
|
||||
go search.InitializeIndex(serverConfig.IndexingInterval)
|
||||
index.Initialize(serverConfig.IndexingInterval)
|
||||
_, err := os.Stat(serverConfig.Root)
|
||||
checkErr(err)
|
||||
var listener net.Listener
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
server:
|
||||
port: 8080
|
||||
baseURL: "/"
|
||||
root: "/srv"
|
||||
auth:
|
||||
method: noauth
|
||||
signup: true
|
||||
|
|
|
@ -3,7 +3,7 @@ package http
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/search"
|
||||
"github.com/gtsteffaniak/filebrowser/index"
|
||||
)
|
||||
|
||||
var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
|
@ -12,8 +12,9 @@ var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *dat
|
|||
|
||||
// Retrieve the User-Agent and X-Auth headers from the request
|
||||
sessionId := r.Header.Get("SessionId")
|
||||
indexInfo, fileTypes := search.SearchAllIndexes(query, r.URL.Path, sessionId)
|
||||
for _, path := range indexInfo {
|
||||
index := *index.GetIndex()
|
||||
results, fileTypes := index.Search(query, r.URL.Path, sessionId)
|
||||
for _, path := range results {
|
||||
responseObj := map[string]interface{}{
|
||||
"path": path,
|
||||
"dir": true,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package search
|
||||
package index
|
||||
|
||||
import (
|
||||
"regexp"
|
|
@ -0,0 +1,142 @@
|
|||
package index
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
)
|
||||
|
||||
const (
|
||||
maxIndexSize = 1000
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
Dirs []string
|
||||
Files []string
|
||||
}
|
||||
|
||||
var (
|
||||
rootPath string = "/rootPath"
|
||||
indexes Index
|
||||
indexMutex sync.RWMutex
|
||||
lastIndexed time.Time
|
||||
)
|
||||
|
||||
func GetIndex() *Index {
|
||||
return &indexes
|
||||
}
|
||||
|
||||
func Initialize(intervalMinutes uint32) {
|
||||
// Initialize the index
|
||||
indexes = Index{
|
||||
Dirs: make([]string, 0, maxIndexSize),
|
||||
Files: make([]string, 0, maxIndexSize),
|
||||
}
|
||||
rootPath = settings.GlobalConfiguration.Server.Root
|
||||
var numFiles, numDirs int
|
||||
log.Println("Indexing files...")
|
||||
lastIndexedStart := time.Now()
|
||||
// Call the function to index files and directories
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
go indexingScheduler(intervalMinutes)
|
||||
log.Println("Successfully indexed files.")
|
||||
log.Println("Files found :", totalNumFiles)
|
||||
log.Println("Directories found :", totalNumDirs)
|
||||
}
|
||||
|
||||
func indexingScheduler(intervalMinutes uint32) {
|
||||
log.Printf("Indexing scheduler will run every %v minutes", intervalMinutes)
|
||||
for {
|
||||
indexes.Dirs = slices.Compact(indexes.Dirs)
|
||||
indexes.Files = slices.Compact(indexes.Files)
|
||||
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
|
||||
var numFiles, numDirs int
|
||||
lastIndexedStart := time.Now()
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
if totalNumFiles+totalNumDirs > 0 {
|
||||
log.Println("re-indexing found changes and updated the index.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeFromSlice(slice []string, target string) []string {
|
||||
for i, s := range slice {
|
||||
if s == target {
|
||||
// Swap the target element with the last element
|
||||
slice[i], slice[len(slice)-1] = slice[len(slice)-1], slice[i]
|
||||
// Resize the slice to exclude the last element
|
||||
slice = slice[:len(slice)-1]
|
||||
break // Exit the loop, assuming there's only one target element
|
||||
}
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
// Define a function to recursively index files and directories
|
||||
func indexFiles(path string, numFiles *int, numDirs *int) (int, int, error) {
|
||||
// Check if the current directory has been modified since last indexing
|
||||
dir, err := os.Open(path)
|
||||
if err != nil {
|
||||
// directory must have been deleted, remove from index
|
||||
indexes.Dirs = removeFromSlice(indexes.Dirs, path)
|
||||
indexes.Files = removeFromSlice(indexes.Files, path)
|
||||
}
|
||||
defer dir.Close()
|
||||
dirInfo, err := dir.Stat()
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Compare the last modified time of the directory with the last indexed time
|
||||
if dirInfo.ModTime().Before(lastIndexed) {
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
// Read the directory contents
|
||||
files, err := dir.Readdir(-1)
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Iterate over the files and directories
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
*numDirs++
|
||||
addToIndex(path, file.Name(), true)
|
||||
_, _, err := indexFiles(path+"/"+file.Name(), numFiles, numDirs) // recursive
|
||||
if err != nil {
|
||||
log.Println("Could not index :", err)
|
||||
}
|
||||
} else {
|
||||
*numFiles++
|
||||
addToIndex(path, file.Name(), false)
|
||||
}
|
||||
}
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
|
||||
func addToIndex(path string, fileName string, isDir bool) {
|
||||
indexMutex.Lock()
|
||||
defer indexMutex.Unlock()
|
||||
path = strings.TrimPrefix(path, rootPath+"/")
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
adjustedPath := path + "/" + fileName
|
||||
if path == rootPath {
|
||||
adjustedPath = fileName
|
||||
}
|
||||
if isDir {
|
||||
indexes.Dirs = append(indexes.Dirs, adjustedPath)
|
||||
} else {
|
||||
indexes.Files = append(indexes.Files, adjustedPath)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package index
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkFillIndex(b *testing.B) {
|
||||
indexes = Index{
|
||||
Dirs: make([]string, 0, 1000),
|
||||
Files: make([]string, 0, 1000),
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
createMockData(50, 3) // 1000 dirs, 3 files per dir
|
||||
}
|
||||
}
|
||||
|
||||
func createMockData(numDirs, numFilesPerDir int) {
|
||||
for i := 0; i < numDirs; i++ {
|
||||
dirName := generateRandomPath(rand.Intn(3) + 1)
|
||||
addToIndex("/", dirName, true)
|
||||
for j := 0; j < numFilesPerDir; j++ {
|
||||
fileName := "file-" + getRandomTerm() + getRandomExtension()
|
||||
addToIndex("/"+dirName, fileName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateRandomPath(levels int) string {
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
dirName := "srv"
|
||||
for i := 0; i < levels; i++ {
|
||||
dirName += "/" + getRandomTerm()
|
||||
}
|
||||
return dirName
|
||||
}
|
||||
|
||||
func getRandomTerm() string {
|
||||
wordbank := []string{
|
||||
"hi", "test", "other", "name",
|
||||
"cool", "things", "more", "items",
|
||||
}
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func getRandomExtension() string {
|
||||
wordbank := []string{
|
||||
".txt", ".mp3", ".mov", ".doc",
|
||||
".mp4", ".bak", ".zip", ".jpg",
|
||||
}
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func generateRandomSearchTerms(numTerms int) []string {
|
||||
// Generate random search terms
|
||||
searchTerms := make([]string, numTerms)
|
||||
for i := 0; i < numTerms; i++ {
|
||||
searchTerms[i] = getRandomTerm()
|
||||
}
|
||||
return searchTerms
|
||||
}
|
||||
|
||||
// JSONBytesEqual compares the JSON in two byte slices.
|
||||
func JSONBytesEqual(a, b []byte) (bool, error) {
|
||||
var j, j2 interface{}
|
||||
if err := json.Unmarshal(a, &j); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &j2); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return reflect.DeepEqual(j2, j), nil
|
||||
}
|
||||
|
||||
func TestGetIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want *map[string][]string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetIndex(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetIndex() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitializeIndex(t *testing.T) {
|
||||
type args struct {
|
||||
intervalMinutes uint32
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
Initialize(tt.args.intervalMinutes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_indexingScheduler(t *testing.T) {
|
||||
type args struct {
|
||||
intervalMinutes uint32
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
indexingScheduler(tt.args.intervalMinutes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_indexFiles(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
numFiles *int
|
||||
numDirs *int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
want1 int
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1, err := indexFiles(tt.args.path, tt.args.numFiles, tt.args.numDirs)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("indexFiles() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("indexFiles() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("indexFiles() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_addToIndex(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
fileName string
|
||||
isDir bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
addToIndex(tt.args.path, tt.args.fileName, tt.args.isDir)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package search
|
||||
package index
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"os"
|
||||
|
@ -13,142 +12,55 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
sessionInProgress sync.Map // Track session with requests in progress
|
||||
rootPath string = "/srv"
|
||||
indexes map[string][]string
|
||||
sessionInProgress sync.Map
|
||||
mutex sync.RWMutex
|
||||
lastIndexed time.Time
|
||||
maxSearchResults = 100
|
||||
bytesInMegabyte int64 = 1000000
|
||||
)
|
||||
|
||||
func InitializeIndex(intervalMinutes uint32) {
|
||||
// Initialize the indexes map
|
||||
indexes = make(map[string][]string)
|
||||
indexes["dirs"] = []string{}
|
||||
indexes["files"] = []string{}
|
||||
var numFiles, numDirs int
|
||||
log.Println("Indexing files...")
|
||||
lastIndexedStart := time.Now()
|
||||
// Call the function to index files and directories
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
go indexingScheduler(intervalMinutes)
|
||||
log.Println("Successfully indexed files.")
|
||||
log.Println("Files found :", totalNumFiles)
|
||||
log.Println("Directories found :", totalNumDirs)
|
||||
}
|
||||
|
||||
func indexingScheduler(intervalMinutes uint32) {
|
||||
log.Printf("Indexing scheduler will run every %v minutes", intervalMinutes)
|
||||
for {
|
||||
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
|
||||
var numFiles, numDirs int
|
||||
lastIndexedStart := time.Now()
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
if totalNumFiles+totalNumDirs > 0 {
|
||||
log.Println("re-indexing found changes and updated the index.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define a function to recursively index files and directories
|
||||
func indexFiles(path string, numFiles *int, numDirs *int) (int, int, error) {
|
||||
// Check if the current directory has been modified since last indexing
|
||||
dir, err := os.Open(path)
|
||||
if err != nil {
|
||||
// directory must have been deleted, remove from index
|
||||
delete(indexes, path)
|
||||
}
|
||||
defer dir.Close()
|
||||
dirInfo, err := dir.Stat()
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Compare the last modified time of the directory with the last indexed time
|
||||
if dirInfo.ModTime().Before(lastIndexed) {
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
// Read the directory contents
|
||||
files, err := dir.Readdir(-1)
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Iterate over the files and directories
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
*numDirs++
|
||||
addToIndex(path, file.Name(), true)
|
||||
_, _, err := indexFiles(path+"/"+file.Name(), numFiles, numDirs) // recursive
|
||||
if err != nil {
|
||||
log.Println("Could not index :", err)
|
||||
return 0, 0, nil
|
||||
}
|
||||
} else {
|
||||
*numFiles++
|
||||
addToIndex(path, file.Name(), false)
|
||||
}
|
||||
}
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
|
||||
func addToIndex(path string, fileName string, isDir bool) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
path = strings.TrimPrefix(path, rootPath+"/")
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
adjustedPath := path + "/" + fileName
|
||||
if path == rootPath {
|
||||
adjustedPath = fileName
|
||||
}
|
||||
if isDir {
|
||||
indexes["dirs"] = append(indexes["dirs"], adjustedPath)
|
||||
} else {
|
||||
indexes["files"] = append(indexes["files"], adjustedPath)
|
||||
}
|
||||
}
|
||||
|
||||
func SearchAllIndexes(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
|
||||
func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
|
||||
runningHash := generateRandomHash(4)
|
||||
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
|
||||
|
||||
searchOptions := ParseSearch(search)
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
fileListTypes := make(map[string]map[string]bool)
|
||||
var matching []string
|
||||
maximum := 100
|
||||
|
||||
for _, searchTerm := range searchOptions.Terms {
|
||||
if searchTerm == "" {
|
||||
continue
|
||||
}
|
||||
// Iterate over the indexes
|
||||
for _, i := range []string{"dirs", "files"} {
|
||||
isdir := i == "dirs"
|
||||
// Iterate over the embedded index.Index fields Dirs and Files
|
||||
for _, i := range []string{"Dirs", "Files"} {
|
||||
isDir := false
|
||||
count := 0
|
||||
for _, path := range indexes[i] {
|
||||
var paths []string
|
||||
|
||||
switch i {
|
||||
case "Dirs":
|
||||
isDir = true
|
||||
paths = si.Dirs
|
||||
case "Files":
|
||||
paths = si.Files
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
value, found := sessionInProgress.Load(sourceSession)
|
||||
if !found || value != runningHash {
|
||||
return []string{}, map[string]map[string]bool{}
|
||||
}
|
||||
if count > maximum {
|
||||
if count > maxSearchResults {
|
||||
break
|
||||
}
|
||||
pathName := scopedPathNameFilter(path, scope)
|
||||
if pathName == "" {
|
||||
continue
|
||||
}
|
||||
matches, fileType := containsSearchTerm(path, searchTerm, *searchOptions, isdir)
|
||||
matches, fileType := containsSearchTerm(path, searchTerm, *searchOptions, isDir)
|
||||
if !matches {
|
||||
continue
|
||||
}
|
||||
if isdir {
|
||||
if isDir {
|
||||
pathName = pathName + "/"
|
||||
}
|
||||
matching = append(matching, pathName)
|
||||
|
@ -216,9 +128,9 @@ func containsSearchTerm(pathName string, searchTerm string, options SearchOption
|
|||
var matchesCondition bool
|
||||
switch t {
|
||||
case "larger":
|
||||
matchesCondition = fileSize > int64(options.LargerThan)*1000000
|
||||
matchesCondition = fileSize > int64(options.LargerThan)*bytesInMegabyte
|
||||
case "smaller":
|
||||
matchesCondition = fileSize < int64(options.SmallerThan)*1000000
|
||||
matchesCondition = fileSize < int64(options.SmallerThan)*bytesInMegabyte
|
||||
default:
|
||||
matchesCondition = v == fileTypes[t]
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
package index
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkSearchAllIndexes(b *testing.B) {
|
||||
indexes = Index{
|
||||
Dirs: make([]string, 0, 1000),
|
||||
Files: make([]string, 0, 1000),
|
||||
}
|
||||
// Create mock data
|
||||
createMockData(50, 3) // 1000 dirs, 3 files per dir
|
||||
|
||||
// Generate 100 random search terms
|
||||
searchTerms := generateRandomSearchTerms(100)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Execute the SearchAllIndexes function
|
||||
for _, term := range searchTerms {
|
||||
indexes.Search(term, "/", "test")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over test files and compare output
|
||||
func TestParseSearch(t *testing.T) {
|
||||
value := ParseSearch("my test search")
|
||||
want := &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
},
|
||||
Terms: []string{"my test search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("case:exact my|test|search")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": true,
|
||||
},
|
||||
Terms: []string{"my", "test", "search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:largerThan=100 type:smallerThan=1000 test")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"larger": true,
|
||||
},
|
||||
Terms: []string{"test"},
|
||||
LargerThan: 100,
|
||||
SmallerThan: 1000,
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:audio thisfile")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"audio": true,
|
||||
},
|
||||
Terms: []string{"thisfile"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchIndexes(t *testing.T) {
|
||||
type args struct {
|
||||
search string
|
||||
scope string
|
||||
sourceSession string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
want1 map[string]map[string]bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1 := indexes.Search(tt.args.search, tt.args.scope, tt.args.sourceSession)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("SearchAllIndexes() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if !reflect.DeepEqual(got1, tt.want1) {
|
||||
t.Errorf("SearchAllIndexes() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_scopedPathNameFilter(t *testing.T) {
|
||||
type args struct {
|
||||
pathName string
|
||||
scope string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := scopedPathNameFilter(tt.args.pathName, tt.args.scope); got != tt.want {
|
||||
t.Errorf("scopedPathNameFilter() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_containsSearchTerm(t *testing.T) {
|
||||
type args struct {
|
||||
pathName string
|
||||
searchTerm string
|
||||
options SearchOptions
|
||||
isDir bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
want1 map[string]bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1 := containsSearchTerm(tt.args.pathName, tt.args.searchTerm, tt.args.options, tt.args.isDir)
|
||||
if got != tt.want {
|
||||
t.Errorf("containsSearchTerm() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if !reflect.DeepEqual(got1, tt.want1) {
|
||||
t.Errorf("containsSearchTerm() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_isDoc(t *testing.T) {
|
||||
type args struct {
|
||||
extension string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := isDoc(tt.args.extension); got != tt.want {
|
||||
t.Errorf("isDoc() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getFileSize(t *testing.T) {
|
||||
type args struct {
|
||||
filepath string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int64
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getFileSize(tt.args.filepath); got != tt.want {
|
||||
t.Errorf("getFileSize() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_isArchive(t *testing.T) {
|
||||
type args struct {
|
||||
extension string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := isArchive(tt.args.extension); got != tt.want {
|
||||
t.Errorf("isArchive() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getLastPathComponent(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getLastPathComponent(tt.args.path); got != tt.want {
|
||||
t.Errorf("getLastPathComponent() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_generateRandomHash(t *testing.T) {
|
||||
type args struct {
|
||||
length int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := generateRandomHash(tt.args.length); got != tt.want {
|
||||
t.Errorf("generateRandomHash() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// loop over test files and compare output
|
||||
func TestParseSearch(t *testing.T) {
|
||||
value := ParseSearch("my test search")
|
||||
want := &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
},
|
||||
Terms: []string{"my test search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("case:exact my|test|search")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": true,
|
||||
},
|
||||
Terms: []string{"my", "test", "search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:largerThan=100 type:smallerThan=1000 test")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"larger": true,
|
||||
},
|
||||
Terms: []string{"test"},
|
||||
LargerThan: 100,
|
||||
SmallerThan: 1000,
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:audio thisfile")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"audio": true,
|
||||
},
|
||||
Terms: []string{"thisfile"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSearchAllIndexes(b *testing.B) {
|
||||
indexes = make(map[string][]string)
|
||||
|
||||
// Create mock data
|
||||
createMockData(50, 3) // 1000 dirs, 3 files per dir
|
||||
|
||||
// Generate 100 random search terms
|
||||
searchTerms := generateRandomSearchTerms(100)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Execute the SearchAllIndexes function
|
||||
for _, term := range searchTerms {
|
||||
SearchAllIndexes(term, "/", "test")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFillIndex(b *testing.B) {
|
||||
indexes = make(map[string][]string)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
createMockData(50, 3) // 1000 dirs, 3 files per dir
|
||||
}
|
||||
}
|
||||
|
||||
func createMockData(numDirs, numFilesPerDir int) {
|
||||
for i := 0; i < numDirs; i++ {
|
||||
dirName := generateRandomPath(rand.Intn(3) + 1)
|
||||
addToIndex("/", dirName, true)
|
||||
for j := 0; j < numFilesPerDir; j++ {
|
||||
fileName := "file-" + getRandomTerm() + getRandomExtension()
|
||||
addToIndex("/"+dirName, fileName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateRandomPath(levels int) string {
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
dirName := "srv"
|
||||
for i := 0; i < levels; i++ {
|
||||
dirName += "/" + getRandomTerm()
|
||||
}
|
||||
return dirName
|
||||
}
|
||||
|
||||
func getRandomTerm() string {
|
||||
wordbank := []string{
|
||||
"hi", "test", "other", "name",
|
||||
"cool", "things", "more", "items",
|
||||
}
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func getRandomExtension() string {
|
||||
wordbank := []string{
|
||||
".txt", ".mp3", ".mov", ".doc",
|
||||
".mp4", ".bak", ".zip", ".jpg",
|
||||
}
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func generateRandomSearchTerms(numTerms int) []string {
|
||||
// Generate random search terms
|
||||
searchTerms := make([]string, numTerms)
|
||||
for i := 0; i < numTerms; i++ {
|
||||
searchTerms[i] = getRandomTerm()
|
||||
}
|
||||
return searchTerms
|
||||
}
|
||||
|
||||
// JSONBytesEqual compares the JSON in two byte slices.
|
||||
func JSONBytesEqual(a, b []byte) (bool, error) {
|
||||
var j, j2 interface{}
|
||||
if err := json.Unmarshal(a, &j); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &j2); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return reflect.DeepEqual(j2, j), nil
|
||||
}
|
|
@ -18,7 +18,6 @@ func Initialize(configFile string) {
|
|||
log.Fatalf("Error unmarshaling YAML data: %v", err)
|
||||
}
|
||||
GlobalConfiguration.UserDefaults.Perm = GlobalConfiguration.UserDefaults.Permissions
|
||||
GlobalConfiguration.Server.Root = "/srv" // hardcoded for now. TODO allow changing
|
||||
}
|
||||
|
||||
func loadConfigFile(configFile string) []byte {
|
||||
|
|
|
@ -2,6 +2,7 @@ package settings
|
|||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
|
@ -50,3 +51,56 @@ func TestConfigLoadSpecificValues(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
type args struct {
|
||||
configFile string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
Initialize(tt.args.configFile)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadConfigFile(t *testing.T) {
|
||||
type args struct {
|
||||
configFile string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []byte
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := loadConfigFile(tt.args.configFile); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("loadConfigFile() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_setDefaults(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want Settings
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := setDefaults(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("setDefaults() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package settings
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/rules"
|
||||
)
|
||||
|
||||
func TestSettings_MakeUserDir(t *testing.T) {
|
||||
type fields struct {
|
||||
Key []byte
|
||||
Signup bool
|
||||
CreateUserDir bool
|
||||
UserHomeBasePath string
|
||||
Commands map[string][]string
|
||||
Shell []string
|
||||
AdminUsername string
|
||||
AdminPassword string
|
||||
Rules []rules.Rule
|
||||
Server Server
|
||||
Auth Auth
|
||||
Frontend Frontend
|
||||
Users []UserDefaults
|
||||
UserDefaults UserDefaults
|
||||
}
|
||||
type args struct {
|
||||
username string
|
||||
userScope string
|
||||
serverRoot string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &Settings{
|
||||
Key: tt.fields.Key,
|
||||
Signup: tt.fields.Signup,
|
||||
CreateUserDir: tt.fields.CreateUserDir,
|
||||
UserHomeBasePath: tt.fields.UserHomeBasePath,
|
||||
Commands: tt.fields.Commands,
|
||||
Shell: tt.fields.Shell,
|
||||
AdminUsername: tt.fields.AdminUsername,
|
||||
AdminPassword: tt.fields.AdminPassword,
|
||||
Rules: tt.fields.Rules,
|
||||
Server: tt.fields.Server,
|
||||
Auth: tt.fields.Auth,
|
||||
Frontend: tt.fields.Frontend,
|
||||
Users: tt.fields.Users,
|
||||
UserDefaults: tt.fields.UserDefaults,
|
||||
}
|
||||
got, err := s.MakeUserDir(tt.args.username, tt.args.userScope, tt.args.serverRoot)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Settings.MakeUserDir() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Settings.MakeUserDir() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_cleanUsername(t *testing.T) {
|
||||
type args struct {
|
||||
s string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := cleanUsername(tt.args.s); got != tt.want {
|
||||
t.Errorf("cleanUsername() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ import HeaderBar from "@/components/header/HeaderBar";
|
|||
import Breadcrumbs from "@/components/Breadcrumbs";
|
||||
import Errors from "@/views/Errors";
|
||||
import Preview from "@/views/files/Preview";
|
||||
import ListingView from "@/views/files/Listing";
|
||||
import Listing from "@/views/files/Listing";
|
||||
|
||||
function clean(path) {
|
||||
return path.endsWith("/") ? path.slice(0, -1) : path;
|
||||
|
@ -38,7 +38,7 @@ export default {
|
|||
Breadcrumbs,
|
||||
Errors,
|
||||
Preview,
|
||||
ListingView,
|
||||
Listing,
|
||||
Editor: () => import("@/views/files/Editor"),
|
||||
},
|
||||
data: function () {
|
||||
|
|
|
@ -26,7 +26,7 @@ import css from "@/utils/css";
|
|||
import throttle from "lodash.throttle";
|
||||
|
||||
export default {
|
||||
name: "listingView",
|
||||
name: "listing",
|
||||
components: {
|
||||
HeaderBar,
|
||||
Action,
|
||||
|
@ -129,12 +129,12 @@ export default {
|
|||
// Reset the show value
|
||||
this.showLimit = 50;
|
||||
|
||||
// Ensures that the listingView is displayed
|
||||
// Ensures that the listing is displayed
|
||||
Vue.nextTick(() => {
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill and fit the window with listingView items
|
||||
// Fill and fit the window with listing items
|
||||
this.fillWindow(true);
|
||||
});
|
||||
},
|
||||
|
@ -143,10 +143,10 @@ export default {
|
|||
// Check the columns size for the first time.
|
||||
this.colunmsResize();
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill and fit the window with listingView items
|
||||
// Fill and fit the window with listing items
|
||||
this.fillWindow(true);
|
||||
|
||||
// Add the needed event listeners to the window and document.
|
||||
|
@ -375,7 +375,7 @@ export default {
|
|||
let columns = Math.floor(
|
||||
document.querySelector("main").offsetWidth / this.columnWidth
|
||||
);
|
||||
let items = css(["#listingView.mosaic .item", ".mosaic#listingView .item"]);
|
||||
let items = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
|
||||
if (columns === 0) columns = 1;
|
||||
items.style.width = `calc(${100 / columns}% - 1em)`;
|
||||
},
|
||||
|
@ -402,7 +402,7 @@ export default {
|
|||
this.dragCounter++;
|
||||
|
||||
// When the user starts dragging an item, put every
|
||||
// file on the listingView with 50% opacity.
|
||||
// file on the listing with 50% opacity.
|
||||
let items = document.getElementsByClassName("item");
|
||||
|
||||
Array.from(items).forEach((file) => {
|
||||
|
@ -544,9 +544,9 @@ export default {
|
|||
this.width = window.innerWidth;
|
||||
|
||||
// Listing element is not displayed
|
||||
if (this.$refs.listingView == null) return;
|
||||
if (this.$refs.listing == null) return;
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill but not fit the window
|
||||
|
@ -598,13 +598,13 @@ export default {
|
|||
},
|
||||
setItemWeight() {
|
||||
// Listing element is not displayed
|
||||
if (this.$refs.listingView == null) return;
|
||||
if (this.$refs.listing == null) return;
|
||||
|
||||
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
||||
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
this.itemWeight = this.$refs.listingView.offsetHeight / itemQuantity;
|
||||
// How much every listing item affects the window height
|
||||
this.itemWeight = this.$refs.listing.offsetHeight / itemQuantity;
|
||||
},
|
||||
fillWindow(fit = false) {
|
||||
const totalItems = this.req.numDirs + this.req.numFiles;
|
||||
|
|
|
@ -37,7 +37,7 @@ import Search from "@/components/Search.vue";
|
|||
|
||||
|
||||
export default {
|
||||
name: "listingView",
|
||||
name: "listing",
|
||||
components: {
|
||||
HeaderBar,
|
||||
Action,
|
||||
|
@ -138,12 +138,12 @@ export default {
|
|||
// Reset the show value
|
||||
this.showLimit = 50;
|
||||
|
||||
// Ensures that the listingView is displayed
|
||||
// Ensures that the listing is displayed
|
||||
Vue.nextTick(() => {
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill and fit the window with listingView items
|
||||
// Fill and fit the window with listing items
|
||||
this.fillWindow(true);
|
||||
});
|
||||
},
|
||||
|
@ -152,10 +152,10 @@ export default {
|
|||
// Check the columns size for the first time.
|
||||
this.colunmsResize();
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill and fit the window with listingView items
|
||||
// Fill and fit the window with listing items
|
||||
this.fillWindow(true);
|
||||
|
||||
// Add the needed event listeners to the window and document.
|
||||
|
@ -384,7 +384,7 @@ export default {
|
|||
let columns = Math.floor(
|
||||
document.querySelector("main").offsetWidth / this.columnWidth
|
||||
);
|
||||
let items = css(["#listingView.mosaic .item", ".mosaic#listingView .item"]);
|
||||
let items = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
|
||||
if (columns === 0) columns = 1;
|
||||
items.style.width = `calc(${100 / columns}% - 1em)`;
|
||||
},
|
||||
|
@ -411,7 +411,7 @@ export default {
|
|||
this.dragCounter++;
|
||||
|
||||
// When the user starts dragging an item, put every
|
||||
// file on the listingView with 50% opacity.
|
||||
// file on the listing with 50% opacity.
|
||||
let items = document.getElementsByClassName("item");
|
||||
|
||||
Array.from(items).forEach((file) => {
|
||||
|
@ -553,9 +553,9 @@ export default {
|
|||
this.width = window.innerWidth;
|
||||
|
||||
// Listing element is not displayed
|
||||
if (this.$refs.listingView == null) return;
|
||||
if (this.$refs.listing == null) return;
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill but not fit the window
|
||||
|
@ -597,13 +597,13 @@ export default {
|
|||
},
|
||||
setItemWeight() {
|
||||
// Listing element is not displayed
|
||||
if (this.$refs.listingView == null) return;
|
||||
if (this.$refs.listing == null) return;
|
||||
|
||||
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
||||
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
this.itemWeight = this.$refs.listingView.offsetHeight / itemQuantity;
|
||||
// How much every listing item affects the window height
|
||||
this.itemWeight = this.$refs.listing.offsetHeight / itemQuantity;
|
||||
},
|
||||
fillWindow(fit = false) {
|
||||
const totalItems = this.req.numDirs + this.req.numFiles;
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
multiple
|
||||
/>
|
||||
</div>
|
||||
<div v-else id="listingView" ref="listingView" :class="user.viewMode + ' file-icons'">
|
||||
<div v-else id="listing" ref="listing" :class="user.viewMode + ' file-icons'">
|
||||
<div>
|
||||
<div class="item header">
|
||||
<div></div>
|
||||
|
@ -213,7 +213,7 @@ import Action from "@/components/header/Action";
|
|||
import Item from "@/components/files/ListingItem";
|
||||
|
||||
export default {
|
||||
name: "listingView",
|
||||
name: "listing",
|
||||
components: {
|
||||
Action,
|
||||
Item,
|
||||
|
@ -313,12 +313,12 @@ export default {
|
|||
// Reset the show value
|
||||
this.showLimit = 50;
|
||||
|
||||
// Ensures that the listingView is displayed
|
||||
// Ensures that the listing is displayed
|
||||
Vue.nextTick(() => {
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill and fit the window with listingView items
|
||||
// Fill and fit the window with listing items
|
||||
this.fillWindow(true);
|
||||
});
|
||||
},
|
||||
|
@ -327,10 +327,10 @@ export default {
|
|||
// Check the columns size for the first time.
|
||||
this.colunmsResize();
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill and fit the window with listingView items
|
||||
// Fill and fit the window with listing items
|
||||
this.fillWindow(true);
|
||||
|
||||
// Add the needed event listeners to the window and document.
|
||||
|
@ -527,7 +527,7 @@ export default {
|
|||
let columns = Math.floor(
|
||||
document.querySelector("main").offsetWidth / this.columnWidth
|
||||
);
|
||||
let items = css(["#listingView.mosaic .item", ".mosaic#listingView .item"]);
|
||||
let items = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
|
||||
if (columns === 0) columns = 1;
|
||||
items.style.width = `calc(${100 / columns}% - 1em)`;
|
||||
},
|
||||
|
@ -554,7 +554,7 @@ export default {
|
|||
this.dragCounter++;
|
||||
|
||||
// When the user starts dragging an item, put every
|
||||
// file on the listingView with 50% opacity.
|
||||
// file on the listing with 50% opacity.
|
||||
let items = document.getElementsByClassName("item");
|
||||
|
||||
Array.from(items).forEach((file) => {
|
||||
|
@ -696,9 +696,9 @@ export default {
|
|||
this.width = window.innerWidth;
|
||||
|
||||
// Listing element is not displayed
|
||||
if (this.$refs.listingView == null) return;
|
||||
if (this.$refs.listing == null) return;
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
// How much every listing item affects the window height
|
||||
this.setItemWeight();
|
||||
|
||||
// Fill but not fit the window
|
||||
|
@ -740,13 +740,13 @@ export default {
|
|||
},
|
||||
setItemWeight() {
|
||||
// Listing element is not displayed
|
||||
if (this.$refs.listingView == null) return;
|
||||
if (this.$refs.listing == null) return;
|
||||
|
||||
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
||||
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
||||
|
||||
// How much every listingView item affects the window height
|
||||
this.itemWeight = this.$refs.listingView.offsetHeight / itemQuantity;
|
||||
// How much every listing item affects the window height
|
||||
this.itemWeight = this.$refs.listing.offsetHeight / itemQuantity;
|
||||
},
|
||||
fillWindow(fit = false) {
|
||||
const totalItems = this.req.numDirs + this.req.numFiles;
|
||||
|
|
Loading…
Reference in New Issue