浏览代码

[Web] Remove blocking user_details function request in bcc list for faster loading with many mailboxes

andryyy 4 年之前
父节点
当前提交
7ab1405b00
共有 6 个文件被更改,包括 122 次插入95 次删除
  1. 32 0
      data/web/js/site/mailbox.js
  2. 28 1
      data/web/json_api.php
  3. 1 0
      data/web/lang/lang.de.json
  4. 2 2
      data/web/lang/lang.en.json
  5. 11 45
      data/web/modals/mailbox.php
  6. 48 47
      data/web/user.php

+ 32 - 0
data/web/js/site/mailbox.js

@@ -98,6 +98,38 @@ $(document).ready(function() {
     auto_fill_quota($('#addSelectDomain').val());
     auto_fill_quota($('#addSelectDomain').val());
   });
   });
   auto_fill_quota($('#addSelectDomain').val());
   auto_fill_quota($('#addSelectDomain').val());
+
+  // Read bcc local dests
+  // Using ajax to not be a blocking moo
+  $.get("/api/v1/get/bcc-destination-options", function(data){
+    // Domains
+    var optgroup = "<optgroup label='" + lang.domains + "'>";
+    $.each(data.domains, function(index, domain){
+      optgroup += "<option value='" + domain + "'>" + domain + "</option>"
+    });
+    optgroup += "</optgroup>"
+    $('#bcc-local-dest').append(optgroup);
+    // Alias domains
+    var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
+    $.each(data.alias_domains, function(index, alias_domain){
+      optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"
+    });
+    optgroup += "</optgroup>"
+    $('#bcc-local-dest').append(optgroup);
+    // Mailboxes and aliases
+    $.each(data.mailboxes, function(mailbox, aliases){
+      var optgroup = "<optgroup label='" + mailbox + "'>";
+      $.each(aliases, function(index, alias){
+        optgroup += "<option value='" + alias + "'>" + alias + "</option>"
+      });
+      optgroup += "</optgroup>"
+      $('#bcc-local-dest').append(optgroup);
+    });
+    // Finish
+    $('#bcc-local-dest').find('option:selected').remove();
+    $('#bcc-local-dest').selectpicker('refresh');
+  });
+
   $(".goto_checkbox").click(function( event ) {
   $(".goto_checkbox").click(function( event ) {
    $("form[data-id='add_alias'] .goto_checkbox").not(this).prop('checked', false);
    $("form[data-id='add_alias'] .goto_checkbox").not(this).prop('checked', false);
     if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
     if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {

+ 28 - 1
data/web/json_api.php

@@ -520,7 +520,7 @@ if (isset($_GET['query'])) {
               break;
               break;
             }
             }
           break;
           break;
-          
+
           case "postcat":
           case "postcat":
             switch ($object) {
             switch ($object) {
               default:
               default:
@@ -935,6 +935,33 @@ if (isset($_GET['query'])) {
               break;
               break;
             }
             }
           break;
           break;
+          case "bcc-destination-options":
+            $domains = mailbox('get', 'domains');
+            $alias_domains = mailbox('get', 'alias_domains');
+            $data = array();
+            if (!empty($domains)) {
+              foreach ($domains as $domain) {
+                $data['domains'][] = $domain;
+                $mailboxes = mailbox('get', 'mailboxes', $domain);
+                foreach ($mailboxes as $mailbox) {
+                  $data['mailboxes'][$mailbox][] = $mailbox;
+                  $user_alias_details = user_get_alias_details($mailbox);
+                  foreach ($user_alias_details['direct_aliases'] as $k => $v) {
+                    $data['mailboxes'][$mailbox][] = $k;
+                  }
+                  foreach ($user_alias_details['shared_aliases'] as $k => $v) {
+                    $data['mailboxes'][$mailbox][] = $k;
+                  }
+                }
+              }
+            }
+            if (!empty($alias_domains)) {
+              foreach ($alias_domains as $alias_domain) {
+                $data['alias_domains'][] = $alias_domain;
+              }
+            }
+            process_get_return($data);
+          break;
           case "syncjobs":
           case "syncjobs":
             switch ($object) {
             switch ($object) {
               case "all":
               case "all":

+ 1 - 0
data/web/lang/lang.de.json

@@ -48,6 +48,7 @@
         "app_password": "App-Passwort hinzufügen",
         "app_password": "App-Passwort hinzufügen",
         "automap": "Ordner automatisch mappen (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
         "automap": "Ordner automatisch mappen (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
         "backup_mx_options": "Relay-Optionen",
         "backup_mx_options": "Relay-Optionen",
+        "bcc_dest_format": "BCC-Ziel muss eine gültige E-Mail-Adresse sein.",
         "comment_info": "Ein privater Kommentar ist für den Benutzer nicht einsehbar. Ein öffentlicher Kommentar wird als Tooltip im Interface des Benutzers angezeigt.",
         "comment_info": "Ein privater Kommentar ist für den Benutzer nicht einsehbar. Ein öffentlicher Kommentar wird als Tooltip im Interface des Benutzers angezeigt.",
         "custom_params": "Eigene Parameter",
         "custom_params": "Eigene Parameter",
         "custom_params_hint": "Richtig: --param=xy, falsch: --param xy",
         "custom_params_hint": "Richtig: --param=xy, falsch: --param xy",

+ 2 - 2
data/web/lang/lang.en.json

@@ -48,7 +48,7 @@
         "app_password": "Add app password",
         "app_password": "Add app password",
         "automap": "Try to automap folders (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
         "automap": "Try to automap folders (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
         "backup_mx_options": "Relay options",
         "backup_mx_options": "Relay options",
-        "bcc_dest_format": "BCC destination must be a single valid email address.<br> If you need to send a copy to multiple addresses, create an Alias and use it here.",
+        "bcc_dest_format": "BCC destination must be a single valid email address.<br>If you need to send a copy to multiple addresses, create an alias and use it here.",
         "comment_info": "A private comment is not visible to the user, while a public comment is shown as tooltip when hovering it in a user's overview",
         "comment_info": "A private comment is not visible to the user, while a public comment is shown as tooltip when hovering it in a user's overview",
         "custom_params": "Custom parameters",
         "custom_params": "Custom parameters",
         "custom_params_hint": "Right: --param=xy, wrong: --param xy",
         "custom_params_hint": "Right: --param=xy, wrong: --param xy",
@@ -529,7 +529,7 @@
         "app_passwd": "App password",
         "app_passwd": "App password",
         "automap": "Try to automap folders (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
         "automap": "Try to automap folders (\"Sent items\", \"Sent\" => \"Sent\" etc.)",
         "backup_mx_options": "Relay options",
         "backup_mx_options": "Relay options",
-        "bcc_dest_format": "BCC destination must be a single valid email address.<br> If you need to send a copy to multiple addresses, create an Alias and use it here.",
+        "bcc_dest_format": "BCC destination must be a single valid email address.<br>If you need to send a copy to multiple addresses, create an alias and use it here.",
         "client_id": "Client ID",
         "client_id": "Client ID",
         "client_secret": "Client secret",
         "client_secret": "Client secret",
         "comment_info": "A private comment is not visible to the user, while a public comment is shown as tooltip when hovering it in a user's overview",
         "comment_info": "A private comment is not visible to the user, while a public comment is shown as tooltip when hovering it in a user's overview",

+ 11 - 45
data/web/modals/mailbox.php

@@ -112,8 +112,8 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
             <label class="control-label col-sm-2" for="mailboxes"><?=$lang['add']['max_mailboxes'];?></label>
             <label class="control-label col-sm-2" for="mailboxes"><?=$lang['add']['max_mailboxes'];?></label>
             <div class="col-sm-10">
             <div class="col-sm-10">
             <input type="number" class="form-control" name="mailboxes" value="10" required>
             <input type="number" class="form-control" name="mailboxes" value="10" required>
-						</div>
-					</div>
+            </div>
+          </div>
           <div class="form-group">
           <div class="form-group">
             <label class="control-label col-sm-2" for="defquota"><?=$lang['add']['mailbox_quota_def'];?></label>
             <label class="control-label col-sm-2" for="defquota"><?=$lang['add']['mailbox_quota_def'];?></label>
             <div class="col-sm-10">
             <div class="col-sm-10">
@@ -123,7 +123,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           <div class="form-group">
           <div class="form-group">
             <label class="control-label col-sm-2" for="maxquota"><?=$lang['add']['mailbox_quota_m'];?></label>
             <label class="control-label col-sm-2" for="maxquota"><?=$lang['add']['mailbox_quota_m'];?></label>
             <div class="col-sm-10">
             <div class="col-sm-10">
-						<input type="number" class="form-control" name="maxquota" value="10240" required>
+            <input type="number" class="form-control" name="maxquota" value="10240" required>
             </div>
             </div>
           </div>
           </div>
           <div class="form-group">
           <div class="form-group">
@@ -652,42 +652,8 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
           <div class="form-group">
           <div class="form-group">
             <label class="control-label col-sm-2" for="local_dest"><?=$lang['mailbox']['bcc_local_dest'];?></label>
             <label class="control-label col-sm-2" for="local_dest"><?=$lang['mailbox']['bcc_local_dest'];?></label>
             <div class="col-sm-10">
             <div class="col-sm-10">
-              <select data-live-search="true" data-size="20" name="local_dest" required>
-              <?php
-              $domains = mailbox('get', 'domains');
-              $alias_domains = mailbox('get', 'alias_domains');
-              if (!empty($domains)) {
-                echo '<optgroup label="',$lang['mailbox']['domains'],'">';
-                foreach ($domains as $domain) {
-                  echo "<option>".htmlspecialchars($domain)."</option>";
-                }
-                echo "</optgroup>";
-              }
-              if (!empty($alias_domains)) {
-                echo '<optgroup label="',$lang['mailbox']['domain_aliases'],'">';
-                foreach ($alias_domains as $alias_domain) {
-                  echo "<option>".htmlspecialchars($alias_domain)."</option>";
-                }
-                echo "</optgroup>";
-              }
-              if (!empty($domains)) {
-                foreach ($domains as $domain) {
-                  $mailboxes = mailbox('get', 'mailboxes', $domain);
-                  foreach ($mailboxes as $mailbox) {
-                    echo "<optgroup label=\"" . htmlspecialchars($mailbox) . "\">";
-                    echo "<option> " . htmlspecialchars($mailbox) . "</option>";
-                    $user_alias_details = user_get_alias_details($mailbox);
-                    foreach ($user_alias_details['direct_aliases'] as $k => $v) {
-                      echo "<option>" . htmlspecialchars($k) . "</option>";
-                    }
-                    foreach ($user_alias_details['shared_aliases'] as $k => $v) {
-                      echo "<option>" . htmlspecialchars($k) . "</option>";
-                    }
-                    echo "</optgroup>";
-                  }
-                }
-              }
-              ?>
+              <select id="bcc-local-dest" data-live-search="true" data-size="20" name="local_dest" required>
+                <option selected><?=$lang['footer']['loading'];?></option>
               </select>
               </select>
             </div>
             </div>
           </div>
           </div>
@@ -826,9 +792,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
   <div class="modal-dialog modal-lg" role="document">
   <div class="modal-dialog modal-lg" role="document">
     <div class="modal-content">
     <div class="modal-content">
       <div class="modal-header">
       <div class="modal-header">
-	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
-	    <h3 class="modal-title">Log</h3>
-	  </div>
+      <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+      <h3 class="modal-title">Log</h3>
+    </div>
       <div class="modal-body">
       <div class="modal-body">
         <textarea class="form-control" rows="20" id="logText" spellcheck="false"></textarea>
         <textarea class="form-control" rows="20" id="logText" spellcheck="false"></textarea>
       </div>
       </div>
@@ -840,9 +806,9 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
   <div class="modal-dialog modal-lg" role="document">
   <div class="modal-dialog modal-lg" role="document">
     <div class="modal-content">
     <div class="modal-content">
       <div class="modal-header">
       <div class="modal-header">
-	    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
-	    <h3 class="modal-title"><?=$lang['diagnostics']['dns_records'];?></h3>
-	  </div>
+      <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+      <h3 class="modal-title"><?=$lang['diagnostics']['dns_records'];?></h3>
+    </div>
       <div class="modal-body">
       <div class="modal-body">
         <p><?=$lang['diagnostics']['dns_records_24hours'];?></p>
         <p><?=$lang['diagnostics']['dns_records_24hours'];?></p>
         <div class="dns-modal-body"></div>
         <div class="dns-modal-body"></div>

+ 48 - 47
data/web/user.php

@@ -6,11 +6,12 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
   / DOMAIN ADMIN
   / DOMAIN ADMIN
   */
   */
 
 
-	require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
-	$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+  require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/header.inc.php';
+  $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
   $tfa_data = get_tfa();
   $tfa_data = get_tfa();
   $fido2_data = fido2(array("action" => "get_friendly_names"));
   $fido2_data = fido2(array("action" => "get_friendly_names"));
-	$username = $_SESSION['mailcow_cc_username'];
+  $username = $_SESSION['mailcow_cc_username'];
+  print_r(mailbox('get', 'mailbox_count'));
 
 
 ?>
 ?>
 <div class="container">
 <div class="container">
@@ -523,14 +524,14 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
     </div>
     </div>
   </div>
   </div>
 
 
-	<div role="tabpanel" class="tab-pane" id="SpamAliases">
+  <div role="tabpanel" class="tab-pane" id="SpamAliases">
     <div class="row">
     <div class="row">
       <div class="col-md-12 col-sm-12 col-xs-12">
       <div class="col-md-12 col-sm-12 col-xs-12">
         <div class="table-responsive">
         <div class="table-responsive">
           <table class="table table-striped" id="tla_table"></table>
           <table class="table table-striped" id="tla_table"></table>
         </div>
         </div>
       </div>
       </div>
-		</div>
+    </div>
     <div class="mass-actions-user">
     <div class="mass-actions-user">
       <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_alias'];?>">
       <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_alias'];?>">
         <div class="btn-group">
         <div class="btn-group">
@@ -566,9 +567,9 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>
-	</div>
+  </div>
 
 
-	<div role="tabpanel" class="tab-pane" id="Spamfilter">
+  <div role="tabpanel" class="tab-pane" id="Spamfilter">
     <h4><?=$lang['user']['spamfilter_behavior'];?></h4>
     <h4><?=$lang['user']['spamfilter_behavior'];?></h4>
     <div class="row">
     <div class="row">
       <div class="col-sm-12">
       <div class="col-sm-12">
@@ -599,10 +600,10 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
         </form>
         </form>
       </div>
       </div>
     </div>
     </div>
-		<hr>
-		<div class="row">
-			<div class="col-sm-6">
-				<h4><?=$lang['user']['spamfilter_wl'];?></h4>
+    <hr>
+    <div class="row">
+      <div class="col-sm-6">
+        <h4><?=$lang['user']['spamfilter_wl'];?></h4>
         <p><?=$lang['user']['spamfilter_wl_desc'];?></p>
         <p><?=$lang['user']['spamfilter_wl_desc'];?></p>
         <form class="form-inline space20" data-id="add_wl_policy_mailbox">
         <form class="form-inline space20" data-id="add_wl_policy_mailbox">
           <div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
           <div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
@@ -623,8 +624,8 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
-			<div class="col-sm-6">
-				<h4><?=$lang['user']['spamfilter_bl'];?></h4>
+      <div class="col-sm-6">
+        <h4><?=$lang['user']['spamfilter_bl'];?></h4>
         <p><?=$lang['user']['spamfilter_bl_desc'];?></p>
         <p><?=$lang['user']['spamfilter_bl_desc'];?></p>
         <form class="form-inline space20" data-id="add_bl_policy_mailbox">
         <form class="form-inline space20" data-id="add_bl_policy_mailbox">
           <div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
           <div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
@@ -648,13 +649,13 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
     </div>
     </div>
   </div>
   </div>
 
 
-	<div role="tabpanel" class="tab-pane" id="Syncjobs">
-		<div class="table-responsive">
+  <div role="tabpanel" class="tab-pane" id="Syncjobs">
+    <div class="table-responsive">
       <table class="table table-striped" id="sync_job_table"></table>
       <table class="table table-striped" id="sync_job_table"></table>
-		</div>
+    </div>
     <div class="mass-actions-user">
     <div class="mass-actions-user">
       <div class="btn-group" data-acl="<?=$_SESSION['acl']['syncjobs'];?>">
       <div class="btn-group" data-acl="<?=$_SESSION['acl']['syncjobs'];?>">
-	    <div class="btn-group">
+      <div class="btn-group">
         <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
         <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
         <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
         <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
         <ul class="dropdown-menu">
         <ul class="dropdown-menu">
@@ -664,40 +665,40 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
           <li><a data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#"><?=$lang['mailbox']['remove'];?></a></li>
           <li><a data-action="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#"><?=$lang['mailbox']['remove'];?></a></li>
         </ul>
         </ul>
         <div class="clearfix visible-xs"></div>
         <div class="clearfix visible-xs"></div>
-	    </div>
-	    <div class="btn-group">
+      </div>
+      <div class="btn-group">
         <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><i class="bi bi-plus-lg"></i> <?=$lang['user']['create_syncjob'];?></a>
         <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><i class="bi bi-plus-lg"></i> <?=$lang['user']['create_syncjob'];?></a>
-	    </div>
+      </div>
       </div>
       </div>
     </div>
     </div>
   </div>
   </div>
 
 
-	<div role="tabpanel" class="tab-pane" id="AppPasswds">
-	    <p><?=$lang['user']['app_hint'];?></p>
-		<div class="table-responsive">
-	      <table class="table table-striped" id="app_passwd_table"></table>
-		</div>
-	    <div class="mass-actions-user">
-	      <div class="btn-group" data-acl="<?=$_SESSION['acl']['app_passwds'];?>">
-		    <div class="btn-group">
-	          <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="apppasswd" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
-	          <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
-	          <ul class="dropdown-menu">
-	            <li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
-	            <li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
-	            <li role="separator" class="divider"></li>
-	            <li><a data-action="delete_selected" data-id="apppasswd" data-api-url='delete/app-passwd' href="#"><?=$lang['mailbox']['remove'];?></a></li>
-	          </ul>
-	          <div class="clearfix visible-xs"></div>
-		    </div>
-		    <div class="btn-group">
-	          <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addAppPasswdModal"><i class="bi bi-plus-lg"></i> <?=$lang['user']['create_app_passwd'];?></a>
-		    </div>
-	      </div>
-	    </div>
-	</div>
+  <div role="tabpanel" class="tab-pane" id="AppPasswds">
+      <p><?=$lang['user']['app_hint'];?></p>
+    <div class="table-responsive">
+        <table class="table table-striped" id="app_passwd_table"></table>
+    </div>
+      <div class="mass-actions-user">
+        <div class="btn-group" data-acl="<?=$_SESSION['acl']['app_passwds'];?>">
+        <div class="btn-group">
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" id="toggle_multi_select_all" data-id="apppasswd" href="#"><i class="bi bi-check-all"></i> <?=$lang['mailbox']['toggle_all'];?></a>
+            <a class="btn btn-sm btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+            <ul class="dropdown-menu">
+              <li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
+              <li><a data-action="edit_selected" data-id="apppasswd" data-api-url='edit/app-passwd' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
+              <li role="separator" class="divider"></li>
+              <li><a data-action="delete_selected" data-id="apppasswd" data-api-url='delete/app-passwd' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+            </ul>
+            <div class="clearfix visible-xs"></div>
+        </div>
+        <div class="btn-group">
+            <a class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" href="#" data-toggle="modal" data-target="#addAppPasswdModal"><i class="bi bi-plus-lg"></i> <?=$lang['user']['create_app_passwd'];?></a>
+        </div>
+        </div>
+      </div>
+  </div>
 
 
-	<div role="tabpanel" class="tab-pane" id="Pushover">
+  <div role="tabpanel" class="tab-pane" id="Pushover">
     <form data-id="pushover" class="form well" method="post">
     <form data-id="pushover" class="form well" method="post">
       <input type="hidden" value="0" name="evaluate_x_prio">
       <input type="hidden" value="0" name="evaluate_x_prio">
       <input type="hidden" value="0" name="only_x_prio">
       <input type="hidden" value="0" name="only_x_prio">
@@ -803,7 +804,7 @@ $js_minifier->add('/web/js/site/pwgen.js');
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
 }
 }
 else {
 else {
-	header('Location: /');
-	exit();
+  header('Location: /');
+  exit();
 }
 }
 ?>
 ?>