mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 00:50:31 +00:00
web admin: make base url configurable
This commit is contained in:
parent
5acf29dae6
commit
0bc4db9950
14 changed files with 241 additions and 143 deletions
|
@ -218,8 +218,11 @@ func Init() {
|
|||
TemplatesPath: "templates",
|
||||
StaticFilesPath: "static",
|
||||
BackupsPath: "backups",
|
||||
WebAdminRoot: "",
|
||||
CertificateFile: "",
|
||||
CertificateKeyFile: "",
|
||||
CACertificates: nil,
|
||||
CARevocationLists: nil,
|
||||
},
|
||||
HTTPConfig: httpclient.Config{
|
||||
Timeout: 20,
|
||||
|
@ -857,6 +860,7 @@ func setViperDefaults() {
|
|||
viper.SetDefault("httpd.templates_path", globalConf.HTTPDConfig.TemplatesPath)
|
||||
viper.SetDefault("httpd.static_files_path", globalConf.HTTPDConfig.StaticFilesPath)
|
||||
viper.SetDefault("httpd.backups_path", globalConf.HTTPDConfig.BackupsPath)
|
||||
viper.SetDefault("httpd.web_admin_root", globalConf.HTTPDConfig.WebAdminRoot)
|
||||
viper.SetDefault("httpd.certificate_file", globalConf.HTTPDConfig.CertificateFile)
|
||||
viper.SetDefault("httpd.certificate_key_file", globalConf.HTTPDConfig.CertificateKeyFile)
|
||||
viper.SetDefault("httpd.ca_certificates", globalConf.HTTPDConfig.CACertificates)
|
||||
|
|
|
@ -204,6 +204,7 @@ The configuration file contains the following sections:
|
|||
- `templates_path`, string. Path to the HTML web templates. This can be an absolute path or a path relative to the config dir
|
||||
- `static_files_path`, string. Path to the static files for the web interface. This can be an absolute path or a path relative to the config dir. If both `templates_path` and `static_files_path` are empty the built-in web interface will be disabled
|
||||
- `backups_path`, string. Path to the backup directory. This can be an absolute path or a path relative to the config dir. We don't allow backups in arbitrary paths for security reasons
|
||||
- `web_admin_root`, string. Defines a base URL for the web admin. If empty web admin resources will be available at the root ("/") URI. If defined it must be an absolute URI or it will be ignored
|
||||
- `certificate_file`, string. Certificate for HTTPS. This can be an absolute path or a path relative to the config dir.
|
||||
- `certificate_key_file`, string. Private key matching the above certificate. This can be an absolute path or a path relative to the config dir. If both the certificate and the private key are provided, the server will expect HTTPS connections. Certificate and key files can be reloaded on demand sending a `SIGHUP` signal on Unix based systems and a `paramchange` request to the running service on Windows.
|
||||
- `ca_certificates`, list of strings. Set of root certificate authorities to be used to verify client certificates.
|
||||
|
|
138
httpd/httpd.go
138
httpd/httpd.go
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -27,46 +28,47 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
logSender = "httpd"
|
||||
tokenPath = "/api/v2/token"
|
||||
logoutPath = "/api/v2/logout"
|
||||
activeConnectionsPath = "/api/v2/connections"
|
||||
quotaScanPath = "/api/v2/quota-scans"
|
||||
quotaScanVFolderPath = "/api/v2/folder-quota-scans"
|
||||
userPath = "/api/v2/users"
|
||||
versionPath = "/api/v2/version"
|
||||
folderPath = "/api/v2/folders"
|
||||
serverStatusPath = "/api/v2/status"
|
||||
dumpDataPath = "/api/v2/dumpdata"
|
||||
loadDataPath = "/api/v2/loaddata"
|
||||
updateUsedQuotaPath = "/api/v2/quota-update"
|
||||
updateFolderUsedQuotaPath = "/api/v2/folder-quota-update"
|
||||
defenderBanTime = "/api/v2/defender/bantime"
|
||||
defenderUnban = "/api/v2/defender/unban"
|
||||
defenderScore = "/api/v2/defender/score"
|
||||
adminPath = "/api/v2/admins"
|
||||
adminPwdPath = "/api/v2/changepwd/admin"
|
||||
healthzPath = "/healthz"
|
||||
webBasePath = "/web"
|
||||
webLoginPath = "/web/login"
|
||||
webLogoutPath = "/web/logout"
|
||||
webUsersPath = "/web/users"
|
||||
webUserPath = "/web/user"
|
||||
webConnectionsPath = "/web/connections"
|
||||
webFoldersPath = "/web/folders"
|
||||
webFolderPath = "/web/folder"
|
||||
webStatusPath = "/web/status"
|
||||
webAdminsPath = "/web/admins"
|
||||
webAdminPath = "/web/admin"
|
||||
webMaintenancePath = "/web/maintenance"
|
||||
webBackupPath = "/web/backup"
|
||||
webRestorePath = "/web/restore"
|
||||
webScanVFolderPath = "/web/folder-quota-scans"
|
||||
webQuotaScanPath = "/web/quota-scans"
|
||||
webChangeAdminPwdPath = "/web/changepwd/admin"
|
||||
webTemplateUser = "/web/template/user"
|
||||
webTemplateFolder = "/web/template/folder"
|
||||
webStaticFilesPath = "/static"
|
||||
logSender = "httpd"
|
||||
tokenPath = "/api/v2/token"
|
||||
logoutPath = "/api/v2/logout"
|
||||
activeConnectionsPath = "/api/v2/connections"
|
||||
quotaScanPath = "/api/v2/quota-scans"
|
||||
quotaScanVFolderPath = "/api/v2/folder-quota-scans"
|
||||
userPath = "/api/v2/users"
|
||||
versionPath = "/api/v2/version"
|
||||
folderPath = "/api/v2/folders"
|
||||
serverStatusPath = "/api/v2/status"
|
||||
dumpDataPath = "/api/v2/dumpdata"
|
||||
loadDataPath = "/api/v2/loaddata"
|
||||
updateUsedQuotaPath = "/api/v2/quota-update"
|
||||
updateFolderUsedQuotaPath = "/api/v2/folder-quota-update"
|
||||
defenderBanTime = "/api/v2/defender/bantime"
|
||||
defenderUnban = "/api/v2/defender/unban"
|
||||
defenderScore = "/api/v2/defender/score"
|
||||
adminPath = "/api/v2/admins"
|
||||
adminPwdPath = "/api/v2/changepwd/admin"
|
||||
healthzPath = "/healthz"
|
||||
webRootPathDefault = "/"
|
||||
webBasePathDefault = "/web"
|
||||
webLoginPathDefault = "/web/login"
|
||||
webLogoutPathDefault = "/web/logout"
|
||||
webUsersPathDefault = "/web/users"
|
||||
webUserPathDefault = "/web/user"
|
||||
webConnectionsPathDefault = "/web/connections"
|
||||
webFoldersPathDefault = "/web/folders"
|
||||
webFolderPathDefault = "/web/folder"
|
||||
webStatusPathDefault = "/web/status"
|
||||
webAdminsPathDefault = "/web/admins"
|
||||
webAdminPathDefault = "/web/admin"
|
||||
webMaintenancePathDefault = "/web/maintenance"
|
||||
webBackupPathDefault = "/web/backup"
|
||||
webRestorePathDefault = "/web/restore"
|
||||
webScanVFolderPathDefault = "/web/folder-quota-scans"
|
||||
webQuotaScanPathDefault = "/web/quota-scans"
|
||||
webChangeAdminPwdPathDefault = "/web/changepwd/admin"
|
||||
webTemplateUserDefault = "/web/template/user"
|
||||
webTemplateFolderDefault = "/web/template/folder"
|
||||
webStaticFilesPathDefault = "/static"
|
||||
// MaxRestoreSize defines the max size for the loaddata input file
|
||||
MaxRestoreSize = 10485760 // 10 MB
|
||||
maxRequestSize = 1048576 // 1MB
|
||||
|
@ -80,8 +82,33 @@ var (
|
|||
jwtTokensCleanupDone chan bool
|
||||
invalidatedJWTTokens sync.Map
|
||||
csrfTokenAuth *jwtauth.JWTAuth
|
||||
webRootPath string
|
||||
webBasePath string
|
||||
webLoginPath string
|
||||
webLogoutPath string
|
||||
webUsersPath string
|
||||
webUserPath string
|
||||
webConnectionsPath string
|
||||
webFoldersPath string
|
||||
webFolderPath string
|
||||
webStatusPath string
|
||||
webAdminsPath string
|
||||
webAdminPath string
|
||||
webMaintenancePath string
|
||||
webBackupPath string
|
||||
webRestorePath string
|
||||
webScanVFolderPath string
|
||||
webQuotaScanPath string
|
||||
webChangeAdminPwdPath string
|
||||
webTemplateUser string
|
||||
webTemplateFolder string
|
||||
webStaticFilesPath string
|
||||
)
|
||||
|
||||
func init() {
|
||||
updateWebAdminURLs("")
|
||||
}
|
||||
|
||||
// Binding defines the configuration for a network listener
|
||||
type Binding struct {
|
||||
// The address to listen on. A blank value means listen on all available network interfaces.
|
||||
|
@ -153,6 +180,9 @@ type Conf struct {
|
|||
StaticFilesPath string `json:"static_files_path" mapstructure:"static_files_path"`
|
||||
// Path to the backup directory. This can be an absolute path or a path relative to the config dir
|
||||
BackupsPath string `json:"backups_path" mapstructure:"backups_path"`
|
||||
// Defines a base URL for the web admin. If empty web admin resources will be available at the
|
||||
// root ("/") URI. If defined it must be an absolute URI or it will be ignored.
|
||||
WebAdminRoot string `json:"web_admin_root" mapstructure:"web_admin_root"`
|
||||
// If files containing a certificate and matching private key for the server are provided the server will expect
|
||||
// HTTPS connections.
|
||||
// Certificate and key files can be reloaded on demand sending a "SIGHUP" signal on Unix based systems and a
|
||||
|
@ -199,6 +229,7 @@ func (c *Conf) Initialize(configDir string) error {
|
|||
certificateFile := getConfigPath(c.CertificateFile, configDir)
|
||||
certificateKeyFile := getConfigPath(c.CertificateKeyFile, configDir)
|
||||
if enableWebAdmin {
|
||||
updateWebAdminURLs(c.WebAdminRoot)
|
||||
loadTemplates(templatesPath)
|
||||
} else {
|
||||
logger.Info(logSender, "", "built-in web interface disabled, please set templates_path and static_files_path to enable it")
|
||||
|
@ -298,6 +329,33 @@ func fileServer(r chi.Router, path string, root http.FileSystem) {
|
|||
})
|
||||
}
|
||||
|
||||
func updateWebAdminURLs(baseURL string) {
|
||||
if !path.IsAbs(baseURL) {
|
||||
baseURL = "/"
|
||||
}
|
||||
webRootPath = path.Join(baseURL, webRootPathDefault)
|
||||
webBasePath = path.Join(baseURL, webBasePathDefault)
|
||||
webLoginPath = path.Join(baseURL, webLoginPathDefault)
|
||||
webLogoutPath = path.Join(baseURL, webLogoutPathDefault)
|
||||
webUsersPath = path.Join(baseURL, webUsersPathDefault)
|
||||
webUserPath = path.Join(baseURL, webUserPathDefault)
|
||||
webConnectionsPath = path.Join(baseURL, webConnectionsPathDefault)
|
||||
webFoldersPath = path.Join(baseURL, webFoldersPathDefault)
|
||||
webFolderPath = path.Join(baseURL, webFolderPathDefault)
|
||||
webStatusPath = path.Join(baseURL, webStatusPathDefault)
|
||||
webAdminsPath = path.Join(baseURL, webAdminsPathDefault)
|
||||
webAdminPath = path.Join(baseURL, webAdminPathDefault)
|
||||
webMaintenancePath = path.Join(baseURL, webMaintenancePathDefault)
|
||||
webBackupPath = path.Join(baseURL, webBackupPathDefault)
|
||||
webRestorePath = path.Join(baseURL, webRestorePathDefault)
|
||||
webScanVFolderPath = path.Join(baseURL, webScanVFolderPathDefault)
|
||||
webQuotaScanPath = path.Join(baseURL, webQuotaScanPathDefault)
|
||||
webChangeAdminPwdPath = path.Join(baseURL, webChangeAdminPwdPathDefault)
|
||||
webTemplateUser = path.Join(baseURL, webTemplateUserDefault)
|
||||
webTemplateFolder = path.Join(baseURL, webTemplateFolderDefault)
|
||||
webStaticFilesPath = path.Join(baseURL, webStaticFilesPathDefault)
|
||||
}
|
||||
|
||||
// GetHTTPRouter returns an HTTP handler suitable to use for test cases
|
||||
func GetHTTPRouter() http.Handler {
|
||||
b := Binding{
|
||||
|
|
|
@ -257,6 +257,7 @@ func (s *httpdServer) initializeRouter() {
|
|||
|
||||
s.router.Use(saveConnectionAddress)
|
||||
s.router.Use(middleware.GetHead)
|
||||
s.router.Use(middleware.StripSlashes)
|
||||
|
||||
s.router.Group(func(r chi.Router) {
|
||||
r.Get(healthzPath, func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -334,7 +335,7 @@ func (s *httpdServer) initializeRouter() {
|
|||
})
|
||||
|
||||
if s.enableWebAdmin {
|
||||
router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
router.Get(webRootPath, func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, webLoginPath, http.StatusMovedPermanently)
|
||||
})
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ type basePage struct {
|
|||
FolderQuotaScanURL string
|
||||
StatusURL string
|
||||
MaintenanceURL string
|
||||
StaticURL string
|
||||
UsersTitle string
|
||||
AdminsTitle string
|
||||
ConnectionsTitle string
|
||||
|
@ -182,6 +183,7 @@ type loginPage struct {
|
|||
Version string
|
||||
Error string
|
||||
CSRFToken string
|
||||
StaticURL string
|
||||
}
|
||||
|
||||
type userTemplateFields struct {
|
||||
|
@ -290,6 +292,7 @@ func getBasePageData(title, currentURL string, r *http.Request) basePage {
|
|||
StatusURL: webStatusPath,
|
||||
FolderQuotaScanURL: webScanVFolderPath,
|
||||
MaintenanceURL: webMaintenancePath,
|
||||
StaticURL: webStaticFilesPath,
|
||||
UsersTitle: pageUsersTitle,
|
||||
AdminsTitle: pageAdminsTitle,
|
||||
ConnectionsTitle: pageConnectionsTitle,
|
||||
|
@ -1030,6 +1033,7 @@ func renderLoginPage(w http.ResponseWriter, error string) {
|
|||
Version: version.Get().Version,
|
||||
Error: error,
|
||||
CSRFToken: createCSRFToken(),
|
||||
StaticURL: webStaticFilesPath,
|
||||
}
|
||||
renderTemplate(w, templateLogin, data)
|
||||
}
|
||||
|
|
|
@ -165,6 +165,7 @@
|
|||
"templates_path": "templates",
|
||||
"static_files_path": "static",
|
||||
"backups_path": "backups",
|
||||
"web_admin_root": "",
|
||||
"certificate_file": "",
|
||||
"certificate_key_file": "",
|
||||
"ca_certificates": [],
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/static/vendor/fonts/Roboto-Bold-webfont.woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/static/vendor/fonts/Roboto-Regular-webfont.woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/static/vendor/fonts/Roboto-Light-webfont.woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
|
@ -3,11 +3,11 @@
|
|||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="/static/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
|
@ -83,15 +83,15 @@
|
|||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="/static/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="/static/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="/static/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="/static/vendor/datatables/ellipsis.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/ellipsis.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function deleteAction() {
|
||||
|
|
|
@ -12,16 +12,36 @@
|
|||
|
||||
<title>SFTPGo - {{template "title" .}}</title>
|
||||
|
||||
<link rel="shortcut icon" href="/static/favicon.ico" />
|
||||
<link rel="shortcut icon" href="{{.StaticURL}}/favicon.ico" />
|
||||
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="/static/vendor/fontawesome-free/css/fontawesome.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="/static/vendor/fontawesome-free/css/solid.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="/static/css/fonts.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/fontawesome-free/css/fontawesome.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="{{.StaticURL}}/vendor/fontawesome-free/css/solid.min.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<!-- Custom styles for this template-->
|
||||
<link href="/static/css/sb-admin-2.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/css/sb-admin-2.min.css" rel="stylesheet">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('{{.StaticURL}}/vendor/fonts/Roboto-Bold-webfont.woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('{{.StaticURL}}/vendor/fonts/Roboto-Regular-webfont.woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('{{.StaticURL}}/vendor/fonts/Roboto-Light-webfont.woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.dt-buttons {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
@ -212,14 +232,14 @@
|
|||
{{block "dialog" .}}{{end}}
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
<script src="/static/vendor/jquery/jquery.min.js"></script>
|
||||
<script src="/static/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/jquery/jquery.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="/static/vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="/static/js/sb-admin-2.min.js"></script>
|
||||
<script src="{{.StaticURL}}/js/sb-admin-2.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function fixedEncodeURIComponent(str) {
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="/static/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
|
@ -20,7 +20,6 @@
|
|||
<h6 class="m-0 font-weight-bold text-primary">View and manage connections</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{if .Connections}}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered nowrap" id="dataTable" width="100%" cellspacing="0">
|
||||
<thead>
|
||||
|
@ -45,11 +44,6 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="card mb-2 border-left-info">
|
||||
<div class="card-body">No user connected</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
@ -82,14 +76,14 @@
|
|||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="/static/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="/static/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="/static/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function disconnectAction() {
|
||||
|
@ -151,6 +145,9 @@
|
|||
"scrollX": false,
|
||||
"scrollY": false,
|
||||
"responsive": true,
|
||||
"language": {
|
||||
"emptyTable": "No user connected"
|
||||
},
|
||||
"order": [[1, 'asc']]
|
||||
});
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="/static/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
|
@ -81,15 +81,15 @@
|
|||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="/static/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="/static/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="/static/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="/static/vendor/datatables/ellipsis.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/ellipsis.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function deleteAction() {
|
||||
|
@ -241,6 +241,9 @@ function deleteAction() {
|
|||
"scrollX": false,
|
||||
"scrollY": false,
|
||||
"responsive": true,
|
||||
"language": {
|
||||
"emptyTable": "No folder defined"
|
||||
},
|
||||
"order": [[0, 'asc']]
|
||||
});
|
||||
|
||||
|
|
|
@ -11,14 +11,40 @@
|
|||
|
||||
<title>SFTPGo - Login</title>
|
||||
|
||||
<link rel="shortcut icon" href="/static/favicon.ico" />
|
||||
|
||||
<!-- Custom fonts for this template-->
|
||||
<link href="/static/css/fonts.css" rel="stylesheet">
|
||||
<link rel="shortcut icon" href="{{.StaticURL}}/favicon.ico" />
|
||||
|
||||
<!-- Custom styles for this template-->
|
||||
<link href="/static/css/sb-admin-2.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/css/sb-admin-2.min.css" rel="stylesheet">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('{{.StaticURL}}/vendor/fonts/Roboto-Bold-webfont.woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('{{.StaticURL}}/vendor/fonts/Roboto-Regular-webfont.woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('{{.StaticURL}}/vendor/fonts/Roboto-Light-webfont.woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
div.dt-buttons {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.text-form-error {
|
||||
color: var(--red) !important;
|
||||
}
|
||||
|
||||
div.dt-buttons {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
@ -94,14 +120,14 @@
|
|||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript-->
|
||||
<script src="/static/vendor/jquery/jquery.min.js"></script>
|
||||
<script src="/static/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/jquery/jquery.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Core plugin JavaScript-->
|
||||
<script src="/static/vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/jquery-easing/jquery.easing.min.js"></script>
|
||||
|
||||
<!-- Custom scripts for all pages-->
|
||||
<script src="/static/js/sb-admin-2.min.js"></script>
|
||||
<script src="{{.StaticURL}}/js/sb-admin-2.min.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="/static/vendor/tempusdominus/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/tempusdominus/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
|
@ -423,8 +423,8 @@
|
|||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="/static/vendor/moment/js/moment.min.js"></script>
|
||||
<script src="/static/vendor/tempusdominus/js/tempusdominus-bootstrap-4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/moment/js/moment.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/tempusdominus/js/tempusdominus-bootstrap-4.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
{{define "title"}}{{.Title}}{{end}}
|
||||
|
||||
{{define "extra_css"}}
|
||||
<link href="/static/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="/static/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/fixedHeader.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.css" rel="stylesheet">
|
||||
<link href="{{.StaticURL}}/vendor/datatables/select.bootstrap4.min.css" rel="stylesheet">
|
||||
{{end}}
|
||||
|
||||
{{define "page_body"}}
|
||||
|
@ -84,15 +84,15 @@
|
|||
{{end}}
|
||||
|
||||
{{define "extra_js"}}
|
||||
<script src="/static/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="/static/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="/static/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="/static/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="/static/vendor/datatables/ellipsis.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/buttons.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.fixedHeader.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/responsive.bootstrap4.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/dataTables.select.min.js"></script>
|
||||
<script src="{{.StaticURL}}/vendor/datatables/ellipsis.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function deleteAction() {
|
||||
|
@ -262,6 +262,9 @@
|
|||
"scrollX": false,
|
||||
"scrollY": false,
|
||||
"responsive": true,
|
||||
"language": {
|
||||
"emptyTable": "No user defined"
|
||||
},
|
||||
"order": [[1, 'asc']]
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue