Browse Source

WebUI: make error messages user dismissible

Fixes #1171

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
Nicola Murino 2 years ago
parent
commit
04ab8e72f6
43 changed files with 369 additions and 319 deletions
  1. 3 3
      go.mod
  2. 6 6
      go.sum
  3. 1 1
      internal/vfs/azblobfs.go
  4. 5 2
      templates/common/forgot-password.html
  5. 5 2
      templates/common/reset-password.html
  6. 5 2
      templates/webadmin/admin.html
  7. 6 9
      templates/webadmin/admins.html
  8. 5 2
      templates/webadmin/adminsetup.html
  9. 5 2
      templates/webadmin/changepassword.html
  10. 13 13
      templates/webadmin/connections.html
  11. 7 8
      templates/webadmin/defender.html
  12. 5 2
      templates/webadmin/eventaction.html
  13. 10 8
      templates/webadmin/eventactions.html
  14. 5 2
      templates/webadmin/eventrule.html
  15. 10 8
      templates/webadmin/eventrules.html
  16. 7 8
      templates/webadmin/events.html
  17. 5 2
      templates/webadmin/folder.html
  18. 11 12
      templates/webadmin/folders.html
  19. 5 2
      templates/webadmin/group.html
  20. 10 8
      templates/webadmin/groups.html
  21. 5 2
      templates/webadmin/iplist.html
  22. 7 8
      templates/webadmin/iplists.html
  23. 5 2
      templates/webadmin/login.html
  24. 5 2
      templates/webadmin/maintenance.html
  25. 36 39
      templates/webadmin/mfa.html
  26. 5 2
      templates/webadmin/profile.html
  27. 5 2
      templates/webadmin/role.html
  28. 10 8
      templates/webadmin/roles.html
  29. 5 2
      templates/webadmin/twofactor-recovery.html
  30. 5 2
      templates/webadmin/twofactor.html
  31. 5 2
      templates/webadmin/user.html
  32. 11 12
      templates/webadmin/users.html
  33. 5 2
      templates/webclient/changepassword.html
  34. 6 5
      templates/webclient/editfile.html
  35. 20 31
      templates/webclient/files.html
  36. 37 40
      templates/webclient/mfa.html
  37. 5 2
      templates/webclient/profile.html
  38. 5 2
      templates/webclient/share.html
  39. 22 21
      templates/webclient/sharefiles.html
  40. 12 14
      templates/webclient/shares.html
  41. 14 13
      templates/webclient/shareupload.html
  42. 5 2
      templates/webclient/twofactor-recovery.html
  43. 5 2
      templates/webclient/twofactor.html

+ 3 - 3
go.mod

