From 5806060775240e623a379a9fbd7b7685235e0f35 Mon Sep 17 00:00:00 2001 From: Graham Steffaniak Date: Wed, 12 Jul 2023 21:23:29 -0500 Subject: [PATCH] updaeted a lot` --- .gitignore | 2 +- Dockerfile | 5 +- src/backend/http/search.go | 17 ++- src/backend/search/conditions.go | 7 +- src/backend/search/indexing.go | 163 +++++++++++++------------ src/frontend/src/components/Search.vue | 25 ++-- src/frontend/src/css/header.css | 65 ++++++---- 7 files changed, 162 insertions(+), 122 deletions(-) diff --git a/.gitignore b/.gitignore index ee2774fd..6935b232 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ rice-box.go /filebrowser /filebrowser.exe /dist -/src/backend/vendor/* +/src/backend/vendor .DS_Store node_modules diff --git a/Dockerfile b/Dockerfile index a6feaaf8..d8ae4f28 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ -FROM node:14.21-slim as nbuild +FROM node:slim as nbuild WORKDIR /app -COPY ./src/frontend ./ +COPY ./src/frontend/package*.json ./ RUN npm i +COPY ./src/frontend/ ./ RUN npm run build FROM golang:alpine as base diff --git a/src/backend/http/search.go b/src/backend/http/search.go index 0a05c0ad..304da28b 100644 --- a/src/backend/http/search.go +++ b/src/backend/http/search.go @@ -8,12 +8,17 @@ import ( var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { response := []map[string]interface{}{} query := r.URL.Query().Get("query") - files, dirs := search.SearchAllIndexes(query, r.URL.Path) - for _,v := range(files){ - response = append(response, map[string]interface{}{ - "dir": false, - "path": v, - }) + files, dirs, fileTypes := search.SearchAllIndexes(query, r.URL.Path) + for _,path := range(files){ + f := fileTypes[path] + responseObj := map[string]interface{}{ + "dir" : false, + "path" : path, + } + for _,filterType := range(search.FilterableTypes) { + if f[filterType] { responseObj[filterType] = f[filterType] } + } + response = append(response,responseObj) } for _,v := range(dirs){ response = append(response, map[string]interface{}{ diff --git a/src/backend/search/conditions.go b/src/backend/search/conditions.go index 9c7e3a58..025d37bb 100644 --- a/src/backend/search/conditions.go +++ b/src/backend/search/conditions.go @@ -11,6 +11,8 @@ var documentTypes = []string{ ".word", ".pdf", ".txt", + ".doc", + ".docx", } var compressedFile = []string{ @@ -45,7 +47,6 @@ func ParseSearch(value string) *searchOptions { if len(filterType) == 1 { continue } - switch filterType[1] { case "image": opts.Conditions["image"] = true @@ -55,8 +56,8 @@ func ParseSearch(value string) *searchOptions { opts.Conditions["video"] = true case "doc": opts.Conditions["doc"] = true - case "zip": - opts.Conditions["zip"] = true + case "archive": + opts.Conditions["archive"] = true } } diff --git a/src/backend/search/indexing.go b/src/backend/search/indexing.go index 21d70335..2bd281f8 100644 --- a/src/backend/search/indexing.go +++ b/src/backend/search/indexing.go @@ -13,7 +13,8 @@ import ( var ( rootPath string = "/srv" - indexes map[string][]string + indexes = map[string][]string{} + FilterableTypes = []string{"audio","image","video","doc","archive"} mutex sync.RWMutex lastIndexed time.Time ) @@ -21,6 +22,8 @@ var ( 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() @@ -79,78 +82,80 @@ func indexFiles(path string, numFiles *int, numDirs *int) (int, int, error) { for _, file := range files { if file.IsDir() { *numDirs++ - indexFiles(path+"/"+file.Name(), numFiles, numDirs) + addToIndex(path, file.Name(), true) + indexFiles(path+"/"+file.Name(), numFiles, numDirs) // recursive + } else { + *numFiles++ + addToIndex(path, file.Name(), false) } - *numFiles++ - addToIndex(path, file.Name()) } return *numFiles, *numDirs, nil } -func addToIndex(path string, fileName string) { +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 { - path = "/" + adjustedPath = fileName } - info, exists := indexes[path] - if !exists { - info = []string{} + if isDir { + indexes["dirs"] = append(indexes["dirs"], adjustedPath) + }else{ + indexes["files"] = append(indexes["files"], adjustedPath) } - info = append(info, fileName) - indexes[path] = info } -func SearchAllIndexes(search string, scope string) ([]string, []string) { +func SearchAllIndexes(search string, scope string) ([]string, []string, map[string]map[string]bool) { searchOptions := ParseSearch(search) mutex.RLock() defer mutex.RUnlock() + fileListTypes := make(map[string]map[string]bool) var matchingFiles []string var matchingDirs []string - maximum := 100 - count := 0 + maximum := 125 + for _, searchTerm := range searchOptions.Terms { if searchTerm == "" { continue } + count := 0 // Iterate over the indexes - for dirName, v := range indexes { + for _, dirName := range indexes["dirs"] { if count > maximum { break } - searchItems := v - // Iterate over the path names - for _, pathName := range searchItems { - if count > maximum { - break - } - if dirName != "/" { - pathName = dirName + "/" + pathName - } - // Check if the path name contains the search term - if !containsSearchTerm(pathName, searchTerm, searchOptions.Conditions) { - continue - } - pathName = scopedPathNameFilter(pathName, scope) - if pathName == "" { - continue - } - count++ - matchingFiles = append(matchingFiles, pathName) - } - // Check if the path name contains the search term - if !containsSearchTerm(dirName, searchTerm, searchOptions.Conditions) { - continue - } pathName := scopedPathNameFilter(dirName, scope) if pathName == "" { continue } + matches, _ := containsSearchTerm(pathName, searchTerm, searchOptions.Conditions) + if !matches { + continue + } count++ matchingDirs = append(matchingDirs, pathName) } + count = 0 + for _, fileName := range indexes["files"] { + if count > maximum { + break + } + pathName := scopedPathNameFilter(fileName, scope) + if pathName == "" { + continue + } + // Check if the path name contains the search term + matches, fileType := containsSearchTerm(pathName, searchTerm, searchOptions.Conditions) + if !matches { + continue + } + matchingFiles = append(matchingFiles, pathName) + fileListTypes[pathName] = fileType + count++ + } } // Sort the strings based on the number of elements after splitting by "/" sort.Slice(matchingFiles, func(i, j int) bool { @@ -164,7 +169,7 @@ func SearchAllIndexes(search string, scope string) ([]string, []string) { parts2 := strings.Split(matchingDirs[j], "/") return len(parts1) < len(parts2) }) - return matchingFiles, matchingDirs + return matchingFiles, matchingDirs, fileListTypes } func scopedPathNameFilter(pathName string, scope string) string { @@ -177,51 +182,51 @@ func scopedPathNameFilter(pathName string, scope string) string { return pathName } -func containsSearchTerm(pathName string, searchTerm string, conditions map[string]bool) bool { - path := getLastPathComponent(pathName) +func containsSearchTerm(pathName string, searchTerm string, conditions map[string]bool) (bool, map[string]bool) { + path := getLastPathComponent(pathName) + fileTypes := map[string]bool{} + matchesCondition := false + extension := filepath.Ext(strings.ToLower(path)) + mimetype := mime.TypeByExtension(extension) + filterTypes := FilterableTypes + fileTypes["audio"] = strings.HasPrefix(mimetype, "audio") + fileTypes["image"] = strings.HasPrefix(mimetype, "image") + fileTypes["video"] = strings.HasPrefix(mimetype, "video") + fileTypes["doc"] = isDoc(extension) + fileTypes["archive"] = isArchive(extension) + anyFilter := false + for _,t := range(filterTypes){ + if conditions[t] { + anyFilter = true + matchesCondition = fileTypes[t] + } + } + if !anyFilter { + matchesCondition = true + } if !conditions["exact"] { path = strings.ToLower(path) searchTerm = strings.ToLower(searchTerm) } - matchesCondition := true - if conditions["audio"] { - extension := filepath.Ext(path) - mimetype := mime.TypeByExtension(extension) - matchesCondition = strings.HasPrefix(mimetype, "audio") - } - if conditions["video"] { - extension := filepath.Ext(path) - mimetype := mime.TypeByExtension(extension) - matchesCondition = strings.HasPrefix(mimetype, "video") - } - if conditions["image"] { - extension := filepath.Ext(path) - mimetype := mime.TypeByExtension(extension) - matchesCondition = strings.HasPrefix(mimetype, "image") - } - if conditions["doc"] { - extension := filepath.Ext(path) - for _, typefile := range documentTypes { - if extension == typefile { - matchesCondition = true - continue - } else { - matchesCondition = false - } + return strings.Contains(path, searchTerm) && matchesCondition, fileTypes +} + +func isDoc(extension string) bool { + for _, typefile := range documentTypes { + if extension == typefile { + return true } - } - if conditions["zip"] { - extension := filepath.Ext(path) - for _, typefile := range compressedFile { - if extension == typefile { - matchesCondition = true - continue - } else { - matchesCondition = false - } + } + return false +} + +func isArchive(extension string) bool { + for _, typefile := range compressedFile { + if extension == typefile { + return true } - } - return strings.Contains(path, searchTerm) && matchesCondition + } + return false } func getLastPathComponent(path string) string { diff --git a/src/frontend/src/components/Search.vue b/src/frontend/src/components/Search.vue index ab2ec4a9..09cac6dd 100644 --- a/src/frontend/src/components/Search.vue +++ b/src/frontend/src/components/Search.vue @@ -24,7 +24,9 @@
-
+
+
+
    -
  • - - folder - insert_drive_file - ./{{ s.path }} +
    Searching Scope : {{ path }}
    +
  • + + folder + volume_up + photo + movie + archive + insert_drive_file + {{ s.path }}
@@ -92,7 +99,6 @@ export default { watch: { show(val, old) { this.active = val === "search"; - if (old === "search" && !this.active) { if (this.reload) { this.setReload(true); @@ -155,8 +161,13 @@ export default { close(event) { event.stopPropagation(); event.preventDefault(); + console.log("closing") this.closeHovers(); }, + navigate(url, event) { + this.close(event); // pass the event object to the close method + this.$router.push(url); + }, keyup(event) { if (event.keyCode === 27) { this.close(event); diff --git a/src/frontend/src/css/header.css b/src/frontend/src/css/header.css index 3dc8bd51..d4a32908 100644 --- a/src/frontend/src/css/header.css +++ b/src/frontend/src/css/header.css @@ -82,7 +82,7 @@ header .menu-button { } #search #input { - background-color: #f5f5f5; + background-color: rgba(100, 100, 100, 0.2); display: flex; height: 100%; padding: 0em 0.75em; @@ -93,9 +93,9 @@ header .menu-button { } #search.active #input { - border-bottom: 1px solid rgba(0, 0, 0, 0.075); - box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); - background-color: #fff; + border-bottom: 3px solid rgba(0, 0, 0, 0.075); + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(6px); height: 4em; } @@ -103,11 +103,6 @@ header .menu-button { border-radius: 0 !important; } -#search.active i, -#search.active input { - color: #212121; -} - #search #input>.action, #search #input>i { margin-right: 0.3em; @@ -121,20 +116,35 @@ header .menu-button { padding: 0; } +#result-list { + width: 60em; + max-width: 100%; + padding: 0.5em; + overflow-x: hidden; + overflow-y: auto; +} + #search #result { - visibility: visible; - max-height: none; - background-color: #f8f8f8; + overflow: hidden; + background: white; + display: flex; + top: -4em; + flex-direction: column; + align-items: center; text-align: left; padding: 0; color: rgba(0, 0, 0, 0.6); height: 0; - transition: .1s ease height, .1s ease padding; - overflow-x: hidden; - overflow-y: auto; + transition: .2s ease height, .2s ease padding; z-index: 1; } +@media screen and (min-width: 800px) { + #search #result { + background: linear-gradient(to right, white 15%,lightgray 25%,lightgray 75%,white 85%); + } +} + body.rtl #search #result { direction: ltr; } @@ -156,12 +166,12 @@ body.rtl #search #result ul>* { #search.active #result { padding: .5em; - height: calc(100% - 4em); + height: 100% } #search ul { + margin-top: 1em; padding: 0; - margin: 0; list-style: none; } @@ -169,11 +179,6 @@ body.rtl #search #result ul>* { margin-bottom: .5em; } -#search #result>div { - max-width: 45em; - margin: 0 auto; -} - #search #result #renew { width: 100%; text-align: center; @@ -186,8 +191,20 @@ body.rtl #search #result ul>* { display: block; } -#search.active #result i { - color: #ccc; +.folder-icons { + color: var(--icon-blue); +} +.video-icons { + color: lightskyblue; +} +.image-icons { + color: lightcoral; +} +.archive-icons { + color: tan; +} +.audio-icons { + color: plum; } #search.active #result>p>i {