Quellcode durchsuchen

FM progress bar while uploading. Minor CPanel improvements as well as performance.

Alexander vor 4 Jahren
Ursprung
Commit
5b2c180d86
36 geänderte Dateien mit 311 neuen und 244 gelöschten Zeilen
  1. 12 0
      src/react/src/ControlPanelService/Firewalls.js
  2. 2 2
      src/react/src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput.jsx
  3. 2 5
      src/react/src/components/ControlPanel/ListItem/ListItem.jsx
  4. 5 5
      src/react/src/components/Firewall/Add/AddFirewall.jsx
  5. 1 1
      src/react/src/components/InternetProtocol/Edit/EditInternetProtocol.jsx
  6. 5 6
      src/react/src/components/InternetProtocol/InternetProtocol.jsx
  7. 8 0
      src/react/src/components/InternetProtocol/InternetProtocol.scss
  8. 1 1
      src/react/src/components/Lists/Row/Row.jsx
  9. 13 1
      src/react/src/components/Lists/Row/Row.scss
  10. 1 1
      src/react/src/components/MailAccount/Add/AddMailAccount.jsx
  11. 1 1
      src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx
  12. 4 4
      src/react/src/components/MainNav/Panel/Panel.jsx
  13. 4 5
      src/react/src/components/MainNav/Panel/Panel.scss
  14. 83 60
      src/react/src/components/MainNav/Stat-menu/Menu.jsx
  15. 1 1
      src/react/src/components/Modal/Archive.jsx
  16. 7 1
      src/react/src/components/Path/Path.jsx
  17. 2 2
      src/react/src/components/ProgressBar/ProgressBar.jsx
  18. 10 7
      src/react/src/components/ProgressBar/ProgressBar.scss
  19. 35 39
      src/react/src/components/Server/Edit/EditBackupOption.jsx
  20. 6 0
      src/react/src/components/Server/Edit/EditServer.jsx
  21. 2 2
      src/react/src/components/Server/Edit/EditVestaPlugins.jsx
  22. 1 0
      src/react/src/components/Server/Server.jsx
  23. 10 20
      src/react/src/components/User/User.jsx
  24. 2 1
      src/react/src/components/WebDomain/Add/AddWebDomain.jsx
  25. 6 5
      src/react/src/components/WebDomain/Add/AdditionalFtpForEditing/AdditionalFtpForEditing.jsx
  26. 1 1
      src/react/src/components/WebDomain/WebDomain.jsx
  27. 7 1
      src/react/src/containers/Databases/Databases.jsx
  28. 47 49
      src/react/src/containers/FileManager/FileManager.js
  29. 2 3
      src/react/src/containers/Firewalls/Banlist/index.jsx
  30. 2 2
      src/react/src/containers/Firewalls/Firewalls.jsx
  31. 2 2
      src/react/src/containers/MailWrapper/MailWrapper.jsx
  32. 1 1
      src/react/src/containers/Mails/Mails.jsx
  33. 3 8
      src/react/src/containers/Servers/Servers.jsx
  34. 12 1
      src/react/src/containers/Users/Users.jsx
  35. 7 3
      src/react/src/containers/WebLogs/WebLogs.jsx
  36. 3 3
      src/react/src/containers/WebLogs/WebLogs.scss

+ 12 - 0
src/react/src/ControlPanelService/Firewalls.js

@@ -17,6 +17,18 @@ export const getBanList = () => {
   return axios.get(BASE_URL + banListUri);
 }
 
+export const bulkFirewallAction = (action, ips) => {
+  const formData = new FormData();
+  formData.append("action", action);
+  formData.append("token", getAuthToken());
+
+  ips.forEach(ip => {
+    formData.append("rule[]", ip);
+  });
+
+  return axios.post(BASE_URL + '/api/v1/bulk/firewall/', formData);
+};
+
 export const bulkAction = (action, ips, banIps) => {
   const formData = new FormData();
   formData.append("action", action);

+ 2 - 2
src/react/src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput.jsx

@@ -9,7 +9,7 @@ const TextInput = ({ id, name, title, optionalTitle = '', type = 'text', onChang
     }
   }, [value]);
 
