aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--weed/server/filer_ui/filer.html182
-rw-r--r--weed/server/filer_ui/templates.go178
-rw-r--r--weed/server/master_ui/master.html110
-rw-r--r--weed/server/master_ui/templates.go112
-rw-r--r--weed/server/volume_server_ui/templates.go191
-rw-r--r--weed/server/volume_server_ui/volume.html194
6 files changed, 498 insertions, 469 deletions
diff --git a/weed/server/filer_ui/filer.html b/weed/server/filer_ui/filer.html
new file mode 100644
index 000000000..84dc4d4d6
--- /dev/null
+++ b/weed/server/filer_ui/filer.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>SeaweedFS Filer</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;
+ }
+
+ #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;
+ }
+
+ .button:hover {
+ background: #ddd;
+ }
+
+ #fileElem {
+ display: none;
+ }
+
+ .qrImage {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ }
+ </style>
+</head>
+<body>
+<div class="container">
+ <div class="page-header">
+ <h1>
+ <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
+ SeaweedFS Filer
+ </h1>
+ </div>
+ <div class="row">
+ <div>
+ {{ range $entry := .Breadcrumbs }}
+ <a href="{{ printpath $entry.Link }}">
+ {{ $entry.Name }}
+ </a>
+ {{ end }}
+ <label class="button" for="fileElem">Upload</label>
+ </div>
+ </div>
+
+ <div class="row" id="drop-area">
+ <form class="upload-form">
+ <input type="file" id="fileElem" multiple onchange="handleFiles(this.files)">
+
+ <table width="90%">
+ {{$path := .Path }}
+ {{ range $entry_index, $entry := .Entries }}
+ <tr>
+ <td>
+ {{if $entry.IsDirectory}}
+ <img src="/seaweedfsstatic/images/folder.gif" width="20" height="23">
+ <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 $entry.IsDirectory}}
+ {{else}}
+ {{ $entry.Mime }}&nbsp;
+ {{end}}
+ </td>
+ <td align="right" nowrap>
+ {{if $entry.IsDirectory}}
+ {{else}}
+ {{ $entry.Size | humanizeBytes }}&nbsp;
+ {{end}}
+ </td>
+ <td nowrap>
+ {{ $entry.Timestamp.Format "2006-01-02 15:04" }}
+ </td>
+ </tr>
+ {{ end }}
+
+ </table>
+ </form>
+ </div>
+
+ {{if .ShouldDisplayLoadMore}}
+ <div class="row">
+ <a href={{ print .Path "?limit=" .Limit "&lastFileName=" .LastFileName}} >
+ Load more
+ </a>
+ </div>
+ {{end}}
+
+ <br/>
+ <br/>
+
+ <div class="navbar navbar-fixed-bottom">
+ <img src="data:image/png;base64,{{.QrImage}}" class="qrImage"/>
+ </div>
+
+</div>
+</body>
+<script type="text/javascript">
+ // ************************ Drag and drop ***************** //
+ let dropArea = document.getElementById("drop-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 handleFiles(files) {
+ files = [...files]
+ files.forEach(uploadFile)
+ window.location.reload()
+ }
+
+ function uploadFile(file, i) {
+ var url = window.location.href
+ var xhr = new XMLHttpRequest()
+ var formData = new FormData()
+ xhr.open('POST', url, false)
+
+ formData.append('file', file)
+ xhr.send(formData)
+ }
+</script>
+</html>
diff --git a/weed/server/filer_ui/templates.go b/weed/server/filer_ui/templates.go
index 648b97f22..f9ef064bc 100644
--- a/weed/server/filer_ui/templates.go
+++ b/weed/server/filer_ui/templates.go
@@ -1,6 +1,7 @@
package filer_ui
import (
+ _ "embed"
"github.com/dustin/go-humanize"
"html/template"
"net/url"
@@ -18,178 +19,7 @@ var funcMap = template.FuncMap{
"printpath": printpath,
}
-var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(`<!DOCTYPE html>
-<html>
-<head>
- <title>SeaweedFS Filer</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;
-}
-#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;
-}
-.button:hover {
- background: #ddd;
-}
-#fileElem {
- display: none;
-}
-.qrImage {
- display: block;
- margin-left: auto;
- margin-right: auto;
-}
-</style>
-</head>
-<body>
- <div class="container">
- <div class="page-header">
- <h1>
- <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
- SeaweedFS Filer
- </h1>
- </div>
- <div class="row">
- <div>
- {{ range $entry := .Breadcrumbs }}
- <a href="{{ printpath $entry.Link }}" >
- {{ $entry.Name }}
- </a>
- {{ end }}
- <label class="button" for="fileElem">Upload</label>
- </div>
- </div>
-
- <div class="row" id="drop-area">
- <form class="upload-form">
- <input type="file" id="fileElem" multiple onchange="handleFiles(this.files)">
-
- <table width="90%">
- {{$path := .Path }}
- {{ range $entry_index, $entry := .Entries }}
- <tr>
- <td>
- {{if $entry.IsDirectory}}
- <img src="/seaweedfsstatic/images/folder.gif" width="20" height="23">
- <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 $entry.IsDirectory}}
- {{else}}
- {{ $entry.Mime }}&nbsp;
- {{end}}
- </td>
- <td align="right" nowrap>
- {{if $entry.IsDirectory}}
- {{else}}
- {{ $entry.Size | humanizeBytes }}&nbsp;
- {{end}}
- </td>
- <td nowrap>
- {{ $entry.Timestamp.Format "2006-01-02 15:04" }}
- </td>
- </tr>
- {{ end }}
-
- </table>
- </form>
- </div>
-
- {{if .ShouldDisplayLoadMore}}
- <div class="row">
- <a href={{ print .Path "?limit=" .Limit "&lastFileName=" .LastFileName}} >
- Load more
- </a>
- </div>
- {{end}}
-
- <br/>
- <br/>
-
- <div class="navbar navbar-fixed-bottom">
- <img src="data:image/png;base64,{{.QrImage}}" class="qrImage" />
- </div>
-
- </div>
-</body>
-<script type="text/javascript">
-// ************************ Drag and drop ***************** //
-let dropArea = document.getElementById("drop-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)
-})
+//go:embed filer.html
+var filerHtml string
-;['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 handleFiles(files) {
- files = [...files]
- files.forEach(uploadFile)
- window.location.reload()
-}
-
-function uploadFile(file, i) {
- var url = window.location.href
- var xhr = new XMLHttpRequest()
- var formData = new FormData()
- xhr.open('POST', url, false)
-
- formData.append('file', file)
- xhr.send(formData)
-}
-</script>
-</html>
-`))
+var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(filerHtml))
diff --git a/weed/server/master_ui/master.html b/weed/server/master_ui/master.html
new file mode 100644
index 000000000..e0241d66d
--- /dev/null
+++ b/weed/server/master_ui/master.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>SeaweedFS {{ .Version }}</title>
+ <link rel="stylesheet" href="/seaweedfsstatic/bootstrap/3.3.1/css/bootstrap.min.css">
+</head>
+<body>
+<div class="container">
+ <div class="page-header">
+ <h1>
+ <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
+ SeaweedFS <small>{{ .Version }}</small>
+ </h1>
+ </div>
+
+ <div class="row">
+ <div class="col-sm-6">
+ <h2>Cluster status</h2>
+ <table class="table table-condensed table-striped">
+ <tbody>
+ <tr>
+ <th>Volume Size Limit</th>
+ <td>{{ .VolumeSizeLimitMB }}MB</td>
+ </tr>
+ <tr>
+ <th>Free</th>
+ <td>{{ .Topology.Free }}</td>
+ </tr>
+ <tr>
+ <th>Max</th>
+ <td>{{ .Topology.Max }}</td>
+ </tr>
+ {{ with .RaftServer }}
+ <tr>
+ <th>Leader</th>
+ <td><a href="http://{{ .Leader }}">{{ .Leader }}</a></td>
+ </tr>
+ <tr>
+ <th>Other Masters</th>
+ <td class="col-sm-5">
+ <ul class="list-unstyled">
+ {{ range $k, $p := .Peers }}
+ <li><a href="http://{{ $p.Name }}/ui/index.html">{{ $p.Name }}</a></li>
+ {{ end }}
+ </ul>
+ </td>
+ </tr>
+ {{ end }}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="col-sm-6">
+ <h2>System Stats</h2>
+ <table class="table table-condensed table-striped">
+ <tr>
+ <th>Concurrent Connections</th>
+ <td>{{ .Counters.Connections.WeekCounter.Sum }}</td>
+ </tr>
+ {{ range $key, $val := .Stats }}
+ <tr>
+ <th>{{ $key }}</th>
+ <td>{{ $val }}</td>
+ </tr>
+ {{ end }}
+ </table>
+ </div>
+ </div>
+
+ <div class="row">
+ <h2>Topology</h2>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Data Center</th>
+ <th>Rack</th>
+ <th>RemoteAddr</th>
+ <th>#Volumes</th>
+ <th>Volume Ids</th>
+ <th>#ErasureCodingShards</th>
+ <th>Max</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{ range $dc_index, $dc := .Topology.DataCenters }}
+ {{ range $rack_index, $rack := $dc.Racks }}
+ {{ range $dn_index, $dn := $rack.DataNodes }}
+ <tr>
+ <td><code>{{ $dc.Id }}</code></td>
+ <td>{{ $rack.Id }}</td>
+ <td><a href="http://{{ $dn.Url }}/ui/index.html">{{ $dn.Url }}</a>
+ {{ if ne $dn.PublicUrl $dn.Url }}
+ / <a href="http://{{ $dn.PublicUrl }}/ui/index.html">{{ $dn.PublicUrl }}</a>
+ {{ end }}
+ </td>
+ <td>{{ $dn.Volumes }}</td>
+ <td>{{ $dn.VolumeIds}}</td>
+ <td>{{ $dn.EcShards }}</td>
+ <td>{{ $dn.Max }}</td>
+ </tr>
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ </tbody>
+ </table>
+ </div>
+
+</div>
+</body>
+</html>
diff --git a/weed/server/master_ui/templates.go b/weed/server/master_ui/templates.go
index 31b6353e9..415022b97 100644
--- a/weed/server/master_ui/templates.go
+++ b/weed/server/master_ui/templates.go
@@ -1,115 +1,11 @@
package master_ui
import (
+ _ "embed"
"html/template"
)
-var StatusTpl = template.Must(template.New("status").Parse(`<!DOCTYPE html>
-<html>
- <head>
- <title>SeaweedFS {{ .Version }}</title>
- <link rel="stylesheet" href="/seaweedfsstatic/bootstrap/3.3.1/css/bootstrap.min.css">
- </head>
- <body>
- <div class="container">
- <div class="page-header">
- <h1>
- <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
- SeaweedFS <small>{{ .Version }}</small>
- </h1>
- </div>
+//go:embed master.html
+var masterHtml string
- <div class="row">
- <div class="col-sm-6">
- <h2>Cluster status</h2>
- <table class="table table-condensed table-striped">
- <tbody>
- <tr>
- <th>Volume Size Limit</th>
- <td>{{ .VolumeSizeLimitMB }}MB</td>
- </tr>
- <tr>
- <th>Free</th>
- <td>{{ .Topology.Free }}</td>
- </tr>
- <tr>
- <th>Max</th>
- <td>{{ .Topology.Max }}</td>
- </tr>
- {{ with .RaftServer }}
- <tr>
- <th>Leader</th>
- <td><a href="http://{{ .Leader }}">{{ .Leader }}</a></td>
- </tr>
- <tr>
- <th>Other Masters</th>
- <td class="col-sm-5"><ul class="list-unstyled">
- {{ range $k, $p := .Peers }}
- <li><a href="http://{{ $p.Name }}/ui/index.html">{{ $p.Name }}</a></li>
- {{ end }}
- </ul></td>
- </tr>
- {{ end }}
- </tbody>
- </table>
- </div>
-
- <div class="col-sm-6">
- <h2>System Stats</h2>
- <table class="table table-condensed table-striped">
- <tr>
- <th>Concurrent Connections</th>
- <td>{{ .Counters.Connections.WeekCounter.Sum }}</td>
- </tr>
- {{ range $key, $val := .Stats }}
- <tr>
- <th>{{ $key }}</th>
- <td>{{ $val }}</td>
- </tr>
- {{ end }}
- </table>
- </div>
- </div>
-
- <div class="row">
- <h2>Topology</h2>
- <table class="table table-striped">
- <thead>
- <tr>
- <th>Data Center</th>
- <th>Rack</th>
- <th>RemoteAddr</th>
- <th>#Volumes</th>
- <th>Volume Ids</th>
- <th>#ErasureCodingShards</th>
- <th>Max</th>
- </tr>
- </thead>
- <tbody>
- {{ range $dc_index, $dc := .Topology.DataCenters }}
- {{ range $rack_index, $rack := $dc.Racks }}
- {{ range $dn_index, $dn := $rack.DataNodes }}
- <tr>
- <td><code>{{ $dc.Id }}</code></td>
- <td>{{ $rack.Id }}</td>
- <td><a href="http://{{ $dn.Url }}/ui/index.html">{{ $dn.Url }}</a>
- {{ if ne $dn.PublicUrl $dn.Url }}
- / <a href="http://{{ $dn.PublicUrl }}/ui/index.html">{{ $dn.PublicUrl }}</a>
- {{ end }}
- </td>
- <td>{{ $dn.Volumes }}</td>
- <td>{{ $dn.VolumeIds}}</td>
- <td>{{ $dn.EcShards }}</td>
- <td>{{ $dn.Max }}</td>
- </tr>
- {{ end }}
- {{ end }}
- {{ end }}
- </tbody>
- </table>
- </div>
-
- </div>
- </body>
-</html>
-`))
+var StatusTpl = template.Must(template.New("status").Parse(masterHtml))
diff --git a/weed/server/volume_server_ui/templates.go b/weed/server/volume_server_ui/templates.go
index 79f1a14a0..8034d8218 100644
--- a/weed/server/volume_server_ui/templates.go
+++ b/weed/server/volume_server_ui/templates.go
@@ -1,6 +1,7 @@
package volume_server_ui
import (
+ _ "embed"
"fmt"
"github.com/chrislusf/seaweedfs/weed/util"
"html/template"
@@ -26,191 +27,7 @@ var funcMap = template.FuncMap{
"percentFrom": percentFrom,
}
-var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(`<!DOCTYPE html>
-<html>
- <head>
- <title>SeaweedFS {{ .Version }}</title>
- <link rel="stylesheet" href="/seaweedfsstatic/bootstrap/3.3.1/css/bootstrap.min.css">
- <script type="text/javascript" src="/seaweedfsstatic/javascript/jquery-3.6.0.min.js"></script>
- <script type="text/javascript" src="/seaweedfsstatic/javascript/jquery-sparklines/2.1.2/jquery.sparkline.min.js"></script>
- <script type="text/javascript">
- $(function() {
- var periods = ['second', 'minute', 'hour', 'day'];
- for (i = 0; i < periods.length; i++) {
- var period = periods[i];
- $('.inlinesparkline-'+period).sparkline('html', {
- type: 'line',
- barColor: 'red',
- tooltipSuffix:' request per '+period,
- });
- }
- });
- </script>
- <style>
- #jqstooltip{
- height: 28px !important;
- width: 150px !important;
- }
- </style>
- </head>
- <body>
- <div class="container">
- <div class="page-header">
- <h1>
- <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
- SeaweedFS <small>{{ .Version }}</small>
- </h1>
- </div>
-
- <div class="row">
- <div class="col-sm-6">
- <h2>Disk Stats</h2>
- <table class="table table-striped">
- <thead>
- <tr>
- <th>Path</th>
- <th>Disk</th>
- <th>Total</th>
- <th>Free</th>
- <th>Usage</th>
- </tr>
- </thead>
- <tbody>
- {{ range .DiskStatuses }}
- <tr>
- <td>{{ .Dir }}</td>
- <td>{{ .DiskType }}</td>
- <td>{{ bytesToHumanReadable .All }}</td>
- <td>{{ bytesToHumanReadable .Free }}</td>
- <td>{{ percentFrom .All .Used}}%</td>
- </tr>
- {{ end }}
- </tbody>
- </table>
- </div>
-
- <div class="col-sm-6">
- <h2>System Stats</h2>
- <table class="table table-condensed table-striped">
- <tr>
- <th>Masters</th>
- <td>{{.Masters}}</td>
- </tr>
- <tr>
- <th>Weekly # ReadRequests</th>
- <td><span class="inlinesparkline-day">{{ .Counters.ReadRequests.WeekCounter.ToList | join }}</span></td>
- </tr>
- <tr>
- <th>Daily # ReadRequests</th>
- <td><span class="inlinesparkline-hour">{{ .Counters.ReadRequests.DayCounter.ToList | join }}</span></td>
- </tr>
- <tr>
- <th>Hourly # ReadRequests</th>
- <td><span class="inlinesparkline-minute">{{ .Counters.ReadRequests.HourCounter.ToList | join }}</span></td>
- </tr>
- <tr>
- <th>Last Minute # ReadRequests</th>
- <td><span class="inlinesparkline-second">{{ .Counters.ReadRequests.MinuteCounter.ToList | join }}</span></td>
- </tr>
- {{ range $key, $val := .Stats }}
- <tr>
- <th>{{ $key }}</th>
- <td>{{ $val }}</td>
- </tr>
- {{ end }}
- </table>
- </div>
- </div>
-
- <div class="row">
- <h2>Volumes</h2>
- <table class="table table-striped">
- <thead>
- <tr>
- <th>Id</th>
- <th>Collection</th>
- <th>Disk</th>
- <th>Data Size</th>
- <th>Files</th>
- <th>Trash</th>
- <th>TTL</th>
- <th>ReadOnly</th>
- </tr>
- </thead>
- <tbody>
- {{ range .Volumes }}
- <tr>
- <td><code>{{ .Id }}</code></td>
- <td>{{ .Collection }}</td>
- <td>{{ .DiskType }}</td>
- <td>{{ bytesToHumanReadable .Size }}</td>
- <td>{{ .FileCount }}</td>
- <td>{{ .DeleteCount }} / {{bytesToHumanReadable .DeletedByteCount}}</td>
- <td>{{ .Ttl }}</td>
- <td>{{ .ReadOnly }}</td>
- </tr>
- {{ end }}
- </tbody>
- </table>
- </div>
-
- <div class="row">
- <h2>Remote Volumes</h2>
- <table class="table table-striped">
- <thead>
- <tr>
- <th>Id</th>
- <th>Collection</th>
- <th>Size</th>
- <th>Files</th>
- <th>Trash</th>
- <th>Remote</th>
- <th>Key</th>
- </tr>
- </thead>
- <tbody>
- {{ range .RemoteVolumes }}
- <tr>
- <td><code>{{ .Id }}</code></td>
- <td>{{ .Collection }}</td>
- <td>{{ bytesToHumanReadable .Size }}</td>
- <td>{{ .FileCount }}</td>
- <td>{{ .DeleteCount }} / {{bytesToHumanReadable .DeletedByteCount}}</td>
- <td>{{ .RemoteStorageName }}</td>
- <td>{{ .RemoteStorageKey }}</td>
- </tr>
- {{ end }}
- </tbody>
- </table>
- </div>
-
- <div class="row">
- <h2>Erasure Coding Shards</h2>
- <table class="table table-striped">
- <thead>
- <tr>
- <th>Id</th>
- <th>Collection</th>
- <th>Shard Size</th>
- <th>Shards</th>
- <th>CreatedAt</th>
- </tr>
- </thead>
- <tbody>
- {{ range .EcVolumes }}
- <tr>
- <td><code>{{ .VolumeId }}</code></td>
- <td>{{ .Collection }}</td>
- <td>{{ bytesToHumanReadable .ShardSize }}</td>
- <td>{{ .ShardIdList }}</td>
- <td>{{ .CreatedAt.Format "02 Jan 06 15:04 -0700" }}</td>
- </tr>
- {{ end }}
- </tbody>
- </table>
- </div>
+//go:embed volume.html
+var volumeHtml string
- </div>
- </body>
-</html>
-`))
+var StatusTpl = template.Must(template.New("status").Funcs(funcMap).Parse(volumeHtml))
diff --git a/weed/server/volume_server_ui/volume.html b/weed/server/volume_server_ui/volume.html
new file mode 100644
index 000000000..973b0bfbe
--- /dev/null
+++ b/weed/server/volume_server_ui/volume.html
@@ -0,0 +1,194 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>SeaweedFS {{ .Version }}</title>
+ <link rel="stylesheet" href="/seaweedfsstatic/bootstrap/3.3.1/css/bootstrap.min.css">
+ <script type="text/javascript" src="/seaweedfsstatic/javascript/jquery-3.6.0.min.js"></script>
+ <script type="text/javascript"
+ src="/seaweedfsstatic/javascript/jquery-sparklines/2.1.2/jquery.sparkline.min.js"></script>
+ <script type="text/javascript">
+ $(function () {
+ var periods = ['second', 'minute', 'hour', 'day'];
+ for (i = 0; i < periods.length; i++) {
+ var period = periods[i];
+ $('.inlinesparkline-' + period).sparkline('html', {
+ type: 'line',
+ barColor: 'red',
+ tooltipSuffix: ' request per ' + period,
+ });
+ }
+ });
+ </script>
+ <style>
+ #jqstooltip {
+ height: 28px !important;
+ width: 150px !important;
+ }
+ </style>
+</head>
+<body>
+<div class="container">
+ <div class="page-header">
+ <h1>
+ <a href="https://github.com/chrislusf/seaweedfs"><img src="/seaweedfsstatic/seaweed50x50.png"></img></a>
+ SeaweedFS <small>{{ .Version }}</small>
+ </h1>
+ </div>
+
+ <div class="row">
+ <div class="col-sm-6">
+ <h2>Disk Stats</h2>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Path</th>
+ <th>Disk</th>
+ <th>Total</th>
+ <th>Free</th>
+ <th>Usage</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{ range .DiskStatuses }}
+ <tr>
+ <td>{{ .Dir }}</td>
+ <td>{{ .DiskType }}</td>
+ <td>{{ bytesToHumanReadable .All }}</td>
+ <td>{{ bytesToHumanReadable .Free }}</td>
+ <td>{{ percentFrom .All .Used}}%</td>
+ </tr>
+ {{ end }}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="col-sm-6">
+ <h2>System Stats</h2>
+ <table class="table table-condensed table-striped">
+ <tr>
+ <th>Masters</th>
+ <td>{{.Masters}}</td>
+ </tr>
+ <tr>
+ <th>Weekly # ReadRequests</th>
+ <td><span class="inlinesparkline-day">{{ .Counters.ReadRequests.WeekCounter.ToList | join }}</span>
+ </td>
+ </tr>
+ <tr>
+ <th>Daily # ReadRequests</th>
+ <td><span class="inlinesparkline-hour">{{ .Counters.ReadRequests.DayCounter.ToList | join }}</span>
+ </td>
+ </tr>
+ <tr>
+ <th>Hourly # ReadRequests</th>
+ <td><span
+ class="inlinesparkline-minute">{{ .Counters.ReadRequests.HourCounter.ToList | join }}</span>
+ </td>
+ </tr>
+ <tr>
+ <th>Last Minute # ReadRequests</th>
+ <td><span
+ class="inlinesparkline-second">{{ .Counters.ReadRequests.MinuteCounter.ToList | join }}</span>
+ </td>
+ </tr>
+ {{ range $key, $val := .Stats }}
+ <tr>
+ <th>{{ $key }}</th>
+ <td>{{ $val }}</td>
+ </tr>
+ {{ end }}
+ </table>
+ </div>
+ </div>
+
+ <div class="row">
+ <h2>Volumes</h2>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Id</th>
+ <th>Collection</th>
+ <th>Disk</th>
+ <th>Data Size</th>
+ <th>Files</th>
+ <th>Trash</th>
+ <th>TTL</th>
+ <th>ReadOnly</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{ range .Volumes }}
+ <tr>
+ <td><code>{{ .Id }}</code></td>
+ <td>{{ .Collection }}</td>
+ <td>{{ .DiskType }}</td>
+ <td>{{ bytesToHumanReadable .Size }}</td>
+ <td>{{ .FileCount }}</td>
+ <td>{{ .DeleteCount }} / {{bytesToHumanReadable .DeletedByteCount}}</td>
+ <td>{{ .Ttl }}</td>
+ <td>{{ .ReadOnly }}</td>
+ </tr>
+ {{ end }}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="row">
+ <h2>Remote Volumes</h2>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Id</th>
+ <th>Collection</th>
+ <th>Size</th>
+ <th>Files</th>
+ <th>Trash</th>
+ <th>Remote</th>
+ <th>Key</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{ range .RemoteVolumes }}
+ <tr>
+ <td><code>{{ .Id }}</code></td>
+ <td>{{ .Collection }}</td>
+ <td>{{ bytesToHumanReadable .Size }}</td>
+ <td>{{ .FileCount }}</td>
+ <td>{{ .DeleteCount }} / {{bytesToHumanReadable .DeletedByteCount}}</td>
+ <td>{{ .RemoteStorageName }}</td>
+ <td>{{ .RemoteStorageKey }}</td>
+ </tr>
+ {{ end }}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="row">
+ <h2>Erasure Coding Shards</h2>
+ <table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Id</th>
+ <th>Collection</th>
+ <th>Shard Size</th>
+ <th>Shards</th>
+ <th>CreatedAt</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{ range .EcVolumes }}
+ <tr>
+ <td><code>{{ .VolumeId }}</code></td>
+ <td>{{ .Collection }}</td>
+ <td>{{ bytesToHumanReadable .ShardSize }}</td>
+ <td>{{ .ShardIdList }}</td>
+ <td>{{ .CreatedAt.Format "02 Jan 06 15:04 -0700" }}</td>
+ </tr>
+ {{ end }}
+ </tbody>
+ </table>
+ </div>
+
+</div>
+</body>
+</html>