@@ -24,7 +24,7 @@ require (
 	github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001
 	github.com/fclairamb/ftpserverlib v0.21.0
 	github.com/fclairamb/go-log v0.4.1
-	github.com/go-acme/lego/v4 v4.9.2-0.20230104103215-fd54758bba4c
+	github.com/go-acme/lego/v4 v4.10.0
 	github.com/go-chi/chi/v5 v5.0.8
 	github.com/go-chi/jwtauth/v5 v5.1.0
 	github.com/go-chi/render v1.0.2
@@ -154,10 +154,10 @@ require (
 	go.opencensus.io v0.24.0 // indirect
 	golang.org/x/mod v0.8.0 // indirect
 	golang.org/x/text v0.7.0 // indirect
-	golang.org/x/tools v0.5.0 // indirect
+	golang.org/x/tools v0.6.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 // indirect
+	google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc // indirect
 	google.golang.org/grpc v1.53.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect

+ 6 - 6
go.sum

@@ -918,8 +918,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
-github.com/go-acme/lego/v4 v4.9.2-0.20230104103215-fd54758bba4c h1:PDd4Q867Ia2D68T+KglkyxMDoIUEp3sNYVXuN3TXjAE=
-github.com/go-acme/lego/v4 v4.9.2-0.20230104103215-fd54758bba4c/go.mod h1:qib35rauo2OW1BzAI0qUfR3xw/JIIuaO0ZA83QIsw0s=
+github.com/go-acme/lego/v4 v4.10.0 h1:G4Cgq4lsPxCjqsTKsqhUjRs3oKAGVMFPhvrl6kzzs44=
+github.com/go-acme/lego/v4 v4.10.0/go.mod h1:EMbf0Jmqwv94nJ5WL9qWnSXIBZnvsS9gNypansHGc6U=
 github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
 github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
 github.com/go-chi/jwtauth/v5 v5.1.0 h1:wJyf2YZ/ohPvNJBwPOzZaQbyzwgMZZceE1m8FOzXLeA=
@@ -2510,8 +2510,8 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
-golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4=
-golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
+golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2713,8 +2713,8 @@ google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZV
 google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
 google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
 google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
-google.golang.org/genproto v0.0.0-20230202175211-008b39050e57 h1:vArvWooPH749rNHpBGgVl+U9B9dATjiEhJzcWGlovNs=
-google.golang.org/genproto v0.0.0-20230202175211-008b39050e57/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc h1:ijGwO+0vL2hJt5gaygqP2j6PfflOBrRot0IczKbmtio=
+google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
 google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=

+ 1 - 1
internal/vfs/azblobfs.go

@@ -1180,7 +1180,7 @@ func getAzContainerClientOptions() *container.ClientOptions {
 	return &container.ClientOptions{
 		ClientOptions: azcore.ClientOptions{
 			Telemetry: policy.TelemetryOptions{
-				ApplicationID: fmt.Sprintf("SFTPGo-%v_%v", version.Version, version.CommitHash),
+				ApplicationID: fmt.Sprintf("SFTPGo-%s", version.CommitHash),
 			},
 		},
 	}

+ 5 - 2
templates/common/forgot-password.html

@@ -60,8 +60,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                         <p class="mb-4">If you have added an email address to your account, we'll email you a code to reset your password. Enter your account username below</p>
                                     </div>
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="forgot_password_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"

+ 5 - 2
templates/common/reset-password.html

@@ -60,8 +60,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                         <p class="mb-4">Check your email for the confirmation code</p>
                                     </div>
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="forgot_password_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"

+ 5 - 2
templates/webadmin/admin.html

@@ -28,8 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="admin_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 6 - 9
templates/webadmin/admins.html

@@ -28,12 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
 {{define "page_body"}}
 
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
-</div>
-
-<div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
-    <div id="successTxt" class="card-body"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div class="card shadow mb-4">
@@ -130,6 +129,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         var username = table.row({ selected: true }).data()[1];
         var path = '{{.AdminURL}}' + "/" + fixedEncodeURIComponent(username);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -153,9 +153,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }

+ 5 - 2
templates/webadmin/adminsetup.html

@@ -55,8 +55,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                         <h1 class="h5 text-gray-900 mb-4">To start using SFTPGo you need to create an admin user</h1>
                                     </div>
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="login_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"

+ 5 - 2
templates/webadmin/changepassword.html

@@ -25,8 +25,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="user_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 13 - 13
templates/webadmin/connections.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div class="card shadow mb-4">
@@ -105,13 +108,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function disconnectAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('disconnect:name').enable(false);
-        var selectedData = table.row({ selected: true }).data()
-        var connectionID = selectedData[0];
-        var nodeID = selectedData[1];
-        var path = '{{.ConnectionsURL}}' + "/" + fixedEncodeURIComponent(connectionID)+"?node="+encodeURIComponent(nodeID);
+        let selectedData = table.row({ selected: true }).data()
+        let connectionID = selectedData[0];
+        let nodeID = selectedData[1];
+        let path = '{{.ConnectionsURL}}' + "/" + fixedEncodeURIComponent(connectionID)+"?node="+encodeURIComponent(nodeID);
         $('#disconnectModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -119,9 +124,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
             headers: {'X-CSRF-TOKEN' : '{{.CSRFToken}}'},
             timeout: 15000,
             success: function (result) {
-                setTimeout(function () {
-                    window.location.href = '{{.ConnectionsURL}}';
-                }, 1000);
+                window.location.href = '{{.ConnectionsURL}}';
             },
             error: function ($xhr, textStatus, errorThrown) {
                 var txt = "Failed to close the selected connection";
@@ -137,9 +140,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }

+ 7 - 8
templates/webadmin/defender.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 <div class="card shadow mb-4">
     <div class="card-header py-3">
@@ -94,6 +97,8 @@ function deleteAction() {
         let id = table.row({ selected: true }).data()["id"];
         let path = '{{.DefenderHostsURL}}' + "/" + fixedEncodeURIComponent(id);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -117,9 +122,6 @@ function deleteAction() {
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }
@@ -163,9 +165,6 @@ function deleteAction() {
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                 }
             },
             "deferRender": true,

+ 5 - 2
templates/webadmin/eventaction.html

@@ -39,8 +39,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="eventaction_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 10 - 8
templates/webadmin/eventactions.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 <div class="card shadow mb-4">
     <div class="card-header py-3">
@@ -101,11 +104,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function deleteAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('delete:name').enable(false);
-        var name = table.row({ selected: true }).data()[0];
-        var path = '{{.EventActionURL}}' + "/" + fixedEncodeURIComponent(name);
+        let name = table.row({ selected: true }).data()[0];
+        let path = '{{.EventActionURL}}' + "/" + fixedEncodeURIComponent(name);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -129,9 +134,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }

+ 5 - 2
templates/webadmin/eventrule.html

@@ -28,8 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="eventrule_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 10 - 8
templates/webadmin/eventrules.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 <div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
     <div id="successTxt" class="card-body"></div>
@@ -138,6 +141,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         let name = table.row({ selected: true }).data()[1];
         let path = '{{.EventRuleURL}}' + "/run/" + fixedEncodeURIComponent(name);
         $('#runModal').modal('hide');
+        $('#successMsg').hide();
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -165,9 +171,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 8000);
             }
         });
     }