-  const changeCheckbox = event => {
+  const changeInputHandler = event => {
     setInputValue(event.target.value);
     onChange(event);
   }
@@ -24,7 +24,7 @@ const TextInput = ({ id, name, title, optionalTitle = '', type = 'text', onChang
         type={type}
         name={name}
         id={id}
-        onChange={changeCheckbox}
+        onChange={changeInputHandler}
         readOnly={disabled}
         value={inputValue}
         className="form-control" />

+ 2 - 5
src/react/src/components/ControlPanel/ListItem/ListItem.jsx

@@ -52,14 +52,10 @@ const ListItem = (props) => {
       className += ' outdated';
     }
 
-    if (suspended) {
+    if (suspended || stopped) {
       className += ' suspended';
     }
 
-    if (stopped) {
-      className += ' stopped';
-    }
-
     if (focused) {
       className += ' focused';
     }
@@ -84,6 +80,7 @@ const ListItem = (props) => {
           <div onClick={starItem}><FontAwesomeIcon icon="star" /></div>
         </div>
         {props.suspended && <div className='suspended'>{i18n.suspended}</div>}
+        {props.stopped && <div className='stopped'>{i18n.stopped}</div>}
       </Container>
       {props.children}
     </div>

+ 5 - 5
src/react/src/components/Firewall/Add/AddFirewall.jsx

@@ -23,13 +23,13 @@ const AddFirewall = props => {
   const [state, setState] = useState({
     loading: false,
     actions: [
-      i18n['DROP'],
-      i18n['ACCEPT']
+      'DROP',
+      'ACCEPT'
     ],
     protocols: [
-      i18n['TCP'],
-      i18n['UDP'],
-      i18n['ICMP']
+      'TCP',
+      'UDP',
+      'ICMP'
     ],
     okMessage: '',
     errorMessage: ''

+ 1 - 1
src/react/src/components/InternetProtocol/Edit/EditInternetProtocol.jsx

@@ -70,7 +70,7 @@ const EditInternetProtocol = () => {
 
     updatedIP['token'] = token;
     updatedIP['save'] = 'save';
-    updatedIP['v_ip'] = state.data.database;
+    updatedIP['v_ip'] = state.data.ip;
 
     if (Object.keys(updatedIP).length !== 0 && updatedIP.constructor === Object) {
       setState({ ...state, loading: true });

+ 5 - 6
src/react/src/components/InternetProtocol/InternetProtocol.jsx

@@ -1,15 +1,14 @@
-import React, { Component } from 'react';
+import React from 'react';
 import ListItem from '../ControlPanel/ListItem/ListItem';
 import Container from '../ControlPanel/Container/Container';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import './InternetProtocol.scss';
 import { Link } from 'react-router-dom';
 import { useSelector } from 'react-redux';
+import './InternetProtocol.scss';
 
 const InternetProtocol = props => {
   const { data } = props;
   const { i18n } = useSelector(state => state.session);
-  const token = localStorage.getItem("token");
 
   const toggleFav = (starred) => {
     if (starred) {
@@ -38,7 +37,7 @@ const InternetProtocol = props => {
       checkItem={checkItem}>
 
       <Container className="r-col w-85">
-        <div className="name">{data.NAME}</div>
+        <div className="name">{data.NAT ? <>{data.NAT} <FontAwesomeIcon icon="long-arrow-alt-right" /> {data.NAME}</> : data.NAME}</div>
         <br />
         <div className="stats">
           <Container className="c-1 w-35">
@@ -51,7 +50,7 @@ const InternetProtocol = props => {
           </Container>
           <Container className="c-3 w-35">
             <div>{i18n.Owner}: <span className="stat">{data.OWNER}</span></div>
-            <div>{i18n.Users}: <span className="stat">{data.U_SYS_USERS.replace(',', ', ')}</span></div>
+            <div>{i18n.Users}: <span className="stat">{data.U_SYS_USERS.replaceAll(',', ', ')}</span></div>
           </Container>
         </div>
       </Container>
@@ -74,4 +73,4 @@ const InternetProtocol = props => {
   );
 }
 
-export default InternetProtocol;
+export default InternetProtocol;

+ 8 - 0
src/react/src/components/InternetProtocol/InternetProtocol.scss

@@ -0,0 +1,8 @@
+.internetProtocols {
+  .ip-wrapper {
+    .name svg {
+      margin: 0 10px;
+      font-size: 20px;
+    }
+  }
+}

+ 1 - 1
src/react/src/components/Lists/Row/Row.jsx

@@ -174,7 +174,7 @@ class Row extends Component {
   render() {
     const { data: { name, owner, permissions, size, date, time } } = this.props;
     return (
-      <li className={this.className()} onClick={this.selectRow} >
+      <li className={this.className()} onClick={this.selectRow} id={name}>
         <span className="marker"></span>
         {this.glyph()}
         <span className="fName"><span className="name" onClick={(e) => this.openItem(e)}>{this.props.cursor === 0 ? ".." : name}</span></span>

+ 13 - 1
src/react/src/components/Lists/Row/Row.scss

@@ -169,8 +169,20 @@ li.inactive {
   background: rgb(220, 220, 220);
 }
 
-@media (max-width: 1320px){
+@media (max-width: 1400px){
   .fPermissions, .fOwner {
     display: none;
   }
 }
+
+@media (max-width: 1100px){
+  .fDate {
+    display: none;
+  }
+}
+
+@media (max-width: 970px){
+  .fTime {
+    display: none;
+  }
+}

+ 1 - 1
src/react/src/components/MailAccount/Add/AddMailAccount.jsx

@@ -139,7 +139,7 @@ export default function AddMailAccount(props) {
 
                 <TextInput
                   title={i18n['Account']}
-                  onChange={e => setState({ ...state, username: e.target.value })}
+                  onChange={e => setState({ ...state, userName: e.target.value })}
                   name="v_account"
                   id="account" />
 

+ 1 - 1
src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx

@@ -106,7 +106,7 @@ export default function MailInfoBlock({ webMail, hostName, domain, userName = ''
 
           <div>
             <span>{i18n['Webmail URL']}:</span>
-            <span><Link to={{ pathname: `${window.location.protocol}//${window.location.hostname}${state.webMail}` }}>{webMail}</Link></span>
+            <span><Link to={{ pathname: `http://${window.location.hostname}${webMail}` }} target="_blank">{webMail}</Link></span>
           </div>
 
           <input type="hidden" name={i18n['Username']} value={`@${domain}`} />

+ 4 - 4
src/react/src/components/MainNav/Panel/Panel.jsx

@@ -9,7 +9,7 @@ import { Link } from "react-router-dom";
 import './Panel.scss';
 
 const Panel = props => {
-  const { i18n, userName } = useSelector(state => state.session);
+  const { i18n, userName, panel } = useSelector(state => state.session);
   const { session } = useSelector(state => state.userSession);
   const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
   const dispatch = useDispatch();
@@ -113,8 +113,8 @@ const Panel = props => {
           )}
         </div>
         <div className="container profile-menu">
-          <Notifications />
-          <div>
+          {panel[userName]['NOTIFICATIONS'] === 'yes' && <Notifications />}
+          <div className="edit-user">
             <Link to={`/edit/user?user=${userName}`}>
               {session.look
                 ? <div className="long-username">
@@ -126,7 +126,7 @@ const Panel = props => {
               }
             </Link>
           </div>
-          <div><button onClick={signOut}>{i18n['Log out']}</button></div>
+          <div className="logout-button"><button onClick={signOut}>{i18n['Log out']}</button></div>
         </div>
       </div>
 

+ 4 - 5
src/react/src/components/MainNav/Panel/Panel.scss

@@ -144,7 +144,6 @@ $textColor: #555;
     width: auto;
 
     div {
-      width: 4rem;
       height: 100%;
     }
 
@@ -169,7 +168,7 @@ $textColor: #555;
       }
     }
 
-    div + div a {
+    .edit-user a {
       color: #a4abad;
       font-weight: 700;
     
@@ -182,8 +181,8 @@ $textColor: #555;
       }
     }
 
-    div + div + div a,
-    div + div + div button {
+    .logout-button a,
+    .logout-button button {
       color: white;
       cursor: pointer;
       font-weight: 100;
@@ -220,7 +219,7 @@ $textColor: #555;
     justify-content: space-between;
     align-items: center;
 
-    > div + div {
+    > .edit-user {
       width: max-content;
     }
 

+ 83 - 60
src/react/src/components/MainNav/Stat-menu/Menu.jsx

@@ -27,7 +27,7 @@ const style = ({ menuHeight, mobile }) => {
 
 const Menu = props => {
   const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
-  const { i18n } = useSelector(state => state.session);
+  const { i18n, panel, userName } = useSelector(state => state.session);
   const { session } = useSelector(state => state.userSession);
   const { user } = useSelector(state => state.menuCounters);
   const dispatch = useDispatch();
@@ -72,10 +72,16 @@ const Menu = props => {
             <h3>{i18n.USER}</h3>
             <div className="stats">
               {
-                session.look
+                session.look && panel[session.look]
                   ? (<>
-                    <div><span>{i18n.Disk}:</span> <span>{sizeFormatter(user.U_DISK)}</span></div>
-                    <div><span>{i18n.Bandwidth}:</span> <span>{sizeFormatter(user.U_BANDWIDTH)}</span></div>
+                    <div>
+                      <span>{i18n.Disk}:</span>
+                      <span><span className="value">{user.U_DISK} <span className="unit">{panel[session.look]['U_DISK_MEASURE']}</span></span></span>
+                    </div>
+                    <div>
+                      <span>{i18n.Bandwidth}:</span>
+                      <span><span className="value">{user.U_BANDWIDTH} <span className="unit">{panel[session.look]['U_BANDWIDTH_MEASURE']}</span></span></span>
+                    </div>
                   </>)
                   : (<>
                     <div><span>{i18n.users}:</span> <span>{user.U_USERS}</span></div>
@@ -85,62 +91,79 @@ const Menu = props => {
             </div>
           </Link>
         </div>
-        <div className={statClassName("/list/web/")}>
-          <Link to="/list/web/" onClick={event => handleState("/list/web/", event)} onKeyPress={event => event.preventDefault()}>
-            <h3>{i18n.WEB}</h3>
-            <div className="stats">
-              <div><span>{i18n.domains}:</span> <span>{user.U_WEB_DOMAINS}</span></div>
-              <div><span>{i18n.aliases}:</span> <span>{user.U_WEB_ALIASES}</span></div>
-              <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_WEB}</span></div>
-            </div>
-          </Link>
-        </div>
-        <div className={statClassName("/list/dns/")}>
-          <Link to="/list/dns/" onClick={event => handleState("/list/dns/", event)} onKeyPress={event => event.preventDefault()}>
-            <h3>{i18n.DNS}</h3>
-            <div className="stats">
-              <div><span>{i18n.domains}:</span> <span>{user.U_DNS_DOMAINS}</span></div>
-              <div><span>{i18n.records}:</span> <span>{user.U_DNS_RECORDS}</span></div>
-              <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_DNS}</span></div>
-            </div>
-          </Link>
-        </div>
-        <div className={statClassName("/list/mail/")}>
-          <Link to="/list/mail/" onClick={event => handleState("/list/mail/", event)} onKeyPress={event => event.preventDefault()}>
-            <h3>{i18n.MAIL}</h3>
-            <div className="stats">
-              <div><span>{i18n.domains}:</span> <span>{user.U_MAIL_DOMAINS}</span></div>
-              <div><span>{i18n.accounts}:</span> <span>{user.U_MAIL_ACCOUNTS}</span></div>
-              <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_MAIL}</span></div>
-            </div>
-          </Link>
-        </div>
-        <div className={statClassName("/list/db/")}>
-          <Link to="/list/db/" onClick={event => handleState("/list/db/", event)} onKeyPress={event => event.preventDefault()}>
-            <h3>{i18n.DB}</h3>
-            <div className="stats">
-              <div><span>{i18n.databases}:</span> <span>{user.U_DATABASES}</span></div>
-              <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_DB}</span></div>
-            </div>
-          </Link>
-        </div>
-        <div className={statClassName("/list/cron/")}>
-          <Link to="/list/cron/" onClick={event => handleState("/list/cron/", event)} onKeyPress={event => event.preventDefault()}>
-            <h3>{i18n.CRON}</h3>
-            <div className="stats">
-              <div><span>{i18n.jobs}:</span> <span>{user.U_CRON_JOBS}</span></div>
-              <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_CRON}</span></div>
-            </div>
-          </Link>
-        </div>
-        <div className={statClassName("/list/backup/") + ' last'}>
-          <Link to="/list/backup/" onClick={event => handleState("/list/backup/", event)} onKeyPress={event => event.preventDefault()}>
-            <h3>{i18n.BACKUP}</h3>
-            <div className="stats">
-              <div><span>{i18n.backups}:</span> <span>{user.U_BACKUPS}</span></div>
-            </div>
-          </Link>
-        </div>
+        {
+          panel[userName]['WEB_DOMAINS'] !== '0' && (<div className={statClassName("/list/web/")}>
+            <Link to="/list/web/" onClick={event => handleState("/list/web/", event)} onKeyPress={event => event.preventDefault()}>
+              <h3>{i18n.WEB}</h3>
+              <div className="stats">
+                <div><span>{i18n.domains}:</span> <span>{user.U_WEB_DOMAINS}</span></div>
+                <div><span>{i18n.aliases}:</span> <span>{user.U_WEB_ALIASES}</span></div>
+                <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_WEB}</span></div>
+              </div>
+            </Link>
+          </div>)
+        }
+
+        {
+          panel[userName]['DNS_DOMAINS'] !== '0' && (<div className={statClassName("/list/dns/")}>
+            <Link to="/list/dns/" onClick={event => handleState("/list/dns/", event)} onKeyPress={event => event.preventDefault()}>
+              <h3>{i18n.DNS}</h3>
+              <div className="stats">
+                <div><span>{i18n.domains}:</span> <span>{user.U_DNS_DOMAINS}</span></div>
+                <div><span>{i18n.records}:</span> <span>{user.U_DNS_RECORDS}</span></div>
+                <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_DNS}</span></div>
+              </div>
+            </Link>
+          </div>)
+        }
+
+        {
+          panel[userName]['MAIL_DOMAINS'] !== '0' && (<div className={statClassName("/list/mail/")}>
+            <Link to="/list/mail/" onClick={event => handleState("/list/mail/", event)} onKeyPress={event => event.preventDefault()}>
+              <h3>{i18n.MAIL}</h3>
+              <div className="stats">
+                <div><span>{i18n.domains}:</span> <span>{user.U_MAIL_DOMAINS}</span></div>
+                <div><span>{i18n.accounts}:</span> <span>{user.U_MAIL_ACCOUNTS}</span></div>
+                <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_MAIL}</span></div>
+              </div>
+            </Link>
+          </div>)
+        }
+
+        {
+          panel[userName]['DATABASES'] !== '0' && (<div className={statClassName("/list/db/")}>
+            <Link to="/list/db/" onClick={event => handleState("/list/db/", event)} onKeyPress={event => event.preventDefault()}>
+              <h3>{i18n.DB}</h3>
+              <div className="stats">
+                <div><span>{i18n.databases}:</span> <span>{user.U_DATABASES}</span></div>
+                <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_DB}</span></div>
+              </div>
+            </Link>
+          </div>)
+        }
+
+        {
+          panel[userName]['CRON_JOBS'] !== '0' && (<div className={statClassName("/list/cron/")}>
+            <Link to="/list/cron/" onClick={event => handleState("/list/cron/", event)} onKeyPress={event => event.preventDefault()}>
+              <h3>{i18n.CRON}</h3>
+              <div className="stats">
+                <div><span>{i18n.jobs}:</span> <span>{user.U_CRON_JOBS}</span></div>
+                <div><span>{i18n.spnd}:</span> <span>{user.SUSPENDED_CRON}</span></div>
+              </div>
+            </Link>
+          </div>)
+        }
+
+        {
+          panel[userName]['BACKUPS'] !== '0' && (<div className={statClassName("/list/backup/") + ' last'}>
+            <Link to="/list/backup/" onClick={event => handleState("/list/backup/", event)} onKeyPress={event => event.preventDefault()}>
+              <h3>{i18n.BACKUP}</h3>
+              <div className="stats">
+                <div><span>{i18n.backups}:</span> <span>{user.U_BACKUPS}</span></div>
+              </div>
+            </Link>
+          </div>)
+        }
       </div>
     </div>
   );

+ 1 - 1
src/react/src/components/Modal/Archive.jsx

@@ -15,7 +15,7 @@ const Archive = (props) => {
         <input type="text" autoFocus defaultValue={`${props.path}/${props.fName}.tar.gz`} onBlur={props.onChange} ref={props.reference}></input>
       </div>
       <div className="modal-footer">
-        <button type="button" className="btn btn-danger mr-auto" onClick={props.close}>{i18n.Compress}</button>
+        <button type="button" className="btn btn-danger mr-auto" onClick={props.close}>{i18n.Cancel}</button>
         <button type="button" className="btn btn-primary" onClick={props.save}>{i18n.Compress}</button>
       </div>
     </div>

+ 7 - 1
src/react/src/components/Path/Path.jsx

@@ -1,11 +1,17 @@
-import React from 'react';
+import React, { useEffect } from 'react';
 import { useSelector } from 'react-redux';
+import { useHistory } from 'react-router';
 
 import Dropdown from './Dropdown/Dropdown';
 import './Path.scss';
 
 const Path = ({ path, isActive, className, openDirectory, changeSorting, sorting, order }) => {
   const { user } = useSelector(state => state.menuCounters);
+  const history = useHistory();
+
+  useEffect(() => {
+    if (!user) return history.push('/login');
+  }, [user]);
 
   const clickablePath = () => {
     let splitPath = path.split('/');

+ 2 - 2
src/react/src/components/ProgressBar/ProgressBar.jsx

@@ -3,10 +3,10 @@ import './ProgressBar.scss';
 
 const ProgressBar = (props) => {
   return (
-    <div class="progress">
+    <div class="progress upload" style={{ overflow: props.progress !== "0" ? 'visible' : 'hidden' }}>
       <div class="progress-bar" role="progressbar" style={{ width: `${props.progress}%` }} aria-valuenow={props.progress} aria-valuemin="0" aria-valuemax="100"></div>
     </div>
   );
 }
 
-export default ProgressBar;
+export default ProgressBar;

+ 10 - 7
src/react/src/components/ProgressBar/ProgressBar.scss

@@ -1,13 +1,16 @@
-.spinner-wrapper .progress {
-  position: absolute;
-  top: 0;
-  z-index: 5;
+.progress.upload {
+  position: fixed;
+  left: 0px;
+  top: 0px;
+  z-index: 9999;
+  height: 5px;
+  position: fixed;
   width: 100%;
   margin: 0;
-  height: 6px;
   display: inline-table;
+  background: transparent;
 
   .progress-bar {
-    height: 10px;
+    height: 5px;
   }
-}
+}

+ 35 - 39
src/react/src/components/Server/Edit/EditBackupOption.jsx

@@ -31,51 +31,47 @@ const EditBackupOption = ({ data, visible }) => {
         name="v_backup_dir"
         id="v-backup-dir" />
 
+      <button type="button" onClick={() => setRemoteBackup(!remoteBackup)}>
+        {i18n['Remote backup']}
+        {remoteBackup ? <FontAwesomeIcon icon="caret-up" /> : <FontAwesomeIcon icon="caret-down" />}
+      </button>
+
       {
-        data.backup_remote_adv && (
-          <>
-            <button type="button" onClick={() => setRemoteBackup(!remoteBackup)}>
-              {i18n['Remote backup']}
-              {remoteBackup ? <FontAwesomeIcon icon="caret-up" /> : <FontAwesomeIcon icon="caret-down" />}
-            </button>
+        remoteBackup && (
+          <div style={{ transform: 'translateX(3rem)' }}>
+            <br />
 
-            {
-              remoteBackup && (
-                <>
-                  <SelectInput
-                    selected={data.backup_type}
-                    options={data.protocols}
-                    title={i18n['Protocol']}
-                    name="v_backup_type"
-                    id="backup_type" />
+            <SelectInput
+              selected={data.backup_type}
+              options={data.protocols}
+              title={i18n['Protocol']}
+              name="v_backup_type"
+              id="backup_type" />
 
-                  <TextInput
-                    title={i18n['Host']}
-                    value={data.backup_host}
-                    name="v_backup_host"
-                    id="backup_host" />
+            <TextInput
+              title={i18n['Host']}
+              value={data.backup_host}
+              name="v_backup_host"
+              id="backup_host" />
 
-                  <TextInput
-                    title={i18n['Username']}
-                    value={data.backup_username}
-                    name="v_backup_username"
-                    id="backup_username" />
+            <TextInput
+              title={i18n['Username']}
+              value={data.backup_username}
+              name="v_backup_username"
+              id="backup_username" />
 
-                  <TextInput
-                    title={i18n['Password']}
-                    value={data.backup_password}
-                    name="v_backup_password"
-                    id="backup_password" />
+            <TextInput
+              title={i18n['Password']}
+              value={data.backup_password}
+              name="v_backup_password"
+              id="backup_password" />
 
-                  <TextInput
-                    title={i18n['Directory']}
-                    value={data.backup_bpath}
-                    name="v_backup_bpath"
-                    id="backup_bpath" />
-                </>
-              )
-            }
-          </>
+            <TextInput
+              title={i18n['Directory']}
+              value={data.backup_bpath}
+              name="v_backup_bpath"
+              id="backup_bpath" />
+          </div>
         )
       }
     </div>

+ 6 - 0
src/react/src/components/Server/Edit/EditServer.jsx

@@ -163,6 +163,12 @@ const EditServer = props => {
               name="v_language"
               id="language" />
 
+            {/* <TextInput
+              value={state.data.port}
+              title={i18n['Default Port'] ?? 'Default Port'}
+              name="port"
+              id="port" /> */}
+
             <div className="modules">
               <button type="button" onClick={() => toggleOption('webOption')}>
                 {i18n['WEB']}

+ 2 - 2
src/react/src/components/Server/Edit/EditVestaPlugins.jsx

@@ -156,14 +156,14 @@ const EditVestaPluginsOption = ({ data, visible }) => {
 
       <SelectInput
         title={i18n['Reseller Role']}
-        options={[i18n['yes']]}
+        options={[i18n['no']]}
         name="v_reseller"
         id="reseller"
         disabled />
 
       <SelectInput
         title={i18n['Backup Migration Manager']}
-        options={[i18n['yes']]}
+        options={[i18n['no']]}
         name="v_backup_manager"
         id="backup_manager"
         disabled />

+ 1 - 0
src/react/src/components/Server/Server.jsx

@@ -19,6 +19,7 @@ const Server = props => {
       id={data.NAME}
       focused={data.FOCUSED}
       checked={data.isChecked}
+      stopped={data.STATE === 'stopped'}
       checkItem={checkItem}>
 
       <Container className="r-col w-85">

+ 10 - 20
src/react/src/components/User/User.jsx

@@ -1,16 +1,14 @@
 import React from 'react';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { loginAs, logout } from 'src/actions/Session/sessionActions';
 import Container from '../ControlPanel/Container/Container';
 import ListItem from '../ControlPanel/ListItem/ListItem';
-import { useDispatch, useSelector } from 'react-redux';
+import { useSelector } from 'react-redux';
 import { Link } from 'react-router-dom';
 
 import './User.scss';
 
-const User = ({ data, toggleFav, handleModal, checkItem }) => {
+const User = ({ data, toggleFav, handleModal, checkItem, logOut, logInAs }) => {
   const { i18n, userName } = useSelector(state => state.session);
-  const dispatch = useDispatch();
 
   const printNameServers = servers => {
     let serversArray = servers.split(',');
@@ -20,20 +18,12 @@ const User = ({ data, toggleFav, handleModal, checkItem }) => {
     );
   }
 
-  const signInAs = username => {
-    dispatch(loginAs(username));
-  }
-
-  const signOut = () => {
-    dispatch(logout());
-  }
-
   const printLoginActionButton = user => {
     let currentUser = userName;
     if (currentUser === user) {
       return (
         <div>
-          <button onClick={signOut}>{i18n['Log out']}
+          <button onClick={logOut}>{i18n['Log out']}
             {data.FOCUSED ? <span className="shortcut-button">L</span> : <FontAwesomeIcon icon="user-lock" />}
           </button>
         </div>
@@ -41,7 +31,7 @@ const User = ({ data, toggleFav, handleModal, checkItem }) => {
     } else {
       return (
         <div>
-          <button onClick={() => signInAs(user)}>{i18n['login as']} {user}
+          <button onClick={() => logInAs(user)}>{i18n['login as']} {user}
             {data.FOCUSED ? <span className="shortcut-button">L</span> : <FontAwesomeIcon icon="user-lock" />}
           </button>
         </div>
@@ -86,16 +76,16 @@ const User = ({ data, toggleFav, handleModal, checkItem }) => {
         <div>{data.FNAME} {data.LNAME}</div>
         <div className="stats">
           <Container className="c-1">
-            <div className="bandwidth">{i18n.Bandwidth} <span><span className="stat">{data.U_BANDWIDTH}</span> {i18n.mb}</span></div>
-            <div className="disk">{i18n.Disk}: <span><span className="stat">{data.U_DISK}</span> {i18n.mb}</span></div>
+            <div className="bandwidth">{i18n.Bandwidth} <span><span className="stat">{data.U_BANDWIDTH}</span> {data.U_BANDWIDTH_MEASURE}</span></div>
+            <div className="disk">{i18n.Disk}: <span><span className="stat">{data.U_DISK}</span> {data.U_DISK_MEASURE}</span></div>
             <div className="sub-disk-stats">
               <div>
-                <div><span>{i18n.Web}:</span> <span><b>{data.U_DISK_WEB}</b> {i18n.mb}</span></div>
-                <div><span>{i18n.Mail}:</span> <span><b>{data.U_DISK_MAIL}</b> {i18n.mb}</span></div>
+                <div><span>{i18n.Web}:</span> <span><b>{data.U_DISK_WEB}</b> {data.U_DISK_WEB_MEASURE}</span></div>
+                <div><span>{i18n.Mail}:</span> <span><b>{data.U_DISK_MAIL}</b> {data.U_DISK_MAIL_MEASURE}</span></div>
               </div>
               <div>
-                <div><span>{i18n.Databases}:</span> <span><b>{data.U_DATABASES}</b> {i18n.mb}</span></div>
-                <div><span>{i18n['User Directories']}:</span> <span><b>{data.U_DISK_DIRS}</b> {i18n.mb}</span></div>
+                <div><span>{i18n.Databases}:</span> <span><b>{data.U_DATABASES}</b> {data.U_DATABASES_MEASURE}</span></div>
+                <div><span>{i18n['User Directories']}:</span> <span><b>{data.U_DISK_DIRS}</b> {data.U_DISK_DIRS_MEASURE}</span></div>
               </div>
             </div>
           </Container>

+ 2 - 1
src/react/src/components/WebDomain/Add/AddWebDomain.jsx

@@ -40,6 +40,7 @@ const AddWebDomain = props => {
     webStats: [],
     prefixI18N: '',
     prePath: '',
+    aliases: '',
     proxy_ext: '',
     internetProtocols: []
   });
@@ -99,7 +100,7 @@ const AddWebDomain = props => {
   }
 
   const onBlurChangeAliases = value => {
-    setState({ ...state, domain: value });
+    setState({ ...state, aliases: `www.${value}`});
   }
 
   const checkboxHandler = (input, checked) => {

+ 6 - 5
src/react/src/components/WebDomain/Add/AdditionalFtpForEditing/AdditionalFtpForEditing.jsx

@@ -9,7 +9,7 @@ const AdditionalFtpForEditing = ({ domain, data = {}, onDeleteAdditionalFtp, pre
   const { i18n, userName } = useSelector(state => state.session);
   const [state, setState] = useState({
     username: data.v_ftp_user || '',
-    path: ''
+    path: data.v_ftp_path || '',
   });
 
   const renderForm = () => {
@@ -32,8 +32,9 @@ const AdditionalFtpForEditing = ({ domain, data = {}, onDeleteAdditionalFtp, pre
       return (
         <div className="additional-ftp">
           <div className="title">
+            <input type="hidden" name={`v_ftp_user[${data.id}][v_ftp_user]`} value={data.v_ftp_user} />
             <input type="hidden" name={`v_ftp_user[${data.id}][delete]`} value="0" />
-            <input type="hidden" name={`v_ftp_user[${data.id}][is_new]`} value="1" />
+            <input type="hidden" name={`v_ftp_user[${data.id}][is_new]`} value={data.is_new} />
 
             <span className="data.indexed-name">{i18n.FTP} #{data.id + 1}</span>
             <span>
@@ -67,17 +68,17 @@ const AdditionalFtpForEditing = ({ domain, data = {}, onDeleteAdditionalFtp, pre
 
             <div className="form-group">
               <input type="hidden" name="v_ftp_pre_path" value={prePath} />
-              <input type="hidden" name={`v_ftp_user[${data.id}][v_ftp_path_prev]`} value={data.v_ftp_path !== '/' ? '/' : ''} />
+              <input type="hidden" name={`v_ftp_user[${data.id}][v_ftp_path_prev]`} value={data.v_ftp_path} />
 
               <label htmlFor={`path${data.id}`}>{i18n.Path}</label>
               <input
                 type="text"
                 value={state.path}
-                onChange={event => setState({ ...state, path: event.target.value })}
+                onChange={event => setState({ ...state, path: event.target.value.indexOf('/') !== 0 ? `/${event.target.value}` : event.target.value })}
                 className="form-control"
                 id={`path${data.id}`}
                 name={`v_ftp_user[${data.id}][v_ftp_path]`} />
-              <span className="path-note">{prePath}</span>
+              <span className="path-note">{prePath}{state.path}</span>
             </div>
 
             {

+ 1 - 1
src/react/src/components/WebDomain/WebDomain.jsx

@@ -72,7 +72,7 @@ export default function WebDomain(props) {
       <Container className="r-col w-85">
         <div className="name">
           <div>{data.NAME}</div>
-          <div><span className="dns-name-span">{data.ALIAS}</span></div>
+          <div><span className="dns-name-span">{data.ALIAS.replaceAll(',', ', ')}</span></div>
         </div>
         <div>{data.IP}</div>
         <div className="stats">

+ 7 - 1
src/react/src/containers/Databases/Databases.jsx

@@ -17,6 +17,7 @@ import Spinner from '../../components/Spinner/Spinner';
 import './Databases.scss';
 import { Helmet } from 'react-helmet';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
+import { Link } from 'react-router-dom';
 
 const Databases = props => {
   const { i18n } = useSelector(state => state.session);
@@ -35,6 +36,8 @@ const Databases = props => {
     toggledAll: false,
     dbAdmin: '',
     dbAdminLink: '',
+    db_myadmin_link: '',
+    db_pgadmin_link: '',
     sorting: i18n.Date,
     order: "descending",
     selection: [],
@@ -174,6 +177,8 @@ const Databases = props => {
             databases: reformatData(result.data.data),
             dbAdmin: result.data.db_admin,
             dbAdminLink: result.data.db_admin_link,
+            db_myadmin_link: result.data.db_myadmin_link,
+            db_pgadmin_link: result.data.db_pgadmin_link,
             dbFav: result.data.dbFav,
             selection: [],
             toggledAll: false,
@@ -387,7 +392,8 @@ const Databases = props => {
         <LeftButton name="Add Database" href="/add/db" showLeftMenu={true} />
         <div className="r-menu">
           <div className="input-group input-group-sm">
-            <a href={state.dbAdminLink} className="button-extra" type="submit" target="_blank" rel="noopener noreferrer">{state.dbAdmin}</a>
+            {state.db_myadmin_link && <Link to={{ pathname: state.db_myadmin_link }} className="button-extra" type="submit" target="_blank">phpMyAdmin</Link>}
+            {state.db_pgadmin_link && <Link to={{ pathname: state.db_pgadmin_link }} className="button-extra" type="submit" target="_blank">phpPgAdmin</Link>}
             <Checkbox toggleAll={toggleAll} toggled={state.toggledAll} />
             <Select list='dbList' bulkAction={bulk} />
             <DropdownFilter changeSorting={changeSorting} sorting={state.sorting} order={state.order} list="dbList" />

+ 47 - 49
src/react/src/containers/FileManager/FileManager.js

@@ -20,15 +20,15 @@ class FileManager extends Component {
     super(props);
     this.state = {
       leftList: {
-        path: this.props.menuCounters.user.HOME,
+        path: '',
         files: { listing: [] },
       },
       rightList: {
-        path: this.props.menuCounters.user.HOME,
+        path: '',
         files: { listing: [] },
       },
-      currentPath: this.props.menuCounters.user.HOME,
-      currentUser: this.props.menuCounters.user.HOME,
+      currentPath: '',
+      currentUser: '',
       activeWindow: "left",
       modalWindow: null,
       modalVisible: false,
@@ -44,17 +44,20 @@ class FileManager extends Component {
   }
 
   UNSAFE_componentWillMount = () => {
+    if (!this.props.session.userName) return this.props.history.push('/login');
+
     FM.cacheData(this.state.currentUser, this.props.history, this.props.menuCounters.user.HOME);
     let currentPath = FM.activeWindowPath();
-    this.setState({ currentPath });
+    this.setState({
+      currentPath,
+      currentUser: this.props.menuCounters.user.HOME,
+      leftList: { ...this.state.leftList, path: this.props.menuCounters.user.HOME },
+      rightList: { ...this.state.rightList, path: this.props.menuCounters.user.HOME }
+    });
     this.changeDirectoryOnLoading();
   }
 
   componentDidMount = () => {
-    if (!localStorage.getItem("token") || !this.props.session.userName) {
-      this.props.history.push('/login/');
-    }
-
     window.addEventListener("keydown", this.switchActiveList);
     window.addEventListener("keydown", this.toggleActiveListOnTab);
     document.addEventListener("keydown", this.hotkeysListener);
@@ -90,22 +93,17 @@ class FileManager extends Component {
   }
 
   changeDirectory = () => {
-    const { activeWindow, currentPath } = this.state;
-    FM.changeDirectory(server, currentPath)
+    const { leftList, rightList } = this.state;
+    Promise.all([FM.changeDirectory(server, leftList.path), FM.changeDirectory(server, rightList.path)])
       .then(result => {
-        let listing = result.data.listing;
-
-        if (this.state.leftList.path === this.state.rightList.path) {
-          this.setState({ leftList: { files: { listing }, path: currentPath }, rightList: { files: { listing }, path: currentPath }, loading: false });
-          this.leftList.resetData();
-          this.rightList.resetData();
-        } else if (activeWindow === "left") {
-          this.setState({ leftList: { files: { listing }, path: currentPath }, loading: false });
-          this.leftList.resetData();
-        } else {
-          this.setState({ rightList: { files: { listing }, path: currentPath }, loading: false });
-          this.rightList.resetData();
-        }
+        const [leftListResponse, rightListResponse] = result;
+        let leftListing = leftListResponse.data.listing;
+        let rightListing = rightListResponse.data.listing;
+
+        this.setState({ leftList: { ...leftList, files: { listing: leftListing } }, rightList: { ...rightList, files: { listing: rightListing } }, loading: false });
+
+        this.leftList.resetData();
+        this.rightList.resetData();
       });
   }
 
@@ -235,6 +233,7 @@ class FileManager extends Component {
     if (itemsSelected.length > 0) {
       await this.setStateAsync({ loading: true });
       await FM.deleteItems(server, FM.encodePath(currentPath), itemsSelected);
+      await this.setStateAsync({ itemsSelected: [] });
       this.changeDirectory();
     } else {
       this.validateAction(`${server}item=${FM.encodePath(currentPath)}%2F${itemName}&dir=${FM.encodePath(currentPath)}&action=delete_files`);
@@ -421,35 +420,12 @@ class FileManager extends Component {
 
   render() {
     const { activeWindow, modalWindow, modalVisible, itemsSelected, itemName, loading, uploadPercent, itemType } = this.state;
-    const DirectoryLists = ['left', 'right'].map((side) =>
-      <DirectoryList
-        changePathAfterToggle={this.changePathAfterToggle}
-        openCertainDirectory={this.openCertainDirectory}
-        isActive={activeWindow === side}
-        openDirectory={this.openDirectory}
-        passSelection={this.passSelection}
-        data={this.state[`${side}List`].files}
-        onClick={this.toggleActiveList}
-        changePath={this.changePath}
-        modalVisible={modalVisible}
-        addToPath={this.addToPath}
-        cursor={this.state.cursor}
-        passData={this.passData}
-        rootDir={this.props.menuCounters.user.HOME}
-        ref={el => this[`${side}List`] = el}
-        download={this.download}
-        moveBack={this.moveBack}
-        path={this.state[`${side}List`].path}
-        history={this.props.history}
-        loading={loading}
-        list={side} />
-    )
     return (
       <div className="window">
         <Helmet>
           <title>{this.props.session.i18n['File Manager']}</title>
         </Helmet>
-        {uploadPercent !== "0" ? <ProgressBar progress={uploadPercent} /> : null}
+        {uploadPercent !== "0" && <ProgressBar progress={uploadPercent} />}
         <ToastContainer />
         <Menu
           onDelete={this.onDeleteFileHandler}
@@ -462,7 +438,29 @@ class FileManager extends Component {
           cursor={this.state.cursor}
           name={itemName} />
         <div className="lists-container">
-          {DirectoryLists}
+          {this.props.session.userName && ['left', 'right'].map((side) =>
+            <DirectoryList
+              changePathAfterToggle={this.changePathAfterToggle}
+              openCertainDirectory={this.openCertainDirectory}
+              isActive={activeWindow === side}
+              openDirectory={this.openDirectory}
+              passSelection={this.passSelection}
+              data={this.state[`${side}List`].files}
+              onClick={this.toggleActiveList}
+              changePath={this.changePath}
+              modalVisible={modalVisible}
+              addToPath={this.addToPath}
+              cursor={this.state.cursor}
+              passData={this.passData}
+              rootDir={this.props.menuCounters.user.HOME}
+              ref={el => this[`${side}List`] = el}
+              download={this.download}
+              moveBack={this.moveBack}
+              path={this.state[`${side}List`].path}
+              history={this.props.history}
+              loading={loading}
+              list={side} />
+          )}
           <div className="fixed-buttons fm">
             <div className="hotkey-button">
               <button onClick={() => this.hotkeysList.classList.toggle('hide')}>

+ 2 - 3
src/react/src/containers/Firewalls/Banlist/index.jsx

@@ -16,7 +16,6 @@ import { Helmet } from 'react-helmet';
 import { useHistory } from 'react-router';
 
 import './styles.scss';
-import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 
 const BanLists = props => {
   const { i18n } = useSelector(state => state.session);
@@ -237,7 +236,7 @@ const BanLists = props => {
         .then(result => {
           if (result.status === 200) {
             toggleAll(false);
-            fetchData();
+            fetchData().then(() => setLoading(false));
           }
         })
         .catch(err => console.error(err));
@@ -261,7 +260,7 @@ const BanLists = props => {
           setLoading(false);
           return displayModal(res.data.error, '');
         }
-        fetchData();
+        fetchData().then(() => setLoading(false));
       })
       .catch(err => { setLoading(false); console.error(err); });
   }

+ 2 - 2
src/react/src/containers/Firewalls/Firewalls.jsx

@@ -1,7 +1,7 @@
 import React, { useEffect, useState } from 'react';
 import { addControlPanelContentFocusedElement, removeControlPanelContentFocusedElement } from '../../actions/ControlPanelContent/controlPanelContentActions';
 import { addActiveElement, removeFocusedElement } from '../../actions/MainNavigation/mainNavigationActions';
-import { bulkAction, getFirewallList, handleAction } from '../../ControlPanelService/Firewalls';
+import { bulkFirewallAction, getFirewallList, handleAction } from '../../ControlPanelService/Firewalls';
 import DropdownFilter from '../../components/MainNav/Toolbar/DropdownFilter/DropdownFilter';
 import * as MainNavigation from '../../actions/MainNavigation/mainNavigationActions';
 import SearchInput from '../../components/MainNav/Toolbar/SearchInput/SearchInput';
@@ -321,7 +321,7 @@ const Firewalls = props => {
 
     if (selection.length && action) {
       setLoading(true);
-      bulkAction(action, selection)
+      bulkFirewallAction(action, selection)
         .then(result => {
           if (result.status === 200) {
             toggleAll(false);

+ 2 - 2
src/react/src/containers/MailWrapper/MailWrapper.jsx

@@ -28,8 +28,8 @@ export default function MailWrapper(props) {
       </Helmet>
       {
         mailDomain
-          ? <MailAccounts {...props} domain={mailDomain} changeSearchTerm={props.handleSearchTerm} />
-          : <Mails {...props} changeSearchTerm={props.handleSearchTerm} />
+          ? <MailAccounts {...props} domain={mailDomain} changeSearchTerm={props.changeSearchTerm} />
+          : <Mails {...props} changeSearchTerm={props.changeSearchTerm} />
       }
     </>
   );

+ 1 - 1
src/react/src/containers/Mails/Mails.jsx

@@ -396,7 +396,7 @@ const Mails = props => {
         <div className="r-menu">
           <div className="input-group input-group-sm">
             <Link
-              to={{ pathname: `${window.location.protocol}//${window.location.hostname}${state.webmail}` }}
+              to={{ pathname: `http://${window.location.hostname}${state.webmail}` }}
               target="_blank"
               className="button-extra"
               type="submit">

+ 3 - 8
src/react/src/containers/Servers/Servers.jsx

@@ -15,7 +15,6 @@ import Server from '../../components/Server/Server';
 import { Link } from 'react-router-dom';
 import { Helmet } from 'react-helmet';
 import './Servers.scss';
-import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 
 const Servers = props => {
   const { i18n } = useSelector(state => state.session);
@@ -216,7 +215,7 @@ const Servers = props => {
             displayModal(res.data.error);
           }
 
-          setLoading(false);
+          fetchData().then(() => setLoading(false));
         })
         .catch(err => {
           setLoading(false);
@@ -260,7 +259,7 @@ const Servers = props => {
           }
 
           toggleAll(false);
-          fetchData().then(() => refreshMenuCounters());
+          fetchData().then(() => setLoading(false));
         })
         .catch(err => console.error(err));
     }
@@ -302,15 +301,11 @@ const Servers = props => {
           return displayModal(res.data.error, '');
         }
 
-        fetchData().then(() => refreshMenuCounters());
+        fetchData().then(() => setLoading(false));
       })
       .catch(err => { setLoading(false); console.error(err); });
   }
 
-  const refreshMenuCounters = () => {
-    dispatch(refreshCounters()).then(() => setLoading(false));
-  }
-
   const modalCancelHandler = () => {
     setModal({ ...modal, visible: false, text: '' });
   }

+ 12 - 1
src/react/src/containers/Users/Users.jsx

@@ -18,6 +18,7 @@ import { Helmet } from 'react-helmet';
 import './Users.scss';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import { useHistory } from 'react-router';
+import { loginAs, logout } from 'src/actions/Session/sessionActions';
 
 const Users = props => {
   const { userName, i18n } = useSelector(state => state.session);
@@ -248,10 +249,20 @@ const Users = props => {
     let sortedResult = sortArray(users);
 
     return sortedResult.map((item, index) => {
-      return <User data={item} key={index} toggleFav={toggleFav} checkItem={checkItem} handleModal={displayModal} />;
+      return <User data={item} key={index} toggleFav={toggleFav} checkItem={checkItem} handleModal={displayModal} logOut={logOutHandler} logInAs={logInAsHandler} />;
     });
   }
 
+  const logOutHandler = () => {
+    setLoading(true);
+    dispatch(logout()).then(() => setLoading(false));
+  }
+
+  const logInAsHandler = username => {
+    setLoading(true);
+    dispatch(loginAs(username)).then(() => setLoading(false));
+  }
+
   const checkItem = name => {
     const { selection, users } = state;
     let duplicate = [...selection];

+ 7 - 3
src/react/src/containers/WebLogs/WebLogs.jsx

@@ -10,6 +10,7 @@ import './WebLogs.scss';
 import { getWebLogs } from 'src/ControlPanelService/WebLogs';
 import Spinner from 'src/components/Spinner/Spinner';
 import { Helmet } from 'react-helmet';
+import HtmlParser from 'react-html-parser';
 
 export default function WebLogs() {
   const { i18n, userName } = useSelector(state => state.session);
@@ -19,6 +20,7 @@ export default function WebLogs() {
   const [domain, setDomain] = useState();
   const [state, setState] = useState({
     data: "",
+    prefix: "",
     loading: false
   });
 
@@ -40,7 +42,7 @@ export default function WebLogs() {
     let uri = `/list/web-log/?domain=${domain}&type=${type}`;
     fetchData(uri);
 
-    dispatch(addActiveElement(`/list/web-log/${type}`));
+    dispatch(addActiveElement(`/list/web-log/?domain=${domain}&type=${type}`));
   }, [mainNavigation.activeElement]);
 
   const fetchData = uri => {
@@ -52,7 +54,7 @@ export default function WebLogs() {
     getWebLogs(uri)
       .then(result => {
         if (result.data) {
-          setState({ ...state, data: result.data.data, loading: false });
+          setState({ ...state, data: result.data.data, prefix: result.data.prefix, loading: false });
         }
       })
       .catch(error => {
@@ -92,12 +94,14 @@ export default function WebLogs() {
       </Helmet>
       <TopPanel menuItems={menuItems} extraMenuItems={extraMenuItems} />
       <div className="content">
+        <h6>{state.prefix}</h6>
+        <br />
         {
           state.loading
             ? <Spinner />
             : (
               <pre>
-                {state.data}
+                {HtmlParser(state.data)}
               </pre>
             )
         }

+ 3 - 3
src/react/src/containers/WebLogs/WebLogs.scss

@@ -1,8 +1,8 @@
 .web-logs {
   .content {
-    padding: 50px 10px 0;
-    color: #7d7d7d;
-    font-size: 20px;
+    font-size: 14px;
+    color: #555;
+    padding-top: 4rem;
   }
 
   .nav-link:nth-child(3),