WebClient: various UI/UX improvements

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2023-12-26 08:59:52 +01:00
parent 723c15fb3e
commit a9341d7c0f
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
21 changed files with 578 additions and 225 deletions

8
go.mod
View file

@ -16,7 +16,7 @@ require (
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.9
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.19.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.6
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0
github.com/aws/aws-sdk-go-v2/service/sts v1.26.6
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/cockroachdb/cockroach-go/v2 v2.3.5
@ -109,7 +109,7 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.1 // indirect
github.com/go-logr/logr v1.4.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
@ -165,7 +165,7 @@ require (
go.opentelemetry.io/otel/metric v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.21.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/text v0.14.0 // indirect
@ -176,7 +176,7 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/grpc v1.60.1 // indirect
google.golang.org/protobuf v1.31.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

16
go.sum
View file

@ -65,8 +65,8 @@ github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.19.5 h1:Fp3Gcbp3lAJA
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.19.5/go.mod h1:XABJbVXMa0xnVqaGbhkfUeVV0GrPsc3Jqscu87IovXU=
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7 h1:o0ASbVwUAIrfp/WcCac+6jioZt4Hd8k/1X8u7GJ/QeM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.6 h1:L9Cu6ejuozkr5ipYnaXuRBZoyaFIIXZiurN4gUrQL+U=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.6/go.mod h1:4Ae1NCLK6ghmjzd45Tc33GgCKhUWD2ORAlULtMO1Cbs=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0 h1:dPCRgAL4WD9tSMaDglRNGOiAtSTjkwNiUW5GDpWFfHA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.26.0/go.mod h1:4Ae1NCLK6ghmjzd45Tc33GgCKhUWD2ORAlULtMO1Cbs=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM=
@ -154,8 +154,8 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.0 h1:wx+BduGRXjIL6VPeeb7DRX+ii7sR/ch8DlRifHR589o=
github.com/go-logr/logr v1.4.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@ -432,8 +432,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
gocloud.dev v0.35.0 h1:x/Gtt5OJdT4j+ir1AXAIXb7bBnFawXAAaJptCUGk3HU=
gocloud.dev v0.35.0/go.mod h1:wbyF+BhfdtLWyUtVEWRW13hFLb1vXnV2ovEhYGQe3ck=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@ -558,8 +558,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -53,7 +53,8 @@
"reset_pwd_err_generic": "Unexpected error while resetting password",
"reset_ok_login_error": "The password reset completed successfully but an unexpected error occurred while signing in",
"ip_not_allowed": "Login is not allowed from this IP address",
"two_factor_required": "Set up two-factor authentication, it is required for the following protocols: {{val}}"
"two_factor_required": "Set up two-factor authentication, it is required for the following protocols: {{val}}",
"link": "Go to {{link}}"
},
"theme": {
"light": "Light",
@ -72,7 +73,7 @@
"error_edit_dir": "Cannot edit a directory",
"error_edit_size": "The file size exceeds the maximum allowed size",
"invalid_form": "Invalid form",
"invalid_credentials": "Invalid credentials",
"invalid_credentials": "Invalid credentials, please retry",
"invalid_csrf": "The form token is not valid",
"invalid_token": "Invalid permissions",
"confirm_logout": "Are you sure you want to sign out?",
@ -80,7 +81,7 @@
"or": "or",
"ok": "OK",
"none": "None",
"cancel": "Cancel",
"cancel": "No, back",
"submit": "Save",
"back": "Back",
"add": "Add",
@ -91,9 +92,10 @@
"configuration": "Configuration",
"config_saved": "Configuration saved",
"rename": "Rename",
"confirm": "Confirm",
"confirm": "Yes, proceed",
"edit": "Edit",
"delete": "Delete",
"delete_confirm_btn": "Yes, delete",
"delete_confirm": "Do you want to delete \"{{- name}}\"? This action is irreversible",
"delete_confirm_generic": "Do you want to delete the selected item? This action is irreversible",
"delete_multi_confirm": "Do you want to delete the selected items? This action is irreversible",
@ -124,8 +126,6 @@
"pub_key_placeholder": "Paste your public key here",
"verify": "Verify",
"problems": "Having problems?",
"generate": "Generate",
"view": "View",
"allowed_ip_mask": "Allowed IP/Mask",
"allowed_ip_mask_help": "Comma separated IP/Mask in CIDR format, for example \"192.168.1.0/24,10.8.0.100/32\"",
"allowed_ip_mask_invalid": "Invalid allowed IP/Mask",
@ -144,7 +144,9 @@
"err_quota_read": "Read denied due to quota limit",
"profile_updated": "Your profile has been successfully updated",
"share_ok": "Share access successful, you can now use your link",
"qr_code": "QR Code"
"qr_code": "QR Code",
"copy_link": "Copy link",
"copied": "Copied"
},
"fs": {
"view_file": "View file \"{{- path}}\"",
@ -212,6 +214,7 @@
"err_429": "$t(fs.move.err_generic). $t(fs.err_429)"
},
"rename": {
"title": "Rename \"{{- name}}\"",
"new_name": "New name",
"err_generic": "Unable to rename \"{{- name}}\"",
"err_403": "$t(fs.rename.err_generic). $t(fs.err_403)",
@ -260,7 +263,7 @@
"msg_disabled": "Secure Your Account",
"msg_info": "Two-factor authentication adds an extra layer of security to your account. To log in you'll need to provide an additional authentication code.",
"require_for": "Require 2FA for",
"generate": "Generate new secret",
"generate": "Generate new secret key",
"recovery_codes": "Recovery codes",
"new_recovery_codes": "New recovery codes",
"recovery_codes_msg1": "Recovery codes are a set of one time use codes that can be used in place of the authentication code to login to the web UI. You can use them if you lose access to your phone to login to your account and disable or regenerate two-factor auth configuration.",
@ -275,7 +278,7 @@
"setup_msg": "Use your preferred Authenticator App (e.g. Microsoft Authenticator, Google Authenticator, Authy, 1Password etc. ) to scan the QR code. It will generate an authentication code for you to enter below.",
"setup_help": "If you have trouble using the QR code, select manual entry on your app, and enter the code:",
"disable_question": "Do you want to disable two-factor authentication?",
"generate_question": "Do you want to generate a new secret and invalidate the previous one? Any registered Authenticator App will stop working",
"generate_question": "Do you want to generate a new secret key and invalidate the previous one? Any registered Authenticator App will stop working",
"disabled": "Two-factor authentication is disabled",
"recovery_codes_gen_err": "Failed to generate new recovery codes",
"recovery_codes_get_err": "Unable to obtain recovery codes",
@ -284,7 +287,9 @@
"save_err": "Failed to save configuration",
"auth_code_required": "The authentication code is required",
"no_protocol": "Please select at least a protocol",
"required_protocols": "The following protocols are required: {{val}}"
"required_protocols": "The security policy configured for your account requires two-factor authentication for the following protocols: {{val}}",
"recovery_codes_generate": "Generate new recovery codes",
"recovery_codes_view": "View recovery codes"
},
"share": {
"scope": "Scope",
@ -319,7 +324,17 @@
"usage_exceed": "Maximum sharing usage exceeded",
"expired": "Sharing has expired",
"browsable_multiple_paths": "A share with multiple paths is not browsable",
"browsable_non_dir": "The share is not a directory so it is not browsable"
"browsable_non_dir": "The share is not a directory so it is not browsable",
"go": "Go to share",
"access_links_title": "Share access links",
"link_single_title": "Single zip file",
"link_single_desc": "You can download the shared content as a single zip file",
"link_dir_title": "Single directory",
"link_dir_desc": "If the share consists of a single directory, you can browse and download files",
"link_uncompressed_title": "Uncompressed file",
"link_uncompressed_desc": "If the share consists of a single file, it can also be downloaded uncompressed",
"upload_desc": "You can upload one or more files to the shared directory",
"expired_desc": "This share is no longer accessible because it has expired"
},
"select2": {
"no_results": "No results found",

View file

@ -53,7 +53,8 @@
"reset_pwd_err_generic": "Errore imprevisto durante la reimpostazione della password",
"reset_ok_login_error": "La reimpostazione della password è stata completata correttamente ma si è verificato un errore imprevisto durante l'accesso",
"ip_not_allowed": "L'accesso non è consentito da questo indirizzo IP",
"two_factor_required": "Configura l'autenticazione a due fattori, è obbligatoria per i seguenti protocolli: {{val}}"
"two_factor_required": "Configura l'autenticazione a due fattori, è obbligatoria per i seguenti protocolli: {{val}}",
"link": "Vai a {{link}}"
},
"theme": {
"light": "Chiaro",
@ -72,7 +73,7 @@
"error_edit_dir": "Impossibile modificare una cartella",
"error_edit_size": "La dimensione del file supera la dimensione massima consentita",
"invalid_form": "Modulo non valido",
"invalid_credentials": "Credenziali non valide",
"invalid_credentials": "Credenziali non valide, riprovare",
"invalid_csrf": "Il token del modulo non è valido",
"invalid_token": "Permessi non validi",
"confirm_logout": "Sei sicuro di volerti disconnettere?",
@ -80,7 +81,7 @@
"or": "o",
"ok": "OK",
"none": "Nessuna",
"cancel": "Annulla",
"cancel": "No, indietro",
"submit": "Salva",
"back": "Indietro",
"add": "Aggiungi",
@ -91,9 +92,10 @@
"configuration": "Configurazione",
"config_saved": "Configurazione salvata",
"rename": "Rinomina",
"confirm": "Conferma",
"confirm": "Si, procedi",
"edit": "Modifica",
"delete": "Elimina",
"delete_confirm_btn": "Si, elimina",
"delete_confirm": "Vuoi eliminare \"{{- name}}\"? Questa azione è irreversibile",
"delete_confirm_generic": "Vuoi eliminare l'elemento selezionato? Questa azione è irreversibile",
"delete_multi_confirm": "Vuoi eliminare gli elementi selezionati? Questa azione è irreversibile",
@ -124,8 +126,6 @@
"pub_key_placeholder": "Incolla qui la tua chiave pubblica",
"verify": "Verifica",
"problems": "Hai problemi?",
"generate": "Genera",
"view": "Visualizza",
"allowed_ip_mask": "IP/Reti permesse",
"allowed_ip_mask_help": "IP/reti separate da virgola in formato CIDR, ad esempio \"192.168.1.0/24,10.8.0.100/32\"",
"allowed_ip_mask_invalid": "IP/reti permesse non valide",
@ -144,7 +144,9 @@
"err_quota_read": "Lettura negata a causa del limite di quota",
"profile_updated": "Il tuo profilo è stato aggiornato con successo",
"share_ok": "Accesso alla condivisione riuscito, ora puoi utilizzare il tuo collegamento",
"qr_code": "Codice QR"
"qr_code": "Codice QR",
"copy_link": "Copia collegamento",
"copied": "Copiato"
},
"fs": {
"view_file": "Visualizza file \"{{- path}}\"",
@ -212,6 +214,7 @@
"err_429": "$t(fs.move.err_generic). $t(fs.err_429)"
},
"rename": {
"title": "Rinomina \"{{- name}}\"",
"new_name": "Nuovo nome",
"err_generic": "Impossibile rinominare \"{{- name}}\"",
"err_403": "$t(fs.rename.err_generic): $t(fs.err_403)",
@ -260,7 +263,7 @@
"msg_disabled": "Metti il tuo account in sicurezza",
"msg_info": "L'autenticazione a due fattori aggiunge un ulteriore livello di sicurezza al tuo account. Per accedere dovrai fornire un ulteriore codice di autenticazione.",
"require_for": "Richiedi 2FA per",
"generate": "Genera nuovo segreto",
"generate": "Genera una nuova chiave segreta",
"recovery_codes": "Codici di ripristino",
"new_recovery_codes": "Nuovi codici di ripristino",
"recovery_codes_msg1": "I codici di ripristino sono un insieme di codici monouso che possono essere utilizzati al posto del codice di autenticazione per accedere all'interfaccia utente Web. Puoi utilizzarli se perdi l'accesso al tuo telefono per accedere al tuo account e disabilitare o rigenerare la configurazione dell'autenticazione a due fattori.",
@ -275,7 +278,7 @@
"setup_msg": "Utilizza la tua app di autenticazione preferita (ad esempio Microsoft Authenticator, Google Authenticator, Authy, 1Password ecc.) per scansionare il codice QR. Verrà generato un codice di autenticazione da inserire di seguito.",
"setup_help": "Se hai problemi con l'utilizzo del codice QR, seleziona l'inserimento manuale sulla tua app e inserisci il codice:",
"disable_question": "Vuoi disattivare l'autenticazione a due fattori?",
"generate_question": "Vuoi generare un nuovo segreto e invalidare quello precedente? Qualsiasi app di autenticazione registrata smetterà di funzionare",
"generate_question": "Vuoi generare un nuova chiave segreta e invalidare quella precedente? Qualsiasi app di autenticazione registrata smetterà di funzionare",
"disabled": "L'autenticazione a due fattori è disabilitata",
"recovery_codes_gen_err": "Impossibile generare nuovi codici di ripristino",
"recovery_codes_get_err": "Impossibile ottenere i codici di ripristino",
@ -284,7 +287,9 @@
"save_err": "Impossibile salvare la configurazione",
"auth_code_required": "Il codice di autenticazione è obbligatorio",
"no_protocol": "Seleziona almeno un protocollo",
"required_protocols": "I seguenti protocolli sono obbligatori: {{val}}"
"required_protocols": "La politica di sicurezza configurata per il tuo account richiede l'autenticazione a due fattori per i seguenti protocolli: {{val}}",
"recovery_codes_generate": "Genera nuovi codici di ripristino",
"recovery_codes_view": "Visualizza codici di ripristino"
},
"share": {
"scope": "Ambito",
@ -319,7 +324,17 @@
"usage_exceed": "Utilizzo massimo della condivisione superato",
"expired": "La condivisione è scaduta",
"browsable_multiple_paths": "Una condivisione con più percorsi non è navigabile",
"browsable_non_dir": "La condivisione non è una directory quindi non è navigabile"
"browsable_non_dir": "La condivisione non è una directory quindi non è navigabile",
"go": "Vai alla condivisione",
"access_links_title": "Accesso alla condivisione",
"link_single_title": "File zip singolo",
"link_single_desc": "È possibile scaricare il contenuto condiviso come un singolo file zip",
"link_dir_title": "Directory singola",
"link_dir_desc": "Se la condivisione è costituita da un'unica directory, è possibile navigarla e scaricare file",
"link_uncompressed_title": "File non compresso",
"link_uncompressed_desc": "Se la condivisione è costituita da un unico file è possibile scaricarlo anche non compresso",
"upload_desc": "È possibile caricare uno o più file nella directory condivisa",
"expired_desc": "Questa condivisione non è più accessibile perché è scaduta"
},
"select2": {
"no_results": "Nessun risultato trovato",

View file

@ -15,7 +15,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
-->
{{- define "errmsg"}}
<div id="errorMsg" class="{{if not . }}d-none {{end}}rounded border-warning border border-dashed bg-light-warning d-flex align-items-center p-5 mb-10">
<i class="ki-duotone ki-information fs-3x text-warning me-5">
<i class="ki-duotone ki-information-5 fs-3x text-warning me-5">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
@ -24,10 +24,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<span {{if .}}data-i18n="{{.Message}}" {{if .HasArgs}}data-i18n-options="{{.Args}}"{{end}}{{end}} id="errorTxt"></span>
</div>
<button id="id_dismiss_error_msg" type="button" class="position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 btn btn-icon btn-sm btn-active-light-primary ms-sm-auto">
<i class="ki-duotone ki-cross fs-2x text-primary">
<span class="path1"></span>
<span class="path2"></span>
</i>
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</button>
</div>
{{- end}}
@ -231,6 +228,33 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
el.localize(options);
}
function handlePasswordInputVisibility(el) {
let pwdVisibility = el.querySelector('[data-password-control="visibility"]');
let passwordInput = el.querySelector('[data-password-control="input"]');
pwdVisibility.addEventListener('click', function(){
let visibleIcon = this.querySelector(':scope > i:not(.d-none)');
let hiddenIcon = this.querySelector(':scope > i.d-none');
visibleIcon.classList.add('d-none');
hiddenIcon.classList.remove('d-none');
if (passwordInput){
if (passwordInput.getAttribute('type').toLowerCase() === 'password' ) {
passwordInput.setAttribute('type', 'text');
} else {
passwordInput.setAttribute('type', 'password');
}
passwordInput.focus();
}
});
}
function getCurrentURI(){
let port = window.location.port;
if (port){
return window.location.protocol+"//"+window.location.hostname+":"+port;
}
return window.location.protocol+"//"+window.location.hostname;
}
KTUtil.onDOMContentLoaded(function () {
var dismissErrorBtn = $('#id_dismiss_error_msg');
if (dismissErrorBtn){
@ -246,6 +270,10 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
});
}
document.querySelectorAll('[data-password-control="container"]').forEach(el => {
handlePasswordInputVisibility(el);
});
initLocalizer();
});
</script>
@ -268,6 +296,18 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
.line-through {
text-decoration: line-through;
}
.section-title {
color: var(--bs-text-gray-800);
font-weight: 600 !important;
font-size: 1.45rem !important;
}
.section-title-inner {
color: var(--bs-text-gray-800);
font-weight: 600 !important;
font-size: 1.3rem !important;
}
</style>
{{- end}}