@@ -178,6 +181,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         let name = table.row({ selected: true }).data()[1];
         let path = '{{.EventRuleURL}}' + "/" + fixedEncodeURIComponent(name);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -201,9 +206,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 8000);
             }
         });
     }

+ 7 - 8
templates/webadmin/events.html

@@ -28,8 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 <div class="card shadow mb-4">
     <div class="card-header py-3">
@@ -332,6 +335,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     }
 
     function initProviderDatatable(){
+        $('#errorMsg').hide();
         let tableProvider = $('#dataTableProvider').DataTable({
             "ajax": {
                 "url": getSearchURL(false),
@@ -351,9 +355,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                 }
             },
             "deferRender": true,
@@ -417,6 +418,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     }
 
     function initFsDatatable(){
+        $('#errorMsg').hide();
         let tableFs = $('#dataTableFs').DataTable({
             "ajax": {
                 "url": getSearchURL(false),
@@ -436,9 +438,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                 }
             },
             "deferRender": true,

+ 5 - 2
templates/webadmin/folder.html

@@ -28,8 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         {{if eq .Mode 3}}

+ 11 - 12
templates/webadmin/folders.html

@@ -27,8 +27,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
@@ -115,11 +118,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
 function deleteAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('delete:name').enable(false);
-        var folderName = table.row({ selected: true }).data()[1];
-        var path = '{{.FolderURL}}' + "/" + fixedEncodeURIComponent(folderName);
+        let folderName = table.row({ selected: true }).data()[1];
+        let path = '{{.FolderURL}}' + "/" + fixedEncodeURIComponent(folderName);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -143,9 +148,6 @@ function deleteAction() {
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }
@@ -217,7 +219,7 @@ function deleteAction() {
                         $('#successMsg').show();
                         setTimeout(function () {
                             $('#successMsg').hide();
-                        }, 5000);
+                        }, 15000);
                     },
                     error: function ($xhr, textStatus, errorThrown) {
                         dt.button('quota_scan:name').enable(true);
@@ -234,9 +236,6 @@ function deleteAction() {
                         }
                         $('#errorTxt').text(txt);
                         $('#errorMsg').show();
-                        setTimeout(function () {
-                            $('#errorMsg').hide();
-                        }, 5000);
                     }
                 });
             },

+ 5 - 2
templates/webadmin/group.html

@@ -29,8 +29,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <div class="card mb-4 border-left-info">

+ 10 - 8
templates/webadmin/groups.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div class="card shadow mb-4">
@@ -100,11 +103,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function deleteAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('delete:name').enable(false);
-        var groupName = table.row({ selected: true }).data()[0];
-        var path = '{{.GroupURL}}' + "/" + fixedEncodeURIComponent(groupName);
+        let groupName = table.row({ selected: true }).data()[0];
+        let path = '{{.GroupURL}}' + "/" + fixedEncodeURIComponent(groupName);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -128,9 +133,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }

+ 5 - 2
templates/webadmin/iplist.html

@@ -29,8 +29,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="iplist_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 7 - 8
templates/webadmin/iplists.html

@@ -27,8 +27,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 <div class="card shadow mb-4">
     <div class="card-header py-3">
@@ -260,6 +263,8 @@ function deleteAction() {
     let selectedRow = table.row({ selected: true }).data();
     let path = '{{.IPListURL}}' + "/" + fixedEncodeURIComponent(selectedRow["type"])+"/"+ fixedEncodeURIComponent(selectedRow["ipornet"]);
     $('#deleteModal').modal('hide');
+    $('#errorMsg').hide();
+
     $.ajax({
         url: path,
         type: 'DELETE',
@@ -283,9 +288,6 @@ function deleteAction() {
             }
             $('#errorTxt').text(txt);
             $('#errorMsg').show();
-            setTimeout(function () {
-                $('#errorMsg').hide();
-            }, 5000);
         }
     });
 }
@@ -406,9 +408,6 @@ $(document).ready(function () {
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 10000);
             }
         },
         "deferRender": true,

+ 5 - 2
templates/webadmin/login.html

@@ -22,8 +22,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                         <h1 class="h4 text-gray-900 mb-4">{{.Branding.ShortName}} - {{.Version}}</h1>
                                     </div>
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="login_form" action="{{.CurrentURL}}" method="POST"

+ 5 - 2
templates/webadmin/maintenance.html

@@ -24,8 +24,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="restore_form" enctype="multipart/form-data" action="{{.RestorePath}}" method="POST">

+ 36 - 39
templates/webadmin/mfa.html

@@ -31,8 +31,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         <div id="successTOTPMsg" class="card mb-4 border-left-success" style="display: none;">
             <div id="successTOTPTxt" class="card-body"></div>
         </div>
