merge initial v0.2.3 commit (#97) (#98)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Graham Steffaniak <graham.steffaniak@autodesk.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Graham Steffaniak 2023-12-20 14:44:25 -06:00 committed by GitHub
parent ac544738a2
commit 398ac49aa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 140 additions and 119 deletions

View File

@ -2,15 +2,18 @@
All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version). All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version).
## v0.2.3
- Feature: token expiration time now configurable
- FIX: Hidden files are still directly accessible. (https://github.com/filebrowser/filebrowser/issues/2698)
- FIX: search/user context bug
## v0.2.2 ## v0.2.2
- **Major Indexing Changes:** - CHG: **Speed:** (0m57s) - Decreased by 78% compared to the previous release.
- **Speed:** (0m57s) - Decreased by 78% compared to the previous release. - CHG: **Memory Usage:** (41MB) - Reduced by 45% compared to the previous release.
- **Memory Usage:** (41MB) - Reduced by 45% compared to the previous release. - Feature: Now utilizes the index for file browser listings!
- Now utilizes the index for file browser listings! - FIX: Editor issues fixed on save and themes.
- **[Work in Progress]** Hidden files are still directly accessible.
- **[Work in Progress]** Editor issues fixed on save and themes.
- **[Work in Progress]** `running-config.yaml` gets updated when settings change, ensuring that running settings are up to date.
## v0.2.1 ## v0.2.1

View File

@ -119,9 +119,11 @@ func (si *Index) InsertFiles(path string) {
buffer := bytes.Buffer{} buffer := bytes.Buffer{}
for _, f := range si.GetQuickList() { for _, f := range si.GetQuickList() {
if !f.IsDir {
buffer.WriteString(f.Name + ";") buffer.WriteString(f.Name + ";")
si.UpdateCount("files") si.UpdateCount("files")
} }
}
// Use GetMetadataInfo and SetFileMetadata for safer read and write operations // Use GetMetadataInfo and SetFileMetadata for safer read and write operations
subDirectory.Files = buffer.String() subDirectory.Files = buffer.String()
si.SetDirectoryInfo(adjustedPath, subDirectory) si.SetDirectoryInfo(adjustedPath, subDirectory)

View File

@ -16,16 +16,15 @@ var (
) )
func (si *Index) Search(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) {
if scope == "" { // Remove slashes
scope = "/" scope = strings.TrimLeft(scope, "/")
} scope = strings.TrimRight(scope, "/")
runningHash := generateRandomHash(4) runningHash := generateRandomHash(4)
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
searchOptions := ParseSearch(search) searchOptions := ParseSearch(search)
fileListTypes := make(map[string]map[string]bool) fileListTypes := make(map[string]map[string]bool)
matching := []string{} matching := []string{}
count := 0 count := 0
for _, searchTerm := range searchOptions.Terms { for _, searchTerm := range searchOptions.Terms {
if searchTerm == "" { if searchTerm == "" {
continue continue
@ -46,7 +45,6 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
if pathName == "" { if pathName == "" {
continue // path not matched continue // path not matched
} }
fileTypes := map[string]bool{} fileTypes := map[string]bool{}
matches, fileType := containsSearchTerm(dirName, searchTerm, *searchOptions, isDir, fileTypes) matches, fileType := containsSearchTerm(dirName, searchTerm, *searchOptions, isDir, fileTypes)
if matches { if matches {
@ -74,7 +72,6 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
if !matches { if !matches {
continue continue
} }
fileListTypes[fullName] = fileType fileListTypes[fullName] = fileType
matching = append(matching, fullName) matching = append(matching, fullName)
count++ count++
@ -91,11 +88,11 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
} }
func scopedPathNameFilter(pathName string, scope string, isDir bool) string { func scopedPathNameFilter(pathName string, scope string, isDir bool) string {
scope = strings.TrimPrefix(scope, "/") pathName = strings.TrimLeft(pathName, "/")
pathName = strings.TrimPrefix(pathName, "/") pathName = strings.TrimRight(pathName, "/")
pathName = strings.TrimSuffix(pathName, "/") if strings.HasPrefix(pathName, scope) || scope == "" {
if strings.HasPrefix(pathName, scope) {
pathName = strings.TrimPrefix(pathName, scope) pathName = strings.TrimPrefix(pathName, scope)
pathName = strings.TrimLeft(pathName, "/")
if isDir { if isDir {
pathName = pathName + "/" pathName = pathName + "/"
} }

View File

@ -163,25 +163,38 @@ func TestSearchIndexes(t *testing.T) {
} }
func Test_scopedPathNameFilter(t *testing.T) { func Test_scopedPathNameFilter(t *testing.T) {
type args struct {
pathName string
scope string
}
tests := []struct { tests := []struct {
name string name string
args args args struct {
pathName string
scope string
isDir bool // Assuming isDir should be included in args
}
want string want string
}{ }{
// TODO: Add test cases. {
name: "scope test",
args: struct {
pathName string
scope string
isDir bool
}{
pathName: "/",
scope: "/",
isDir: false,
},
want: "", // Update this with the expected result
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if got := scopedPathNameFilter(tt.args.pathName, tt.args.scope, false); got != tt.want { if got := scopedPathNameFilter(tt.args.pathName, tt.args.scope, tt.args.isDir); got != tt.want {
t.Errorf("scopedPathNameFilter() = %v, want %v", got, tt.want) t.Errorf("scopedPathNameFilter() = %v, want %v", got, tt.want)
} }
}) })
} }
} }
func Test_isDoc(t *testing.T) { func Test_isDoc(t *testing.T) {
type args struct { type args struct {
extension string extension string

View File

@ -19,9 +19,9 @@ require (
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.17.0
golang.org/x/image v0.12.0 golang.org/x/image v0.12.0
golang.org/x/text v0.13.0 golang.org/x/text v0.14.0
) )
require ( require (
@ -49,7 +49,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/bbolt v1.3.4 // indirect go.etcd.io/bbolt v1.3.4 // indirect
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect golang.org/x/sys v0.15.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@ -280,8 +280,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -426,8 +426,8 @@ golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -440,8 +440,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@ -2,6 +2,7 @@ package http
import ( import (
"encoding/json" "encoding/json"
"fmt"
"log" "log"
"net/http" "net/http"
"os" "os"
@ -16,10 +17,6 @@ import (
"github.com/gtsteffaniak/filebrowser/users" "github.com/gtsteffaniak/filebrowser/users"
) )
const (
TokenExpirationTime = time.Hour * 2
)
type authToken struct { type authToken struct {
User users.User `json:"user"` User users.User `json:"user"`
jwt.RegisteredClaims jwt.RegisteredClaims
@ -158,11 +155,16 @@ var renewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data
}) })
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) { func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) {
duration, err := time.ParseDuration(settings.Config.Auth.TokenExpirationTime)
if err != nil {
fmt.Println("Error parsing duration:", err)
duration = time.Hour * 2
}
claims := &authToken{ claims := &authToken{
User: *user, User: *user,
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpirationTime)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(duration)),
Issuer: "File Browser", Issuer: "File Browser",
}, },
} }

View File

@ -7,7 +7,6 @@ import (
"github.com/tomasen/realip" "github.com/tomasen/realip"
"github.com/gtsteffaniak/filebrowser/rules"
"github.com/gtsteffaniak/filebrowser/runner" "github.com/gtsteffaniak/filebrowser/runner"
"github.com/gtsteffaniak/filebrowser/settings" "github.com/gtsteffaniak/filebrowser/settings"
"github.com/gtsteffaniak/filebrowser/storage" "github.com/gtsteffaniak/filebrowser/storage"
@ -27,9 +26,6 @@ type data struct {
// Check implements rules.Checker. // Check implements rules.Checker.
func (d *data) Check(path string) bool { func (d *data) Check(path string) bool {
if d.user.HideDotfiles && rules.MatchHidden(path) {
return false
}
allow := true allow := true
for _, rule := range d.settings.Rules { for _, rule := range d.settings.Rules {

View File

@ -16,7 +16,6 @@ var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *dat
userScope := r.Header.Get("UserScope") userScope := r.Header.Get("UserScope")
index := files.GetIndex(settings.Config.Server.Root) index := files.GetIndex(settings.Config.Server.Root)
combinedScope := strings.TrimPrefix(userScope+r.URL.Path, ".") combinedScope := strings.TrimPrefix(userScope+r.URL.Path, ".")
combinedScope = strings.TrimPrefix(combinedScope, "/")
results, fileTypes := index.Search(query, combinedScope, sessionId) results, fileTypes := index.Search(query, combinedScope, sessionId)
for _, path := range results { for _, path := range results {
responseObj := map[string]interface{}{ responseObj := map[string]interface{}{

View File

@ -60,6 +60,7 @@ func setDefaults() Settings {
Root: "/srv", Root: "/srv",
}, },
Auth: Auth{ Auth: Auth{
TokenExpirationTime: "2h",
AdminUsername: "admin", AdminUsername: "admin",
AdminPassword: "admin", AdminPassword: "admin",
Method: "password", Method: "password",

View File

@ -17,6 +17,7 @@ type Settings struct {
} }
type Auth struct { type Auth struct {
TokenExpirationTime string `json:"tokenExpirationTime"`
Recaptcha Recaptcha `json:"recaptcha"` Recaptcha Recaptcha `json:"recaptcha"`
Header string `json:"header"` Header string `json:"header"`
Method string `json:"method"` Method string `json:"method"`

View File

@ -2,7 +2,7 @@ package version
var ( var (
// Version is the current File Browser version. // Version is the current File Browser version.
Version = "(0.2.2)" Version = "(0.2.3)"
// CommitSHA is the commmit sha. // CommitSHA is the commmit sha.
CommitSHA = "(unknown)" CommitSHA = "(unknown)"
) )

View File

@ -31,6 +31,7 @@ auth:
host: "" host: ""
key: "" key: ""
secret: "" secret: ""
tokenExpirationTime: 2h
header: "" header: ""
method: json method: json
command: "" command: ""

View File

@ -1045,9 +1045,9 @@
}, },
"node_modules/@vue/vue-loader-v15": { "node_modules/@vue/vue-loader-v15": {
"name": "vue-loader", "name": "vue-loader",
"version": "15.10.2", "version": "15.11.1",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.2.tgz", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz",
"integrity": "sha512-ndeSe/8KQc/nlA7TJ+OBhv2qalmj1s+uBs7yHDRFaAXscFTApBzY9F1jES3bautmgWjDlDct0fw8rPuySDLwxw==", "integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@vue/component-compiler-utils": "^3.1.0", "@vue/component-compiler-utils": "^3.1.0",
@ -5341,9 +5341,9 @@
} }
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "3.3.6", "version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -5896,9 +5896,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.29", "version": "8.4.32",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
"integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -5914,7 +5914,7 @@
} }
], ],
"dependencies": { "dependencies": {
"nanoid": "^3.3.6", "nanoid": "^3.3.7",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
}, },

View File

@ -43,11 +43,6 @@
"eslint-plugin-vue": "^9.17.0", "eslint-plugin-vue": "^9.17.0",
"vue-template-compiler": "^2.6.10" "vue-template-compiler": "^2.6.10"
}, },
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [ "browserslist": [
"> 1%", "> 1%",
"last 2 versions", "last 2 versions",

View File

@ -30,7 +30,7 @@
<div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result"> <div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result">
<div id="result-list"> <div id="result-list">
<div class="button" style="width: 100%"> <div class="button" style="width: 100%">
Search Context: {{ this.searchContext }} Search Context: {{ getContext }}
</div> </div>
<ul v-show="results.length > 0"> <ul v-show="results.length > 0">
<li <li
@ -91,7 +91,7 @@
</div> </div>
</div> </div>
<div v-show="!isMobile && active" id="result-desktop" ref="result"> <div v-show="!isMobile && active" id="result-desktop" ref="result">
<div class="searchContext">Search Context: {{ this.searchContext }}</div> <div class="searchContext">Search Context: {{ getContext }}</div>
<div id="result-list"> <div id="result-list">
<template> <template>
<p v-show="isEmpty && isRunning" id="renew"> <p v-show="isEmpty && isRunning" id="renew">
@ -535,7 +535,6 @@ export default {
name: "search", name: "search",
data: function () { data: function () {
return { return {
searchContext: "./",
largerThan: "", largerThan: "",
smallerThan: "", smallerThan: "",
noneMessage: "Start typing 3 or more characters to begin searching.", noneMessage: "Start typing 3 or more characters to begin searching.",
@ -632,10 +631,16 @@ export default {
searchHelp() { searchHelp() {
return this.showHelp; return this.showHelp;
}, },
getContext() {
let path = this.$route.path
path = path.slice(1);
path = "./" + path.substring(path.indexOf("/") + 1);
path = path.replace(/\/+$/, "") + "/";
return path
},
}, },
mounted() { mounted() {
window.addEventListener("resize", this.handleResize); window.addEventListener("resize", this.handleResize);
this.searchContext = this.getContext(this.$route.path)
this.handleResize(); // Call this once to set the initial width this.handleResize(); // Call this once to set the initial width
}, },
methods: { methods: {
@ -647,19 +652,15 @@ export default {
await this.$nextTick(); await this.$nextTick();
setTimeout(() => this.$router.push(url), 0); setTimeout(() => this.$router.push(url), 0);
}, },
getContext(url) {
url = url.slice(1);
let path = "./" + url.substring(url.indexOf("/") + 1);
return path.replace(/\/+$/, "") + "/";
},
basePath(str,isDir) { basePath(str,isDir) {
let parts = str.replace(/(\/$|^\/)/, "").split("/"); let parts = str.replace(/(\/$|^\/)/, "").split("/");
if (parts.length <= 2) { if (parts.length <= 1) {
if (isDir) { if (isDir) {
return "/" return "/"
} }
return ""; return "";
} }
console.log("basePath",parts)
parts.pop(); parts.pop();
parts = parts.join("/") + "/"; parts = parts.join("/") + "/";
if (isDir) { if (isDir) {

View File

@ -42,7 +42,7 @@
<languages <languages
class="input input--block" class="input input--block"
id="locale" id="locale"
:locale.sync="user.locale" v-model:locale="user.locale"
></languages> ></languages>
</p> </p>
@ -55,13 +55,13 @@
{{ $t("settings.lockPassword") }} {{ $t("settings.lockPassword") }}
</p> </p>
<permissions :perm.sync="user.perm" /> <permissions :perm="user.perm" />
<commands v-if="isExecEnabled" :commands.sync="user.commands" /> <commands v-if="isExecEnabled" v-model:commands="user.commands" />
<div v-if="!isDefault"> <div v-if="!isDefault">
<h3>{{ $t("settings.rules") }}</h3> <h3>{{ $t("settings.rules") }}</h3>
<p class="small">{{ $t("settings.rulesHelp") }}</p> <p class="small">{{ $t("settings.rulesHelp") }}</p>
<rules :rules.sync="user.rules" /> <rules v-model:rules="user.rules" />
</div> </div>
</div> </div>
</template> </template>
@ -75,7 +75,7 @@ import { enableExec } from "@/utils/constants";
export default { export default {
name: "user", name: "user",
data: () => { data() {
return { return {
createUserDirData: false, createUserDirData: false,
originalUserScope: "/", originalUserScope: "/",
@ -104,15 +104,17 @@ export default {
displayHomeDirectoryCheckbox() { displayHomeDirectoryCheckbox() {
return this.isNew && this.createUserDir; return this.isNew && this.createUserDir;
}, },
isExecEnabled: () => enableExec, isExecEnabled() {
return enableExec; // Removed arrow function
},
}, },
watch: { watch: {
"user.perm.admin": function () { "user.perm.admin": function () {
if (!this.user.perm.admin) return; if (!this.user.perm.admin) return;
this.user.lockPassword = false; this.user.lockPassword = false;
}, },
createUserDirData() { createUserDirData(newVal) {
this.user.scope = this.createUserDirData ? "" : this.originalUserScope; this.user.scope = newVal ? "" : this.originalUserScope;
}, },
}, },
}; };

View File

@ -29,7 +29,7 @@
<h3>{{ $t("settings.rules") }}</h3> <h3>{{ $t("settings.rules") }}</h3>
<p class="small">{{ $t("settings.globalRules") }}</p> <p class="small">{{ $t("settings.globalRules") }}</p>
<rules :rules.sync="settings.rules" /> <rules :rules="settings.rules" @update:rules="updateRules" />
<div v-if="isExecEnabled"> <div v-if="isExecEnabled">
<h3>{{ $t("settings.executeOnShell") }}</h3> <h3>{{ $t("settings.executeOnShell") }}</h3>
@ -116,7 +116,8 @@
<user-form <user-form
:isNew="false" :isNew="false"
:isDefault="true" :isDefault="true"
:user.sync="settings.defaults" :user="settings.defaults"
@update:user="updateUser"
/> />
</div> </div>
@ -149,8 +150,8 @@
</i18n> </i18n>
<div <div
v-for="command in settings.commands" v-for="(command, index) in settings.commands"
:key="command.name" :key="index"
class="collapsible" class="collapsible"
> >
<input :id="command.name" type="checkbox" /> <input :id="command.name" type="checkbox" />
@ -231,6 +232,12 @@ export default {
}, },
methods: { methods: {
...mapMutations(["setLoading"]), ...mapMutations(["setLoading"]),
updateRules(updatedRules) {
this.settings.rules = updatedRules;
},
updateUser(updatedUser) {
this.settings.defaults = updatedUser;
},
capitalize(name, where = "_") { capitalize(name, where = "_") {
if (where === "caps") where = /(?=[A-Z])/; if (where === "caps") where = /(?=[A-Z])/;
let splitted = name.split(where); let splitted = name.split(where);

View File

@ -26,13 +26,15 @@
<h3>Listing View Style</h3> <h3>Listing View Style</h3>
<ViewMode <ViewMode
class="input input--block" class="input input--block"
:viewMode.sync="viewMode" :viewMode="viewMode"
@update:viewMode="updateViewMode"
></ViewMode> ></ViewMode>
<h3>{{ $t("settings.language") }}</h3> <h3>{{ $t("settings.language") }}</h3>
<languages <Languages
class="input input--block" class="input input--block"
:locale.sync="locale" :locale="locale"
></languages> @update:locale="updateLocale"
></Languages>
</div> </div>
<div class="card-action"> <div class="card-action">
@ -93,7 +95,7 @@ export default {
ViewMode, ViewMode,
Languages, Languages,
}, },
data: function () { data() {
return { return {
password: "", password: "",
passwordConf: "", passwordConf: "",
@ -184,6 +186,12 @@ export default {
this.$showError(e); this.$showError(e);
} }
}, },
updateViewMode(updatedMode) {
this.viewMode = updatedMode;
},
updateLocale(updatedLocale) {
this.locale = updatedLocale;
},
}, },
}; };
</script> </script>

View File

@ -10,10 +10,12 @@
<div class="card-content"> <div class="card-content">
<user-form <user-form
:user.sync="user" :user="user"
:createUserDir.sync="createUserDir" :createUserDir="createUserDir"
:isDefault="false" :isDefault="false"
:isNew="isNew" :isNew="isNew"
@update:user="updatedUser => user = updatedUser"
@update:createUserDir="updatedDir => createUserDir = updatedDir"
/> />
</div> </div>
@ -73,7 +75,7 @@ export default {
UserForm, UserForm,
Errors, Errors,
}, },
data: () => { data() {
return { return {
error: null, error: null,
originalUser: null, originalUser: null,
@ -91,7 +93,7 @@ export default {
}, },
...mapState(["loading"]), ...mapState(["loading"]),
showDeletePrompt() { showDeletePrompt() {
return this.showDelete return this.showDelete;
}, },
}, },
watch: { watch: {
@ -129,7 +131,7 @@ export default {
} }
}, },
deletePrompt() { deletePrompt() {
this.showDelete = true this.showDelete = true;
}, },
async deleteUser(event) { async deleteUser(event) {
event.preventDefault(); event.preventDefault();

View File

@ -1,19 +1,10 @@
# Planned Roadmap # Planned Roadmap
Next release (0.2.1): Next version :
- Improve browsing directory performance by utilizing the index.
- Add editor themes back that were removed because of issues.
- Add "running config" which is editable in filebrowser settings to add rules, users, settings which would normally be done via commands.
- baseurl issue https://github.com/filebrowser/filebrowser/pull/2579
- https://github.com/filebrowser/filebrowser/issues/2526
- https://github.com/filebrowser/filebrowser/issues/2698
- https://github.com/filebrowser/filebrowser/pull/2667
- https://github.com/filebrowser/filebrowser/issues/2632
- https://github.com/filebrowser/filebrowser/issues/2619
- https://github.com/filebrowser/filebrowser/issues/2618
- https://github.com/filebrowser/filebrowser/issues/2607
- Feature: config gets updated when settings change, ensuring that running settings are up to date.
- Feature: Move / Create Action Dialogs https://github.com/filebrowser/filebrowser/pull/2667
- Feature: playable shared video https://github.com/filebrowser/filebrowser/issues/2537
Future releases (within 6 months): Future releases (within 6 months):
@ -26,4 +17,3 @@ Future releases (within 6 months):
- Use vite instead of webpack - Use vite instead of webpack
- upgrade to vue3 - upgrade to vue3
- support minio/s3 https://github.com/filebrowser/filebrowser/issues/2544 - support minio/s3 https://github.com/filebrowser/filebrowser/issues/2544
- https://github.com/filebrowser/filebrowser/issues/2537

View File