View file

@ -297,17 +297,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="toast-container position-fixed top-0 end-0 p-3">
<div id="toast_container" class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="false">
<div class="toast-body border-0 d-flex align-items-center">
<i class="ki-duotone ki-information fs-3x text-warning me-5">
<i class="ki-duotone ki-information-5 fs-3x text-warning me-5">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
<span id="toast_msg" class="fs-5 fw-semibold text-gray-800 me-auto"></span>
<button data-i18n="[aria-label]general.close" type="button" class="btn btn-icon btn-sm btn-close position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 ms-sm-auto" data-bs-dismiss="toast" aria-label="Close">
<i class="ki-duotone ki-cross fs-2x text-primary">
<span class="path1"></span>
<span class="path2"></span>
</i>
<button data-i18n="[aria-label]general.close" type="button" class="btn btn-icon btn-sm btn-active-light-primary position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 ms-sm-auto" data-bs-dismiss="toast" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</button>
</div>
</div>
@ -382,17 +379,16 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
switch (params.icon){
case "warning":
$("#modal_alert_icon").html(`<i class="ki-duotone ki-information fs-5x text-danger">
$("#modal_alert_icon").html(`<i class="ki-duotone ki-information-5 fs-5x text-danger">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>`);
break;
case "success":
$("#modal_alert_icon").html(`<i class="ki-duotone ki-information-2 fs-5x text-success">
$("#modal_alert_icon").html(`<i class="ki-duotone ki-check-square fs-5x text-success">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>`);
break;
default:

View file

@ -18,7 +18,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- define "page_body"}}
<div class="card shadow-sm">
<div class="card-header bg-light">
<h3 data-i18n="title.change_password" class="card-title text-primary">Change password</h3>
<h3 data-i18n="title.change_password" class="card-title section-title">Change password</h3>
</div>
<div class="card-body">
<div class="notice d-flex bg-light-primary rounded border-primary border border-dashed p-6 mb-5">
@ -41,22 +41,67 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="form-group row">
<label data-i18n="change_pwd.current" class="col-md-3 col-form-label required">Current password</label>
<div class="col-md-9">
<input type="password" class="form-control" placeholder="" name="current_password"
spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input type="password" data-password-control="input" class="form-control" placeholder=""
name="current_password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
</div>
</div>
<div class="form-group row mt-10">
<label data-i18n="change_pwd.new" class="col-md-3 col-form-label required">New password</label>
<div class="col-md-9">
<input type="password" class="form-control" placeholder="" name="new_password1"
autocomplete="new-password" spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input type="password" data-password-control="input" class="form-control" placeholder=""
name="new_password1" autocomplete="new-password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
</div>
</div>
<div class="form-group row mt-10">
<label data-i18n="change_pwd.confirm" class="col-md-3 col-form-label required">Confirm password</label>
<div class="col-md-9">
<input type="password" class="form-control" placeholder="" name="new_password2"
autocomplete="new-password" spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input type="password" data-password-control="input" class="form-control" placeholder=""
name="new_password2" autocomplete="new-password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
</div>
</div>
<div class="d-flex justify-content-end mt-12">