-        <div id="errorTOTPMsg" class="card mb-4 border-left-warning" style="display: none;">
-            <div id="errorTOTPTxt" class="card-body text-form-error"></div>
+        <div id="errorTOTPMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+            <span id="errorTOTPTxt"></span>
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         <div>
             <p>Status: {{if .TOTPConfig.Enabled }}"Enabled". Current configuration: "{{.TOTPConfig.ConfigName}}"{{else}}"Disabled"{{end}}</p>
@@ -90,8 +93,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         <div id="successRecCodesMsg" class="card mb-4 border-left-success" style="display: none;">
             <div id="successRecCodesTxt" class="card-body"></div>
         </div>
-        <div id="errorRecCodesMsg" class="card mb-4 border-left-warning" style="display: none;">
-            <div id="errorRecCodesTxt" class="card-body text-form-error"></div>
+        <div id="errorRecCodesMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+            <span id="errorRecCodesTxt"></span>
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         <div>
             <p>Recovery codes are a set of one time use codes that can be used in place of the TOTP 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 TOTP configuration.</p>
@@ -152,7 +158,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function totpGenerate() {
-        var path = "{{.GenerateTOTPURL}}";
+        $('#errorTOTPMsg').hide();
+        let path = "{{.GenerateTOTPURL}}";
         $.ajax({
             url: path,
             type: 'POST',
@@ -170,9 +177,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 window.scrollTo(0, $("#idTOTPDetails").offset().top);
             },
             error: function ($xhr, textStatus, errorThrown) {
-                var txt = "Failed to generate a new TOTP secret";
+                let txt = "Failed to generate a new TOTP secret";
                 if ($xhr) {
-                    var json = $xhr.responseJSON;
+                    let json = $xhr.responseJSON;
                     if (json) {
                         if (json.message){
                             txt += ": " + json.message;
@@ -183,21 +190,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function totpValidate() {
-        var passcode = $('#idPasscode').val();
+        $('#errorTOTPMsg').hide();
+        let passcode = $('#idPasscode').val();
         if (passcode == "") {
             $('#errorTOTPTxt').text("The verification code is required");
             $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             return;
         }
         var path = "{{.ValidateTOTPURL}}";
@@ -226,15 +228,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function totpSave() {
-        var path = "{{.SaveTOTPURL}}";
+        let path = "{{.SaveTOTPURL}}";
+        $('#errorTOTPMsg').hide();
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -251,9 +252,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }, 3000);
             },
             error: function ($xhr, textStatus, errorThrown) {
-                var txt = "Failed to save the new configuration";
+                let txt = "Failed to save the new configuration";
                 if ($xhr) {
-                    var json = $xhr.responseJSON;
+                    let json = $xhr.responseJSON;
                     if (json) {
                         if (json.message){
                             txt += ": " + json.message;
@@ -264,9 +265,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
@@ -277,7 +275,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
     function totpDisable() {
         $('#disableTOTPModal').modal('hide');
-        var path = "{{.SaveTOTPURL}}";
+        $('#errorTOTPMsg').hide();
+        let path = "{{.SaveTOTPURL}}";
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -303,15 +303,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function getRecoveryCodes() {
-        var path = "{{.RecCodesURL}}";
+        $('#errorRecCodesMsg').hide();
+        let path = "{{.RecCodesURL}}";
+
         $.ajax({
             url: path,
             type: 'GET',
@@ -331,9 +330,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 window.scrollTo(0, $("#idRecoveryCodesCard").offset().top);
             },
             error: function ($xhr, textStatus, errorThrown) {
-                var txt = "Failed to get your recovery codes";
+                let txt = "Failed to get your recovery codes";
                 if ($xhr) {
-                    var json = $xhr.responseJSON;
+                    let json = $xhr.responseJSON;
                     if (json) {
                         if (json.message){
                             txt += ": " + json.message;
@@ -344,15 +343,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorRecCodesTxt').text(txt);
                 $('#errorRecCodesMsg').show();
-                setTimeout(function () {
-                    $('#errorRecCodesMsg').hide();
-                }, 8000);
+                window.scrollTo(0, $("#idRecoveryCodesCard").offset().top);
             }
         });
     }
 
     function generateRecoveryCodes() {
-        var path = "{{.RecCodesURL}}";
+        $('#errorRecCodesMsg').hide();
+        let path = "{{.RecCodesURL}}";
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -375,9 +374,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }, 5000);
             },
             error: function ($xhr, textStatus, errorThrown) {
-                var txt = "Failed to generate new recovery codes";
+                let txt = "Failed to generate new recovery codes";
                 if ($xhr) {
-                    var json = $xhr.responseJSON;
+                    let json = $xhr.responseJSON;
                     if (json) {
                         if (json.message){
                             txt += ": " + json.message;
@@ -388,9 +387,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorRecCodesTxt').text(txt);
                 $('#errorRecCodesMsg').show();
-                setTimeout(function () {
-                    $('#errorRecCodesMsg').hide();
-                }, 8000);
+                window.scrollTo(0, $("#idRecoveryCodesCard").offset().top);
             }
         });
     }

+ 5 - 2
templates/webadmin/profile.html

@@ -25,8 +25,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="profile_form" action="{{.CurrentURL}}" method="POST">

+ 5 - 2
templates/webadmin/role.html

@@ -25,8 +25,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="role_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 10 - 8
templates/webadmin/roles.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div class="card shadow mb-4">
@@ -100,11 +103,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function deleteAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('delete:name').enable(false);
-        var roleName = table.row({ selected: true }).data()[0];
-        var path = '{{.RoleURL}}' + "/" + fixedEncodeURIComponent(roleName);
+        let roleName = table.row({ selected: true }).data()[0];
+        let path = '{{.RoleURL}}' + "/" + fixedEncodeURIComponent(roleName);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -128,9 +133,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }

+ 5 - 2
templates/webadmin/twofactor-recovery.html

@@ -22,8 +22,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                         <h1 class="h4 text-gray-900 mb-4">{{.Branding.Name}} - {{.Version}}</h1>
                                     </div>
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="login_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"

+ 5 - 2
templates/webadmin/twofactor.html

@@ -22,8 +22,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                                         <h1 class="h4 text-gray-900 mb-4">{{.Branding.Name}} - {{.Version}}</h1>
                                     </div>
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="login_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"

+ 5 - 2
templates/webadmin/user.html

@@ -31,8 +31,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         {{if eq .Mode 3}}

+ 11 - 12
templates/webadmin/users.html

@@ -28,8 +28,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
 {{define "page_body"}}
 
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
@@ -130,11 +133,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function deleteAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('delete:name').enable(false);
-        var username = table.row({ selected: true }).data()[1];
-        var path = '{{.UserURL}}' + "/" + fixedEncodeURIComponent(username);
+        let username = table.row({ selected: true }).data()[1];
+        let path = '{{.UserURL}}' + "/" + fixedEncodeURIComponent(username);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -158,9 +163,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }
@@ -237,7 +239,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                         $('#successMsg').show();
                         setTimeout(function () {
                             $('#successMsg').hide();
-                        }, 5000);
+                        }, 15000);
                     },
                     error: function ($xhr, textStatus, errorThrown) {
                         dt.button('quota_scan:name').enable(true);
@@ -254,9 +256,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                         }
                         $('#errorTxt').text(txt);
                         $('#errorMsg').show();
-                        setTimeout(function () {
-                            $('#errorMsg').hide();
-                        }, 5000);
                     }
                 });
             },

+ 5 - 2
templates/webclient/changepassword.html

@@ -25,8 +25,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="user_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 6 - 5
templates/webclient/editfile.html

@@ -42,8 +42,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 <div class="card shadow mb-4">
     <div class="card-header">
@@ -150,6 +153,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     {{if not .ReadOnly}}
     function saveFile() {
         $('#idSave').addClass("disabled");
+        $('#errorMsg').hide();
 
         async function uploadFile() {
             var errorMessage = "Error saving file";
@@ -193,9 +197,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
             $('#idSave').removeClass("disabled");
             $('#errorTxt').text(error.message);
             $('#errorMsg').show();
-            setTimeout(function () {
-                $('#errorMsg').hide();
-            }, 5000);
         });
     }
     {{end}}

