snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
36
weed/server/filer_ui/breadcrumb.go
Normal file
36
weed/server/filer_ui/breadcrumb.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package filer_ui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
)
|
||||
|
||||
type Breadcrumb struct {
|
||||
Name string
|
||||
Link string
|
||||
}
|
||||
|
||||
func ToBreadcrumb(fullpath string) (crumbs []Breadcrumb) {
|
||||
parts := strings.Split(fullpath, "/")
|
||||
if fullpath == "/" {
|
||||
parts = []string{""}
|
||||
}
|
||||
|
||||
for i := 0; i < len(parts); i++ {
|
||||
name := parts[i]
|
||||
if name == "" {
|
||||
name = "/"
|
||||
}
|
||||
crumb := Breadcrumb{
|
||||
Name: name,
|
||||
Link: "/" + util.Join(parts[0:i+1]...),
|
||||
}
|
||||
if !strings.HasSuffix(crumb.Link, "/") {
|
||||
crumb.Link += "/"
|
||||
}
|
||||
crumbs = append(crumbs, crumb)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
104
weed/server/filer_ui/breadcrumb_test.go
Normal file
104
weed/server/filer_ui/breadcrumb_test.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package filer_ui
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToBreadcrumb(t *testing.T) {
|
||||
type args struct {
|
||||
fullpath string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantCrumbs []Breadcrumb
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
args: args{
|
||||
fullpath: "",
|
||||
},
|
||||
wantCrumbs: []Breadcrumb{
|
||||
{
|
||||
Name: "/",
|
||||
Link: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test1",
|
||||
args: args{
|
||||
fullpath: "/",
|
||||
},
|
||||
wantCrumbs: []Breadcrumb{
|
||||
{
|
||||
Name: "/",
|
||||
Link: "/",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test2",
|
||||
args: args{
|
||||
fullpath: "/abc",
|
||||
},
|
||||
wantCrumbs: []Breadcrumb{
|
||||
{
|
||||
Name: "/",
|
||||
Link: "/",
|
||||
},
|
||||
{
|
||||
Name: "abc",
|
||||
Link: "/abc/",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test3",
|
||||
args: args{
|
||||
fullpath: "/abc/def",
|
||||
},
|
||||
wantCrumbs: []Breadcrumb{
|
||||
{
|
||||
Name: "/",
|
||||
Link: "/",
|
||||
},
|
||||
{
|
||||
Name: "abc",
|
||||
Link: "/abc/",
|
||||
},
|
||||
{
|
||||
Name: "def",
|
||||
Link: "/abc/def/",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotCrumbs := ToBreadcrumb(tt.args.fullpath); !reflect.DeepEqual(gotCrumbs, tt.wantCrumbs) {
|
||||
t.Errorf("ToBreadcrumb() = %v, want %v", gotCrumbs, tt.wantCrumbs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintPathPreservesPathSafeTimestampChars(t *testing.T) {
|
||||
got := printpath("/logs/run_id=backfill__2025-01-31T15:00:00+00:00/")
|
||||
want := "/logs/run_id=backfill__2025-01-31T15:00:00+00:00/"
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("printpath() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryEscapePreservesPlusInLoadMoreCursor(t *testing.T) {
|
||||
got := funcMap["queryEscape"].(func(string) string)("task:1+next")
|
||||
want := "task%3A1%2Bnext"
|
||||
|
||||
if got != want {
|
||||
t.Fatalf("queryEscape() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
364
weed/server/filer_ui/filer.html
Normal file
364
weed/server/filer_ui/filer.html
Normal file
@@ -0,0 +1,364 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SeaweedFS Filer {{ .Version }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/seaweedfsstatic/bootstrap/3.3.1/css/bootstrap.min.css">
|
||||
<style>
|
||||
body {
|
||||
padding-bottom: 128px;
|
||||
}
|
||||
|
||||
#drop-area {
|
||||
border: 1px transparent;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#drop-area.highlight {
|
||||
border-color: purple;
|
||||
border: 2px dashed #ccc;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 2px;
|
||||
background: #ccc;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #ccc;
|
||||
float: right;
|
||||
margin-left: 2px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
#fileElem {
|
||||
display: none;
|
||||
}
|
||||
|
||||
td, th {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.table-hover > tbody > tr:hover > * > div.operations {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.table > tbody > tr {
|
||||
height: 39px;
|
||||
}
|
||||
|
||||
div.operations {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 5%;
|
||||
min-width: 25%;
|
||||
border-left: 1px solid #ccc;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.add-files {
|
||||
font-size: 46px;
|
||||
text-align: center;
|
||||
border: 1px dashed #999;
|
||||
padding-bottom: 9px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
<a href="https://github.com/seaweedfs/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
|
||||
SeaweedFS Filer <small>{{ .Version }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div>
|
||||
<div class="btn-group btn-group-sm pull-right" role="group" style="margin-top:3px;">
|
||||
<label class="btn btn-default" onclick="handleCreateDir()">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> New Folder
|
||||
</label>
|
||||
<label class="btn btn-default" for="fileElem">
|
||||
<span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Upload
|
||||
</label>
|
||||
</div>
|
||||
<ol class="breadcrumb">
|
||||
{{ range $entry := .Breadcrumbs }}
|
||||
<li><a href="{{ printpath $entry.Link }}">
|
||||
{{ $entry.Name }}
|
||||
</a></li>
|
||||
{{ end }}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" id="drop-area">
|
||||
<form class="upload-form">
|
||||
<input type="file" id="fileElem" multiple onchange="handleFiles(this.files)">
|
||||
|
||||
{{ if .EmptyFolder }}
|
||||
<div class="row add-files">
|
||||
+
|
||||
</div>
|
||||
{{ else }}
|
||||
<table width="100%" class="table table-hover">
|
||||
{{ $path := .Path }}
|
||||
{{ $showDirDel := .ShowDirectoryDelete }}
|
||||
{{ range $entry_index, $entry := .Entries }}
|
||||
<tr>
|
||||
<td>
|
||||
{{ if $entry.IsDirectory }}
|
||||
<span class="glyphicon glyphicon-folder-open" aria-hidden="true"></span>
|
||||
<a href="{{ printpath $path "/" $entry.Name "/"}}" >
|
||||
{{ $entry.Name }}
|
||||
</a>
|
||||
{{ else }}
|
||||
<a href="{{ printpath $path "/" $entry.Name }}" >
|
||||
{{ $entry.Name }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td align="right" nowrap>
|
||||
{{ if not $entry.IsDirectory }}
|
||||
{{ $entry.Mime }}
|
||||
{{ end }}
|
||||
</td>
|
||||
<td align="right" nowrap>
|
||||
{{ if not $entry.IsDirectory }}
|
||||
{{ $entry.Size | humanizeBytes }}
|
||||
{{ end }}
|
||||
</td>
|
||||
<td align="right" nowrap>
|
||||
{{ $entry.Timestamp.Format "2006-01-02 15:04" }}
|
||||
</td>
|
||||
<td style="width:75px">
|
||||
<div class="btn-group btn-group-xs pull-right operations" role="group">
|
||||
<label class="btn" onclick="handleRename('{{ $entry.Name }}', '{{ printpath $path "/" }}')">
|
||||
<span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
|
||||
</label>
|
||||
{{ if and $entry.IsDirectory $showDirDel }}
|
||||
<label class="btn" onclick="handleDelete('{{ printpath $path "/" $entry.Name "/" }}')">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
|
||||
</label>
|
||||
{{ end }}
|
||||
{{ if not $entry.IsDirectory }}
|
||||
<label class="btn" onclick="handleDelete('{{ printpath $path "/" $entry.Name }}')">
|
||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
|
||||
</label>
|
||||
{{ end }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</table>
|
||||
{{ end }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{ if .ShouldDisplayLoadMore }}
|
||||
<div class="row">
|
||||
<a href="{{ printpath .Path }}?limit={{ .Limit }}&lastFileName={{ queryEscape .LastFileName }}" >
|
||||
Load more
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
<div id="progress-area" class="footer" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
// ************************ Drag and drop ***************** //
|
||||
let dropArea = document.getElementById("drop-area");
|
||||
let progressArea = document.getElementById("progress-area");
|
||||
|
||||
// Prevent default drag behaviors
|
||||
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||
dropArea.addEventListener(eventName, preventDefaults, false);
|
||||
document.body.addEventListener(eventName, preventDefaults, false);
|
||||
});
|
||||
|
||||
// Highlight drop area when item is dragged over it
|
||||
;['dragenter', 'dragover'].forEach(eventName => {
|
||||
dropArea.addEventListener(eventName, highlight, false);
|
||||
});
|
||||
|
||||
;['dragleave', 'drop'].forEach(eventName => {
|
||||
dropArea.addEventListener(eventName, unhighlight, false);
|
||||
});
|
||||
|
||||
// Handle dropped files
|
||||
dropArea.addEventListener('drop', handleDrop, false);
|
||||
|
||||
function preventDefaults(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function highlight(e) {
|
||||
dropArea.classList.add('highlight');
|
||||
}
|
||||
|
||||
function unhighlight(e) {
|
||||
dropArea.classList.remove('highlight');
|
||||
}
|
||||
|
||||
function handleDrop(e) {
|
||||
var dt = e.dataTransfer;
|
||||
var files = dt.files;
|
||||
|
||||
handleFiles(files);
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
window.location.reload(true);
|
||||
}
|
||||
|
||||
var uploadList = {};
|
||||
|
||||
function handleFiles(files) {
|
||||
files = [...files];
|
||||
files.forEach(startUpload);
|
||||
renderProgress();
|
||||
files.forEach(uploadFile);
|
||||
}
|
||||
|
||||
function startUpload(file, i) {
|
||||
uploadList[file.name] = {'name': file.name, 'percent': 0, 'finish': false};
|
||||
}
|
||||
|
||||
function renderProgress() {
|
||||
var values = Object.values(uploadList);
|
||||
var html = '<table class="table">\n<tr><th>Uploading</th><\/tr>\n';
|
||||
for (let i of values) {
|
||||
var progressBarClass = 'progress-bar-striped active';
|
||||
if (i.percent >= 100) {
|
||||
progressBarClass = 'progress-bar-success';
|
||||
}
|
||||
html += '<tr>\n<td>\n';
|
||||
html += '<div class="progress" style="margin-bottom: 2px;">\n';
|
||||
html += '<div class="progress-bar ' + progressBarClass + '" role="progressbar" aria-valuenow="' + '100" aria-valuemin="0" aria-valuemax="100" style="width:' + i.percent + '%;">';
|
||||
html += '<span style="margin-right: 10px;">' + i.name + '</span>' + i.percent + '%<\/div>';
|
||||
html += '<\/div>\n<\/td>\n<\/tr>\n';
|
||||
}
|
||||
html += '<\/table>\n';
|
||||
progressArea.innerHTML = html;
|
||||
if (values.length > 0) {
|
||||
progressArea.attributes.style.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
function reportProgress(file, percent) {
|
||||
var item = uploadList[file]
|
||||
item.percent = percent;
|
||||
renderProgress();
|
||||
}
|
||||
|
||||
function finishUpload(file) {
|
||||
uploadList[file]['finish'] = true;
|
||||
renderProgress();
|
||||
var allFinish = true;
|
||||
for (let i of Object.values(uploadList)) {
|
||||
if (!i.finish) {
|
||||
allFinish = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allFinish) {
|
||||
console.log('All Finish');
|
||||
reloadPage();
|
||||
}
|
||||
}
|
||||
|
||||
function uploadFile(file, i) {
|
||||
var url = window.location.href;
|
||||
var xhr = new XMLHttpRequest();
|
||||
var fileName = file.name;
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||
finishUpload(fileName)
|
||||
}
|
||||
}
|
||||
xhr.upload.addEventListener('progress', function(e) {
|
||||
if (e.lengthComputable) {
|
||||
var percent = Math.ceil((e.loaded / e.total) * 100);
|
||||
reportProgress(fileName, percent)
|
||||
}
|
||||
});
|
||||
xhr.upload.addEventListener('loadend', function(e) {
|
||||
finishUpload(fileName);
|
||||
});
|
||||
var formData = new FormData();
|
||||
xhr.open('POST', url, true);
|
||||
formData.append('file', file);
|
||||
xhr.send(formData);
|
||||
}
|
||||
|
||||
function handleCreateDir() {
|
||||
var dirName = prompt('Folder Name:', '');
|
||||
dirName = dirName.trim();
|
||||
if (dirName == null || dirName == '') {
|
||||
return;
|
||||
}
|
||||
var baseUrl = window.location.origin + window.location.pathname;
|
||||
if (!baseUrl.endsWith('/')) {
|
||||
baseUrl += '/';
|
||||
}
|
||||
var url = baseUrl + encodeURIComponent(dirName);
|
||||
if (!url.endsWith('/')) {
|
||||
url += '/';
|
||||
}
|
||||
url += window.location.search;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', '');
|
||||
xhr.send();
|
||||
reloadPage();
|
||||
}
|
||||
|
||||
function handleRename(originName, basePath) {
|
||||
var newName = prompt('New Name:', originName);
|
||||
if (newName == null || newName == '') {
|
||||
return;
|
||||
}
|
||||
var url = basePath + encodeURIComponent(newName);
|
||||
var originPath = basePath + originName;
|
||||
url += '?mv.from=' + encodeURIComponent(originPath);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, false);
|
||||
xhr.setRequestHeader('Content-Type', '');
|
||||
xhr.send();
|
||||
reloadPage();
|
||||
}
|
||||
|
||||
function handleDelete(path) {
|
||||
if (!confirm('Are you sure to delete ' + path + '?')) {
|
||||
return;
|
||||
}
|
||||
var url = path;
|
||||
if (url.endsWith('/')) {
|
||||
url += '?recursive=true';
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('DELETE', url, false);
|
||||
xhr.send();
|
||||
reloadPage();
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
27
weed/server/filer_ui/templates.go
Normal file
27
weed/server/filer_ui/templates.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package filer_ui
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
func printpath(parts ...string) string {
|
||||
concat := strings.Join(parts, "")
|
||||
escaped := url.PathEscape(concat)
|
||||
return strings.ReplaceAll(escaped, "%2F", "/")
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"humanizeBytes": humanize.Bytes,
|
||||
"printpath": printpath,
|
||||
"queryEscape": url.QueryEscape,
|
||||
}
|
||||
|
||||
//go:embed filer.html
|
||||
var filerHtml string
|
||||
|
||||
var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(filerHtml))
|
||||
Reference in New Issue
Block a user