View file

@ -42,7 +42,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- template "errmsg" ""}}
<div class="card shadow-sm">
<div class="card-header">
<h6 id="card_title" class="card-title"></h6>
<h6 id="card_title" class="card-title section-title"></h6>
<div class="card-toolbar">
<a data-i18n="general.back" class="btn btn-light-primary px-10 me-5" href='{{.FilesURL}}?path={{.CurrentDir}}' role="button">Back</a>
{{- if not .ReadOnly}}
@ -68,8 +68,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-content">
<div class="modal-header">
<h3 data-i18n="editor.keybinding" class="modal-title">Editor keybindings</h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary ms-2" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body">

View file

@ -49,7 +49,25 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</button>
{{- end}}
</div>
<div class="d-flex justify-content-end align-items-center d-none" data-kt-filemanager-table-toolbar="selected">
</div>
</div>
<div class="card-body">
<div class="d-flex flex-stack">
<div class="badge badge-lg badge-light-primary" data-kt-filemanager-table-nav-bar="base">
<div class="d-flex align-items-center flex-wrap">
<i class="ki-duotone ki-home fs-1 text-primary me-3"></i>
<a data-i18n="fs.home" href="{{.FilesURL}}?path=%2F">Home</a>
{{- range .Paths}}
<i class="ki-duotone ki-right fs-2x text-primary mx-1"></i>
{{- if eq .Href ""}}
<span>{{.DirName}}</span>
{{- else}}
<a href="{{.Href}}">{{.DirName}}</a>
{{- end}}
{{- end}}
</div>
</div>
<div class="d-flex align-items-center d-none" data-kt-filemanager-table-toolbar="selected">
<div class="fw-bold me-5">
<span class="me-2" data-kt-filemanager-table-select="selected_count"></span>
</div>
@ -101,25 +119,10 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}}
</div>
</div>
</div>
<div class="card-body">
<div class="d-flex flex-stack">
<div class="badge badge-lg badge-light-primary">
<div class="d-flex align-items-center flex-wrap">
<i class="ki-duotone ki-home fs-1 text-primary me-3"></i>
<a data-i18n="fs.home" href="{{.FilesURL}}?path=%2F">Home</a>
{{- range .Paths}}
<i class="ki-duotone ki-right fs-2x text-primary mx-1"></i>
{{- if eq .Href ""}}
<span>{{.DirName}}</span>
{{- else}}
<a href="{{.Href}}">{{.DirName}}</a>
{{- end}}
{{- end}}
</div>
</div>
<div class="new_folder_divider py-2 d-none">
<hr>
</div>
<div id="file_manager_new_folder" class="d-flex align-items-center py-7 d-none">
<div id="file_manager_new_folder" class="d-flex align-items-center d-none">
<span>
<i class="ki-duotone ki-folder fs-2x text-primary me-4">
<span class="path1"></span>
@ -136,15 +139,15 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</span>
</button>
<button class="btn btn-icon btn-light-danger" id="file_manager_cancel_folder">
<i class="ki-duotone ki-cross fs-1">
<span class="path1"></span>
<span class="path2"></span>
</i>
<i class="ki-solid ki-cross fs-1"></i>
</button>
</div>
<div class="new_folder_divider py-2 d-none">
<hr>
</div>
<table id="file_manager_list" class="table align-middle table-row-dashed fs-6 gy-5">
<thead>
<tr class="text-start text-muted fw-bold fs-6 gs-0">
<tr class="text-start text-muted fw-bold fs-6 gs-0 text-gray-500">
<th class="w-10px pe-2">
<div class="form-check form-check-sm form-check-custom form-check-solid me-3">
<input id="select_checkbox" class="form-check-input" type="checkbox"/>
@ -375,6 +378,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
submitButton.removeAttribute('data-kt-indicator');
submitButton.disabled = false;
cancelButton.disabled = false;
$('.dir_browser_folder_divider').addClass("d-none");
$('#dirsbrowser_new_folder').addClass("d-none");
}).catch(function (error) {
let errorMessage = "";
@ -770,7 +774,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}
function handleToogleToolbar(pageSelected, totalSelected) {
const toolbarBase = document.querySelector('[data-kt-filemanager-table-toolbar="base"]');
const navBar = document.querySelector('[data-kt-filemanager-table-nav-bar="base"]');
const toolbarSelected = document.querySelector('[data-kt-filemanager-table-toolbar="selected"]');
const selectedCount = document.querySelector('[data-kt-filemanager-table-select="selected_count"]');
const selectAllContainer = document.querySelector('[data-kt-filemanager-table-select="select_all_pages_container"]');
@ -789,8 +793,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
if (selectedCount){
selectedCount.innerHTML = $.t('general.selected_items', { count: totalSelected});
}
if (toolbarBase){
toolbarBase.classList.add('d-none');
if (navBar){
navBar.classList.add('d-none');
}
if (toolbarSelected){
toolbarSelected.classList.remove('d-none');
@ -798,10 +802,10 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
} else {
$('#select_checkbox').prop("checked", false);
selectAllCheck.checked = false;
if (toolbarBase) {
toolbarBase.classList.remove('d-none');
if (navBar) {
navBar.classList.remove('d-none');
}
if (toolbarBase) {
if (toolbarSelected) {
toolbarSelected.classList.add('d-none');
}
}
@ -961,7 +965,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
ModalAlert.fire({
text: $.t('general.delete_multi_confirm'),
icon: "warning",
confirmButtonText: $.t('general.delete'),
confirmButtonText: $.t('general.delete_confirm_btn'),
cancelButtonText: $.t('general.cancel'),
customClass: {
confirmButton: "btn btn-danger",
@ -1361,7 +1365,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
ModalAlert.fire({
text: $.t('general.delete_confirm', {name: itemName}),
icon: "warning",
confirmButtonText: $.t('general.delete'),
confirmButtonText: $.t('general.delete_confirm_btn'),
cancelButtonText: $.t('general.cancel'),
customClass: {
confirmButton: "btn btn-danger",
@ -1420,7 +1424,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
let oldName = getNameFromMeta(meta);
$('#rename_old_name').val(meta);
$('#rename_new_name').val(oldName);
$('#rename_title').text(`Rename "${oldName}"`);
$('#rename_title').text($.t('fs.rename.title', { name: oldName}));
$('#modal_rename').modal('show');
}
@ -1473,6 +1477,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
function showCreateNewFolder(sender) {
if (sender == 0) {
$('.new_folder_divider').removeClass("d-none");
$('#file_manager_new_folder').removeClass("d-none");
$('#errorMsg').addClass("d-none");
let el = $('#file_manager_new_folder_input');
@ -1480,6 +1485,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
el.focus();
return;
}
$('.dir_browser_folder_divider').removeClass("d-none");
$('#dirsbrowser_new_folder').removeClass("d-none");
$('#errorModalMsg').addClass("d-none");
let el = $('#dirsbrowser_new_folder_input');
@ -1489,8 +1495,10 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
function hideCreateNewFolder(sender) {
if (sender == 0){
$('.new_folder_divider').addClass("d-none");
$('#file_manager_new_folder').addClass("d-none");
} else {
$('.dir_browser_folder_divider').addClass("d-none");
$('#dirsbrowser_new_folder').addClass("d-none");
}
}
@ -1808,7 +1816,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- if $files}}
{{- $percentage := .QuotaUsage.GetQuotaFilesPercentage}}
<div class="{{if .QuotaUsage.IsQuotaFilesLow}}text-warning{{else}}text-gray-700{{end}} fw-semibold fs-6">
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.files_percentage" data-i18n-options='{ "val": "{{$files}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.files" data-i18n-options='{ "val": "{{$files}}" }'{{end}}></span>
<span {{if gt $percentage 0}}data-i18n="fs.quota_usage.files_percentage" data-i18n-options='{ "val": "{{$files}}", "percentage": {{$percentage}} }'{{else}}data-i18n="fs.quota_usage.files" data-i18n-options='{ "num": "{{$files}}" }'{{end}}></span>
</div>
{{- end}}
</div>
@ -1866,8 +1874,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-content">
<div class="modal-header border-0">
<h3 data-i18n="fs.upload.text" class="modal-title">Upload files</h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body">
@ -1900,8 +1908,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<h5 class="modal-title">
<span id="video_title"></span>
</h5>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
@ -1922,8 +1930,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<h5 class="modal-title">
<span id="rename_title"></span>
</h5>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
@ -1937,7 +1945,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-footer border-0">
<button data-i18n="general.cancel" type="button" class="btn btn-secondary me-5" data-bs-dismiss="modal">Cancel</button>
<button data-i18n="general.submit" id="id_do_rename_button" type="button" class="btn btn-primary" data-bs-dismiss="modal">Submit</button>
<button data-i18n="general.confirm" id="id_do_rename_button" type="button" class="btn btn-primary" data-bs-dismiss="modal">Submit</button>
</div>
</div>
</div>
@ -1950,19 +1958,19 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<h3 data-i18n="general.choose_target_folder" class="modal-title">
Choose target folder
</h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body">
<div id="errorModalMsg" class="d-none rounded border-warning border border-dashed bg-light-warning d-flex align-items-center p-5 mb-10">
<i class="ki-duotone ki-information fs-3x text-warning me-5"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i>
<i class="ki-duotone ki-information-5 fs-3x text-warning me-5"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i>
<div class="text-gray-700 fw-bold fs-5 d-flex flex-column pe-0 pe-sm-10">
<span id="errorModalTxt"></span>
</div>
<button id="id_dismiss_error_modal_msg" type="button" class="position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 btn btn-icon btn-sm btn-active-light-primary ms-sm-auto">
<i class="ki-duotone ki-cross fs-2x text-primary"><span class="path1"></span><span class="path2"></span></i>
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</button>
</div>
<div class="row">
@ -1982,7 +1990,10 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</button>
</div>
</div>
<div id="dirsbrowser_new_folder" class="d-flex align-items-center py-7 d-none">
<div class="dir_browser_folder_divider py-2 d-none">
<hr>
</div>
<div id="dirsbrowser_new_folder" class="d-flex align-items-center d-none">
<span>
<i class="ki-duotone ki-folder fs-2x text-primary me-4">
<span class="path1"></span>
@ -1999,13 +2010,12 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</span>
</button>
<button class="btn btn-icon btn-light-danger" id="dirsbrowser_cancel_folder">
<i class="ki-duotone ki-cross fs-1">
<span class="path1"></span>
<span class="path2"></span>
</i>
<i class="ki-solid ki-cross fs-1"></i>
</button>
</div>
<div class="dir_browser_folder_divider py-2 d-none">
<hr>
</div>
<table id="dirsbrowser_list" class="table align-middle table-row-dashed fs-6 gy-5">
<thead>
<tr class="text-start text-muted fw-bold fs-7 text-uppercase gs-0">

View file

@ -35,7 +35,22 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<input data-i18n="[placeholder]login.username" class="form-control form-control-lg form-control-solid" type="text" name="username" placeholder="Username" autocomplete="on" spellcheck="false" required />
</div>
<div class="fv-row mb-10">
<input data-i18n="[placeholder]login.password" class="form-control form-control-lg form-control-solid" type="password" name="password" placeholder="Password" autocomplete="current-password" spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input data-i18n="[placeholder]login.password" data-password-control="input" class="form-control form-control-lg form-control-solid" type="password" name="password" placeholder="Password" autocomplete="current-password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
<div class="d-flex justify-content-end mt-2">
{{- if .ForgotPwdURL}}
<a data-i18n="login.forgot_password" href="{{.ForgotPwdURL}}" class="link-primary fs-6 fw-bold">Forgot Password ?</a>
@ -65,14 +80,17 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}}
</div>
</form>
<div class=" d-flex flex-stack pt-5 mt-5">
<hr>
<div class="d-flex flex-stack pt-5 mt-3">
<div class="me-10">
<select id="languageSwitcher" name="language" class="form-select form-select-solid form-select-sm" data-control="i18n-select2" data-hide-search="true">
</select>
</div>
<div class="d-flex fw-semibold text-primary">
{{- if .AltLoginURL}}
<a href="{{.AltLoginURL}}" class="px-2">{{.AltLoginName}}</a>
<a href="{{.AltLoginURL}}" class="px-2">
<span data-i18n="login.link" data-i18n-options='{ "link": "{{.AltLoginName}}" }'></span>
</a>
{{- end}}
{{- if and .Branding.DisclaimerName .Branding.DisclaimerPath}}
<a href="{{.StaticURL}}{{.Branding.DisclaimerPath}}" target="_blank" class="px-2">

View file

@ -40,19 +40,19 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- end}}
<div class="card shadow-sm w-lg-600px">
<div class="card-header bg-light">
<h3 data-i18n="{{.Title}}" class="card-title text-primary"></h3>
<h3 data-i18n="{{.Title}}" class="card-title section-title"></h3>
</div>
<div class="card-body">
{{- if .Error}}
<div class="notice d-flex bg-light-warning rounded border-warning border border-dashed p-6">
<i class="ki-duotone ki-information fs-2tx text-warning me-4">
<i class="ki-duotone ki-information-5 fs-2tx text-warning me-4">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
<div class="d-flex flex-stack flex-grow-1 ">
<div class=" fw-semibold">
<div class="fs-5 text-gray-800">
<div class="fs-4 text-gray-800">
<span data-i18n="{{.Error.Message}}" {{if .Error.HasArgs}}data-i18n-options="{{.Error.Args}}"{{end}}></span>
</div>
</div>
@ -68,7 +68,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</i>
<div class="d-flex flex-stack flex-grow-1 ">
<div class=" fw-semibold">
<div class="fs-5 text-gray-800">
<div class="fs-4 text-gray-800">
<span data-i18n="{{.Success}}"></span>
</div>
</div>

View file

@ -16,11 +16,42 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{template "base" .}}
{{- define "page_body"}}
{{- if .TOTPConfig.Enabled}}
<div class="notice d-flex bg-light-primary rounded border-primary border border-dashed p-6 mb-5">
<i class="ki-duotone ki-shield-tick fs-2tx text-primary me-4">
<span class="path1"></span>
<span class="path2"></span>
</i>
<div class="d-flex flex-stack flex-grow-1 flex-wrap flex-md-nowrap">
<div class="mb-3 mb-md-0 fw-semibold">
<h4 class="text-gray-900 fw-bold">
<span data-i18n="2fa.msg_enabled"></span> {{- if gt (len .TOTPConfigs) 1 }}
({{$.TOTPConfig.ConfigName}}) {{- end}}
</h4>
<div class="fs-6 text-gray-800 pe-7">
<span data-i18n="2fa.msg_info"></span>
</div>
</div>
<button type="button" id="disable_btn" class="btn btn-danger ms-4 px-6 align-self-center text-nowrap">
<span data-i18n="general.disable" class="indicator-label">
Disable
</span>
<span data-i18n="general.wait" class="indicator-progress">
Please wait...
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
</span>
</button>
</div>
</div>
{{- end}}
<div class="card shadow-sm">
<div class="card-header bg-light">
<h3 data-i18n="2fa.title" class="card-title text-primary">Two-factor authentication using Authenticator apps</h3>
<h3 data-i18n="2fa.title" class="card-title section-title">Two-factor authentication using Authenticator apps</h3>
</div>
<div class="card-body">
{{- if not .TOTPConfig.Enabled}}
<div class="notice d-flex bg-light-primary rounded border-primary border border-dashed p-6 mb-5">
<i class="ki-duotone ki-shield-tick fs-2tx text-primary me-4">
<span class="path1"></span>
@ -29,33 +60,15 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="d-flex flex-stack flex-grow-1 flex-wrap flex-md-nowrap">
<div class="mb-3 mb-md-0 fw-semibold">
<h4 class="text-gray-900 fw-bold">
{{- if .TOTPConfig.Enabled}}
<span data-i18n="2fa.msg_enabled">Two-factor authentication is enabled</span> {{- if gt (len .TOTPConfigs) 1 }} ({{$.TOTPConfig.ConfigName}}) {{- end}}
{{- else}}
<span data-i18n="2fa.msg_disabled">Secure Your Account</span>
{{- end}}
</h4>
<div class="fs-6 text-gray-800 pe-7">
<span data-i18n="2fa.msg_info">
Two-factor authentication adds an extra layer of security to your account. To log in you'll need
to provide an additional authentication code.
</span>
<span data-i18n="2fa.msg_info"></span>
</div>
</div>
{{- if .TOTPConfig.Enabled}}
<button type="button" id="disable_btn" class="btn btn-danger ms-4 px-6 align-self-center text-nowrap">
<span data-i18n="general.disable" class="indicator-label">
Disable
</span>
<span data-i18n="general.wait" class="indicator-progress">
Please wait...
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
</span>
</button>
{{- end}}
</div>
</div>
{{- end}}
<div class="form-group row mt-10">
<label for="id_config" data-i18n="general.configuration" class="col-md-3 col-form-label">Configuration</label>
<div class="col-md-9">
@ -108,38 +121,40 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</div>
{{- if .TOTPConfig.Enabled}}
<div class="notice d-flex bg-light-primary rounded border-primary border border-dashed p-6 my-10">
<i class="ki-duotone ki-shield-tick fs-2tx text-primary me-4">
<span class="path1"></span>
<span class="path2"></span>
</i>
<div class="d-flex flex-stack flex-grow-1 flex-wrap flex-md-nowrap">
<div class="mb-3 mb-md-0 fw-semibold">
<h4 data-i18n="2fa.recovery_codes" class="text-gray-900 fw-bold">
Recovery codes
</h4>
<div class="fs-6 text-gray-800">
<p data-i18n="2fa.recovery_codes_msg1">Recovery codes are a set of one time use codes that can be used in place of the authentication code to login to the web UI. You can use them if you lose access to your phone to login to your account and disable or regenerate two-factor configuration.</p>
<p data-i18n="2fa.recovery_codes_msg2">To keep your account secure, don't share or distribute your recovery codes. We recommend saving them with a secure password manager.</p>
<p data-i18n="2fa.recovery_codes_msg3">If you generate new recovery codes, you automatically invalidate old ones.</p>
</div>
<div class="d-flex justify-content-center mt-10">
<button type="button" id="generate_recovery_code_btn" class="btn btn-primary px-10 me-10">
<span data-i18n="general.generate" class="indicator-label">
Generate
</span>
<span data-i18n="general.wait" class="indicator-progress">
Please wait...
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
</span>
</button>
<button type="button" id="view_recovery_code_btn" class="btn btn-primary px-10">
<span data-i18n="general.view" id="save_label" class="indicator-label">View</span>
<span data-i18n="general.wait" class="indicator-progress">
Please wait...
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
</span>
</button>
<div class="accordion shadow-sm my-10" id="id_accordion">
<div class="accordion-item">
<h2 class="accordion-header" id="accordion_rec_codes">
<button class="accordion-button section-title text-primary collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#accordion_rec_codes_body" aria-expanded="false" aria-controls="accordion_rec_codes_body">
<span data-i18n="2fa.recovery_codes">
Recovery codes
</span>
</button>
</h2>
<div id="accordion_rec_codes_body" class="accordion-collapse collapse" aria-labelledby="accordion_rec_codes" data-bs-parent="#id_accordion">
<div class="accordion-body">
<div class="fs-5 text-gray-800">
<p data-i18n="2fa.recovery_codes_msg1">Recovery codes are a set of one time use codes that can be used in place of the authentication code to login to the web UI. You can use them if you lose access to your phone to login to your account and disable or regenerate two-factor configuration.</p>
<p data-i18n="2fa.recovery_codes_msg2">To keep your account secure, don't share or distribute your recovery codes. We recommend saving them with a secure password manager.</p>
<p data-i18n="2fa.recovery_codes_msg3" class="fs-4 fw-bold">If you generate new recovery codes, you automatically invalidate old ones.</p>
</div>
<div class="d-flex justify-content-end mt-10">
<button type="button" id="generate_recovery_code_btn" class="btn btn-light-primary px-10 me-10">
<span data-i18n="2fa.recovery_codes_generate" class="indicator-label">
Generate
</span>
<span data-i18n="general.wait" class="indicator-progress">
Please wait...
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
</span>
</button>
<button type="button" id="view_recovery_code_btn" class="btn btn-primary px-10">
<span data-i18n="2fa.recovery_codes_view" id="save_label" class="indicator-label">View</span>
<span data-i18n="general.wait" class="indicator-progress">
Please wait...
<span class="spinner-border spinner-border-sm align-middle ms-2"></span>
</span>
</button>
</div>
</div>
</div>
</div>
@ -165,8 +180,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-content">
<div class="modal-header">
<h3 id="idRecoveryCodesTitle" class="modal-title"></h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary ms-2" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body">
@ -185,8 +200,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-content">
<div class="modal-header">
<h3 data-i18n="2fa.info_title" class="modal-title">Learn about two-factor authentication</h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary ms-2" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body fw-semibold fs-6">
@ -210,8 +225,8 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-content">
<div class="modal-header">
<h3 data-i18n="2fa.setup_title" class="modal-title">Set up two-factor authentication</h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary ms-2" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body scroll-y pt-10 pb-15 px-lg-17">
@ -223,7 +238,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div id="id_qr_code_container" class="pt-5 text-center">
</div>
<div class="notice d-flex bg-light-warning rounded border-warning border border-dashed my-10 p-6">
<i class="ki-duotone ki-information fs-2tx text-warning me-4">
<i class="ki-duotone ki-information-5 fs-2tx text-warning me-4">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
@ -239,12 +254,12 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</div>
<div id="errorModalMsg" class="d-none rounded border-warning border border-dashed bg-light-warning d-flex align-items-center p-5 mb-10">
<i class="ki-duotone ki-information fs-3x text-warning me-5"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i>
<i class="ki-duotone ki-information-5 fs-3x text-warning me-5"><span class="path1"></span><span class="path2"></span><span class="path3"></span></i>
<div class="text-gray-700 fw-bold fs-5 d-flex flex-column pe-0 pe-sm-10">
<span id="errorModalTxt"></span>
</div>
<button id="id_dismiss_error_modal_msg" type="button" class="position-absolute position-sm-relative m-2 m-sm-0 top-0 end-0 btn btn-icon btn-sm btn-active-light-primary ms-sm-auto">
<i class="ki-duotone ki-cross fs-2x text-primary"><span class="path1"></span><span class="path2"></span></i>
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</button>
</div>
@ -332,7 +347,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-danger"
confirmButton: "btn btn-primary"
}
});
});
@ -374,13 +389,24 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-danger"
confirmButton: "btn btn-primary"
}
});
});
}
function disableConfig() {
if (requiredProtocols.length > 0){
ModalAlert.fire({
text: $.t('2fa.required_protocols', {val: requiredProtocols.join(', ')}),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
return;
}
ModalAlert.fire({
text: $.t('2fa.disable_question'),
icon: "warning",
@ -469,7 +495,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}
if ($('#id_protocols').find('option:selected').length == 0){
showToast('2fa.no_protocol');
ModalAlert.fire({
text: $.t('2fa.no_protocol'),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
return;
}
@ -492,7 +525,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
el.removeAttribute('data-kt-indicator');
el.disabled = false;
if (!response.data.secret) {
showToast(errorMessage);
ModalAlert.fire({
text: $.t(errorMessage),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
return;
}
$('#id_secret').text(response.data.secret);
@ -509,7 +549,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}).catch(function (error){
el.removeAttribute('data-kt-indicator');
el.disabled = false;
showToast(errorMessage);
ModalAlert.fire({
text: $.t(errorMessage),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
});
}
@ -522,16 +569,32 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}
let errorMessage = '2fa.save_err';
let protocolsArray = [];
$('#id_protocols').find('option:selected').each(function(){
protocolsArray.push($(this).val());
});
if (protocolsArray.length == 0){
showToast('2fa.no_protocol');
return;
if (!disabled) {
$('#id_protocols').find('option:selected').each(function(){
protocolsArray.push($(this).val());
});
if (protocolsArray.length == 0){
ModalAlert.fire({
text: $.t('2fa.no_protocol'),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
return;
}
}
for (let i = 0; i < requiredProtocols.length > 0; i++){
if (!protocolsArray.includes(requiredProtocols[i])){
showToast('2fa.required_protocols', {val: requiredProtocols.join(', ')});
ModalAlert.fire({
text: $.t('2fa.required_protocols', {val: requiredProtocols.join(', ')}),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
return;
}
}
@ -565,7 +628,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
el.removeAttribute('data-kt-indicator');
el.disabled = false;
if (!response.data.message) {
showToast(errorMessage);
ModalAlert.fire({
text: $.t(errorMessage),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
return;
}
ModalAlert.fire({
@ -583,7 +653,14 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
}).catch(function (error) {
el.removeAttribute('data-kt-indicator');
el.disabled = false;
showToast(errorMessage);
ModalAlert.fire({
text: $.t(errorMessage),
icon: "warning",
confirmButtonText: $.t('general.ok'),
customClass: {
confirmButton: "btn btn-primary"
}
});
});
}

View file

@ -18,7 +18,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- define "page_body"}}
<div class="card shadow-sm">
<div class="card-header bg-light">
<h3 data-i18n="general.my_profile" class="card-title text-primary">My profile</h3>
<h3 data-i18n="general.my_profile" class="card-title section-title">My profile</h3>
</div>
<div class="card-body">
{{- template "errmsg" .Error}}
@ -54,7 +54,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- if .LoggedUser.CanManagePublicKeys}}
<div class="card card-rounded mt-10">
<div class="card-header bg-light">
<h3 data-i18n="general.pub_keys" class="card-title">Public keys</h3>
<h3 data-i18n="general.pub_keys" class="card-title section-title-inner">Public keys</h3>
</div>
<div class="card-body">
<div id="public_keys">

View file

@ -46,10 +46,42 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<input data-i18n="[placeholder]login.confirm_code" class="form-control form-control-lg form-control-solid" type="text" placeholder="Confirmation code" name="code" spellcheck="false" required />
</div>
<div class="fv-row mb-10">
<input data-i18n="[placeholder]general.new_password" class="form-control form-control-lg form-control-solid" type="password" name="password" placeholder="New Password" autocomplete="new-password" spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input data-i18n="[placeholder]general.new_password" data-password-control="input" class="form-control form-control-lg form-control-solid"
type="password" name="password" placeholder="New Password" autocomplete="new-password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
</div>
<div class="fv-row mb-10">
<input data-i18n="[placeholder]general.confirm_password" class="form-control form-control-lg form-control-solid" type="password" name="confirm_password" placeholder="Confirm Password" autocomplete="new-password" spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input data-i18n="[placeholder]general.confirm_password" data-password-control="input" class="form-control form-control-lg form-control-solid"
type="password" name="confirm_password" placeholder="Confirm Password" autocomplete="new-password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
</div>
<div class="text-center">
<input type="hidden" name="_form_token" value="{{.CSRFToken}}">

View file

@ -18,7 +18,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
{{- define "page_body"}}
<div class="card shadow-sm">
<div class="card-header bg-light">
<h3 {{if .IsAdd}}data-i18n="title.add_share"{{else}}data-i18n="title.update_share"{{end}} class="card-title text-primary"></h3>
<h3 {{if .IsAdd}}data-i18n="title.add_share"{{else}}data-i18n="title.update_share"{{end}} class="card-title section-title"></h3>
</div>
<div class="card-body">
{{- template "errmsg" .Error}}
@ -47,7 +47,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="card card-rounded mt-10">
<div class="card-header bg-light">
<h3 data-i18n="share.paths" class="card-title">Paths</h3>
<h3 data-i18n="share.paths" class="card-title section-title-inner">Paths</h3>
</div>
<div class="card-body">
<div id="paths">
@ -127,10 +127,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="col-md-9 d-flex">
<input data-i18n="[placeholder]share.expiration_help" id="id_expiration" class="form-control" placeholder="Pick an expiration date" />
<button class="btn btn-icon btn-light-danger ms-2 d-none" id="id_expiration_clear">
<i class="ki-duotone ki-cross fs-1">
<span class="path1"></span>
<span class="path2"></span>
</i>
<i class="ki-solid ki-cross fs-1"></i>
</button>
</div>
</div>
@ -203,7 +200,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
},
defaultHour: 23,
defaultMinute: 59,
locale: i18next.language,
locale: i18next.resolvedLanguage,
onChange: function(selectedDates, dateStr, instance) {
if (selectedDates.length > 0){
$('#id_expiration_clear').removeClass("d-none");

View file

@ -27,11 +27,17 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</div>
<div class="card shadow-sm w-lg-600px">
<div class="card-header bg-light">
<h3 data-i18n="fs.download_ready" class="card-title text-primary">Your download is ready</h3>
<h3 data-i18n="fs.download_ready" class="card-title section-title">Your download is ready</h3>
</div>
<div class="card-body">
<div>
<a data-i18n="fs.download" href="{{.DownloadLink}}" class="btn btn-primary btn-user-custom btn-block">Download</a>
<a href="{{.DownloadLink}}" class="btn btn-primary btn-block">
<i class="ki-duotone ki-folder-down fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="fs.download">Download</span>
</a>
</div>
</div>
</div>

View file

@ -31,7 +31,23 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</div>
{{- template "errmsg" .Error}}
<div class="fv-row mb-10">
<input data-i18n="[placeholder]login.password" class="form-control form-control-lg form-control-solid" type="password" name="share_password" placeholder="Password" spellcheck="false" required />
<div class="position-relative" data-password-control="container">
<input data-i18n="[placeholder]login.password" data-password-control="input" class="form-control form-control-lg form-control-solid"
type="password" name="share_password" placeholder="Password" spellcheck="false" required />
<span class="btn btn-sm btn-icon position-absolute translate-middle top-50 end-0 me-n2" data-password-control="visibility">
<i class="ki-duotone ki-eye-slash fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
<span class="path4"></span>
</i>
<i class="ki-duotone ki-eye d-none fs-1">
<span class="path1"></span>
<span class="path2"></span>
<span class="path3"></span>
</i>
</span>
</div>
</div>
<div class="text-center">
<input type="hidden" name="_form_token" value="{{.CSRFToken}}">
@ -44,6 +60,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</button>
</div>
</form>
<hr>
<div class=" d-flex flex-stack pt-5 mt-5">
<div class="me-10">
<select id="languageSwitcher" name="language" class="form-select form-select-solid form-select-sm" data-control="i18n-select2" data-hide-search="true">

View file

@ -24,7 +24,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="card shadow-sm">
<div class="card-header bg-light">
<h3 data-i18n="share.view_manage" class="card-title text-primary">View and manage shares</h3>
<h3 data-i18n="share.view_manage" class="card-title section-title">View and manage shares</h3>
</div>
<div id="card_body" class="card-body">
<div id="loader" class="align-items-center text-center my-10">
@ -39,7 +39,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<span class="path2"></span>
</i>
<input name="search" data-i18n="[placeholder]general.search" type="text" data-share-table-filter="search"
class="form-control rounded-1 w-200px ps-15" placeholder="Search" />
class="form-control rounded-1 w-250px ps-15 me-5" placeholder="Search" />
</div>
<div class="d-flex justify-content-end" data-share-table-toolbar="base">
@ -71,31 +71,95 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header border-0">
<h3 class="modal-title">
<h3 data-i18n="share.access_links_title" class="modal-title">
Share access links
</h3>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-color-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-duotone ki-cross fs-1"><span class="path1"></span><span class="path2"></span></i>
<div data-i18n="[aria-label]general.close" class="btn btn-icon btn-sm btn-active-light-primary" data-bs-dismiss="modal" aria-label="Close">
<i class="ki-solid ki-cross fs-2x text-gray-700"></i>
</div>
</div>
<div class="modal-body fs-5">
<div id="readShare">
<p>You can download the shared contents, as single zip file, using this <a id="readLink" href="#" target="_blank">link</a>.</p>
<p>If the share consists of a single directory you can browse and download files using this <a id="readBrowseLink" href="#" target="_blank">page</a>.</p>
<p>If the share consists of a single file you can download it uncompressed using this <a id="readUncompressedLink" href="#" target="_blank">link</a>.</p>
<div class="mb-5">
<h4 data-i18n="share.link_single_title">Single zip file</h4>
<p data-i18n="share.link_single_desc">You can download shared content as a single zip file</p>
<div class="d-flex">
<button id="readLinkCopy" type="button" class="btn btn-flex btn-light-primary btn-clipboard-copy me-3">
<i class="ki-duotone ki-fasten fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="general.copy_link">Copy link</span>
</button>
<a id="readLink" href="#" target="_blank" type="button" class="btn btn-flex btn-primary">
<i class="ki-duotone ki-folder-down fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="fs.download">Download</span>
</a>
</div>
</div>
<hr>
<div class="mb-5">
<h4 data-i18n="share.link_dir_title">Single directory</h4>
<p data-i18n="share.link_dir_desc">If the share consists of a single directory you can browse and download files</p>
<button id="readBrowseLinkCopy" data-clipboard-target="#readBrowseLink" type="button" class="btn btn-flex btn-light-primary btn-clipboard-copy me-3">
<i class="ki-duotone ki-fasten fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="general.copy_link">Copy link</span>
</button>
<a id="readBrowseLink" href="#" target="_blank" type="button" class="btn btn-flex btn-primary">
<i class="ki-duotone ki-arrow-up-right fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="share.go">Go to share</span>
</a>
</div>
<hr>
<div>
<h4 data-i18n="share.link_uncompressed_title">Uncompressed file</h4>
<p data-i18n="share.link_uncompressed_desc">If the share consists of a single file you can download it uncompressed</p>
<button id="readUncompressedLinkCopy" data-clipboard-target="#readUncompressedLink" type="button" class="btn btn-flex btn-light-primary btn-clipboard-copy me-3">
<i class="ki-duotone ki-fasten fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="general.copy_link">Copy link</span>
</button>
<a id="readUncompressedLink" href="#" target="_blank" type="button" class="btn btn-flex btn-primary">
<i class="ki-duotone ki-folder-down fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="fs.download">Download</span>
</a>
</div>
</div>
<div id="writeShare">
<p>You can upload one or more files to the shared directory using this <a id="writePageLink" href="#" target="_blank">page</a></p>
<p data-i18n="share.upload_desc">You can upload one or more files to the shared directory</p>
<button id="writePageLinkCopy" data-clipboard-target="#writePageLink" type="button" class="btn btn-flex btn-light-primary btn-clipboard-copy me-3">
<i class="ki-duotone ki-fasten fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="general.copy_link">Copy link</span>
</button>
<a id="writePageLink" href="#" target="_blank" type="button" class="btn btn-flex btn-primary">
<i class="ki-duotone ki-folder-up fs-2">
<span class="path1"></span>
<span class="path2"></span>
</i>
<span data-i18n="fs.upload.text">Upload</span>
</a>
</div>
<div id="expiredShare">
<div data-i18n="share.expired_desc" id="expiredShare">
This share is no longer accessible because it has expired
</div>
</div>
<div class="modal-footer border-0">
<button class="btn btn-primary" type="button" data-bs-dismiss="modal">
OK
</button>
</div>
</div>
</div>
</div>
@ -109,7 +173,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
ModalAlert.fire({
text: $.t('general.delete_confirm_generic'),
icon: "warning",
confirmButtonText: $.t('general.delete'),
confirmButtonText: $.t('general.delete_confirm_btn'),
cancelButtonText: $.t('general.cancel'),
customClass: {
confirmButton: "btn btn-danger",
@ -170,16 +234,20 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
$('#readShare').show();
$('#readLink').attr("href", shareURL + "/download");
$('#readLink').attr("title", shareURL + "/download");
$('#readLinkCopy').attr("data-clipboard-text",getCurrentURI()+shareURL + "/download");
$('#readUncompressedLink').attr("href", shareURL + "/download?compress=false");
$('#readUncompressedLink').attr("title", shareURL + "/download?compress=false");
$('#readUncompressedLinkCopy').attr("data-clipboard-text",getCurrentURI()+shareURL + "/download?compress=false");
$('#readBrowseLink').attr("href", shareURL + "/browse");
$('#readBrowseLink').attr("title", shareURL + "/browse");
$('#readBrowseLinkCopy').attr("data-clipboard-text",getCurrentURI()+shareURL + "/browse");
} else {
$('#expiredShare').hide();
$('#writeShare').show();
$('#readShare').hide();
$('#writePageLink').attr("href", shareURL + "/upload");
$('#writePageLink').attr("title", shareURL + "/upload");
$('#writePageLinkCopy').attr("data-clipboard-text",getCurrentURI()+shareURL + "/upload");
}
}
$('#link_modal').modal('show');
@ -386,6 +454,23 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
$(document).on("i18nshow", function(){
sharesDatatable.init();
var clipboard = new ClipboardJS('.btn-clipboard-copy',{
container: document.getElementById('link_modal')
});
clipboard.on('success', function (e) {
e.trigger.querySelectorAll('span').forEach(spanEl => {
if (spanEl.getAttribute('data-i18n')){
setI18NData($(spanEl),"general.copied");
setTimeout(function(){
setI18NData($(spanEl),"general.copy_link");
}, 3000)
}
});
e.clearSelection();
});
});
</script>
{{end}}

View file

@ -27,7 +27,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
</div>
<div class="card shadow-sm w-lg-600px">
<div class="card-header bg-light">
<h3 data-i18n="title.upload_to_share" class="card-title text-primary">Upload one or more files to share</h3>
<h3 data-i18n="title.upload_to_share" class="card-title section-title">Upload one or more files to share</h3>
</div>
<div class="card-body">
{{- template "errmsg" ""}}