+ 20 - 31
templates/webclient/files.html

@@ -35,8 +35,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div class="card shadow mb-4">
@@ -45,8 +48,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <div id="tableContainer" class="table-responsive">
@@ -280,6 +286,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     const childProps = new Map();
 
     function openExternalURL(url, fileLink, fileName){
+        $('#errorMsg').hide();
         if (childReference == null || childReference.closed) {
             childProps.set('link', fileLink);
             childProps.set('url', url);
@@ -293,9 +300,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         } else {
             $('#errorTxt').text('An external window is already open, please close it before trying to open a new one');
             $('#errorMsg').show();
-            setTimeout(function () {
-                $('#errorMsg').hide();
-            }, 8000);
         }
     }
 
@@ -395,13 +399,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                 }
 
+                $('#errorMsg').hide();
                 downloadFileAsBlob().catch(function(error){
                     notifyBlobDownloadError(error.message);
                         $('#errorTxt').text(error.message);
                         $('#errorMsg').show();
-                        setTimeout(function () {
-                            $('#errorMsg').hide();
-                        }, 5000);
                 });
                 break;
             case 'saveBlob':
@@ -448,14 +450,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                 }
 
+                $('#errorMsg').hide();
                 saveBlob().catch(function(error){
                     $('#spinnerModal').modal('hide');
                     notifySave("KO", error.message);
                     $('#errorTxt').text(error.message);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 5000);
                 });
 
                 break;
@@ -623,6 +623,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
         $('#deleteModal').modal('hide');
         $('#spinnerModal').modal('show');
+        $('#errorMsg').hide();
 
         function deleteItem() {
             if (index >= selectedItems.length || has_errors){
@@ -679,9 +680,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                     deleteItem();
                 }
             });
