beta v0.3.7 release (#286)
This commit is contained in:
parent
bd4d108b58
commit
1e35473998
|
@ -6,7 +6,32 @@ on:
|
||||||
- "main"
|
- "main"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test_frontend:
|
||||||
|
name: Test Playwright
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3.0.0
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3.0.0
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- working-directory: frontend
|
||||||
|
run: npm i && npm run build
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 'stable'
|
||||||
|
- working-directory: backend
|
||||||
|
run: go build -o filebrowser .
|
||||||
|
- name: Build
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.playwright
|
||||||
|
push: false
|
||||||
push_latest_to_registry:
|
push_latest_to_registry:
|
||||||
|
needs: [ test_frontend ]
|
||||||
name: Push latest
|
name: Push latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -14,9 +39,9 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Find latest tag
|
- name: Find latest beta tag
|
||||||
run: |
|
run: |
|
||||||
echo "LATEST_TAG=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_ENV
|
echo "LATEST_TAG=$(git describe --tags $(git rev-list --tags="*-beta*" --max-count=1)) >> $GITHUB_ENV
|
||||||
echo "latest tag is $LATEST_TAG"
|
echo "latest tag is $LATEST_TAG"
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3.0.0
|
uses: docker/setup-qemu-action@v3.0.0
|
||||||
|
|
|
@ -1,28 +1,37 @@
|
||||||
name: pr-request
|
name: PR Request
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "main"
|
- "dev/v[0-9]+.[0-9]+.[0-9]+"
|
||||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
- "beta/v[0-9]+.[0-9]+.[0-9]+"
|
||||||
|
- "stable/v[0-9]+.[0-9]+.[0-9]+"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
#test_frontend:
|
test_frontend:
|
||||||
# name: Push release
|
name: Test Playwright
|
||||||
# runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# steps:
|
steps:
|
||||||
# - name: Checkout
|
- name: Checkout
|
||||||
# uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
# - name: Set up QEMU
|
- name: Set up QEMU
|
||||||
# uses: docker/setup-qemu-action@v3.0.0
|
uses: docker/setup-qemu-action@v3.0.0
|
||||||
# - name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
# uses: docker/setup-buildx-action@v3.0.0
|
uses: docker/setup-buildx-action@v3.0.0
|
||||||
# - name: Build
|
- uses: actions/setup-node@v4
|
||||||
# uses: docker/build-push-action@v6
|
- working-directory: frontend
|
||||||
# with:
|
run: npm i && npm run build
|
||||||
# context: .
|
- uses: actions/setup-go@v5
|
||||||
# file: ./Dockerfile.playwright
|
with:
|
||||||
# push: false
|
go-version: 'stable'
|
||||||
|
- working-directory: backend
|
||||||
|
run: go build -o filebrowser .
|
||||||
|
- name: Build
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.playwright
|
||||||
|
push: false
|
||||||
push_pr_to_registry:
|
push_pr_to_registry:
|
||||||
name: Push PR
|
name: Push PR
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
@ -9,7 +9,32 @@ permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test_frontend:
|
||||||
|
name: Test Playwright
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3.0.0
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3.0.0
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- working-directory: frontend
|
||||||
|
run: npm i && npm run build
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 'stable'
|
||||||
|
- working-directory: backend
|
||||||
|
run: go build -o filebrowser .
|
||||||
|
- name: Build
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.playwright
|
||||||
|
push: false
|
||||||
create_release_tag:
|
create_release_tag:
|
||||||
|
needs: [ test_frontend ]
|
||||||
name: Create Release
|
name: Create Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -41,6 +66,7 @@ jobs:
|
||||||
name: ${{ steps.extract_branch.outputs.tag_name }}
|
name: ${{ steps.extract_branch.outputs.tag_name }}
|
||||||
|
|
||||||
push_release_to_registry:
|
push_release_to_registry:
|
||||||
|
needs: [ test_frontend ]
|
||||||
name: Push release
|
name: Push release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -9,7 +9,32 @@ permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
test_frontend:
|
||||||
|
name: Test Playwright
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3.0.0
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3.0.0
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
- working-directory: frontend
|
||||||
|
run: npm i && npm run build
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 'stable'
|
||||||
|
- working-directory: backend
|
||||||
|
run: go build -o filebrowser .
|
||||||
|
- name: Build
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.playwright
|
||||||
|
push: false
|
||||||
create_release_tag:
|
create_release_tag:
|
||||||
|
needs: [ test_frontend ]
|
||||||
name: Create Release
|
name: Create Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -40,6 +65,7 @@ jobs:
|
||||||
name: ${{ steps.extract_branch.outputs.tag_name }}
|
name: ${{ steps.extract_branch.outputs.tag_name }}
|
||||||
|
|
||||||
push_release_to_registry:
|
push_release_to_registry:
|
||||||
|
needs: [ test_frontend ]
|
||||||
name: Push release
|
name: Push release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -8,6 +8,7 @@ rice-box.go
|
||||||
/frontend/dist
|
/frontend/dist
|
||||||
/frontend/pkg
|
/frontend/pkg
|
||||||
/frontend/test-results
|
/frontend/test-results
|
||||||
|
/frontend/loginAuth.json
|
||||||
/frontend/package-lock.json
|
/frontend/package-lock.json
|
||||||
/backend/vendor
|
/backend/vendor
|
||||||
/backend/*.cov
|
/backend/*.cov
|
||||||
|
|
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -2,7 +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.3.6
|
## v0.3.7-beta
|
||||||
|
|
||||||
|
**Notes**:
|
||||||
|
- Adding windows builds back to automated process... will replace manually if they throw malicious defender warnings.
|
||||||
|
- Adding playwright tests to all pr's against dev/beta/release branches.
|
||||||
|
- These playwright tests should help keep release more reliably stable.
|
||||||
|
|
||||||
|
**Bugfixes**:
|
||||||
|
- closing with the default bar issue.
|
||||||
|
- tar.gz archive creation issue
|
||||||
|
|
||||||
|
## v0.3.6-beta
|
||||||
|
|
||||||
**New Features**
|
**New Features**
|
||||||
- Adds "externalUrl" server config https://github.com/gtsteffaniak/filebrowser/issues/272
|
- Adds "externalUrl" server config https://github.com/gtsteffaniak/filebrowser/issues/272
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
FROM golang:1.23-alpine AS base
|
FROM gtstef/playwright-base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./backend ./
|
COPY [ "./backend/filebrowser*", "./"]
|
||||||
RUN go build -ldflags="-w -s" -o filebrowser .
|
COPY [ "./frontend/", "./" ]
|
||||||
|
RUN ./filebrowser -c filebrowser-playwright.yaml & sleep 2 && npx playwright test
|
||||||
FROM node:slim
|
|
||||||
WORKDIR /app
|
|
||||||
COPY ./frontend/package.json ./
|
|
||||||
RUN npm i --maxsockets 1
|
|
||||||
RUN npx playwright install --with-deps firefox
|
|
||||||
COPY [ "backend/config.yaml", "./" ]
|
|
||||||
COPY ./frontend/ ./frontend
|
|
||||||
WORKDIR /app/frontend
|
|
||||||
RUN npm run build-docker
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=base /app/filebrowser* ./
|
|
||||||
RUN cp -R frontend/tests/ srv
|
|
||||||
ENV FILEBROWSER_NO_EMBEDED="true"
|
|
||||||
RUN ./filebrowser & sleep 2 && cd frontend && npx playwright test
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
FROM node:22-slim
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./frontend/package.json ./
|
||||||
|
RUN npm i @playwright/test
|
||||||
|
RUN npx playwright install --with-deps firefox
|
|
@ -153,3 +153,6 @@ Starred/pinned files | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
||||||
Content preview icons | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
|
Content preview icons | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
|
||||||
Plugins support | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
Plugins support | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ |
|
||||||
Chromecast support | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
Chromecast support | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||||
|
Share collections of files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||||
|
Can archive selected files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
||||||
|
Can browse archive files | ❌ | ❌ | ❌ | ❌ | ❌ | ✅
|
|
@ -24,14 +24,18 @@ builds:
|
||||||
- upx --force-macos {{ .Path }} # Compress the binary with UPX
|
- upx --force-macos {{ .Path }} # Compress the binary with UPX
|
||||||
|
|
||||||
# Build configuration for windows without arm
|
# Build configuration for windows without arm
|
||||||
# - id: windows
|
- id: windows
|
||||||
# ldflags: *ldflags
|
ldflags: *ldflags
|
||||||
# main: main.go
|
main: main.go
|
||||||
# binary: filebrowser
|
binary: filebrowser
|
||||||
# goos:
|
goos:
|
||||||
# - windows
|
- windows
|
||||||
# goarch:
|
goarch:
|
||||||
# - amd64
|
- amd64
|
||||||
|
- arm64
|
||||||
|
hooks:
|
||||||
|
post:
|
||||||
|
- upx {{ .Path }} # Compress the binary with UPX
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
|
- name_template: "{{.Os}}-{{.Arch}}{{if .Arm}}v{{.Arm}}{{end}}-{{ .ProjectName }}"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
server:
|
||||||
|
port: 80
|
||||||
|
baseURL: "/"
|
||||||
|
root: "./tests/playwright-files"
|
||||||
|
auth:
|
||||||
|
method: password
|
||||||
|
signup: false
|
||||||
|
userDefaults:
|
||||||
|
darkMode: true
|
||||||
|
disableSettings: false
|
||||||
|
scope: "."
|
||||||
|
hideDotfiles: true
|
||||||
|
singleClick: false
|
||||||
|
permissions:
|
||||||
|
admin: false
|
||||||
|
create: false
|
||||||
|
rename: false
|
||||||
|
modify: false
|
||||||
|
delete: false
|
||||||
|
share: false
|
||||||
|
download: false
|
|
@ -192,7 +192,6 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (idx *Index) makeIndexPath(subPath string) string {
|
func (idx *Index) makeIndexPath(subPath string) string {
|
||||||
subPath = strings.ReplaceAll(subPath, "\\", "/")
|
|
||||||
if strings.HasPrefix(subPath, "./") {
|
if strings.HasPrefix(subPath, "./") {
|
||||||
subPath = strings.TrimPrefix(subPath, ".")
|
subPath = strings.TrimPrefix(subPath, ".")
|
||||||
}
|
}
|
||||||
|
@ -203,6 +202,7 @@ func (idx *Index) makeIndexPath(subPath string) string {
|
||||||
subPath = strings.TrimSuffix(subPath, "/")
|
subPath = strings.TrimSuffix(subPath, "/")
|
||||||
// remove index prefix
|
// remove index prefix
|
||||||
adjustedPath := strings.TrimPrefix(subPath, idx.Source.Path)
|
adjustedPath := strings.TrimPrefix(subPath, idx.Source.Path)
|
||||||
|
adjustedPath = strings.ReplaceAll(adjustedPath, "\\", "/")
|
||||||
// remove trailing slash
|
// remove trailing slash
|
||||||
adjustedPath = strings.TrimSuffix(adjustedPath, "/")
|
adjustedPath = strings.TrimSuffix(adjustedPath, "/")
|
||||||
if !strings.HasPrefix(adjustedPath, "/") {
|
if !strings.HasPrefix(adjustedPath, "/") {
|
||||||
|
@ -250,7 +250,6 @@ func (idx *Index) RefreshFileInfo(opts FileOptions) error {
|
||||||
Path: opts.Path,
|
Path: opts.Path,
|
||||||
IsDir: opts.IsDir,
|
IsDir: opts.IsDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !refreshOptions.IsDir {
|
if !refreshOptions.IsDir {
|
||||||
refreshOptions.Path = idx.makeIndexPath(filepath.Dir(refreshOptions.Path))
|
refreshOptions.Path = idx.makeIndexPath(filepath.Dir(refreshOptions.Path))
|
||||||
refreshOptions.IsDir = true
|
refreshOptions.IsDir = true
|
||||||
|
|
|
@ -91,9 +91,6 @@ func TestMakeIndexPath(t *testing.T) {
|
||||||
{"Trailing slash removed", "/test/", "/test"},
|
{"Trailing slash removed", "/test/", "/test"},
|
||||||
{"Subpath without root prefix", "/other/test", "/other/test"},
|
{"Subpath without root prefix", "/other/test", "/other/test"},
|
||||||
{"Complex nested paths", "/nested/path", "/nested/path"},
|
{"Complex nested paths", "/nested/path", "/nested/path"},
|
||||||
// Windows
|
|
||||||
{"Mixed slash", "/first\\second", "/first/second"},
|
|
||||||
{"Windows slash", "\\first\\second", "/first/second"},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -105,6 +102,27 @@ func TestMakeIndexPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tests = []struct {
|
||||||
|
name string
|
||||||
|
subPath string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
// Windows
|
||||||
|
{"Mixed slash", "/first\\second", "/first/second"},
|
||||||
|
{"Windows slash", "\\first\\second", "/first/second"},
|
||||||
|
{"Windows full path", "C:\\Users\\testfolder\\nestedfolder", "/testfolder/nestedfolder"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
idx := &Index{Source: settings.Source{Path: "C:\\Users"}}
|
||||||
|
result := idx.makeIndexPath(tt.subPath)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("makeIndexPath(%q)\ngot %q\nwant %q", tt.name, result, tt.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMakeIndexPathRoot(t *testing.T) {
|
func TestMakeIndexPathRoot(t *testing.T) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ require (
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/swaggo/http-swagger v1.3.4
|
github.com/swaggo/http-swagger v1.3.4
|
||||||
github.com/swaggo/swag v1.16.4
|
github.com/swaggo/swag v1.16.4
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.32.0
|
||||||
golang.org/x/image v0.23.0
|
golang.org/x/image v0.23.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.21.0
|
||||||
)
|
)
|
||||||
|
@ -43,9 +43,9 @@ require (
|
||||||
github.com/swaggo/files v1.0.1 // indirect
|
github.com/swaggo/files v1.0.1 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.etcd.io/bbolt v1.3.11 // indirect
|
go.etcd.io/bbolt v1.3.11 // indirect
|
||||||
golang.org/x/net v0.33.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
golang.org/x/tools v0.28.0 // indirect
|
golang.org/x/tools v0.29.0 // 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
|
||||||
)
|
)
|
||||||
|
|
|
@ -114,8 +114,8 @@ go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
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.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||||
|
@ -133,8 +133,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
|
@ -153,8 +153,8 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
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.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.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=
|
||||||
|
@ -168,8 +168,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
|
|
@ -63,8 +63,7 @@ func rawHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int,
|
||||||
}
|
}
|
||||||
return rawFilesHandler(w, r, d, fileList)
|
return rawFilesHandler(w, r, d, fileList)
|
||||||
}
|
}
|
||||||
|
func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *zip.Writer, flatten bool) error {
|
||||||
func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *zip.Writer) error {
|
|
||||||
idx := files.GetIndex("default")
|
idx := files.GetIndex("default")
|
||||||
realPath, _, _ := idx.GetRealPath(d.user.Scope, path)
|
realPath, _, _ := idx.GetRealPath(d.user.Scope, path)
|
||||||
if !d.user.Check(realPath) {
|
if !d.user.Check(realPath) {
|
||||||
|
@ -75,16 +74,36 @@ func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *z
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the base name of the top-level folder or file
|
||||||
|
baseName := filepath.Base(realPath)
|
||||||
|
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
// Walk through directory contents
|
// Walk through directory contents
|
||||||
return filepath.Walk(realPath, func(filePath string, fileInfo os.FileInfo, err error) error {
|
return filepath.Walk(realPath, func(filePath string, fileInfo os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
relPath, err := filepath.Rel(filepath.Dir(realPath), filePath) // Relative path including base dir
|
|
||||||
|
// Calculate the relative path
|
||||||
|
relPath, err := filepath.Rel(realPath, filePath) // Use realPath directly
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize for tar: convert \ to /
|
||||||
|
relPath = filepath.ToSlash(relPath)
|
||||||
|
|
||||||
|
// Skip adding `.` (current directory)
|
||||||
|
if relPath == "." {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepend base folder name unless flatten is true
|
||||||
|
if !flatten {
|
||||||
|
relPath = filepath.Join(baseName, relPath)
|
||||||
|
relPath = filepath.ToSlash(relPath) // Ensure normalized separators
|
||||||
|
}
|
||||||
|
|
||||||
if fileInfo.IsDir() {
|
if fileInfo.IsDir() {
|
||||||
if tarWriter != nil {
|
if tarWriter != nil {
|
||||||
header := &tar.Header{
|
header := &tar.Header{
|
||||||
|
@ -105,8 +124,8 @@ func addFile(path string, d *requestContext, tarWriter *tar.Writer, zipWriter *z
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a single file if it's not a directory
|
// For a single file, use the base name as the archive path
|
||||||
return addSingleFile(realPath, filepath.Base(realPath), zipWriter, tarWriter)
|
return addSingleFile(realPath, baseName, zipWriter, tarWriter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addSingleFile(realPath, archivePath string, zipWriter *zip.Writer, tarWriter *tar.Writer) error {
|
func addSingleFile(realPath, archivePath string, zipWriter *zip.Writer, tarWriter *tar.Writer) error {
|
||||||
|
@ -122,11 +141,12 @@ func addSingleFile(realPath, archivePath string, zipWriter *zip.Writer, tarWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
if tarWriter != nil {
|
if tarWriter != nil {
|
||||||
header, err := tar.FileInfoHeader(info, realPath)
|
header, err := tar.FileInfoHeader(info, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
header.Name = archivePath
|
// Ensure correct relative path
|
||||||
|
header.Name = filepath.ToSlash(archivePath)
|
||||||
if err = tarWriter.WriteHeader(header); err != nil {
|
if err = tarWriter.WriteHeader(header); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -217,8 +237,10 @@ func createZip(w io.Writer, d *requestContext, filenames ...string) error {
|
||||||
zipWriter := zip.NewWriter(w)
|
zipWriter := zip.NewWriter(w)
|
||||||
defer zipWriter.Close()
|
defer zipWriter.Close()
|
||||||
|
|
||||||
|
// Check if we have exactly one directory
|
||||||
|
//flatten := len(filenames) == 1
|
||||||
for _, fname := range filenames {
|
for _, fname := range filenames {
|
||||||
err := addFile(fname, d, nil, zipWriter)
|
err := addFile(fname, d, nil, zipWriter, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to add %s to ZIP: %v", fname, err)
|
log.Printf("Failed to add %s to ZIP: %v", fname, err)
|
||||||
}
|
}
|
||||||
|
@ -234,8 +256,10 @@ func createTarGz(w io.Writer, d *requestContext, filenames ...string) error {
|
||||||
tarWriter := tar.NewWriter(gzWriter)
|
tarWriter := tar.NewWriter(gzWriter)
|
||||||
defer tarWriter.Close()
|
defer tarWriter.Close()
|
||||||
|
|
||||||
|
// Check if we have exactly one directory
|
||||||
|
//flatten := len(filenames) == 1
|
||||||
for _, fname := range filenames {
|
for _, fname := range filenames {
|
||||||
err := addFile(fname, d, tarWriter, nil)
|
err := addFile(fname, d, tarWriter, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to add %s to TAR.GZ: %v", fname, err)
|
log.Printf("Failed to add %s to TAR.GZ: %v", fname, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,9 @@ func setDefaults() Settings {
|
||||||
Host: "",
|
Host: "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Frontend: Frontend{
|
||||||
|
Name: "FileBrowser Quantum",
|
||||||
|
},
|
||||||
UserDefaults: UserDefaults{
|
UserDefaults: UserDefaults{
|
||||||
StickySidebar: true,
|
StickySidebar: true,
|
||||||
Scope: ".",
|
Scope: ".",
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Browser, firefox, expect, Page } from "@playwright/test";
|
||||||
|
|
||||||
|
|
||||||
|
async function globalSetup() {
|
||||||
|
const browser: Browser = await firefox.launch();
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const page: Page = await context.newPage();
|
||||||
|
await page.goto("http://127.0.0.1/login");
|
||||||
|
await page.getByPlaceholder("Username").fill("admin");
|
||||||
|
await page.getByPlaceholder("Password").fill("admin");
|
||||||
|
await page.getByRole("button", { name: "Login" }).click();
|
||||||
|
await page.waitForURL("**/files/", { timeout: 100 });
|
||||||
|
await expect(page).toHaveTitle('FileBrowser Quantum - Files');
|
||||||
|
let cookies = await context.cookies();
|
||||||
|
expect(cookies.find((c) => c.name == "auth")?.value).toBeDefined();
|
||||||
|
await page.context().storageState({ path: "./loginAuth.json" });
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default globalSetup
|
|
@ -17,10 +17,10 @@
|
||||||
"lint": "eslint --ext .js,.vue,ts src",
|
"lint": "eslint --ext .js,.vue,ts src",
|
||||||
"lint:fix": "eslint --fix src/",
|
"lint:fix": "eslint --fix src/",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"integration-test": "npx playwright test",
|
|
||||||
"test": "vitest run "
|
"test": "vitest run "
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@playwright/test": "^1.49.1",
|
||||||
"ace-builds": "^1.24.2",
|
"ace-builds": "^1.24.2",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"css-vars-ponyfill": "^2.4.3",
|
"css-vars-ponyfill": "^2.4.3",
|
||||||
|
@ -34,7 +34,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
"@intlify/unplugin-vue-i18n": "^4.0.0",
|
||||||
"@playwright/test": "^1.42.1",
|
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"@vue/eslint-config-typescript": "^13.0.0",
|
"@vue/eslint-config-typescript": "^13.0.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { defineConfig, devices } from "@playwright/test";
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
*/
|
*/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
globalSetup: "./global-setup",
|
||||||
|
timeout: 3000,
|
||||||
testDir: "./tests",
|
testDir: "./tests",
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
fullyParallel: true,
|
fullyParallel: true,
|
||||||
|
@ -18,11 +20,13 @@ export default defineConfig({
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
retries: process.env.CI ? 2 : 0,
|
retries: process.env.CI ? 2 : 0,
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : 1, // required for now! todo parallel some tests
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: "line",
|
reporter: "line",
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
|
actionTimeout: 500,
|
||||||
|
storageState: "loginAuth.json",
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
baseURL: "http://127.0.0.1",
|
baseURL: "http://127.0.0.1",
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
<script>
|
<script>
|
||||||
window.FileBrowser = JSON.parse('{{ .globalVars }}');
|
window.FileBrowser = JSON.parse('{{ .globalVars }}');
|
||||||
var dynamicManifest = {
|
var dynamicManifest = {
|
||||||
"name": window.FileBrowser.Name || '',
|
"name": window.FileBrowser.Name || 'FileBrowser Quantum',
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": window.location.origin + "{{ .StaticURL }}/img/icons/android-chrome-256x256.png",
|
"src": window.location.origin + "{{ .StaticURL }}/img/icons/android-chrome-256x256.png",
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<i class="material-icons">settings</i>
|
<i class="material-icons">settings</i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="inner-card">
|
<div class="inner-card logout-button" @click="logout" >
|
||||||
<i v-if="canLogout" @click="logout" class="material-icons">exit_to_app</i>
|
<i v-if="canLogout" class="material-icons">exit_to_app</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -132,7 +132,7 @@ router.beforeResolve(async (to, from, next) => {
|
||||||
|
|
||||||
// Set the page title using i18n
|
// Set the page title using i18n
|
||||||
const title = i18n.global.t(titles[to.name as keyof typeof titles]);
|
const title = i18n.global.t(titles[to.name as keyof typeof titles]);
|
||||||
document.title = title + " - " + name;
|
document.title = name + " - " + title ;
|
||||||
|
|
||||||
// Update store with the current route
|
// Update store with the current route
|
||||||
mutations.setRoute(to);
|
mutations.setRoute(to);
|
||||||
|
|
|
@ -67,13 +67,13 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
signup: () => signup,
|
signup: () => signup,
|
||||||
name: () => name,
|
name: () => name || "FileBrowser Quantum",
|
||||||
logoURL: () => logoURL,
|
logoURL: () => logoURL,
|
||||||
isDarkMode() {
|
isDarkMode() {
|
||||||
return darkMode === true;
|
return darkMode === true;
|
||||||
},
|
},
|
||||||
loginName() {
|
loginName() {
|
||||||
return name || "FileBrowser Quantum"
|
return name
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { url } from "@/utils";
|
import { url } from "@/utils";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { getters, state } from "@/store";
|
import { getters, state, mutations } from "@/store";
|
||||||
import Action from "@/components/Action.vue";
|
import Action from "@/components/Action.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { test, expect } from "./fixtures/auth";
|
import { test, expect } from "@playwright/test";
|
||||||
|
|
||||||
|
test("redirect to login", async ({ page, context }) => {
|
||||||
|
await context.clearCookies();
|
||||||
|
|
||||||
test("redirect to login", async ({ page }) => {
|
|
||||||
await page.goto("/");
|
await page.goto("/");
|
||||||
await expect(page).toHaveURL(/\/login/);
|
await expect(page).toHaveURL(/\/login/);
|
||||||
|
|
||||||
|
@ -8,24 +10,16 @@ test("redirect to login", async ({ page }) => {
|
||||||
await expect(page).toHaveURL(/\/login\?redirect=\/files\//);
|
await expect(page).toHaveURL(/\/login\?redirect=\/files\//);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("login", async ({ authPage, page, context }) => {
|
test("logout", async ({ page, context }) => {
|
||||||
await authPage.goto();
|
await page.goto('/');
|
||||||
await expect(page).toHaveTitle(/Login - FileBrowser Quantum$/);
|
await expect(page.locator("div.wrong")).toBeHidden();
|
||||||
|
await page.waitForURL("**/files/", { timeout: 100 });
|
||||||
await authPage.loginAs("fake", "fake");
|
await expect(page).toHaveTitle('playwright-files - FileBrowser Quantum - Files');
|
||||||
await expect(authPage.wrongCredentials).toBeVisible();
|
|
||||||
|
|
||||||
await authPage.loginAs();
|
|
||||||
await expect(authPage.wrongCredentials).toBeHidden();
|
|
||||||
// await page.waitForURL("**/files/", { timeout: 5000 });
|
|
||||||
await expect(page).toHaveTitle(/.*Files - FileBrowser Quantum$/);
|
|
||||||
|
|
||||||
let cookies = await context.cookies();
|
let cookies = await context.cookies();
|
||||||
expect(cookies.find((c) => c.name == "auth")?.value).toBeDefined();
|
expect(cookies.find((c) => c.name == "auth")?.value).toBeDefined();
|
||||||
|
await page.locator('div.inner-card.logout-button').click();
|
||||||
// await authPage.logout();
|
await page.waitForURL("**/login", { timeout: 100 });
|
||||||
// await page.waitForURL("**/login", { timeout: 5000 });
|
await expect(page).toHaveTitle('FileBrowser Quantum - Login');
|
||||||
// await expect(page).toHaveTitle(/Login - FileBrowser Quantum$/);
|
cookies = await context.cookies();
|
||||||
// cookies = await context.cookies();
|
expect(cookies.find((c) => c.name == "auth")?.value).toBeUndefined();
|
||||||
// expect(cookies.find((c) => c.name == "auth")?.value).toBeUndefined();
|
|
||||||
});
|
});
|
|
@ -1,40 +0,0 @@
|
||||||
import {
|
|
||||||
type Page,
|
|
||||||
type Locator,
|
|
||||||
test as base,
|
|
||||||
expect,
|
|
||||||
} from "@playwright/test";
|
|
||||||
|
|
||||||
export class AuthPage {
|
|
||||||
public readonly wrongCredentials: Locator;
|
|
||||||
|
|
||||||
constructor(public readonly page: Page) {
|
|
||||||
this.wrongCredentials = this.page.locator("div.wrong");
|
|
||||||
}
|
|
||||||
|
|
||||||
async goto() {
|
|
||||||
await this.page.goto("/login");
|
|
||||||
}
|
|
||||||
|
|
||||||
async loginAs(username = "admin", password = "admin") {
|
|
||||||
await this.page.getByPlaceholder("Username").fill(username);
|
|
||||||
await this.page.getByPlaceholder("Password").fill(password);
|
|
||||||
await this.page.getByRole("button", { name: "Login" }).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
//async logout() {
|
|
||||||
// await this.page.getByRole("button", { name: "Logout" }).click();
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = base.extend<{ authPage: AuthPage }>({
|
|
||||||
authPage: async ({ page }, use) => {
|
|
||||||
const authPage = new AuthPage(page);
|
|
||||||
await authPage.goto();
|
|
||||||
await authPage.loginAs();
|
|
||||||
await use(authPage);
|
|
||||||
// await authPage.logout();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export { test, expect };
|
|
Binary file not shown.
|
@ -0,0 +1,11 @@
|
||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
|
||||||
|
test("file preview", async ({ page, context }) => {
|
||||||
|
await page.goto("/files/");
|
||||||
|
await expect(page).toHaveTitle('playwright-files - FileBrowser Quantum - Files');
|
||||||
|
await page.locator('a[aria-label="file.tar.gz"]').waitFor({ state: 'visible' });
|
||||||
|
await page.locator('a[aria-label="file.tar.gz"]').dblclick();
|
||||||
|
await expect(page).toHaveTitle('file.tar.gz - FileBrowser Quantum - Files');
|
||||||
|
await page.locator('button[title="Close"]').click();
|
||||||
|
await expect(page).toHaveTitle('playwright-files - FileBrowser Quantum - Files');
|
||||||
|
});
|
|
@ -20,6 +20,6 @@
|
||||||
},
|
},
|
||||||
"checkJs": false, // check later
|
"checkJs": false, // check later
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.vue"],
|
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.vue", "tests/auth.spec.ts"],
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
}
|
}
|
|
@ -1,74 +0,0 @@
|
||||||
// vite.config.ts
|
|
||||||
import path from "node:path";
|
|
||||||
import { defineConfig } from "file:///Users/steffag/git/personal/filebrowser/frontend/node_modules/vite/dist/node/index.js";
|
|
||||||
import vue from "file:///Users/steffag/git/personal/filebrowser/frontend/node_modules/@vitejs/plugin-vue/dist/index.mjs";
|
|
||||||
import VueI18nPlugin from "file:///Users/steffag/git/personal/filebrowser/frontend/node_modules/@intlify/unplugin-vue-i18n/lib/vite.mjs";
|
|
||||||
import { compression } from "file:///Users/steffag/git/personal/filebrowser/frontend/node_modules/vite-plugin-compression2/dist/index.mjs";
|
|
||||||
var __vite_injected_original_dirname = "/Users/steffag/git/personal/filebrowser/frontend";
|
|
||||||
var plugins = [
|
|
||||||
vue(),
|
|
||||||
VueI18nPlugin({
|
|
||||||
include: [path.resolve(__vite_injected_original_dirname, "./src/i18n/**/*.json")]
|
|
||||||
}),
|
|
||||||
compression({
|
|
||||||
include: /\.(js|woff2|woff)(\?.*)?$/i,
|
|
||||||
deleteOriginalAssets: true
|
|
||||||
})
|
|
||||||
];
|
|
||||||
var resolve = {
|
|
||||||
alias: {
|
|
||||||
"@": path.resolve(__vite_injected_original_dirname, "src")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var vite_config_default = defineConfig(({ command }) => {
|
|
||||||
if (command === "serve") {
|
|
||||||
return {
|
|
||||||
plugins,
|
|
||||||
resolve,
|
|
||||||
server: {
|
|
||||||
proxy: {
|
|
||||||
"/api/command": {
|
|
||||||
target: "ws://127.0.0.1:8080",
|
|
||||||
ws: true
|
|
||||||
},
|
|
||||||
"/api": "http://127.0.0.1:8080"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
plugins,
|
|
||||||
resolve,
|
|
||||||
base: "",
|
|
||||||
build: {
|
|
||||||
rollupOptions: {
|
|
||||||
input: {
|
|
||||||
index: path.resolve(__vite_injected_original_dirname, "./public/index.html")
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
manualChunks: (id) => {
|
|
||||||
if (id.includes("i18n/")) {
|
|
||||||
return "i18n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
experimental: {
|
|
||||||
renderBuiltUrl(filename, { hostType }) {
|
|
||||||
if (hostType === "js") {
|
|
||||||
return { runtime: `window.__prependStaticUrl("${filename}")` };
|
|
||||||
} else if (hostType === "html") {
|
|
||||||
return `{{ .StaticURL }}/${filename}`;
|
|
||||||
} else {
|
|
||||||
return { relative: true };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
export {
|
|
||||||
vite_config_default as default
|
|
||||||
};
|
|
||||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvc3RlZmZhZy9naXQvcGVyc29uYWwvZmlsZWJyb3dzZXIvZnJvbnRlbmRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9Vc2Vycy9zdGVmZmFnL2dpdC9wZXJzb25hbC9maWxlYnJvd3Nlci9mcm9udGVuZC92aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvc3RlZmZhZy9naXQvcGVyc29uYWwvZmlsZWJyb3dzZXIvZnJvbnRlbmQvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgcGF0aCBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tIFwidml0ZVwiO1xuaW1wb3J0IHZ1ZSBmcm9tIFwiQHZpdGVqcy9wbHVnaW4tdnVlXCI7XG5pbXBvcnQgVnVlSTE4blBsdWdpbiBmcm9tIFwiQGludGxpZnkvdW5wbHVnaW4tdnVlLWkxOG4vdml0ZVwiO1xuaW1wb3J0IHsgY29tcHJlc3Npb24gfSBmcm9tIFwidml0ZS1wbHVnaW4tY29tcHJlc3Npb24yXCI7XG5cbmNvbnN0IHBsdWdpbnMgPSBbXG4gIHZ1ZSgpLFxuICBWdWVJMThuUGx1Z2luKHtcbiAgICBpbmNsdWRlOiBbcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgXCIuL3NyYy9pMThuLyoqLyouanNvblwiKV0sXG4gIH0pLFxuICBjb21wcmVzc2lvbih7XG4gICAgaW5jbHVkZTogL1xcLihqc3x3b2ZmMnx3b2ZmKShcXD8uKik/JC9pLFxuICAgIGRlbGV0ZU9yaWdpbmFsQXNzZXRzOiB0cnVlLFxuICB9KSxcbl07XG5cbmNvbnN0IHJlc29sdmUgPSB7XG4gIGFsaWFzOiB7XG4gICAgXCJAXCI6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsIFwic3JjXCIpLFxuICB9LFxufTtcblxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZygoeyBjb21tYW5kIH0pID0+IHtcbiAgaWYgKGNvbW1hbmQgPT09IFwic2VydmVcIikge1xuICAgIHJldHVybiB7XG4gICAgICBwbHVnaW5zLFxuICAgICAgcmVzb2x2ZSxcbiAgICAgIHNlcnZlcjoge1xuICAgICAgICBwcm94eToge1xuICAgICAgICAgIFwiL2FwaS9jb21tYW5kXCI6IHtcbiAgICAgICAgICAgIHRhcmdldDogXCJ3czovLzEyNy4wLjAuMTo4MDgwXCIsXG4gICAgICAgICAgICB3czogdHJ1ZSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIFwiL2FwaVwiOiBcImh0dHA6Ly8xMjcuMC4wLjE6ODA4MFwiLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIC8vIGNvbW1hbmQgPT09ICdidWlsZCdcbiAgICByZXR1cm4ge1xuICAgICAgcGx1Z2lucyxcbiAgICAgIHJlc29sdmUsXG4gICAgICBiYXNlOiBcIlwiLFxuICAgICAgYnVpbGQ6IHtcbiAgICAgICAgcm9sbHVwT3B0aW9uczoge1xuICAgICAgICAgIGlucHV0OiB7XG4gICAgICAgICAgICBpbmRleDogcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgXCIuL3B1YmxpYy9pbmRleC5odG1sXCIpLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgb3V0cHV0OiB7XG4gICAgICAgICAgICBtYW51YWxDaHVua3M6IChpZCkgPT4ge1xuICAgICAgICAgICAgICBpZiAoaWQuaW5jbHVkZXMoXCJpMThuL1wiKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcImkxOG5cIjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIGV4cGVyaW1lbnRhbDoge1xuICAgICAgICByZW5kZXJCdWlsdFVybChmaWxlbmFtZSwgeyBob3N0VHlwZSB9KSB7XG4gICAgICAgICAgaWYgKGhvc3RUeXBlID09PSBcImpzXCIpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHJ1bnRpbWU6IGB3aW5kb3cuX19wcmVwZW5kU3RhdGljVXJsKFwiJHtmaWxlbmFtZX1cIilgIH07XG4gICAgICAgICAgfSBlbHNlIGlmIChob3N0VHlwZSA9PT0gXCJodG1sXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBge3sgLlN0YXRpY1VSTCB9fS8ke2ZpbGVuYW1lfWA7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB7IHJlbGF0aXZlOiB0cnVlIH07XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuICB9XG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBa1UsT0FBTyxVQUFVO0FBQ25WLFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLG1CQUFtQjtBQUMxQixTQUFTLG1CQUFtQjtBQUo1QixJQUFNLG1DQUFtQztBQU16QyxJQUFNLFVBQVU7QUFBQSxFQUNkLElBQUk7QUFBQSxFQUNKLGNBQWM7QUFBQSxJQUNaLFNBQVMsQ0FBQyxLQUFLLFFBQVEsa0NBQVcsc0JBQXNCLENBQUM7QUFBQSxFQUMzRCxDQUFDO0FBQUEsRUFDRCxZQUFZO0FBQUEsSUFDVixTQUFTO0FBQUEsSUFDVCxzQkFBc0I7QUFBQSxFQUN4QixDQUFDO0FBQ0g7QUFFQSxJQUFNLFVBQVU7QUFBQSxFQUNkLE9BQU87QUFBQSxJQUNMLEtBQUssS0FBSyxRQUFRLGtDQUFXLEtBQUs7QUFBQSxFQUNwQztBQUNGO0FBR0EsSUFBTyxzQkFBUSxhQUFhLENBQUMsRUFBRSxRQUFRLE1BQU07QUFDM0MsTUFBSSxZQUFZLFNBQVM7QUFDdkIsV0FBTztBQUFBLE1BQ0w7QUFBQSxNQUNBO0FBQUEsTUFDQSxRQUFRO0FBQUEsUUFDTixPQUFPO0FBQUEsVUFDTCxnQkFBZ0I7QUFBQSxZQUNkLFFBQVE7QUFBQSxZQUNSLElBQUk7QUFBQSxVQUNOO0FBQUEsVUFDQSxRQUFRO0FBQUEsUUFDVjtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBQUEsRUFDRixPQUFPO0FBRUwsV0FBTztBQUFBLE1BQ0w7QUFBQSxNQUNBO0FBQUEsTUFDQSxNQUFNO0FBQUEsTUFDTixPQUFPO0FBQUEsUUFDTCxlQUFlO0FBQUEsVUFDYixPQUFPO0FBQUEsWUFDTCxPQUFPLEtBQUssUUFBUSxrQ0FBVyxxQkFBcUI7QUFBQSxVQUN0RDtBQUFBLFVBQ0EsUUFBUTtBQUFBLFlBQ04sY0FBYyxDQUFDLE9BQU87QUFDcEIsa0JBQUksR0FBRyxTQUFTLE9BQU8sR0FBRztBQUN4Qix1QkFBTztBQUFBLGNBQ1Q7QUFBQSxZQUNGO0FBQUEsVUFDRjtBQUFBLFFBQ0Y7QUFBQSxNQUNGO0FBQUEsTUFDQSxjQUFjO0FBQUEsUUFDWixlQUFlLFVBQVUsRUFBRSxTQUFTLEdBQUc7QUFDckMsY0FBSSxhQUFhLE1BQU07QUFDckIsbUJBQU8sRUFBRSxTQUFTLDhCQUE4QixRQUFRLEtBQUs7QUFBQSxVQUMvRCxXQUFXLGFBQWEsUUFBUTtBQUM5QixtQkFBTyxvQkFBb0IsUUFBUTtBQUFBLFVBQ3JDLE9BQU87QUFDTCxtQkFBTyxFQUFFLFVBQVUsS0FBSztBQUFBLFVBQzFCO0FBQUEsUUFDRjtBQUFBLE1BQ0Y7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
9
makefile
9
makefile
|
@ -16,6 +16,9 @@ update:
|
||||||
build:
|
build:
|
||||||
docker build --build-arg="VERSION=testing" --build-arg="REVISION=n/a" -t gtstef/filebrowser .
|
docker build --build-arg="VERSION=testing" --build-arg="REVISION=n/a" -t gtstef/filebrowser .
|
||||||
|
|
||||||
|
build-backend:
|
||||||
|
cd backend && go build -o filebrowser --ldflags="-w -s -X 'github.com/gtsteffaniak/filebrowser/backend/version.CommitSHA=testingCommit' -X 'github.com/gtsteffaniak/filebrowser/backend/version.Version=testing'"
|
||||||
|
|
||||||
run: run-frontend
|
run: run-frontend
|
||||||
cd backend && swag init --output swagger/docs && \
|
cd backend && swag init --output swagger/docs && \
|
||||||
if [ "$(shell uname)" = "Darwin" ]; then \
|
if [ "$(shell uname)" = "Darwin" ]; then \
|
||||||
|
@ -48,9 +51,9 @@ test-backend:
|
||||||
test-frontend:
|
test-frontend:
|
||||||
cd frontend && npm run test
|
cd frontend && npm run test
|
||||||
|
|
||||||
test-frontend-playwright:
|
test-playwright: run-frontend build-backend
|
||||||
npx playwright install
|
docker build -t filebrowser-playwright-tests -f Dockerfile.playwright .
|
||||||
docker build -t gtstef/filebrowser-tests -f Dockerfile.playwright .
|
docker run --rm --name filebrowser-playwright-tests filebrowser-playwright-tests
|
||||||
|
|
||||||
# Run on a windows machine!
|
# Run on a windows machine!
|
||||||
release-windows:
|
release-windows:
|
||||||
|
|
Loading…
Reference in New Issue