@@ -789,6 +787,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         $("#create_dir_form").submit(function (event) {
             event.preventDefault();
             $('#createDirModal').modal('hide');
+            $('#errorMsg').hide();
             let dirName = replaceSlash($("#directory_name").val());
             let path = '{{.DirsURL}}?path={{.CurrentDir}}' + encodeURIComponent("/"+dirName);
             $.ajax({
@@ -815,9 +814,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 8000);
                 }
             });
         });
@@ -835,6 +831,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
             $('#uploadFilesModal').modal('hide');
             $('#spinnerModal').modal('show');
+            $('#errorMsg').hide();
 
             function uploadFile() {
                 if (index >= files.length || has_errors){
@@ -901,9 +898,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     has_errors = true;
                     $('#errorTxt').text(error.message);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                     uploadFile();
                 });
             }
@@ -930,6 +924,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
             let path = '{{.FileActionsURL}}/move';
             path+='?path={{.CurrentDir}}'+encodeURIComponent("/"+itemName)+'&target='+targetDir+encodeURIComponent("/"+targetName);
             $('#renameModal').modal('hide');
+            $('#errorMsg').hide();
+
             $.ajax({
                 url: path,
                 type: 'POST',
@@ -954,9 +950,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 8000);
                     let selectedItems = table.column(0).checkboxes.selected().length;
                     table.button('rename:name').enable(selectedItems == 1);
                 }
@@ -985,6 +978,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
             spinnerDone = false;
             $('#copyModal').modal('hide');
             $('#spinnerModal').modal('show');
+            $('#errorMsg').hide();
 
             $.ajax({
                 url: path,
@@ -1012,9 +1006,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                     $('#spinnerModal').modal('hide');
                     spinnerDone = true;
                     let selectedItems = table.column(0).checkboxes.selected().length;
@@ -1149,11 +1140,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                             }
                         }
                     }
+                    $('#errorMsg').hide();
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                 }
             },
             "deferRender": true,

+ 37 - 40
templates/webclient/mfa.html

@@ -31,8 +31,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         <div id="successTOTPMsg" class="card mb-4 border-left-success" style="display: none;">
             <div id="successTOTPTxt" class="card-body"></div>
         </div>
-        <div id="errorTOTPMsg" class="card mb-4 border-left-warning" style="display: none;">
-            <div id="errorTOTPTxt" class="card-body text-form-error"></div>
+        <div id="errorTOTPMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+            <span id="errorTOTPTxt"></span>
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         <div>
             <p>Status: {{if .TOTPConfig.Enabled }}"Enabled". Current configuration: "{{.TOTPConfig.ConfigName}}"{{else}}"Disabled"{{end}}</p>
@@ -115,8 +118,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
         <div id="successRecCodesMsg" class="card mb-4 border-left-success" style="display: none;">
             <div id="successRecCodesTxt" class="card-body"></div>
         </div>
-        <div id="errorRecCodesMsg" class="card mb-4 border-left-warning" style="display: none;">
-            <div id="errorRecCodesTxt" class="card-body text-form-error"></div>
+        <div id="errorRecCodesMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+            <span id="errorRecCodesTxt"></span>
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         <div>
             <p>Recovery codes are a set of one time use codes that can be used in place of the TOTP 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 TOTP configuration.</p>
@@ -177,7 +183,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function totpGenerate() {
-        var path = "{{.GenerateTOTPURL}}";
+        $('#errorTOTPMsg').hide();
+        let path = "{{.GenerateTOTPURL}}";
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -209,24 +217,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function totpValidate() {
-        var passcode = $('#idPasscode').val();
+        $('#errorTOTPMsg').hide();
+        let passcode = $('#idPasscode').val();
         if (passcode == "") {
             $('#errorTOTPTxt').text("The verification code is required");
             $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             return;
         }
-        var path = "{{.ValidateTOTPURL}}";
+        let path = "{{.ValidateTOTPURL}}";
         $.ajax({
             url: path,
             type: 'POST',
@@ -252,19 +255,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function totpSave() {
-        var path = "{{.SaveTOTPURL}}";
-        var protocolsArray = [];
+        let path = "{{.SaveTOTPURL}}";
+        let protocolsArray = [];
         $('#idProtocols').find('option:selected').each(function(){
             protocolsArray.push($(this).val());
         });
+        $('#errorTOTPMsg').hide();
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -294,9 +296,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
@@ -306,11 +305,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     }
 
     function totpUpdateProtocols() {
-        var path = "{{.SaveTOTPURL}}";
-        var protocolsArray = [];
+        let path = "{{.SaveTOTPURL}}";
+        let protocolsArray = [];
         $('#idProtocols').find('option:selected').each(function(){
             protocolsArray.push($(this).val());
         });
+        $('#errorTOTPMsg').hide();
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -340,16 +341,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function totpDisable() {
         $('#disableTOTPModal').modal('hide');
-        var path = "{{.SaveTOTPURL}}";
+        $('#errorTOTPMsg').hide();
+        let path = "{{.SaveTOTPURL}}";
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -375,15 +375,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTOTPTxt').text(txt);
                 $('#errorTOTPMsg').show();
-                setTimeout(function () {
-                    $('#errorTOTPMsg').hide();
-                }, 5000);
             }
         });
     }
 
     function getRecoveryCodes() {
-        var path = "{{.RecCodesURL}}";
+        $('#errorRecCodesMsg').hide();
+        let path = "{{.RecCodesURL}}";
+
         $.ajax({
             url: path,
             type: 'GET',
@@ -416,15 +415,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorRecCodesTxt').text(txt);
                 $('#errorRecCodesMsg').show();
-                setTimeout(function () {
-                    $('#errorRecCodesMsg').hide();
-                }, 8000);
+                window.scrollTo(0, $("#idRecoveryCodesCard").offset().top);
             }
         });
     }
 
     function generateRecoveryCodes() {
-        var path = "{{.RecCodesURL}}";
+        $('#errorRecCodesMsg').hide();
+        let path = "{{.RecCodesURL}}";
+
         $.ajax({
             url: path,
             type: 'POST',
@@ -447,9 +446,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }, 5000);
             },
             error: function ($xhr, textStatus, errorThrown) {
-                var txt = "Failed to generate new recovery codes";
+                let txt = "Failed to generate new recovery codes";
                 if ($xhr) {
-                    var json = $xhr.responseJSON;
+                    let json = $xhr.responseJSON;
                     if (json) {
                         if (json.message){
                             txt += ": " + json.message;
@@ -460,9 +459,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorRecCodesTxt').text(txt);
                 $('#errorRecCodesMsg').show();
-                setTimeout(function () {
-                    $('#errorRecCodesMsg').hide();
-                }, 8000);
+                window.scrollTo(0, $("#idRecoveryCodesCard").offset().top);
             }
         });
     }

+ 5 - 2
templates/webclient/profile.html

@@ -25,8 +25,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="profile_form" action="{{.CurrentURL}}" method="POST">

+ 5 - 2
templates/webclient/share.html

@@ -29,8 +29,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
         <form id="share_form" action="{{.CurrentURL}}" method="POST" autocomplete="off">

+ 22 - 21
templates/webclient/sharefiles.html

@@ -39,12 +39,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
     </div>
     <div class="card-body">
         {{if .Error}}
-        <div class="card mb-4 border-left-warning">
-            <div class="card-body text-form-error">{{.Error}}</div>
+        <div class="alert alert-warning alert-dismissible fade show" role="alert">
+            {{.Error}}
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         {{end}}
-        <div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-            <div id="errorTxt" class="card-body text-form-error"></div>
+        <div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+            <span id="errorTxt"></span>
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <span aria-hidden="true">&times;</span>
+            </button>
         </div>
         <div id="tableContainer" class="table-responsive">
             <table class="table table-hover nowrap" id="dataTable" width="100%" cellspacing="0">
@@ -307,14 +313,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
         $("#upload_files_form").submit(function (event){
             event.preventDefault();
-            var files = FilePond.find(document.getElementById("files_name")).getFiles();
-            var has_errors = false;
-            var index = 0;
-            var success = 0;
+            let files = FilePond.find(document.getElementById("files_name")).getFiles();
+            let has_errors = false;
+            let index = 0;
+            let success = 0;
             spinnerDone = false;
 
             $('#uploadFilesModal').modal('hide');
             $('#spinnerModal').modal('show');
+            $('#errorMsg').hide();
 
             function uploadFile() {
                 if (index >= files.length || has_errors){
@@ -327,12 +334,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
 
                 async function saveFile() {
-                    var errorMessage = "Error uploading files";
+                    let errorMessage = "Error uploading files";
                     let response;
                     try {
-                        var f = files[index].file;
-                        var uploadPath = '{{.UploadBaseURL}}'+fixedEncodeURIComponent("/"+escapeHTML(f.name));
-                        var lastModified;
+                        let f = files[index].file;
+                        let uploadPath = '{{.UploadBaseURL}}'+fixedEncodeURIComponent("/"+escapeHTML(f.name));
+                        let lastModified;
                         try {
                             lastModified = f.lastModified;
                         } catch (e) {
@@ -377,9 +384,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     has_errors = true;
                     $('#errorTxt').text(error.message);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                     uploadFile();
                 });
             }
@@ -426,15 +430,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
             enabled: true
         };
 
-        var table = $('#dataTable').DataTable({
+        let table = $('#dataTable').DataTable({
             "ajax": {
                 "url": "{{.DirsURL}}?path={{.CurrentDir}}",
                 "dataSrc": "",
                 "error": function ($xhr, textStatus, errorThrown) {
                     $(".dataTables_processing").hide();
-                    var txt = "Failed to get directory listing";
+                    let txt = "Failed to get directory listing";
                     if ($xhr) {
-                        var json = $xhr.responseJSON;
+                        let json = $xhr.responseJSON;
                         if (json) {
                             if (json.message){
                                 txt += ": " + json.message;
@@ -445,9 +449,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     }
                     $('#errorTxt').text(txt);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                 }
             },
             "deferRender": true,

+ 12 - 14
templates/webclient/shares.html

@@ -26,12 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 {{end}}
 
 {{define "page_body"}}
-<div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-    <div id="errorTxt" class="card-body text-form-error"></div>
-</div>
-
-<div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
-    <div id="successTxt" class="card-body"></div>
+<div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+    <span id="errorTxt"></span>
+    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+      <span aria-hidden="true">&times;</span>
+    </button>
 </div>
 
 <div class="card shadow mb-4">
@@ -153,11 +152,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 <script type="text/javascript">
 
     function deleteAction() {
-        var table = $('#dataTable').DataTable();
+        let table = $('#dataTable').DataTable();
         table.button('delete:name').enable(false);
-        var shareID = table.row({ selected: true }).data()[0];
-        var path = '{{.ShareURL}}' + "/" + fixedEncodeURIComponent(shareID);
+        let shareID = table.row({ selected: true }).data()[0];
+        let path = '{{.ShareURL}}' + "/" + fixedEncodeURIComponent(shareID);
         $('#deleteModal').modal('hide');
+        $('#errorMsg').hide();
+
         $.ajax({
             url: path,
             type: 'DELETE',
@@ -168,9 +169,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 window.location.href = '{{.SharesURL}}';
             },
             error: function ($xhr, textStatus, errorThrown) {
-                var txt = "Unable to delete the selected share";
+                let txt = "Unable to delete the selected share";
                 if ($xhr) {
-                    var json = $xhr.responseJSON;
+                    let json = $xhr.responseJSON;
                     if (json) {
                         if (json.message){
                             txt += ": " + json.message;
@@ -181,9 +182,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
                 $('#errorTxt').text(txt);
                 $('#errorMsg').show();
-                setTimeout(function () {
-                    $('#errorMsg').hide();
-                }, 5000);
             }
         });
     }

+ 14 - 13
templates/webclient/shareupload.html

@@ -26,8 +26,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 <h6 id="success_title" class="m-0 font-weight-bold text-primary" style="display: none;">Upload completed to share "{{.Share.Name}}", user "{{.Share.Username}}"</h6>
             </div>
             <div class="card-body">
-                <div id="errorMsg" class="card mb-4 border-left-warning" style="display: none;">
-                    <div id="errorTxt" class="card-body text-form-error"></div>
+                <div id="errorMsg" class="alert alert-warning alert-dismissible fade show" style="display: none;" role="alert">
+                    <span id="errorTxt"></span>
+                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                      <span aria-hidden="true">&times;</span>
+                    </button>
                 </div>
                 <div id="successMsg" class="card mb-4 border-left-success" style="display: none;">
                     <div id="successTxt" class="card-body">
@@ -72,13 +75,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
         $("#upload_files_form").submit(function (event){
             event.preventDefault();
-            var files = $("#files_name")[0].files;
-            var has_errors = false;
-            var index = 0;
-            var success = 0;
+            let files = $("#files_name")[0].files;
+            let has_errors = false;
+            let index = 0;
+            let success = 0;
             spinnerDone = false;
 
             $('#spinnerModal').modal('show');
+            $('#errorMsg').hide();
 
             function uploadFile() {
                 if (index >= files.length || has_errors){
@@ -95,12 +99,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                 }
 
                 async function saveFile() {
-                    var errorMessage = "Error uploading files";
+                    let errorMessage = "Error uploading files";
                     let response;
                     try {
-                        var f = files[index];
-                        var uploadPath = '{{.UploadBasePath}}/'+fixedEncodeURIComponent(escapeHTML(f.name));
-                        var lastModified;
+                        let f = files[index];
+                        let uploadPath = '{{.UploadBasePath}}/'+fixedEncodeURIComponent(escapeHTML(f.name));
+                        let lastModified;
                         try {
                             lastModified = f.lastModified;
                         } catch (e) {
@@ -145,9 +149,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
                     has_errors = true;
                     $('#errorTxt').text(error.message);
                     $('#errorMsg').show();
-                    setTimeout(function () {
-                        $('#errorMsg').hide();
-                    }, 10000);
                     uploadFile();
                 });
             }

+ 5 - 2
templates/webclient/twofactor-recovery.html

@@ -19,8 +19,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
 {{define "content"}}
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="login_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"

+ 5 - 2
templates/webclient/twofactor.html

@@ -19,8 +19,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
 
 {{define "content"}}
                                     {{if .Error}}
-                                    <div class="card mb-4 border-left-warning">
-                                        <div class="card-body text-form-error">{{.Error}}</div>
+                                    <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                                        {{.Error}}
+                                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+                                            <span aria-hidden="true">&times;</span>
+                                        </button>
                                     </div>
                                     {{end}}
                                     <form id="login_form" action="{{.CurrentURL}}" method="POST" autocomplete="off"