Просмотр исходного кода

Improved new react ui and added view for CSR generation.

Alexander 4 лет назад
Родитель
Сommit
e66ec829f7
58 измененных файлов с 1253 добавлено и 790 удалено
  1. 1 1
      src/react/src/ControlPanelService/Backup.js
  2. 36 1
      src/react/src/ControlPanelService/Web.js
  3. 46 5
      src/react/src/actions/Session/sessionActions.js
  4. 8 0
      src/react/src/actions/UserSession/userSessionActions.js
  5. 1 0
      src/react/src/actions/UserSession/userSessionTypes.js
  6. 14 17
      src/react/src/components/Backup/Exclusion/Edit/index.jsx
  7. 5 3
      src/react/src/components/ControlPanel/AddItemLayout/Form/TextArea/TextArea.jsx
  8. 1 2
      src/react/src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput.jsx
  9. 35 28
      src/react/src/components/CronJob/Edit/EditCronJob.jsx
  10. 26 22
      src/react/src/components/DNSRecord/Edit/EditDNSRecord.jsx
  11. 29 22
      src/react/src/components/Database/Edit/EditDatabase.jsx
  12. 28 22
      src/react/src/components/DomainNameSystem/Edit/EditDomainNameSystem.jsx
  13. 33 29
      src/react/src/components/Firewall/Edit/EditFirewall.jsx
  14. 2 3
      src/react/src/components/InternetProtocol/Add/AddInternetProtocol.jsx
  15. 29 22
      src/react/src/components/InternetProtocol/Edit/EditInternetProtocol.jsx
  16. 0 1
      src/react/src/components/Login/Login.scss
  17. 28 21
      src/react/src/components/Mail/Edit/EditMail.jsx
  18. 3 0
      src/react/src/components/MailAccount/Add/AddMailAccount.jsx
  19. 14 13
      src/react/src/components/MailAccount/Edit/EditMailAccount.jsx
  20. 3 3
      src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx
  21. 14 2
      src/react/src/components/MainNav/MainNav.jsx
  22. 9 10
      src/react/src/components/MainNav/Panel/Panel.jsx
  23. 2 1
      src/react/src/components/MainNav/Stat-menu/Menu.jsx
  24. 0 1
      src/react/src/components/MainNav/Toolbar/DropdownFilter/DropdownFilter.scss
  25. 3 3
      src/react/src/components/Menu/Menu.jsx
  26. 28 21
      src/react/src/components/Package/Edit/EditPackage.jsx
  27. 0 1
      src/react/src/components/Path/Dropdown/Dropdown.scss
  28. 0 1
      src/react/src/components/Preview/Photo/Photo.scss
  29. 2 2
      src/react/src/components/Preview/Preview.jsx
  30. 17 21
      src/react/src/components/Server/Edit/Bind9/Bind9.jsx
  31. 16 16
      src/react/src/components/Server/Edit/Dovecot/Dovecot.jsx
  32. 28 11
      src/react/src/components/Server/Edit/EditServer.jsx
  33. 1 1
      src/react/src/components/Server/Edit/EditServerDnsOption.jsx
  34. 167 195
      src/react/src/components/Server/Edit/EditVestaPlugins.jsx
  35. 17 10
      src/react/src/components/Server/Edit/Httpd/EditHttpd.jsx
  36. 40 25
      src/react/src/components/Server/Edit/Mysql/Mysql.jsx
  37. 42 13
      src/react/src/components/Server/Edit/Nginx/EditServerNginx.jsx
  38. 37 16
      src/react/src/components/Server/Edit/PHP/EditPhp.jsx
  39. 17 21
      src/react/src/components/Server/Edit/Postgresql/Postgresql.jsx
  40. 13 20
      src/react/src/components/Server/Edit/Service/Service.jsx
  41. 2 2
      src/react/src/components/Server/ServerSys.jsx
  42. 2 1
      src/react/src/components/User/Add/AddUser.jsx
  43. 29 24
      src/react/src/components/User/Edit/EditUser.jsx
  44. 1 2
      src/react/src/components/User/User.jsx
  45. 80 25
      src/react/src/components/WebDomain/Add/AddWebDomain.jsx
  46. 17 39
      src/react/src/components/WebDomain/Add/AdvancedOptions/AdvancedOptions.jsx
  47. 71 46
      src/react/src/components/WebDomain/Edit/EditWeb.jsx
  48. 1 0
      src/react/src/components/WebDomain/Edit/SslSupport/SslSupport.scss
  49. 29 18
      src/react/src/components/WebDomain/WebDomain.jsx
  50. 4 14
      src/react/src/containers/ControlPanelContent/ControlPanelContent.jsx
  51. 2 2
      src/react/src/containers/FileManager/FileManager.js
  52. 165 0
      src/react/src/containers/GenerateCSR/index.jsx
  53. 10 3
      src/react/src/containers/Mails/Mails.jsx
  54. 3 2
      src/react/src/containers/Servers/Servers.jsx
  55. 21 1
      src/react/src/containers/Users/Users.jsx
  56. 0 5
      src/react/src/reducers/Session/sessionReducer.js
  57. 19 0
      src/react/src/reducers/UserSession/userSessionReducer.js
  58. 2 0
      src/react/src/reducers/rootReducer.js

+ 1 - 1
src/react/src/ControlPanelService/Backup.js

@@ -3,7 +3,7 @@ import { getAuthToken } from "src/utils/token";
 
 
 const BASE_URL = window.location.origin;
 const BASE_URL = window.location.origin;
 const webApiUri = '/api/v1/list/backup/index.php';
 const webApiUri = '/api/v1/list/backup/index.php';
-const scheduleBackupUri = '/api/v1/schedule/restore/';
+const scheduleBackupUri = '/api/v1/schedule/backup/';
 const backupDetailsUri = '/api/v1/list/backup/index.php';
 const backupDetailsUri = '/api/v1/list/backup/index.php';
 const backupExclusionsUri = '/api/v1/list/backup/exclusions/index.php';
 const backupExclusionsUri = '/api/v1/list/backup/exclusions/index.php';
 const backupExclusionsInfoUri = '/api/v1/edit/backup/exclusions/index.php';
 const backupExclusionsInfoUri = '/api/v1/edit/backup/exclusions/index.php';

+ 36 - 1
src/react/src/ControlPanelService/Web.js

@@ -6,6 +6,7 @@ const addWebUri = '/api/v1/add/web/index.php';
 const webApiUri = '/api/v1/list/web/index.php';
 const webApiUri = '/api/v1/list/web/index.php';
 const webStatsUri = '/api/v1/web-stats.php';
 const webStatsUri = '/api/v1/web-stats.php';
 const domainInfoUri = '/api/v1/edit/web/index.php';
 const domainInfoUri = '/api/v1/edit/web/index.php';
+const generateCSRUri = '/api/v1/generate/ssl/index.php';
 const updateDomainUri = '/api/v1/edit/web/index.php';
 const updateDomainUri = '/api/v1/edit/web/index.php';
 
 
 export const getWebList = () => {
 export const getWebList = () => {
@@ -42,6 +43,14 @@ export const addWeb = data => {
   return axios.post(BASE_URL + addWebUri, formDataObject);
   return axios.post(BASE_URL + addWebUri, formDataObject);
 }
 }
 
 
+export const getWebDomainInfo = domain => {
+  return axios.get(BASE_URL + addWebUri, {
+    params: {
+      token: getAuthToken()
+    }
+  });
+}
+
 export const getWebStats = () => {
 export const getWebStats = () => {
   return axios.get(BASE_URL + webStatsUri);
   return axios.get(BASE_URL + webStatsUri);
 }
 }
@@ -68,4 +77,30 @@ export const updateWebDomain = (data, domain) => {
       token: getAuthToken()
       token: getAuthToken()
     }
     }
   });
   });
-}
+}
+
+export const getCsrInitialData = domain => {
+  if (domain) {
+    return axios.get(BASE_URL + generateCSRUri, {
+      params: {
+        domain
+      }
+    });
+  } else {
+    return axios.get(BASE_URL + generateCSRUri);
+  }
+}
+
+export const generateCSR = (data) => {
+  let formDataObject = new FormData();
+
+  for (let key in data) {
+    formDataObject.append(key, data[key]);
+  }
+
+  return axios.post(BASE_URL + generateCSRUri, formDataObject, {
+    params: {
+      token: getAuthToken()
+    }
+  });
+}

+ 46 - 5
src/react/src/actions/Session/sessionActions.js

@@ -3,6 +3,7 @@ import { checkAuth, signIn, signInAs, signOut } from 'src/services/session';
 import { resetPassword } from 'src/ControlPanelService/ResetPassword';
 import { resetPassword } from 'src/ControlPanelService/ResetPassword';
 import { resetAuthToken, setAuthToken } from 'src/utils/token';
 import { resetAuthToken, setAuthToken } from 'src/utils/token';
 import { REFRESH_COUNTERS } from '../MenuCounters/menuCounterTypes';
 import { REFRESH_COUNTERS } from '../MenuCounters/menuCounterTypes';
+import { SET_USER_SESSION } from '../UserSession/userSessionTypes';
 
 
 const LOGOUT_RESPONSE = 'logged_out';
 const LOGOUT_RESPONSE = 'logged_out';
 const LOGOUT_AS_RESPONSE = 'logged_out_as';
 const LOGOUT_AS_RESPONSE = 'logged_out_as';
@@ -19,7 +20,6 @@ export const login = (user, password) => dispatch => {
         value: {
         value: {
           token: token || '',
           token: token || '',
           panel,
           panel,
-          session,
           i18n: i18n || {},
           i18n: i18n || {},
           userName: user,
           userName: user,
           error
           error
@@ -31,6 +31,10 @@ export const login = (user, password) => dispatch => {
           user: data,
           user: data,
         }
         }
       });
       });
+      dispatch({
+        type: SET_USER_SESSION,
+        value: session
+      });
       resolve(token);
       resolve(token);
     }, (error) => {
     }, (error) => {
       reject(error);
       reject(error);
@@ -48,7 +52,6 @@ export const reset = ({ user = '', code = '', password = '', password_confirm =
         value: {
         value: {
           token,
           token,
           panel,
           panel,
-          session,
           userName: user,
           userName: user,
           error
           error
         },
         },
@@ -59,6 +62,10 @@ export const reset = ({ user = '', code = '', password = '', password_confirm =
           user: {},
           user: {},
         }
         }
       });
       });
+      dispatch({
+        type: SET_USER_SESSION,
+        value: session
+      });
       resolve(token);
       resolve(token);
     }, (error) => {
     }, (error) => {
       reject(error);
       reject(error);
@@ -77,7 +84,6 @@ export const loginAs = username => dispatch => {
         value: {
         value: {
           userName: user,
           userName: user,
           i18n,
           i18n,
-          session,
           panel,
           panel,
           token,
           token,
           error
           error
@@ -89,6 +95,10 @@ export const loginAs = username => dispatch => {
           user: data,
           user: data,
         }
         }
       });
       });
+      dispatch({
+        type: SET_USER_SESSION,
+        value: session
+      });
 
 
       resolve(token);
       resolve(token);
     }, (error) => {
     }, (error) => {
@@ -123,6 +133,10 @@ export const logout = () => (dispatch, getState) => {
             user: {},
             user: {},
           }
           }
         });
         });
+        dispatch({
+          type: SET_USER_SESSION,
+          value: {}
+        });
 
 
         resolve();
         resolve();
       } else if (logout_response === LOGOUT_AS_RESPONSE) {
       } else if (logout_response === LOGOUT_AS_RESPONSE) {
@@ -130,7 +144,6 @@ export const logout = () => (dispatch, getState) => {
           type: LOGGED_OUT_AS,
           type: LOGGED_OUT_AS,
           value: {
           value: {
             userName,
             userName,
-            session,
             panel,
             panel,
             token: '',
             token: '',
             i18n,
             i18n,
@@ -143,6 +156,10 @@ export const logout = () => (dispatch, getState) => {
             user,
             user,
           }
           }
         });
         });
+        dispatch({
+          type: SET_USER_SESSION,
+          value: session
+        });
 
 
         resolve();
         resolve();
       } else {
       } else {
@@ -168,7 +185,6 @@ export const checkAuthHandler = () => (dispatch, getState) => {
           value: {
           value: {
             userName: user,
             userName: user,
             i18n,
             i18n,
-            session,
             panel,
             panel,
             token,
             token,
             error
             error
@@ -180,6 +196,31 @@ export const checkAuthHandler = () => (dispatch, getState) => {
             user: data,
             user: data,
           }
           }
         });
         });
+        dispatch({
+          type: SET_USER_SESSION,
+          value: session
+        });
+
+        resolve(token);
+      })
+      .catch(err => {
+        reject();
+        console.error(err);
+      });
+  });
+}
+
+export const refreshUserSession = () => (dispatch, getState) => {
+  return new Promise((resolve, reject) => {
+    checkAuth()
+      .then(res => {
+        const { session, token } = res.data;
+
+        if (token) setAuthToken(token);
+        dispatch({
+          type: SET_USER_SESSION,
+          value: session
+        });
 
 
         resolve(token);
         resolve(token);
       })
       })

+ 8 - 0
src/react/src/actions/UserSession/userSessionActions.js

@@ -0,0 +1,8 @@
+import { SET_USER_SESSION } from './userSessionTypes';
+
+export const setUserSession = value => {
+  return {
+    type: SET_USER_SESSION,
+    value
+  };
+};

+ 1 - 0
src/react/src/actions/UserSession/userSessionTypes.js

@@ -0,0 +1 @@
+export const SET_USER_SESSION = 'SET_USER_SESSION';

+ 14 - 17
src/react/src/components/Backup/Exclusion/Edit/index.jsx

@@ -18,11 +18,11 @@ const EditBackupExclusions = () => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -30,19 +30,20 @@ const EditBackupExclusions = () => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getBackupExclusionsInfo()
     getBackupExclusionsInfo()
       .then(response => {
       .then(response => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
       .catch(err => console.error(err));
       .catch(err => console.error(err));
-  }, []);
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -61,17 +62,13 @@ const EditBackupExclusions = () => {
       updateBackupExclusions(updatedExclusions)
       updateBackupExclusions(updatedExclusions)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
-
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage: '', loading: false });
-            } else if (okMessage) {
-              setState({ ...state, errorMessage: '', okMessage, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            const { error_msg, ok_msg } = result.data;
+
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -86,12 +83,12 @@ const EditBackupExclusions = () => {
         <div className="search-toolbar-name">{i18n['Editing Backup Exclusions']}</div>
         <div className="search-toolbar-name">{i18n['Editing Backup Exclusions']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 5 - 3
src/react/src/components/ControlPanel/AddItemLayout/Form/TextArea/TextArea.jsx

@@ -1,6 +1,6 @@
 import React from 'react';
 import React from 'react';
 
 
-const TextArea = ({ id, name, defaultValue = '', title, optionalTitle = '', rows = '3', disabled = false }) => {
+const TextArea = ({ id, name, defaultValue = '', title, optionalTitle = '', rows = '3', disabled = false, ...rest }) => {
   return (
   return (
     <div className="form-group">
     <div className="form-group">
       <label className="label-wrapper" htmlFor={id}>
       <label className="label-wrapper" htmlFor={id}>
@@ -13,10 +13,12 @@ const TextArea = ({ id, name, defaultValue = '', title, optionalTitle = '', rows
         rows={rows}
         rows={rows}
         name={name}
         name={name}
         disabled={disabled}
         disabled={disabled}
-        defaultValue={defaultValue}>
+        defaultValue={defaultValue}
+        {...rest}
+      >
       </textarea>
       </textarea>
     </div>
     </div>
   );
   );
 }
 }
 
 
-export default TextArea;
+export default TextArea;

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

@@ -25,7 +25,6 @@ const TextInput = ({ id, name, title, optionalTitle = '', type = 'text', onChang
         name={name}
         name={name}
         id={id}
         id={id}
         onChange={changeCheckbox}
         onChange={changeCheckbox}
-        // disabled={disabled}
         readOnly={disabled}
         readOnly={disabled}
         value={inputValue}
         value={inputValue}
         className="form-control" />
         className="form-control" />
@@ -33,4 +32,4 @@ const TextInput = ({ id, name, title, optionalTitle = '', type = 'text', onChang
   );
   );
 }
 }
 
 
-export default TextInput;
+export default TextInput;

+ 35 - 28
src/react/src/components/CronJob/Edit/EditCronJob.jsx

@@ -21,10 +21,10 @@ const EditMail = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    errorMessage: '',
-    okMessage: '',
     loading: false,
     loading: false,
     generatedCronJob: {
     generatedCronJob: {
       h_min: '*',
       h_min: '*',
@@ -44,29 +44,33 @@ const EditMail = props => {
 
 
     if (job) {
     if (job) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getCronJobInfo(job)
-        .then(response => {
-          setState({
-            ...state,
-            generatedCronJob: {
-              ...state.generatedCronJob,
-              h_min: response.data.min,
-              h_hour: response.data.hour,
-              h_day: response.data.day,
-              h_wday: response.data.wday,
-              h_month: response.data.month
-            },
-            data: response.data,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(job)
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = job => {
+    getCronJobInfo(job)
+      .then(response => {
+        setState({
+          ...state,
+          generatedCronJob: {
+            ...state.generatedCronJob,
+            h_min: response.data.min,
+            h_hour: response.data.hour,
+            h_day: response.data.day,
+            h_wday: response.data.wday,
+            h_month: response.data.month
+          },
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedJob = {};
     let updatedJob = {};
@@ -81,17 +85,20 @@ const EditMail = props => {
       updateCronJob(updatedJob, state.data.job)
       updateCronJob(updatedJob, state.data.job)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setOkMessage('');
+              setErrorMessage(error_msg);
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setOkMessage(ok_msg);
+                setErrorMessage('');
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.data.job))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -125,12 +132,12 @@ const EditMail = props => {
         <div className="search-toolbar-name">{i18n['Editing Cron Job']}</div>
         <div className="search-toolbar-name">{i18n['Editing Cron Job']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 26 - 22
src/react/src/components/DNSRecord/Edit/EditDNSRecord.jsx

@@ -19,6 +19,8 @@ export default function EditDNSRecord(props) {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
   const history = useHistory();
   const history = useHistory();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     selectOptions: [
     selectOptions: [
@@ -37,9 +39,7 @@ export default function EditDNSRecord(props) {
       'TLSA',
       'TLSA',
       'CAA'
       'CAA'
     ],
     ],
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -48,23 +48,24 @@ export default function EditDNSRecord(props) {
     dispatch(addActiveElement('/list/dns/'));
     dispatch(addActiveElement('/list/dns/'));
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
-    if (domain) {
+    if (domain && record_id) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getDNSRecordInfo(domain, record_id)
-        .then(response => {
-          setState({
-            ...state,
-            data: response.data,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(domain, record_id);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = (domain, record_id) => {
+    getDNSRecordInfo(domain, record_id)
+      .then(response => {
+        setState({
+          ...state,
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => console.error(err));
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedRecord = {};
     let updatedRecord = {};
@@ -83,17 +84,20 @@ export default function EditDNSRecord(props) {
       updateDNS(updatedRecord, props.domain, props.record_id)
       updateDNS(updatedRecord, props.domain, props.record_id)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setOkMessage('');
+              setErrorMessage(error_msg);
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setOkMessage(ok_msg);
+                setErrorMessage('');
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(props.domain, props.record_id))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -108,12 +112,12 @@ export default function EditDNSRecord(props) {
         <div className="search-toolbar-name">{i18n['Editing DNS Record']}</div>
         <div className="search-toolbar-name">{i18n['Editing DNS Record']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 29 - 22
src/react/src/components/Database/Edit/EditDatabase.jsx

@@ -22,12 +22,12 @@ const EditDatabase = props => {
   const { i18n, userName } = useSelector(state => state.session);
   const { i18n, userName } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
-    databaseUserInputValue: '',
-    errorMessage: '',
-    okMessage: ''
+    databaseUserInputValue: ''
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -39,22 +39,26 @@ const EditDatabase = props => {
 
 
     if (database) {
     if (database) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getDatabaseInfo(database)
-        .then(response => {
-          setState({
-            ...state,
-            data: response.data,
-            databaseUserInputValue: response.data.dbuser.split('_').splice(1).join('_'),
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(database);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = database => {
+    getDatabaseInfo(database)
+      .then(response => {
+        setState({
+          ...state,
+          data: response.data,
+          databaseUserInputValue: response.data.dbuser.split('_').splice(1).join('_'),
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedDatabase = {};
     let updatedDatabase = {};
@@ -72,17 +76,20 @@ const EditDatabase = props => {
       updateDatabase(updatedDatabase, state.data.database)
       updateDatabase(updatedDatabase, state.data.database)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setOkMessage('');
+              setErrorMessage(error_msg);
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setOkMessage(ok_msg);
+                setErrorMessage('');
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.data.database))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -101,12 +108,12 @@ const EditDatabase = props => {
         <div className="search-toolbar-name">{i18n['Editing Database']}</div>
         <div className="search-toolbar-name">{i18n['Editing Database']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 28 - 22
src/react/src/components/DomainNameSystem/Edit/EditDomainNameSystem.jsx

@@ -13,7 +13,6 @@ import QS from 'qs';
 
 
 import './EditDomainNameSystem.scss';
 import './EditDomainNameSystem.scss';
 import { Helmet } from 'react-helmet';
 import { Helmet } from 'react-helmet';
-import { andler } from 'src/actions/Session/sessionActions';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import HtmlParser from 'react-html-parser';
 import HtmlParser from 'react-html-parser';
 
 
@@ -22,11 +21,11 @@ const EditDomainNameSystem = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -38,21 +37,25 @@ const EditDomainNameSystem = props => {
 
 
     if (domain) {
     if (domain) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getDNSInfo(domain)
-        .then(response => {
-          setState({
-            ...state,
-            data: response.data,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(domain);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = domain => {
+    getDNSInfo(domain)
+      .then(response => {
+        setState({
+          ...state,
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err)
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedDomain = {};
     let updatedDomain = {};
@@ -69,17 +72,20 @@ const EditDomainNameSystem = props => {
       updateDNS(updatedDomain, state.data.domain)
       updateDNS(updatedDomain, state.data.domain)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setErrorMessage('');
+                setOkMessage(ok_msg);
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.data.domain))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -94,12 +100,12 @@ const EditDomainNameSystem = props => {
         <div className="search-toolbar-name">{i18n['Editing DNS Domain']}</div>
         <div className="search-toolbar-name">{i18n['Editing DNS Domain']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 33 - 29
src/react/src/components/Firewall/Edit/EditFirewall.jsx

@@ -20,11 +20,11 @@ const EditFirewall = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -35,24 +35,24 @@ const EditFirewall = props => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     if (rule) {
     if (rule) {
+      setState({ ...state, loading: true });
       fetchData(rule);
       fetchData(rule);
     }
     }
   }, []);
   }, []);
 
 
   const fetchData = rule => {
   const fetchData = rule => {
-    setState({ ...state, loading: true });
-
     getFirewallInfo(rule)
     getFirewallInfo(rule)
       .then(response => {
       .then(response => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
-      .catch(err => console.error(err));
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
   }
   }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
@@ -69,13 +69,10 @@ const EditFirewall = props => {
       updateFirewall(updatedDomain, state.data.rule)
       updateFirewall(updatedDomain, state.data.rule)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
-            } else {
-              setState({ ...state, okMessage, errorMessage: '', loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
         .then(() => fetchData(state.data.rule))
         .then(() => fetchData(state.data.rule))
@@ -93,12 +90,12 @@ const EditFirewall = props => {
         <div className="search-toolbar-name">{i18n['Editing Firewall Rule']}</div>
         <div className="search-toolbar-name">{i18n['Editing Firewall Rule']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
@@ -108,19 +105,26 @@ const EditFirewall = props => {
             <input type="hidden" name="save" value="save" />
             <input type="hidden" name="save" value="save" />
             <input type="hidden" name="token" value={token} />
             <input type="hidden" name="token" value={token} />
 
 
-            <SelectInput
-              options={state.data.actions}
-              selected={state.data.action}
-              title={i18n['Action']}
-              name="v_action"
-              id="action" />
-
-            <SelectInput
-              options={state.data.protocols}
-              selected={state.data.protocol}
-              title={i18n['Protocol']}
-              name="v_protocol"
-              id="protocol" />
+            <div className="form-group select-group">
+              <label className="label-wrapper" htmlFor="action">
+                {i18n['Action']}
+              </label>
+              <select className="form-control" id="action" name="v_action">
+                <option selected={state.data.action === 'DROP'} value="DROP">DROP</option>
+                <option selected={state.data.action === 'ACCEPT'} value="ACCEPT">ACCEPT</option>
+              </select>
+            </div>
+
+            <div className="form-group select-group">
+              <label className="label-wrapper" htmlFor="protocol">
+                {i18n['Protocol']}
+              </label>
+              <select className="form-control" id="protocol" name="v_protocol">
+                <option selected={state.data.protocol === 'TCP'} value="TCP">{i18n['TCP']}</option>
+                <option selected={state.data.protocol === 'UDP'} value="UDP">{i18n['UDP']}</option>
+                <option selected={state.data.protocol === 'ICMP'} value="ICMP">{i18n['ICMP']}</option>
+              </select>
+            </div>
 
 
             <TextInput
             <TextInput
               optionalTitle={i18n['ranges are acceptable']}
               optionalTitle={i18n['ranges are acceptable']}

+ 2 - 3
src/react/src/components/InternetProtocol/Add/AddInternetProtocol.jsx

@@ -19,8 +19,7 @@ import HtmlParser from 'react-html-parser';
 
 
 const AddInternetProtocol = props => {
 const AddInternetProtocol = props => {
   const token = localStorage.getItem("token");
   const token = localStorage.getItem("token");
-  const { i18n } = useSelector(state => state.session);
-  const session = useSelector(state => state.session);
+  const { i18n, userName } = useSelector(state => state.session);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
   const history = useHistory();
   const history = useHistory();
   const [state, setState] = useState({
   const [state, setState] = useState({
@@ -105,7 +104,7 @@ const AddInternetProtocol = props => {
         {state.loading ? <Spinner /> : (
         {state.loading ? <Spinner /> : (
           <form onSubmit={event => submitFormHandler(event)}>
           <form onSubmit={event => submitFormHandler(event)}>
             <input type="hidden" name="ok" value="add" />
             <input type="hidden" name="ok" value="add" />
-            <input type="hidden" name="v_owner" value={session.userName} />
+            <input type="hidden" name="v_owner" value={userName} />
             <input type="hidden" name="token" value={token} />
             <input type="hidden" name="token" value={token} />
 
 
             <TextInput name="v_ip" id="ipAddress" title={i18n['IP address']} />
             <TextInput name="v_ip" id="ipAddress" title={i18n['IP address']} />

+ 29 - 22
src/react/src/components/InternetProtocol/Edit/EditInternetProtocol.jsx

@@ -23,12 +23,12 @@ const EditInternetProtocol = () => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
-    dedicated: false,
-    errorMessage: '',
-    okMessage: ''
+    dedicated: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -40,22 +40,26 @@ const EditInternetProtocol = () => {
 
 
     if (ip) {
     if (ip) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getInternetProtocolInfo(ip)
-        .then(response => {
-          setState({
-            ...state,
-            data: response.data,
-            dedicated: !response.data.dedicated,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(ip);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = ip => {
+    getInternetProtocolInfo(ip)
+      .then(response => {
+        setState({
+          ...state,
+          data: response.data,
+          dedicated: !response.data.dedicated,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err)
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedIP = {};
     let updatedIP = {};
@@ -74,17 +78,20 @@ const EditInternetProtocol = () => {
       updateInternetProtocol(updatedIP, state.data.ip)
       updateInternetProtocol(updatedIP, state.data.ip)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setErrorMessage('');
+                setOkMessage(ok_msg);
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.data.ip))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -103,12 +110,12 @@ const EditInternetProtocol = () => {
         <div className="search-toolbar-name">{i18n['Editing IP Address']}</div>
         <div className="search-toolbar-name">{i18n['Editing IP Address']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 0 - 1
src/react/src/components/Login/Login.scss

@@ -79,7 +79,6 @@ $textColor: #555;
           border: 1px solid $primary;
           border: 1px solid $primary;
           padding: 1px 16px 3px;
           padding: 1px 16px 3px;
           font-size: 13px;;
           font-size: 13px;;
-          width: 100px;
           height: 35px;
           height: 35px;
           color: #fafafa;
           color: #fafafa;
           border-radius: 3px;
           border-radius: 3px;

+ 28 - 21
src/react/src/components/Mail/Edit/EditMail.jsx

@@ -21,11 +21,11 @@ const EditMail = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -37,21 +37,25 @@ const EditMail = props => {
 
 
     if (domain) {
     if (domain) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getMailInfo(domain)
-        .then(response => {
-          setState({
-            ...state,
-            data: response.data,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(domain);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = domain => {
+    getMailInfo(domain)
+      .then(response => {
+        setState({
+          ...state,
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedDomain = {};
     let updatedDomain = {};
@@ -68,17 +72,20 @@ const EditMail = props => {
       updateMail(updatedDomain, state.data.domain)
       updateMail(updatedDomain, state.data.domain)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setErrorMessage('');
+                setOkMessage(ok_msg);
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.data.domain))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -93,12 +100,12 @@ const EditMail = props => {
         <div className="search-toolbar-name">{i18n['Editing Mail Domain']}</div>
         <div className="search-toolbar-name">{i18n['Editing Mail Domain']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 3 - 0
src/react/src/components/MailAccount/Add/AddMailAccount.jsx

@@ -32,6 +32,7 @@ export default function AddMailAccount(props) {
     quotaValue: '',
     quotaValue: '',
     loading: false,
     loading: false,
     password: '',
     password: '',
+    userName: '',
     okMessage: '',
     okMessage: '',
     errorMessage: '',
     errorMessage: '',
   });
   });
@@ -138,6 +139,7 @@ export default function AddMailAccount(props) {
 
 
                 <TextInput
                 <TextInput
                   title={i18n['Account']}
                   title={i18n['Account']}
+                  onChange={e => setState({ ...state, username: e.target.value })}
                   name="v_account"
                   name="v_account"
                   id="account" />
                   id="account" />
 
 
@@ -148,6 +150,7 @@ export default function AddMailAccount(props) {
                 <MailInfoBlock
                 <MailInfoBlock
                   webMail={state.data.webmail}
                   webMail={state.data.webmail}
                   hostName={state.data.hostname}
                   hostName={state.data.hostname}
+                  userName={state.userName}
                   password={state.password}
                   password={state.password}
                   domain={props.domain} />
                   domain={props.domain} />
               </div>
               </div>

+ 14 - 13
src/react/src/components/MailAccount/Edit/EditMailAccount.jsx

@@ -24,13 +24,13 @@ export default function EditMailAccount(props) {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
   const history = useHistory();
   const history = useHistory();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     quotaValue: '',
     quotaValue: '',
     loading: false,
     loading: false,
-    password: '',
-    okMessage: '',
-    errorMessage: '',
+    password: ''
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -58,13 +58,15 @@ export default function EditMailAccount(props) {
       editMailAccount(newMailDomain, props.domain, props.account)
       editMailAccount(newMailDomain, props.domain, props.account)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setErrorMessage('');
+                setOkMessage(ok_msg);
               });
               });
             }
             }
           }
           }
@@ -81,8 +83,6 @@ export default function EditMailAccount(props) {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
 
 
@@ -110,13 +110,13 @@ export default function EditMailAccount(props) {
         <div className="search-toolbar-name">{i18n['Editing Mail Account']}</div>
         <div className="search-toolbar-name">{i18n['Editing Mail Account']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
-            {state.errorMessage}</span>
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
+            {errorMessage}</span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
-            <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
+            <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
@@ -193,6 +193,7 @@ export default function EditMailAccount(props) {
                 <MailInfoBlock
                 <MailInfoBlock
                   webMail={state.data.webmail}
                   webMail={state.data.webmail}
                   hostName={state.data.hostname}
                   hostName={state.data.hostname}
+                  userName={props.account}
                   password={state.password}
                   password={state.password}
                   domain={props.domain} />
                   domain={props.domain} />
               </div>
               </div>

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

@@ -1,13 +1,13 @@
 import React, { useEffect, useState } from 'react';
 import React, { useEffect, useState } from 'react';
 import { useSelector } from 'react-redux';
 import { useSelector } from 'react-redux';
+import { Link } from 'react-router-dom';
 import { mailInfoBlockSelectOptions } from 'src/ControlPanelService/Mail';
 import { mailInfoBlockSelectOptions } from 'src/ControlPanelService/Mail';
 
 
 import './MailInfoBlock.scss';
 import './MailInfoBlock.scss';
 
 
-export default function MailInfoBlock({ webMail, hostName, domain, password }) {
+export default function MailInfoBlock({ webMail, hostName, domain, userName = '', password }) {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const [selectedOption, setSelectedOption] = useState('');
   const [selectedOption, setSelectedOption] = useState('');
-  const { userName } = useSelector(state => state.session);
   const [state, setState] = useState({
   const [state, setState] = useState({
     imapHostName: hostName,
     imapHostName: hostName,
     smtpHostName: hostName,
     smtpHostName: hostName,
@@ -106,7 +106,7 @@ export default function MailInfoBlock({ webMail, hostName, domain, password }) {
 
 
           <div>
           <div>
             <span>{i18n['Webmail URL']}:</span>
             <span>{i18n['Webmail URL']}:</span>
-            <span><a href={webMail}>{webMail}</a></span>
+            <span><Link to={{ pathname: `${window.location.protocol}//${window.location.hostname}${state.webMail}` }}>{webMail}</Link></span>
           </div>
           </div>
 
 
           <input type="hidden" name={i18n['Username']} value={`@${domain}`} />
           <input type="hidden" name={i18n['Username']} value={`@${domain}`} />

+ 14 - 2
src/react/src/components/MainNav/MainNav.jsx

@@ -18,7 +18,8 @@ const MainNav = () => {
     showTopNav: false
     showTopNav: false
   });
   });
 
 
-  const { userName, session: { look } } = useSelector(state => state.session);
+  const { userName } = useSelector(state => state.session);
+  const { session: { look } } = useSelector(state => state.userSession);
   const { user } = useSelector(state => state.menuCounters);
   const { user } = useSelector(state => state.menuCounters);
   const { activeElement, focusedElement, adminMenuTabs, userMenuTabs } = useSelector(state => state.mainNavigation);
   const { activeElement, focusedElement, adminMenuTabs, userMenuTabs } = useSelector(state => state.mainNavigation);
   const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent);
   const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent);
@@ -29,11 +30,22 @@ const MainNav = () => {
       return history.push('/login');
       return history.push('/login');
     }
     }
 
 
+    if (look) {
+      const commonUserRoutes = ['package', 'ip', 'rrd', 'updates', 'firewall', 'server'];
+      const splitPath = history.location.pathname.split('/')[2];
+
+      if (history.location.pathname === '/add/user/') return history.push('/');
+
+      if (commonUserRoutes.includes(splitPath)) {
+        return history.push('/');
+      }
+    }
+
     const tabs = look ? userMenuTabs : adminMenuTabs;
     const tabs = look ? userMenuTabs : adminMenuTabs;
     setState({ ...state, tabs });
     setState({ ...state, tabs });
 
 
     setLoading(false);
     setLoading(false);
-  }, [userName, user, history]);
+  }, [userName, user, history, look]);
 
 
   const controlFocusedTabWithCallback = useCallback(event => {
   const controlFocusedTabWithCallback = useCallback(event => {
     let isSearchInputFocused = document.querySelector('input:focus') || document.querySelector('textarea:focus') || document.querySelector('textarea:focus');
     let isSearchInputFocused = document.querySelector('input:focus') || document.querySelector('textarea:focus') || document.querySelector('textarea:focus');

+ 9 - 10
src/react/src/components/MainNav/Panel/Panel.jsx

@@ -5,15 +5,14 @@ import { logout } from 'src/actions/Session/sessionActions';
 import Notifications from './Notifications/Notifications';
 import Notifications from './Notifications/Notifications';
 import { useSelector, useDispatch } from "react-redux";
 import { useSelector, useDispatch } from "react-redux";
 import Spinner from 'src/components/Spinner/Spinner';
 import Spinner from 'src/components/Spinner/Spinner';
-import { Link, useHistory } from "react-router-dom";
+import { Link } from "react-router-dom";
 import './Panel.scss';
 import './Panel.scss';
 
 
 const Panel = props => {
 const Panel = props => {
-  const { i18n, userName, session: { look, user } } = useSelector(state => state.session);
-  const session = useSelector(state => state.session);
+  const { i18n, userName } = useSelector(state => state.session);
+  const { session: { look, user, FIREWALL_SYSTEM, FILEMANAGER_KEY, SOFTACULOUS } } = useSelector(state => state.userSession);
   const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
   const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
-  const history = useHistory();
   const [loading, setLoading] = useState(false);
   const [loading, setLoading] = useState(false);
   const [state, setState] = useState({
   const [state, setState] = useState({
     smallNavigationClass: 'small-navigation hidden'
     smallNavigationClass: 'small-navigation hidden'
@@ -98,14 +97,14 @@ const Panel = props => {
             <div className={className("/list/updates/")}>
             <div className={className("/list/updates/")}>
               <Link to="/list/updates/" onClick={event => handleState("/list/updates/", event)} onKeyPress={event => event.preventDefault()}>{i18n.Updates}</Link>
               <Link to="/list/updates/" onClick={event => handleState("/list/updates/", event)} onKeyPress={event => event.preventDefault()}>{i18n.Updates}</Link>
             </div>
             </div>
-            {session.session.FIREWALL_SYSTEM && <div className={className("/list/firewall/")}>
+            {FIREWALL_SYSTEM && <div className={className("/list/firewall/")}>
               <Link to="/list/firewall/" onClick={event => handleState("/list/firewall/", event)} onKeyPress={event => event.preventDefault()}>{i18n.Firewall}</Link>
               <Link to="/list/firewall/" onClick={event => handleState("/list/firewall/", event)} onKeyPress={event => event.preventDefault()}>{i18n.Firewall}</Link>
             </div>}
             </div>}
           </>)}
           </>)}
-          {session.session.FILEMANAGER_KEY && <div className={className("/list/directory/")}>
+          {FILEMANAGER_KEY && <div className={className("/list/directory/")}>
             <Link to="/list/directory/">{i18n['File Manager']}</Link>
             <Link to="/list/directory/">{i18n['File Manager']}</Link>
           </div>}
           </div>}
-          {session.session.SOFTACULOUS === "yes" && <div className={className("/softaculous/")}><a href="/softaculous/">{i18n.Apps ?? 'Apps'}</a>
+          {SOFTACULOUS === "yes" && <div className={className("/softaculous/")}><Link to="/softaculous/" target="_blank">{i18n.Apps ?? 'Apps'}</Link>
           </div>}
           </div>}
           {userName === 'admin' && (
           {userName === 'admin' && (
             <div className={className("/list/server/")}>
             <div className={className("/list/server/")}>
@@ -116,14 +115,14 @@ const Panel = props => {
         <div className="container profile-menu">
         <div className="container profile-menu">
           <Notifications />
           <Notifications />
           <div>
           <div>
-            <Link to={`/edit/user?user=${session.userName}`}>
+            <Link to={`/edit/user?user=${userName}`}>
               {look
               {look
                 ? <div className="long-username">
                 ? <div className="long-username">
                   <span>{user}</span>
                   <span>{user}</span>
                   <FontAwesomeIcon icon="long-arrow-alt-right" />
                   <FontAwesomeIcon icon="long-arrow-alt-right" />
                   <span>{look}</span>
                   <span>{look}</span>
                 </div>
                 </div>
-                : session.userName
+                : userName
               }
               }
             </Link>
             </Link>
           </div>
           </div>
@@ -144,7 +143,7 @@ const Panel = props => {
           <div className="bell">
           <div className="bell">
             <FontAwesomeIcon icon="bell" />
             <FontAwesomeIcon icon="bell" />
           </div>
           </div>
-          <div><Link to={`/edit/user?user=${session.userName}`}>{session.userName}</Link></div>
+          <div><Link to={`/edit/user?user=${userName}`}>{userName}</Link></div>
           <div><button onClick={signOut}>{i18n['Log out']}</button></div>
           <div><button onClick={signOut}>{i18n['Log out']}</button></div>
         </div>
         </div>
       </div>
       </div>

+ 2 - 1
src/react/src/components/MainNav/Stat-menu/Menu.jsx

@@ -27,7 +27,8 @@ const style = ({ menuHeight, mobile }) => {
 
 
 const Menu = props => {
 const Menu = props => {
   const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
   const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
-  const { i18n, session: { look } } = useSelector(state => state.session);
+  const { i18n } = useSelector(state => state.session);
+  const { session: { look } } = useSelector(state => state.userSession);
   const { user } = useSelector(state => state.menuCounters);
   const { user } = useSelector(state => state.menuCounters);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
 
 

+ 0 - 1
src/react/src/components/MainNav/Toolbar/DropdownFilter/DropdownFilter.scss

@@ -68,7 +68,6 @@
 
 
       span + span {
       span + span {
         text-align: center;
         text-align: center;
-        width: 100px;
       }
       }
     }
     }
 
 

+ 3 - 3
src/react/src/components/Menu/Menu.jsx

@@ -118,9 +118,9 @@ const Menu = (props) => {
   }
   }
 
 
   const hotKeys = (e) => {
   const hotKeys = (e) => {
-    if (props.modalVisible) {
-      return;
-    }
+    let isSearchInputFocused = document.querySelector('input:focus') || document.querySelector('textarea:focus');
+
+    if (props.modalVisible || isSearchInputFocused) return;
 
 
     if (e.shiftKey && e.keyCode === 117) {
     if (e.shiftKey && e.keyCode === 117) {
       rename();
       rename();

+ 28 - 21
src/react/src/components/Package/Edit/EditPackage.jsx

@@ -24,11 +24,11 @@ const EditPackage = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -39,21 +39,25 @@ const EditPackage = props => {
 
 
     if (queryParams.package) {
     if (queryParams.package) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getPackageInfo(queryParams.package)
-        .then(response => {
-          setState({
-            ...state,
-            data: response.data,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(queryParams.package);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = pkg => {
+    getPackageInfo(pkg)
+      .then(response => {
+        setState({
+          ...state,
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedPackage = {};
     let updatedPackage = {};
@@ -72,17 +76,20 @@ const EditPackage = props => {
       updatePackage(updatedPackage, state.data.package)
       updatePackage(updatedPackage, state.data.package)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setErrorMessage('');
+                setOkMessage(ok_msg);
               });
               });
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.data.package))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -116,12 +123,12 @@ const EditPackage = props => {
         <div className="search-toolbar-name">{i18n['Editing Package']}</div>
         <div className="search-toolbar-name">{i18n['Editing Package']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 0 - 1
src/react/src/components/Path/Dropdown/Dropdown.scss

@@ -41,7 +41,6 @@
 
 
       span + span {
       span + span {
         text-align: center;
         text-align: center;
-        width: 100px;
       }
       }
     }
     }
   }
   }

+ 0 - 1
src/react/src/components/Preview/Photo/Photo.scss

@@ -18,7 +18,6 @@
         }
         }
 
 
         .img {
         .img {
-          height: 90vh;
           width: 90%;
           width: 90%;
         }
         }
     }
     }

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

@@ -6,11 +6,11 @@ import Photo from './Photo/Photo';
 import Video from './Video/Video';
 import Video from './Video/Video';
 
 
 const Preview = (props) => {
 const Preview = (props) => {
-  const session = useSelector(state => state.session);
+  const {userName} = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
 
 
   useEffect(() => {
   useEffect(() => {
-    if (!session.userName) history.push('/login');
+    if (!userName) history.push('/login');
 
 
     document.addEventListener("keydown", hotkeys);
     document.addEventListener("keydown", hotkeys);
 
 

+ 17 - 21
src/react/src/components/Server/Edit/Bind9/Bind9.jsx

@@ -19,11 +19,11 @@ const Bind9 = () => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -31,23 +31,23 @@ const Bind9 = () => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo('bind9')
     getServiceInfo('bind9')
       .then(response => {
       .then(response => {
         if (response.data.config.includes('Error')) {
         if (response.data.config.includes('Error')) {
           history.push('/list/server');
           history.push('/list/server');
         }
         }
 
 
-        setState({
-          ...state,
-          data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
-          loading: false
-        });
+        setState({ ...state, data: response.data, loading: false });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -65,15 +65,11 @@ const Bind9 = () => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
-            if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -90,12 +86,12 @@ const Bind9 = () => {
         </div>
         </div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 16 - 16
src/react/src/components/Server/Edit/Dovecot/Dovecot.jsx

@@ -19,11 +19,11 @@ const Dovecot = () => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -31,7 +31,10 @@ const Dovecot = () => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo('dovecot')
     getServiceInfo('dovecot')
       .then(response => {
       .then(response => {
         if (!response.data.config) {
         if (!response.data.config) {
@@ -41,13 +44,14 @@ const Dovecot = () => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -65,15 +69,11 @@ const Dovecot = () => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
-            if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -90,12 +90,12 @@ const Dovecot = () => {
         </div>
         </div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 28 - 11
src/react/src/components/Server/Edit/EditServer.jsx

@@ -20,12 +20,16 @@ import { useDispatch, useSelector } from 'react-redux';
 import './EditServer.scss';
 import './EditServer.scss';
 import { Helmet } from 'react-helmet';
 import { Helmet } from 'react-helmet';
 import HtmlParser from 'react-html-parser';
 import HtmlParser from 'react-html-parser';
+import { refreshUserSession } from 'src/actions/Session/sessionActions';
 
 
 const EditServer = props => {
 const EditServer = props => {
   const token = localStorage.getItem("token");
   const token = localStorage.getItem("token");
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
+  const { session } = useSelector(state => state.userSession);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
@@ -35,9 +39,7 @@ const EditServer = props => {
     backupOption: false,
     backupOption: false,
     sslOption: false,
     sslOption: false,
     pluginsOption: false,
     pluginsOption: false,
-    dbOption: false,
-    errorMessage: '',
-    okMessage: ''
+    dbOption: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -45,20 +47,23 @@ const EditServer = props => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServerAdditionalInfo()
     getServerAdditionalInfo()
       .then(response => {
       .then(response => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
-      .catch(err => console.error(err));
-
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -71,6 +76,10 @@ const EditServer = props => {
     updatedServer['save'] = 'save';
     updatedServer['save'] = 'save';
     updatedServer['token'] = token;
     updatedServer['token'] = token;
 
 
+    if (updatedServer['v_softaculous'] === 'no' && !session['SOFTACULOUS']) {
+      delete updatedServer['v_softaculous'];
+    }
+
     if (Object.keys(updatedServer).length !== 0 && updatedServer.constructor === Object) {
     if (Object.keys(updatedServer).length !== 0 && updatedServer.constructor === Object) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
 
 
@@ -78,9 +87,17 @@ const EditServer = props => {
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
-            setState({ ...state, errorMessage: error_msg || '', okMessage: ok_msg || '', loading: false });
+
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
+            } else {
+              setErrorMessage('');
+              setOkMessage(ok_msg);
+            }
           }
           }
         })
         })
+        .then(() => dispatch(refreshUserSession()).then(() => fetchData()))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -102,12 +119,12 @@ const EditServer = props => {
         <div className="search-toolbar-name">{i18n['Configuring Server']}</div>
         <div className="search-toolbar-name">{i18n['Configuring Server']}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 1 - 1
src/react/src/components/Server/Edit/EditServerDnsOption.jsx

@@ -9,7 +9,7 @@ const EditServerDnsOption = ({ dnsSystem, selected, dnsCluster, visible }) => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
 
 
   const printHosts = () => {
   const printHosts = () => {
-    return dnsCluster.map((cluster, index) => (
+    return Object.keys(dnsCluster).map((cluster, index) => (
       <TextInput
       <TextInput
         title={`${i18n['DNS Server']} #${index + 1}`}
         title={`${i18n['DNS Server']} #${index + 1}`}
         name="v_dns_remote_host"
         name="v_dns_remote_host"

+ 167 - 195
src/react/src/components/Server/Edit/EditVestaPlugins.jsx

@@ -1,71 +1,125 @@
-import React, { useEffect, useState } from 'react';
+import React, { useState } from 'react';
 
 
 import SelectInput from 'src/components/ControlPanel/AddItemLayout/Form/SelectInput/SelectInput';
 import SelectInput from 'src/components/ControlPanel/AddItemLayout/Form/SelectInput/SelectInput';
 import TextInput from 'src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput';
 import TextInput from 'src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput';
-import { Link } from 'react-router-dom';
 import { useSelector } from 'react-redux';
 import { useSelector } from 'react-redux';
 
 
 const EditVestaPluginsOption = ({ data, visible }) => {
 const EditVestaPluginsOption = ({ data, visible }) => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
-  const [sftpOptions, setSftpOptions] = useState([]);
-  const [fmOptions, setFmOptions] = useState([]);
-  const [sftpDescription, setSftpDescription] = useState(false);
-  const [fmDescription, setFmDescription] = useState(false);
-  const [softaculousDescription, setSoftaculousDescription] = useState(false);
-
-  useEffect(() => {
-    let sftpOptionsArray = [];
-    let fmOptionsArray = [];
-
-    if (data.sftpjail_key) {
-      sftpOptionsArray.push(i18n['Disable and Cancel Licence']);
-    }
-
-    sftpOptionsArray.push(i18n['yes']);
-
-    if (data.fm_key) {
-      fmOptionsArray.push(i18n['Disable and Cancel Licence']);
-    }
-
-    fmOptionsArray.push(i18n['yes']);
-
-    setSftpOptions(sftpOptionsArray);
-    setFmOptions(fmOptionsArray);
+  const { session } = useSelector(state => state.userSession);
+  const [sftpValue, setSftpValue] = useState(data.lead || session['SFTPJAIL_KEY'] ? 'yes' : 'no');
+  const [fmValue, setFmValue] = useState(data.fm_lead || session['FILEMANAGER_KEY'] ? 'yes' : 'no');
+  const [softaculousValue, setSoftaculousValue] = useState(session['SOFTACULOUS'] === 'yes' ? 'yes' : 'no');
+
+  const renderSoftaculous = () => {
+    if (softaculousValue === 'yes') {
+      if (session['SOFTACULOUS'] === 'yes') {
+        return (<div className="soft-module">
+          <div>
+            <span style={{ fontWeight: 'bolder' }}>{i18n['* plugin installation will run in background']}</span>
+            <span>
+              Softaculous is a great Auto Installer having 426 great scripts, 1115 PHP Classes
+              and we are still adding more. Softaculous is ideal for Web Hosting companies and
+              it could give a significant boost to your sales. These scripts cover most of the
+              uses a customer could ever have. We have covered a wide array of Categories so that
+              everyone could find the required script one would need to power their Web Site.
+            </span>
+          </div>
 
 
-    if (data.lead === 'sftp' || data.sftpjail_key !== 'no') {
-      setSftpDescription(true);
+          <div className="buy-license">
+            <a href="https://www.softaculous.com/softaculous/" target="_blank" rel="noopener noreferrer">
+              {i18n['Get Premium License'] ?? 'Get Premium License'}
+            </a>
+          </div>
+        </div>);
+      }
     }
     }
+  }
 
 
-    if (data.lead === 'filemanager' || data.fm_key !== 'no') {
-      setFmDescription(true);
-    }
+  const renderSftp = () => {
+    if (sftpValue === 'yes') {
+      if (!data.sftp_license_key && session['SFTPJAIL_KEY']) {
+        return (<div className="sftp-module">
+          <div>{i18n['Restrict users so that they cannot use SSH and access only their home directory.']}</div>
+          <div className="license-description">
+            <span>{i18n['Licence Key']}:</span>
+            <TextInput
+              title={i18n['License Key']}
+              value={data.licence_key}
+              name="v_sftp_licence"
+              id="sftp_licence" />
+          </div>
+        </div>)
+      } else {
+        return (<div className="sftp-module">
+          <>
+            <span>{i18n['Restrict users so that they cannot use SSH and access only their home directory.']}</span>
+            <span>{i18n['This is a commercial module, you would need to purchace license key to enable it.']}</span>
+          </>
+          <div className="license-description">
+            <span>{i18n['Enter License Key']}:</span>
+            <TextInput
+              title={i18n['Version']}
+              name="v_sftp_licence"
+              id="sftp_licence" />
+          </div>
 
 
-    if (data.lead === 'softaculous' || data.softaculous !== 'no') {
-      setSoftaculousDescription(true);
-    }
-  }, []);
+          <div className="buy-license">
+            <a href={`https://vestacp.com/checkout/2co.php?product_id=6&referer=${data.http_host}`}>
+              {i18n['Buy Licence']} 3$ {i18n['month']}
+            </a>
+            <a href={`https://vestacp.com/checkout/2co.php?product_id=9&referer=${data.http_host}`}>
+              {i18n['Buy Lifetime License']} 18$
+            </a>
+          </div>
 
 
-  const onChangeSftpChroot = value => {
-    if (value !== i18n['yes']) {
-      setSftpDescription(false);
-    } else {
-      setSftpDescription(true);
+          <span>2Checkout.com Inc. (Ohio, USA) is a payment facilitator for goods and services provided by vestacp.com.</span>
+        </div>)
+      }
     }
     }
   }
   }
 
 
-  const onChangeFm = value => {
-    if (value !== i18n['yes']) {
-      setFmDescription(false);
-    } else {
-      setFmDescription(true);
-    }
-  }
+  const renderFm = () => {
+    if (fmValue === 'yes') {
+      if (!data.fm_license_key && session['FILEMANAGER_KEY']) {
+        return (<div className="fm-module">
+          <div>{i18n['Browse, copy, edit, view, and retrieve all of your web domain files using fully featured File Manager.']}</div>
+          <div className="license-description">
+            <span>{i18n['Licence Key']}:</span>
+            <TextInput
+              title={i18n['Licence Key']}
+              value={data.fm_licence_key_option}
+              name="v_filemanager_licence"
+              id="filemanager_licence" />
+          </div>
+        </div>);
+      } else {
+        return (<div className="fm-module">
+          <>
+            <span>{i18n['Browse, copy, edit, view, and retrieve all of your web domain files using fully featured File Manager.']}</span>
+            <span>{i18n['This is a commercial module, you would need to purchace license key to enable it.']}</span>
+          </>
+          <div className="license-description">
+            <span>{i18n['Enter License Key']}:</span>
+            <TextInput
+              title={i18n['Version']}
+              value=""
+              name="v_filemanager_licence"
+              id="sftp_licence" />
+          </div>
+
+          <div className="buy-license">
+            <a href={`https://vestacp.com/checkout/2co.php?product_id=7&referer=${data.http_host}`} target="_blank" rel="noopener noreferrer">
+              {i18n['Buy Licence']} 3$ {i18n['month']}
+            </a>
+            <a href={`https://vestacp.com/checkout/2co.php?product_id=8&referer=${data.http_host}`} target="_blank" rel="noopener noreferrer">
+              {i18n['Buy Lifetime License']} 28$
+            </a>
+          </div>
 
 
-  const onChangeSoftaculous = value => {
-    if (value !== i18n['yes']) {
-      setSoftaculousDescription(true);
-    } else {
-      setSoftaculousDescription(false);
+          <span>2Checkout.com Inc. (Ohio, USA) is a payment facilitator for goods and services provided by vestacp.com.</span>
+        </div>)
+      }
     }
     }
   }
   }
 
 
@@ -78,21 +132,27 @@ const EditVestaPluginsOption = ({ data, visible }) => {
         id="version"
         id="version"
         disabled />
         disabled />
 
 
-      <SelectInput
-        title={i18n['FileSystem Disk Quota']}
-        selected={data.disk_quota}
-        options={data.yes_no_options}
-        name="v_quota"
-        id="quota" />
+      <div className="form-group select-group">
+        <label className="label-wrapper" htmlFor="quota">
+          {i18n['FileSystem Disk Quota']}
+        </label>
+        <select className="form-control" id="quota" name="v_quota">
+          <option value="no">{i18n['no']}</option>
+          <option value="yes" selected={data.disk_quota === 'yes'}>{i18n['yes']}</option>
+        </select>
+      </div>
 
 
       <br />
       <br />
 
 
-      <SelectInput
-        title={i18n['Firewall']}
-        selected={data.firewall_system === 'iptables' ? i18n['yes'] : ''}
-        options={data.yes_no_options}
-        name="v_firewall"
-        id="firewall" />
+      <div className="form-group select-group">
+        <label className="label-wrapper" htmlFor="firewall">
+          {i18n['Firewall']}
+        </label>
+        <select className="form-control" id="firewall" name="v_firewall">
+          <option value="no">{i18n['no']}</option>
+          <option value="yes" selected={data.firewall_system === 'iptables'}>{i18n['yes']}</option>
+        </select>
+      </div>
 
 
       <SelectInput
       <SelectInput
         title={i18n['Reseller Role']}
         title={i18n['Reseller Role']}
@@ -108,143 +168,55 @@ const EditVestaPluginsOption = ({ data, visible }) => {
         id="backup_manager"
         id="backup_manager"
         disabled />
         disabled />
 
 
-      <SelectInput
-        title={i18n['SFTP Chroot']}
-        selected={data.lead === 'sftp' || data.sftpjail_key != '' ? i18n['yes'] : ''}
-        name="v_backup_manager"
-        options={sftpOptions}
-        onChange={onChangeSftpChroot}
-        id="backup_manager" />
-
-      {
-        sftpDescription
-          ? (
-            <div className="sftp-module">
-              <div>{i18n['Restrict users so that they cannot use SSH and access only their home directory.']}</div>
-              <div className="license-description">
-                <span>{i18n['Licence Key']}:</span>
-                <TextInput
-                  title={i18n['Version']}
-                  value={data.version}
-                  name="v_version"
-                  id="version" />
-              </div>
-            </div>
-          )
-          : (
-            <div className="sftp-module">
-              <>
-                <span>{i18n['Restrict users so that they cannot use SSH and access only their home directory.']}</span>
-                <span>{i18n['This is a commercial module, you would need to purchace license key to enable it.']}</span>
-              </>
-              <div className="license-description">
-                <span>{i18n['Enter License Key']}:</span>
-                <TextInput
-                  title={i18n['Version']}
-                  name="v_sftp_licence"
-                  id="sftp_licence" />
-              </div>
-
-              <div className="buy-license">
-                <a href={`https://vestacp.com/checkout/2co.php?product_id=6&referer=${data.http_host}`}>
-                  {i18n['Buy Licence']} 3$ {i18n['month']}
-                </a>
-                <a href={`https://vestacp.com/checkout/2co.php?product_id=9&referer=${data.http_host}`}>
-                  {i18n['Buy Lifetime License']} 18$
-                </a>
-              </div>
-
-              <span>2Checkout.com Inc. (Ohio, USA) is a payment facilitator for goods and services provided by vestacp.com.</span>
-            </div>
-          )
-      }
+      <div className="form-group select-group">
+        <label className="label-wrapper" htmlFor="sftp">
+          {i18n['SFTP Chroot']}
+        </label>
+        <select className="form-control" id="sftp" name="v_sftp" onChange={event => setSftpValue(event.target.value)}>
+          {
+            session['SFTPJAIL_KEY']
+              ? <option value="cancel">{i18n['Disable and Cancel Licence']}</option>
+              : <option value="no">{i18n['no']}</option>
+          }
+
+          <option value="yes" selected={data.lead || session['SFTPJAIL_KEY']}>{i18n['yes']}</option>
+        </select>
+      </div>
+
+      {renderSftp()}
 
 
       <br />
       <br />
 
 
-      <SelectInput
-        title={i18n['File Manager']}
-        selected={data.lead === 'filemanager' || data.fm_key ? i18n['yes'] : ''}
-        options={fmOptions}
-        onChange={onChangeFm}
-        name="v_filemanager"
-        id="filemanager" />
-
-      {
-        fmDescription
-          ? (
-            <div className="fm-module">
-              <div>{i18n['Browse, copy, edit, view, and retrieve all of your web domain files using fully featured File Manager.']}</div>
-              <div className="license-description">
-                <span>{i18n['Licence Key']}:</span>
-                <TextInput
-                  title={i18n['Version']}
-                  value={data.fm_licence_key_option}
-                  name="v_filemanager_licence"
-                  id="filemanager_licence" />
-              </div>
-            </div>
-          )
-          : (
-            <div className="fm-module">
-              <>
-                <span>{i18n['Browse, copy, edit, view, and retrieve all of your web domain files using fully featured File Manager.']}</span>
-                <span>{i18n['This is a commercial module, you would need to purchace license key to enable it.']}</span>
-              </>
-              <div className="license-description">
-                <span>{i18n['Enter License Key']}:</span>
-                <TextInput
-                  title={i18n['Version']}
-                  value=""
-                  name="v_filemanager_licence"
-                  id="sftp_licence" />
-              </div>
-
-              <div className="buy-license">
-                <a href={`https://vestacp.com/checkout/2co.php?product_id=7&referer=${data.http_host}`} target="_blank" rel="noopener noreferrer">
-                  {i18n['Buy Licence']} 3$ {i18n['month']}
-                </a>
-                <a href={`https://vestacp.com/checkout/2co.php?product_id=8&referer=${data.http_host}`} target="_blank" rel="noopener noreferrer">
-                  {i18n['Buy Lifetime License']} 28$
-                </a>
-              </div>
-
-              <span>2Checkout.com Inc. (Ohio, USA) is a payment facilitator for goods and services provided by vestacp.com.</span>
-            </div>
-          )
-      }
+      <div className="form-group select-group">
+        <label className="label-wrapper" htmlFor="filemanager">
+          {i18n['File Manager']}
+        </label>
+        <select className="form-control" id="filemanager" name="v_filemanager" onChange={event => setFmValue(event.target.value)}>
+          {
+            session['FILEMANAGER_KEY']
+              ? <option value="cancel">{i18n['Disable and Cancel Licence']}</option>
+              : <option value="no">{i18n['no']}</option>
+          }
+
+          <option value="yes" selected={data.fm_lead || session['FILEMANAGER_KEY']}>{i18n['yes']}</option>
+        </select>
+      </div>
+
+      {renderFm()}
 
 
       <br />
       <br />
 
 
-      <SelectInput
-        title="Softaculous"
-        selected={data.lead === 'softaculous' || data.softaculous === 'yes' ? i18n['yes'] : ''}
-        options={[i18n['no'], i18n['yes']]}
-        onChange={onChangeSoftaculous}
-        name="v_softaculous"
-        id="softaculous" />
-
-      {
-        softaculousDescription && (
-          <div className="soft-module">
-            <div>
-              <span style={{ fontWeight: 'bolder' }}>{i18n['* plugin installation will run in background']}</span>
-              <span>
-                Softaculous is a great Auto Installer having 426 great scripts, 1115 PHP Classes
-                and we are still adding more. Softaculous is ideal for Web Hosting companies and
-                it could give a significant boost to your sales. These scripts cover most of the
-                uses a customer could ever have. We have covered a wide array of Categories so that
-                everyone could find the required script one would need to power their Web Site.
-              </span>
-            </div>
-
-            <div className="buy-license">
-              <a href="https://www.softaculous.com/softaculous/" target="_blank" rel="noopener noreferrer">
-                {i18n['Get Premium License'] ?? 'Get Premium License'}
-              </a>
-            </div>
-          </div>
-        )
-      }
+      <div className="form-group select-group">
+        <label className="label-wrapper" htmlFor="softaculous">
+          {i18n['Softaculous'] ?? 'Softaculous'}
+        </label>
+        <select className="form-control" id="softaculous" name="v_softaculous" onChange={event => setSoftaculousValue(event.target.value)}>
+          <option value="no">{i18n['no']}</option>
+          <option value="yes" selected={data.softaculous_lead || session['SOFTACULOUS'] === 'yes'}>{i18n['yes']}</option>
+        </select>
+      </div>
+
+      {renderSoftaculous()}
     </div>
     </div>
   );
   );
 }
 }

+ 17 - 10
src/react/src/components/Server/Edit/Httpd/EditHttpd.jsx

@@ -19,6 +19,8 @@ const EditHttpd = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
@@ -31,19 +33,23 @@ const EditHttpd = props => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo('httpd')
     getServiceInfo('httpd')
       .then(response => {
       .then(response => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -62,14 +68,15 @@ const EditHttpd = props => {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
             if (error_msg) {
             if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
-              setState({ ...state, loading: false });
+              setErrorMessage('');
+              setOkMessage(ok_msg);
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -85,12 +92,12 @@ const EditHttpd = props => {
         <div className="link"><Link to="/edit/server/php">{i18n['Configure']} php.ini</Link></div>
         <div className="link"><Link to="/edit/server/php">{i18n['Configure']} php.ini</Link></div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 40 - 25
src/react/src/components/Server/Edit/Mysql/Mysql.jsx

@@ -20,13 +20,14 @@ const Mysql = ({ serviceName = '' }) => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
+  const [restart, setRestart] = useState(true);
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
     basicOptions: true,
     basicOptions: true,
-    advancedOptions: false,
-    errorMessage: '',
-    okMessage: ''
+    advancedOptions: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -38,23 +39,23 @@ const Mysql = ({ serviceName = '' }) => {
     }
     }
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo('mysql')
     getServiceInfo('mysql')
       .then(response => {
       .then(response => {
         if (response.data.config.includes('Error')) {
         if (response.data.config.includes('Error')) {
           history.push('/list/server');
           history.push('/list/server');
         }
         }
 
 
-        setState({
-          ...state,
-          data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
-          loading: false
-        });
+        setState({ ...state, data: response.data, loading: false });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -67,20 +68,19 @@ const Mysql = ({ serviceName = '' }) => {
     if (Object.keys(updatedService).length !== 0 && updatedService.constructor === Object) {
     if (Object.keys(updatedService).length !== 0 && updatedService.constructor === Object) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
 
 
+      updatedService['v_config'] = state.data.config;
+      updatedService['v_restart'] = restart ? 'yes' : 'no';
+
       updateService(updatedService, `/${serviceName}`)
       updateService(updatedService, `/${serviceName}`)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
-            if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -93,6 +93,14 @@ const Mysql = ({ serviceName = '' }) => {
     });
     });
   }
   }
 
 
+  const onUpdateConfig = ({ id, value }) => {
+    if (!value) return;
+
+    var regexp = new RegExp(`(${id})(.+)(${state.data[id]})`, 'gm');
+    const updatedConfig = state.data.config.replace(regexp, `$1$2${value}`);
+    setState({ ...state, data: { ...state.data, config: updatedConfig, [id]: value } });
+  }
+
   return (
   return (
     <div className="edit-template edit-mysql">
     <div className="edit-template edit-mysql">
       <Helmet>
       <Helmet>
@@ -103,12 +111,12 @@ const Mysql = ({ serviceName = '' }) => {
         <div className="search-toolbar-name">{i18n['Configuring Server']} / {state.data.service_name}</div>
         <div className="search-toolbar-name">{i18n['Configuring Server']} / {state.data.service_name}</div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
@@ -134,30 +142,35 @@ const Mysql = ({ serviceName = '' }) => {
                     id="max_connections"
                     id="max_connections"
                     title="max_connections"
                     title="max_connections"
                     name="v_max_connections"
                     name="v_max_connections"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.max_connections} />
                     value={state.data.max_connections} />
 
 
                   <TextInput
                   <TextInput
-                    id="v_max_user_connections"
+                    id="max_user_connections"
                     title="v_max_user_connections"
                     title="v_max_user_connections"
                     name="v_max_user_connections"
                     name="v_max_user_connections"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.max_user_connections} />
                     value={state.data.max_user_connections} />
 
 
                   <TextInput
                   <TextInput
-                    id="v_wait_timeout"
+                    id="wait_timeout"
                     title="v_wait_timeout"
                     title="v_wait_timeout"
                     name="v_wait_timeout"
                     name="v_wait_timeout"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.wait_timeout} />
                     value={state.data.wait_timeout} />
 
 
                   <TextInput
                   <TextInput
-                    id="v_interactive_timeout"
+                    id="interactive_timeout"
                     title="v_interactive_timeout"
                     title="v_interactive_timeout"
                     name="v_interactive_timeout"
                     name="v_interactive_timeout"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.interactive_timeout} />
                     value={state.data.interactive_timeout} />
 
 
                   <TextInput
                   <TextInput
-                    id="v_display_errors"
+                    id="display_errors"
                     title="v_display_errors"
                     title="v_display_errors"
                     name="v_display_errors"
                     name="v_display_errors"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.max_allowed_packet} />
                     value={state.data.max_allowed_packet} />
                 </>
                 </>
               )
               )
@@ -181,6 +194,7 @@ const Mysql = ({ serviceName = '' }) => {
                   <TextArea
                   <TextArea
                     defaultValue={state.data.config}
                     defaultValue={state.data.config}
                     title={state.data.config_path}
                     title={state.data.config_path}
+                    onChange={e => setState({ ...state, data: { ...state.data, config: e.target.value } })}
                     name="v_config"
                     name="v_config"
                     id="v_config"
                     id="v_config"
                     rows="25" />
                     rows="25" />
@@ -190,6 +204,7 @@ const Mysql = ({ serviceName = '' }) => {
                   <Checkbox
                   <Checkbox
                     title={i18n['restart']}
                     title={i18n['restart']}
                     defaultChecked={true}
                     defaultChecked={true}
+                    onChange={checked => setRestart(checked)}
                     name="v_restart"
                     name="v_restart"
                     id="restart" />
                     id="restart" />
                 </>
                 </>

+ 42 - 13
src/react/src/components/Server/Edit/Nginx/EditServerNginx.jsx

@@ -20,13 +20,14 @@ const EditServerNginx = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
+  const [restart, setRestart] = useState(true);
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
     basicOptions: true,
     basicOptions: true,
-    advancedOptions: false,
-    errorMessage: '',
-    okMessage: ''
+    advancedOptions: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -34,19 +35,23 @@ const EditServerNginx = props => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo('nginx')
     getServiceInfo('nginx')
       .then(response => {
       .then(response => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err)
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -59,20 +64,24 @@ const EditServerNginx = props => {
     if (Object.keys(updatedService).length !== 0 && updatedService.constructor === Object) {
     if (Object.keys(updatedService).length !== 0 && updatedService.constructor === Object) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
 
 
+      updatedService['v_config'] = state.data.config;
+      updatedService['v_restart'] = restart ? 'yes' : 'no';
+
       updateService(updatedService, '/nginx')
       updateService(updatedService, '/nginx')
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
             if (error_msg) {
             if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
+              setErrorMessage(error_msg);
+              setOkMessage('');
             } else {
             } else {
-              setState({ ...state, loading: false });
+              setErrorMessage('');
+              setOkMessage(ok_msg);
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -85,6 +94,14 @@ const EditServerNginx = props => {
     });
     });
   }
   }
 
 
+  const onUpdateConfig = ({ id, value }) => {
+    if (!value) return;
+
+    var regexp = new RegExp(`(${id})(.+)(${state.data[id]})`, 'gm');
+    const updatedConfig = state.data.config.replace(regexp, `$1$2${value}`);
+    setState({ ...state, data: { ...state.data, config: updatedConfig, [id]: value } });
+  }
+
   return (
   return (
     <div className="edit-template edit-nginx">
     <div className="edit-template edit-nginx">
       <Helmet>
       <Helmet>
@@ -96,12 +113,12 @@ const EditServerNginx = props => {
         <div className="link"><Link to="/edit/server/php">{i18n['Configure']} php.ini</Link></div>
         <div className="link"><Link to="/edit/server/php">{i18n['Configure']} php.ini</Link></div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
@@ -127,60 +144,70 @@ const EditServerNginx = props => {
                     id="worker_processes"
                     id="worker_processes"
                     title="worker_processes"
                     title="worker_processes"
                     name="v_worker_processes"
                     name="v_worker_processes"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.worker_processes} />
                     value={state.data.worker_processes} />
 
 
                   <TextInput
                   <TextInput
                     id="worker_connections"
                     id="worker_connections"
                     title="worker_connections"
                     title="worker_connections"
                     name="v_worker_connections"
                     name="v_worker_connections"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.worker_connections} />
                     value={state.data.worker_connections} />
 
 
                   <TextInput
                   <TextInput
                     id="client_max_body_size"
                     id="client_max_body_size"
                     title="client_max_body_size"
                     title="client_max_body_size"
                     name="v_client_max_body_size"
                     name="v_client_max_body_size"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.client_max_body_size} />
                     value={state.data.client_max_body_size} />
 
 
                   <TextInput
                   <TextInput
                     id="send_timeout"
                     id="send_timeout"
                     title="send_timeout"
                     title="send_timeout"
                     name="v_send_timeout"
                     name="v_send_timeout"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.send_timeout} />
                     value={state.data.send_timeout} />
 
 
                   <TextInput
                   <TextInput
                     id="proxy_connect_timeout"
                     id="proxy_connect_timeout"
                     title="proxy_connect_timeout"
                     title="proxy_connect_timeout"
                     name="v_proxy_connect_timeout"
                     name="v_proxy_connect_timeout"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.proxy_connect_timeout} />
                     value={state.data.proxy_connect_timeout} />
 
 
                   <TextInput
                   <TextInput
                     id="proxy_send_timeout"
                     id="proxy_send_timeout"
                     title="proxy_send_timeout"
                     title="proxy_send_timeout"
                     name="v_proxy_send_timeout"
                     name="v_proxy_send_timeout"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.proxy_send_timeout} />
                     value={state.data.proxy_send_timeout} />
 
 
                   <TextInput
                   <TextInput
                     id="proxy_read_timeout"
                     id="proxy_read_timeout"
                     title="proxy_read_timeout"
                     title="proxy_read_timeout"
                     name="v_proxy_read_timeout"
                     name="v_proxy_read_timeout"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.proxy_read_timeout} />
                     value={state.data.proxy_read_timeout} />
 
 
                   <TextInput
                   <TextInput
                     id="gzip"
                     id="gzip"
                     title="gzip"
                     title="gzip"
                     name="v_gzip"
                     name="v_gzip"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.gzip} />
                     value={state.data.gzip} />
 
 
                   <TextInput
                   <TextInput
                     id="gzip_comp_level"
                     id="gzip_comp_level"
                     title="gzip_comp_level"
                     title="gzip_comp_level"
                     name="v_gzip_comp_level"
                     name="v_gzip_comp_level"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.gzip_comp_level} />
                     value={state.data.gzip_comp_level} />
 
 
                   <TextInput
                   <TextInput
                     id="charset"
                     id="charset"
                     title="charset"
                     title="charset"
                     name="v_charset"
                     name="v_charset"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.charset} />
                     value={state.data.charset} />
                 </>
                 </>
               )
               )
@@ -204,6 +231,7 @@ const EditServerNginx = props => {
                   <TextArea
                   <TextArea
                     defaultValue={state.data.config}
                     defaultValue={state.data.config}
                     title={state.data.config_path}
                     title={state.data.config_path}
+                    onChange={e => setState({ ...state, data: { ...state.data, config: e.target.value } })}
                     name="v_config"
                     name="v_config"
                     id="v_config"
                     id="v_config"
                     rows="25" />
                     rows="25" />
@@ -213,6 +241,7 @@ const EditServerNginx = props => {
                   <Checkbox
                   <Checkbox
                     title={i18n['restart']}
                     title={i18n['restart']}
                     defaultChecked={true}
                     defaultChecked={true}
+                    onChange={checked => setRestart(checked)}
                     name="v_restart"
                     name="v_restart"
                     id="restart" />
                     id="restart" />
                 </>
                 </>

+ 37 - 16
src/react/src/components/Server/Edit/PHP/EditPhp.jsx

@@ -20,13 +20,14 @@ const EditPhp = ({ serviceName = '' }) => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
+  const [restart, setRestart] = useState(true);
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
     basicOptions: true,
     basicOptions: true,
-    advancedOptions: false,
-    errorMessage: '',
-    okMessage: ''
+    advancedOptions: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -38,19 +39,23 @@ const EditPhp = ({ serviceName = '' }) => {
     }
     }
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo(serviceName)
     getServiceInfo(serviceName)
       .then(response => {
       .then(response => {
         setState({
         setState({
           ...state,
           ...state,
           data: response.data,
           data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
           loading: false
           loading: false
         });
         });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -63,20 +68,19 @@ const EditPhp = ({ serviceName = '' }) => {
     if (Object.keys(updatedService).length !== 0 && updatedService.constructor === Object) {
     if (Object.keys(updatedService).length !== 0 && updatedService.constructor === Object) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
 
 
+      updatedService['v_config'] = state.data.config;
+      updatedService['v_restart'] = restart ? 'yes' : 'no';
+
       updateService(updatedService, `/${serviceName}`)
       updateService(updatedService, `/${serviceName}`)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
-            if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -89,6 +93,14 @@ const EditPhp = ({ serviceName = '' }) => {
     });
     });
   }
   }
 
 
+  const onUpdateConfig = ({ id, value }) => {
+    if (!value) return;
+
+    var regexp = new RegExp(`(${id})(.+)(${state.data[id]})`, 'gm');
+    const updatedConfig = state.data.config.replace(regexp, `$1$2${value}`);
+    setState({ ...state, data: { ...state.data, config: updatedConfig, [id]: value } });
+  }
+
   return (
   return (
     <div className="edit-template edit-php">
     <div className="edit-template edit-php">
       <Helmet>
       <Helmet>
@@ -100,12 +112,12 @@ const EditPhp = ({ serviceName = '' }) => {
         <div className="link"><Link to="/edit/server/php">{i18n['Configure']} php.ini</Link></div>
         <div className="link"><Link to="/edit/server/php">{i18n['Configure']} php.ini</Link></div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
@@ -131,42 +143,49 @@ const EditPhp = ({ serviceName = '' }) => {
                     id="max_execution_time"
                     id="max_execution_time"
                     title="max_execution_time"
                     title="max_execution_time"
                     name="v_max_execution_time"
                     name="v_max_execution_time"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={parseInt(state.data.max_execution_time)} />
                     value={parseInt(state.data.max_execution_time)} />
 
 
                   <TextInput
                   <TextInput
                     id="worker_connections"
                     id="worker_connections"
                     title="worker_connections"
                     title="worker_connections"
                     name="v_worker_connections"
                     name="v_worker_connections"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={parseInt(state.data.max_input_time)} />
                     value={parseInt(state.data.max_input_time)} />
 
 
                   <TextInput
                   <TextInput
                     id="memory_limit"
                     id="memory_limit"
                     title="memory_limit"
                     title="memory_limit"
                     name="v_memory_limit"
                     name="v_memory_limit"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={parseInt(state.data.memory_limit)} />
                     value={parseInt(state.data.memory_limit)} />
 
 
                   <TextInput
                   <TextInput
                     id="error_reporting"
                     id="error_reporting"
                     title="error_reporting"
                     title="error_reporting"
                     name="v_error_reporting"
                     name="v_error_reporting"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.error_reporting} />
                     value={state.data.error_reporting} />
 
 
                   <TextInput
                   <TextInput
                     id="display_errors"
                     id="display_errors"
                     title="display_errors"
                     title="display_errors"
                     name="v_display_errors"
                     name="v_display_errors"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.display_errors} />
                     value={state.data.display_errors} />
 
 
                   <TextInput
                   <TextInput
                     id="post_max_size"
                     id="post_max_size"
                     title="post_max_size"
                     title="post_max_size"
                     name="v_post_max_size"
                     name="v_post_max_size"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.post_max_size} />
                     value={state.data.post_max_size} />
 
 
                   <TextInput
                   <TextInput
                     id="upload_max_filesize"
                     id="upload_max_filesize"
                     title="upload_max_filesize"
                     title="upload_max_filesize"
                     name="v_upload_max_filesize"
                     name="v_upload_max_filesize"
+                    onChange={event => onUpdateConfig(event.target)}
                     value={state.data.upload_max_filesize} />
                     value={state.data.upload_max_filesize} />
                 </>
                 </>
               )
               )
@@ -188,6 +207,7 @@ const EditPhp = ({ serviceName = '' }) => {
               state.advancedOptions && (
               state.advancedOptions && (
                 <>
                 <>
                   <TextArea
                   <TextArea
+                    onChange={e => setState({ ...state, data: { ...state.data, config: e.target.value } })}
                     defaultValue={state.data.config}
                     defaultValue={state.data.config}
                     title={state.data.config_path}
                     title={state.data.config_path}
                     name="v_config"
                     name="v_config"
@@ -199,6 +219,7 @@ const EditPhp = ({ serviceName = '' }) => {
                   <Checkbox
                   <Checkbox
                     title={i18n['restart']}
                     title={i18n['restart']}
                     defaultChecked={true}
                     defaultChecked={true}
+                    onChange={checked => setRestart(checked)}
                     name="v_restart"
                     name="v_restart"
                     id="restart" />
                     id="restart" />
                 </>
                 </>

+ 17 - 21
src/react/src/components/Server/Edit/Postgresql/Postgresql.jsx

@@ -19,11 +19,11 @@ const Postgresql = () => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -31,23 +31,23 @@ const Postgresql = () => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData();
+  }, []);
 
 
+  const fetchData = () => {
     getServiceInfo('postgresql')
     getServiceInfo('postgresql')
       .then(response => {
       .then(response => {
         if (!response.data.config) {
         if (!response.data.config) {
           history.push('/list/server');
           history.push('/list/server');
         }
         }
 
 
-        setState({
-          ...state,
-          data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
-          loading: false
-        });
+        setState({ ...state, data: response.data, loading: false });
       })
       })
-      .catch(err => console.error(err));
-  }, []);
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -65,15 +65,11 @@ const Postgresql = () => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
-            if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData())
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -90,12 +86,12 @@ const Postgresql = () => {
         </div>
         </div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 13 - 20
src/react/src/components/Server/Edit/Service/Service.jsx

@@ -19,11 +19,11 @@ const Service = ({ serviceName = '' }) => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -35,7 +35,10 @@ const Service = ({ serviceName = '' }) => {
     }
     }
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
+    fetchData(serviceName);
+  }, []);
 
 
+  const fetchData = serviceName => {
     getServiceInfo(serviceName)
     getServiceInfo(serviceName)
       .then(response => {
       .then(response => {
         const { config } = response.data;
         const { config } = response.data;
@@ -44,16 +47,10 @@ const Service = ({ serviceName = '' }) => {
           history.push('/list/server');
           history.push('/list/server');
         }
         }
 
 
-        setState({
-          ...state,
-          data: response.data,
-          errorMessage: response.data['error_msg'],
-          okMessage: response.data['ok_msg'],
-          loading: false
-        });
+        setState({ ...state, data: response.data, loading: false });
       })
       })
       .catch(err => console.error(err));
       .catch(err => console.error(err));
-  }, []);
+  }
 
 
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
@@ -71,15 +68,11 @@ const Service = ({ serviceName = '' }) => {
           if (result.status === 200) {
           if (result.status === 200) {
             const { error_msg, ok_msg } = result.data;
             const { error_msg, ok_msg } = result.data;
 
 
-            if (error_msg) {
-              setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
-            } else if (ok_msg) {
-              setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
-            } else {
-              setState({ ...state, loading: false });
-            }
+            setErrorMessage(error_msg || '');
+            setOkMessage(ok_msg || '');
           }
           }
         })
         })
+        .then(() => fetchData(serviceName))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -96,12 +89,12 @@ const Service = ({ serviceName = '' }) => {
         </div>
         </div>
         <div className="error">
         <div className="error">
           <span className="error-message">
           <span className="error-message">
-            {state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}
+            {errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}
           </span>
           </span>
         </div>
         </div>
         <div className="success">
         <div className="success">
           <span className="ok-message">
           <span className="ok-message">
-            {state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
+            {okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span>
           </span>
           </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>

+ 2 - 2
src/react/src/components/Server/ServerSys.jsx

@@ -46,7 +46,7 @@ const Server = props => {
         </div>
         </div>
 
 
         <div>
         <div>
-          <a className="link-download restart" href={`/restart/service?srv=${data.NAME}`} >
+          <button className="link-download restart" onClick={() => props.handleAction(`/api/v1/restart/service?srv=${data.NAME}`)}>
             {i18n.restart}
             {i18n.restart}
             {
             {
               data.FOCUSED
               data.FOCUSED
@@ -56,7 +56,7 @@ const Server = props => {
                   <path fill-rule="evenodd" d="M8 3a4.995 4.995 0 0 0-4.192 2.273.5.5 0 0 1-.837-.546A6 6 0 0 1 14 8a.5.5 0 0 1-1.001 0 5 5 0 0 0-5-5zM2.5 7.5A.5.5 0 0 1 3 8a5 5 0 0 0 9.192 2.727.5.5 0 1 1 .837.546A6 6 0 0 1 2 8a.5.5 0 0 1 .501-.5z" />
                   <path fill-rule="evenodd" d="M8 3a4.995 4.995 0 0 0-4.192 2.273.5.5 0 0 1-.837-.546A6 6 0 0 1 14 8a.5.5 0 0 1-1.001 0 5 5 0 0 0-5-5zM2.5 7.5A.5.5 0 0 1 3 8a5 5 0 0 0 9.192 2.727.5.5 0 1 1 .837.546A6 6 0 0 1 2 8a.5.5 0 0 1 .501-.5z" />
                 </svg>
                 </svg>
             }
             }
-          </a>
+          </button>
         </div>
         </div>
       </div>
       </div>
     </ListItem>
     </ListItem>

+ 2 - 1
src/react/src/components/User/Add/AddUser.jsx

@@ -18,6 +18,7 @@ import HtmlParser from 'react-html-parser';
 
 
 const AddUser = props => {
 const AddUser = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
+  const { session } = useSelector(state => state.userSession);
   const userLanguage = localStorage.getItem("language");
   const userLanguage = localStorage.getItem("language");
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
@@ -101,7 +102,7 @@ const AddUser = props => {
 
 
   const renderLanguageOptions = () => {
   const renderLanguageOptions = () => {
     return state.languages.map((language, index) => (
     return state.languages.map((language, index) => (
-      <option key={index} selected={userLanguage === language} value={language}>{language}</option>
+      <option key={index} selected={session.LANGUAGE === language} value={language}>{language}</option>
     ));
     ));
   }
   }
 
 

+ 29 - 24
src/react/src/components/User/Edit/EditUser.jsx

@@ -11,24 +11,22 @@ import Spinner from '../../../components/Spinner/Spinner';
 import Toolbar from '../../MainNav/Toolbar/Toolbar';
 import Toolbar from '../../MainNav/Toolbar/Toolbar';
 import { useHistory } from 'react-router-dom';
 import { useHistory } from 'react-router-dom';
 import { useDispatch, useSelector } from 'react-redux';
 import { useDispatch, useSelector } from 'react-redux';
-import QS from 'qs';
-
-import './EditUser.scss';
 import { Helmet } from 'react-helmet';
 import { Helmet } from 'react-helmet';
-import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import HtmlParser from 'react-html-parser';
 import HtmlParser from 'react-html-parser';
+import QS from 'qs';
+import './EditUser.scss';
 
 
 const EditUser = props => {
 const EditUser = props => {
   const token = localStorage.getItem("token");
   const token = localStorage.getItem("token");
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     loading: false,
     loading: false,
-    username: '',
-    errorMessage: '',
-    okMessage: ''
+    username: ''
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -40,20 +38,26 @@ const EditUser = props => {
 
 
     if (user) {
     if (user) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getUserInfo(user)
-        .then(response => {
-          setState({
-            ...state,
-            username: user,
-            data: response.data, errorMessage: response.data['error_msg'], okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(user);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = user => {
+    getUserInfo(user)
+      .then(response => {
+        setState({
+          ...state,
+          username: user,
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedUser = {};
     let updatedUser = {};
@@ -73,14 +77,15 @@ const EditUser = props => {
             const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
             const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
 
 
             if (errorMessage) {
             if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+              setErrorMessage(errorMessage);
+              setOkMessage('');
             } else {
             } else {
-              dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
-              });
+              setErrorMessage('');
+              setOkMessage(okMessage);
             }
             }
           }
           }
         })
         })
+        .then(() => fetchData(state.username))
         .catch(err => console.error(err));
         .catch(err => console.error(err));
     }
     }
   }
   }
@@ -103,9 +108,9 @@ const EditUser = props => {
       <Toolbar mobile={false}>
       <Toolbar mobile={false}>
         <div></div>
         <div></div>
         <div className="search-toolbar-name">{i18n['Editing User']}</div>
         <div className="search-toolbar-name">{i18n['Editing User']}</div>
-        <div className="error"><span className="error-message">{state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}</span></div>
+        <div className="error"><span className="error-message">{errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}</span></div>
         <div className="success">
         <div className="success">
-          <span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span> </span>
+          <span className="ok-message">{okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span> </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
       <AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>
       <AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>

+ 1 - 2
src/react/src/components/User/User.jsx

@@ -10,7 +10,6 @@ import './User.scss';
 
 
 const User = ({ data, toggleFav, handleModal, checkItem }) => {
 const User = ({ data, toggleFav, handleModal, checkItem }) => {
   const { i18n, userName } = useSelector(state => state.session);
   const { i18n, userName } = useSelector(state => state.session);
-  const session = useSelector(state => state.session);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
 
 
   const printNameServers = servers => {
   const printNameServers = servers => {
@@ -30,7 +29,7 @@ const User = ({ data, toggleFav, handleModal, checkItem }) => {
   }
   }
 
 
   const printLoginActionButton = user => {
   const printLoginActionButton = user => {
-    let currentUser = session.userName;
+    let currentUser = userName;
     if (currentUser === user) {
     if (currentUser === user) {
       return (
       return (
         <div>
         <div>

+ 80 - 25
src/react/src/components/WebDomain/Add/AddWebDomain.jsx

@@ -2,10 +2,12 @@ import React, { useEffect, useState } from 'react';
 
 
 import { addActiveElement, removeFocusedElement } from "../../../actions/MainNavigation/mainNavigationActions";
 import { addActiveElement, removeFocusedElement } from "../../../actions/MainNavigation/mainNavigationActions";
 import AddItemLayout from '../../ControlPanel/AddItemLayout/AddItemLayout';
 import AddItemLayout from '../../ControlPanel/AddItemLayout/AddItemLayout';
-import { addWeb, getWebStats } from '../../../ControlPanelService/Web';
+import { addWeb, getWebDomainInfo } from '../../../ControlPanelService/Web';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import AdvancedOptions from './AdvancedOptions/AdvancedOptions';
 import AdvancedOptions from './AdvancedOptions/AdvancedOptions';
-import { getIpList } from '../../../ControlPanelService/Ip';
+import Checkbox from 'src/components/ControlPanel/AddItemLayout/Form/Checkbox/Checkbox';
+import SelectInput from 'src/components/ControlPanel/AddItemLayout/Form/SelectInput/SelectInput';
+import TextArea from 'src/components/ControlPanel/AddItemLayout/Form/TextArea/TextArea';
 import Toolbar from '../../MainNav/Toolbar/Toolbar';
 import Toolbar from '../../MainNav/Toolbar/Toolbar';
 import { useHistory } from 'react-router-dom';
 import { useHistory } from 'react-router-dom';
 import Spinner from '../../Spinner/Spinner';
 import Spinner from '../../Spinner/Spinner';
@@ -17,7 +19,8 @@ import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import HtmlParser from 'react-html-parser';
 import HtmlParser from 'react-html-parser';
 
 
 const AddWebDomain = props => {
 const AddWebDomain = props => {
-  const { i18n } = useSelector(state => state.session);
+  const { i18n, panel, userName } = useSelector(state => state.session);
+  const { session } = useSelector(state => state.userSession);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
   const token = localStorage.getItem("token");
   const token = localStorage.getItem("token");
   const history = useHistory();
   const history = useHistory();
@@ -25,12 +28,15 @@ const AddWebDomain = props => {
     loading: false,
     loading: false,
     dnsSupport: true,
     dnsSupport: true,
     mailSupport: true,
     mailSupport: true,
+    proxySupport: true,
     showAdvancedOptions: false,
     showAdvancedOptions: false,
     okMessage: '',
     okMessage: '',
     domain: '',
     domain: '',
     errorMessage: '',
     errorMessage: '',
     webStats: [],
     webStats: [],
     prefixI18N: '',
     prefixI18N: '',
+    prePath: '',
+    proxy_ext: '',
     internetProtocols: []
     internetProtocols: []
   });
   });
 
 
@@ -39,19 +45,22 @@ const AddWebDomain = props => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
 
 
     setState({ ...state, loading: true });
     setState({ ...state, loading: true });
-    Promise.all([getWebStats(), getIpList()])
-      .then(result => {
-        const [webStats, internetProtocols] = result;
-        let internetProtocolNames = getInternetProtocolNames(internetProtocols.data.data);
-
+    getWebDomainInfo()
+      .then(res => {
         setState({
         setState({
           ...state,
           ...state,
-          webStats: webStats.data.data,
-          internetProtocols: internetProtocolNames,
-          prefixI18N: webStats.data.prefixI18N,
+          internetProtocols: getInternetProtocolNames(res.data.ips),
+          webStats: res.data.stats,
+          prefixI18N: res.data.prefix,
+          proxy_ext: res.data.proxy_ext,
+          prePath: res.data.ftp_pre_path,
           loading: false
           loading: false
         });
         });
-      });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      })
   }, []);
   }, []);
 
 
   const getInternetProtocolNames = internetProtocols => {
   const getInternetProtocolNames = internetProtocols => {
@@ -74,7 +83,7 @@ const AddWebDomain = props => {
 
 
   const renderAdvancedOptions = () => {
   const renderAdvancedOptions = () => {
     if (state.showAdvancedOptions) {
     if (state.showAdvancedOptions) {
-      return <AdvancedOptions prefixI18N={state.prefixI18N} domain={state.domain} webStats={state.webStats} />;
+      return <AdvancedOptions prefixI18N={state.prefixI18N} domain={state.domain} webStats={state.webStats} prePath={state.prePath} />;
     }
     }
   }
   }
 
 
@@ -82,6 +91,10 @@ const AddWebDomain = props => {
     setState({ ...state, domain: value });
     setState({ ...state, domain: value });
   }
   }
 
 
+  const checkboxHandler = (input, checked) => {
+    setState({ ...state, [input]: checked });
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let newWebDomain = {};
     let newWebDomain = {};
@@ -154,19 +167,61 @@ const AddWebDomain = props => {
               </select>
               </select>
             </div>
             </div>
 
 
-            <div className="form-group">
-              <div className="checkbox-wrapper">
-                <input type="checkbox" name="v_dns" id="dns-support" checked={state.dnsSupport} />
-                <label htmlFor="dns-support">{i18n['DNS Support']}</label>
-              </div>
+            <div class="form-group">
+              <label htmlFor="aliases">{i18n.Aliases}</label>
+              <textarea
+                class="form-control"
+                id="aliases"
+                rows="3"
+                name="v_aliases"
+                defaultValue={state.aliases}
+              ></textarea>
             </div>
             </div>
 
 
-            <div className="form-group">
-              <div className="checkbox-wrapper">
-                <input type="checkbox" name="v_mail" id="mail-support" checked={state.mailSupport} />
-                <label htmlFor="mail-support">{i18n['Mail Support']}</label>
-              </div>
-            </div>
+            {
+              panel[userName]['DNS_DOMAINS'] !== '0' && (
+                <Checkbox
+                  onChange={checked => checkboxHandler('dnsSupport', checked)}
+                  name="v_dns"
+                  id="dns-support"
+                  title={i18n['DNS Support'] ?? 'DNS Support'}
+                  defaultChecked={state.dnsSupport} />
+              )
+            }
+
+            {
+              panel[userName]['MAIL_DOMAINS'] !== '0' && (
+                <Checkbox
+                  onChange={checked => checkboxHandler('mailSupport', checked)}
+                  name="v_mail"
+                  id="mail-support"
+                  title={i18n['Mail Support'] ?? 'Mail Support'}
+                  defaultChecked={state.mailSupport} />
+              )
+            }
+
+            {
+              session.PROXY_SYSTEM && (
+                <>
+                  <Checkbox
+                    onChange={checked => checkboxHandler('proxySupport', checked)}
+                    name="v_proxy"
+                    id="proxy"
+                    title={i18n['Proxy Support'] ?? 'Proxy Support'}
+                    defaultChecked={state.proxySupport} />
+
+                  {
+                    state.proxySupport && (<div style={{ transform: 'translateX(3rem)' }}>
+                      <TextArea
+                        id="proxy-extensions"
+                        name="v_proxy_ext"
+                        title={i18n['Proxy Extensions']}
+                        defaultValue={state.proxy_ext} />
+                    </div>)
+                  }
+                </>
+              )
+            }
 
 
             <div className="form-group advanced-options-button">
             <div className="form-group advanced-options-button">
               <button type="button" onClick={() => showAdvancedOption()}>
               <button type="button" onClick={() => showAdvancedOption()}>
@@ -184,7 +239,7 @@ const AddWebDomain = props => {
           </form>
           </form>
         )}
         )}
       </AddItemLayout>
       </AddItemLayout>
-    </div>
+    </div >
   );
   );
 }
 }
 
 

+ 17 - 39
src/react/src/components/WebDomain/Add/AdvancedOptions/AdvancedOptions.jsx

@@ -2,18 +2,18 @@ import React, { useEffect, useState } from 'react';
 import { useSelector } from 'react-redux';
 import { useSelector } from 'react-redux';
 import Password from '../../../../components/ControlPanel/AddItemLayout/Form/Password/Password';
 import Password from '../../../../components/ControlPanel/AddItemLayout/Form/Password/Password';
 import AdditionalFtpWrapper from '../AdditionalFtpWrapper/AdditionalFtpWrapper';
 import AdditionalFtpWrapper from '../AdditionalFtpWrapper/AdditionalFtpWrapper';
+import Checkbox from 'src/components/ControlPanel/AddItemLayout/Form/Checkbox/Checkbox';
 import SslSupport from '../SslSupport/SslSupport';
 import SslSupport from '../SslSupport/SslSupport';
 
 
 import './AdvancedOptions.scss';
 import './AdvancedOptions.scss';
 
 
-const AdvancedOptions = props => {
+const AdvancedOptions = ({ prefixI18N, prePath, ...props }) => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const [state, setState] = useState({
   const [state, setState] = useState({
     sslSupport: false,
     sslSupport: false,
     additionalFtp: false,
     additionalFtp: false,
     statisticsAuthCheckbox: false,
     statisticsAuthCheckbox: false,
     statisticsAuth: false,
     statisticsAuth: false,
-    aliases: ''
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -27,12 +27,6 @@ const AdvancedOptions = props => {
     }
     }
   }
   }
 
 
-  const renderAdditionalFtp = () => {
-    if (state.additionalFtp) {
-      return <AdditionalFtpWrapper prefixI18N={props.prefixI18N} domain={props.domain} unCheckAdditionalFtpBox={() => setState({ ...state, additionalFtp: false })} />;
-    }
-  }
-
   const renderWebStats = () => {
   const renderWebStats = () => {
     return props.webStats.map(stat => <option value={stat}>{stat}</option>);
     return props.webStats.map(stat => <option value={stat}>{stat}</option>);
   }
   }
@@ -45,24 +39,8 @@ const AdvancedOptions = props => {
     }
     }
   }
   }
 
 
-  const onChangeAliases = value => {
-    setState({ ...state, aliases: value });
-  }
-
   return (
   return (
-    <div>
-      <div class="form-group">
-        <label htmlFor="aliases">{i18n.Aliases}</label>
-        <textarea
-          class="form-control"
-          id="aliases"
-          rows="3"
-          name="v_aliases"
-          onChange={event => onChangeAliases(event.target.value)}
-          value={state.aliases}
-        ></textarea>
-      </div>
-
+    <div style={{ transform: 'translateX(3rem)' }}>
       <div className="form-group">
       <div className="form-group">
         <div className="checkbox-wrapper">
         <div className="checkbox-wrapper">
           <input
           <input
@@ -105,21 +83,21 @@ const AdvancedOptions = props => {
         <Password name='v_stats_password' />
         <Password name='v_stats_password' />
       </div>
       </div>
 
 
-      <div className="form-group">
-        <div className="checkbox-wrapper">
-          <input
-            type="checkbox"
-            name="v_ftp"
-            id="additional-ftp"
-            checked={state.additionalFtp}
-            onChange={() => setState({ ...state, additionalFtp: !state.additionalFtp })} />
-          <label htmlFor="additional-ftp">{i18n['Additional FTP Account']}</label>
-        </div>
-      </div>
-
-      {renderAdditionalFtp()}
+      <Checkbox
+        onChange={checked => setState({ ...state, additionalFtp: checked })}
+        name="v_ftp"
+        id="add-ftp"
+        checked={state.additionalFtp}
+        title={i18n['Additional FTP Account']} />
+
+      <AdditionalFtpWrapper
+        checked={state.additionalFtp}
+        prefixI18N={prefixI18N}
+        ftps={[{ id: 1, deleted: false, is_new: 1 }]}
+        ftpUserPrePath={prePath}
+        unCheckAdditionalFtpBox={() => setState({ ...state, additionalFtp: false })} />
     </div>
     </div>
   );
   );
 }
 }
 
 
-export default AdvancedOptions;
+export default AdvancedOptions;

+ 71 - 46
src/react/src/components/WebDomain/Edit/EditWeb.jsx

@@ -26,6 +26,8 @@ const EditWeb = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
   const [state, setState] = useState({
   const [state, setState] = useState({
     data: {},
     data: {},
     domain: '',
     domain: '',
@@ -33,10 +35,9 @@ const EditWeb = props => {
     sslSupport: false,
     sslSupport: false,
     letsEncrypt: false,
     letsEncrypt: false,
     additionalFtp: false,
     additionalFtp: false,
+    proxySupport: false,
     statAuth: false,
     statAuth: false,
-    loading: false,
-    errorMessage: '',
-    okMessage: ''
+    loading: false
   });
   });
 
 
   useEffect(() => {
   useEffect(() => {
@@ -48,27 +49,29 @@ const EditWeb = props => {
 
 
     if (domain) {
     if (domain) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
-
-      getDomainInfo(domain)
-        .then(response => {
-          setState({
-            ...state,
-            domain,
-            webStat: response.data.v_stats ? response.data.v_stats : 'none',
-            sslSupport: response.data.ssl === 'yes',
-            letsEncrypt: response.data.letsencrypt === 'yes',
-            data: response.data,
-            additionalFtp: !!response.data.ftp_user,
-            statAuth: response.data.stats_user,
-            errorMessage: response.data['error_msg'],
-            okMessage: response.data['ok_msg'],
-            loading: false
-          });
-        })
-        .catch(err => console.error(err));
+      fetchData(domain);
     }
     }
   }, []);
   }, []);
 
 
+  const fetchData = domain => {
+    getDomainInfo(domain)
+      .then(response => {
+        setState({
+          ...state,
+          domain,
+          webStat: response.data.v_stats ? response.data.v_stats : 'none',
+          sslSupport: response.data.ssl === 'yes',
+          letsEncrypt: response.data.letsencrypt === 'yes',
+          proxySupport: !!response.data.proxy,
+          data: response.data,
+          additionalFtp: !!response.data.ftp_user,
+          statAuth: response.data.stats_user,
+          loading: false
+        });
+      })
+      .catch(err => console.error(err));
+  }
+
   const submitFormHandler = event => {
   const submitFormHandler = event => {
     event.preventDefault();
     event.preventDefault();
     let updatedDomain = {};
     let updatedDomain = {};
@@ -79,19 +82,27 @@ const EditWeb = props => {
 
 
     updatedDomain['v_domain'] = state.domain;
     updatedDomain['v_domain'] = state.domain;
 
 
+    if (updatedDomain['v_ssl'] === 'on') {
+      updatedDomain['v_ssl'] = 'yes';
+    }
+
     if (Object.keys(updatedDomain).length !== 0 && updatedDomain.constructor === Object) {
     if (Object.keys(updatedDomain).length !== 0 && updatedDomain.constructor === Object) {
       setState({ ...state, loading: true });
       setState({ ...state, loading: true });
 
 
       updateWebDomain(updatedDomain, state.domain)
       updateWebDomain(updatedDomain, state.domain)
         .then(result => {
         .then(result => {
           if (result.status === 200) {
           if (result.status === 200) {
-            const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
+            const { error_msg, ok_msg } = result.data;
 
 
-            if (errorMessage) {
-              setState({ ...state, errorMessage, okMessage, loading: false });
+            if (error_msg) {
+              setErrorMessage(error_msg);
+              setOkMessage('');
+              setState({ ...state, loading: false });
             } else {
             } else {
               dispatch(refreshCounters()).then(() => {
               dispatch(refreshCounters()).then(() => {
-                setState({ ...state, okMessage, errorMessage: '', loading: false });
+                setErrorMessage('');
+                setOkMessage(ok_msg);
+                fetchData(state.domain);
               });
               });
             }
             }
           }
           }
@@ -114,6 +125,10 @@ const EditWeb = props => {
     setState({ ...state, sslSupport: checked });
     setState({ ...state, sslSupport: checked });
   }
   }
 
 
+  const onChangeProxySupport = checked => {
+    setState({ ...state, proxySupport: checked });
+  }
+
   const onChangeWebStats = webStat => {
   const onChangeWebStats = webStat => {
     setState({ ...state, webStat });
     setState({ ...state, webStat });
   }
   }
@@ -134,9 +149,9 @@ const EditWeb = props => {
       <Toolbar mobile={false}>
       <Toolbar mobile={false}>
         <div></div>
         <div></div>
         <div className="search-toolbar-name">{i18n['Editing Domain']}</div>
         <div className="search-toolbar-name">{i18n['Editing Domain']}</div>
-        <div className="error"><span className="error-message">{state.data.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}</span></div>
+        <div className="error"><span className="error-message">{errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}</span></div>
         <div className="success">
         <div className="success">
-          <span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span> </span>
+          <span className="ok-message">{okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span> </span>
         </div>
         </div>
       </Toolbar>
       </Toolbar>
       <AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>
       <AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>
@@ -169,8 +184,7 @@ const EditWeb = props => {
               title={i18n['Web Template']} />
               title={i18n['Web Template']} />
 
 
             {
             {
-              state.data.web_backend
-              && (
+              state.data.WEB_BACKEND && (
                 <SelectInput
                 <SelectInput
                   options={state.data.backend_templates}
                   options={state.data.backend_templates}
                   selected={state.data.backend_template || 'default'}
                   selected={state.data.backend_template || 'default'}
@@ -182,24 +196,36 @@ const EditWeb = props => {
             }
             }
 
 
             {
             {
-              state.data.proxy_system
-              && (
-                <SelectInput
-                  options={state.data.proxy_templates}
-                  selected={state.data.proxy_template || 'default'}
-                  optionalTitle={state.data.proxy_system}
-                  name="v_proxy_template"
-                  id="proxy_template"
-                  title={i18n['Proxy Template']} />
+              state.data.proxy_system && (
+                <>
+                  <Checkbox
+                    onChange={onChangeProxySupport}
+                    name="v_proxy"
+                    id="proxy"
+                    title={i18n['Proxy Support'] ?? 'Proxy Support'}
+                    defaultChecked={state.proxySupport} />
+
+                  {
+                    state.proxySupport && (<div style={{ transform: 'translateX(3rem)' }}>
+                      <SelectInput
+                        options={state.data.proxy_templates}
+                        selected={state.data.proxy_template || 'default'}
+                        optionalTitle={state.data.proxy_system}
+                        name="v_proxy_template"
+                        id="proxy_template"
+                        title={i18n['Proxy Template']} />
+
+                      <TextArea
+                        id="proxy-extensions"
+                        name="v_proxy_ext"
+                        title={i18n['Proxy Extensions']}
+                        defaultValue={state.data.proxy_ext} />
+                    </div>)
+                  }
+                </>
               )
               )
             }
             }
 
 
-            <TextArea
-              id="proxy-extensions"
-              name="v_proxy_ext"
-              title={i18n['Proxy Extensions']}
-              defaultValue={state.data.proxy_ext} />
-
             <Checkbox
             <Checkbox
               onChange={onChangeSslSupport}
               onChange={onChangeSslSupport}
               name="v_ssl"
               name="v_ssl"
@@ -208,8 +234,7 @@ const EditWeb = props => {
               defaultChecked={state.sslSupport} />
               defaultChecked={state.sslSupport} />
 
 
             {
             {
-              state.sslSupport
-              && (
+              state.sslSupport && (
                 <SslSupport
                 <SslSupport
                   sslSubject={state.data.ssl_subject}
                   sslSubject={state.data.ssl_subject}
                   sslAliases={state.data.ssl_aliases}
                   sslAliases={state.data.ssl_aliases}

+ 1 - 0
src/react/src/components/WebDomain/Edit/SslSupport/SslSupport.scss

@@ -16,6 +16,7 @@ $textColor: #555;
       span {
       span {
         &:nth-child(1) {
         &:nth-child(1) {
           width: 120px;
           width: 120px;
+          display: inline-block;
         }
         }
 
 
         &:nth-child(2) {
         &:nth-child(2) {

+ 29 - 18
src/react/src/components/WebDomain/WebDomain.jsx

@@ -9,7 +9,6 @@ import { useSelector } from 'react-redux';
 export default function WebDomain(props) {
 export default function WebDomain(props) {
   const { data } = props;
   const { data } = props;
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
-  const token = localStorage.getItem("token");
 
 
   const printStat = (stat, text) => {
   const printStat = (stat, text) => {
     if (text === 'no' || text === '') {
     if (text === 'no' || text === '') {
@@ -31,6 +30,26 @@ export default function WebDomain(props) {
     props.checkItem(data.NAME);
     props.checkItem(data.NAME);
   }
   }
 
 
+  const renderProxySupport = () => {
+    if (!data.PROXY_SYSTEM) return;
+
+    if (data.PROXY_SUPPORT === 'no') {
+      printStat(i18n['Proxy Support'], '');
+    } else {
+      printStat(i18n['Proxy Support'], data.PROXY_SUPPORT);
+    }
+  }
+
+  const renderBackedSupport = () => {
+    if (!data.WEB_BACKEND) return;
+
+    if (data.BACKEND_SUPPORT === 'no') {
+      printStat(i18n['Backend Support'] ?? 'Backend Support', '');
+    } else {
+      printStat(i18n['Backend Support'] ?? 'Backend Support', data.BACKEND_SUPPORT);
+    }
+  }
+
   const handleSuspend = () => {
   const handleSuspend = () => {
     let suspendedStatus = data.SUSPENDED === 'yes' ? 'unsuspend' : 'suspend';
     let suspendedStatus = data.SUSPENDED === 'yes' ? 'unsuspend' : 'suspend';
     props.handleModal(data.spnd_confirmation, `/api/v1/${suspendedStatus}/web/index.php?domain=${data.NAME}`);
     props.handleModal(data.spnd_confirmation, `/api/v1/${suspendedStatus}/web/index.php?domain=${data.NAME}`);
@@ -58,29 +77,21 @@ export default function WebDomain(props) {
         <div>{data.IP}</div>
         <div>{data.IP}</div>
         <div className="stats">
         <div className="stats">
           <Container className="c-1 w-25">
           <Container className="c-1 w-25">
-            <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_SIZE}</span>{data.U_BANDWIDTH_MEASURE}</span></div>
+            <div className="disk">{i18n.Disk}: <span><span className="stat">{data.U_DISK_SIZE}</span>{data.U_DISK_MEASURE}</span></div>
           </Container>
           </Container>
           <Container className="c-2 w-45">
           <Container className="c-2 w-45">
             <div>{i18n['Web Template']}: <span className="stat">{data.TPL}</span></div>
             <div>{i18n['Web Template']}: <span className="stat">{data.TPL}</span></div>
-            {data.LETSENCRYPT === 'yes'
-              ? printStat(i18n['SSL Support'], i18n['Lets Encrypt'])
-              : printStat(i18n['SSL Support'], data.SSL)}
+            {data.SSL === 'no'
+              ? printStat(i18n['SSL Support'], '')
+              : printStat(i18n['SSL Support'], data.LETSENCRYPT === 'yes' ? i18n['Lets Encrypt'] : i18n[data.SSL])}
             {printStat(i18n['Web Statistics'], data.WEB_STATS)}
             {printStat(i18n['Web Statistics'], data.WEB_STATS)}
           </Container>
           </Container>
           <Container className="c-3 w-35">
           <Container className="c-3 w-35">
-            {data.PROXY_SYSTEM !== 'no'
-              ? printStat(i18n['Proxy Support'], data.PROXY_SUPPORT)
-              : printStat(i18n['Proxy Support'], '')}
-            {data.PROXY_SYSTEM !== 'no'
-              ? printStat(i18n['Proxy Template'], data.PROXY)
-              : printStat(i18n['Proxy Template'], '')}
-            {data.BACKEND_SYSTEM !== 'no'
-              ? printStat(i18n['Backend Support'] ?? 'Backend Support', data.BACKEND_SUPPORT)
-              : printStat(i18n['Backend Support'] ?? 'Backend Support', '')}
-            {data.BACKEND_SYSTEM !== 'no'
-              ? printStat(i18n['Backend Template'] ?? 'Backend Template', data.BACKEND)
-              : printStat(i18n['Backend Template'] ?? 'Backend Template', '')}
+            {renderProxySupport()}
+            {data.PROXY_SYSTEM && printStat(i18n['Proxy Template'] ?? 'Proxy Template', data.PROXY)}
+            {renderBackedSupport()}
+            {data.WEB_BACKEND && printStat(i18n['Backend Template'] ?? 'Backend Template', data.BACKEND)}
             {printStat(i18n['Additional FTP Account'], data.FTP)}
             {printStat(i18n['Additional FTP Account'], data.FTP)}
           </Container>
           </Container>
         </div>
         </div>

+ 4 - 14
src/react/src/containers/ControlPanelContent/ControlPanelContent.jsx

@@ -52,13 +52,14 @@ import Users from '../../containers/Users/Users';
 import RRDs from '../../containers/RRDs/RRDs';
 import RRDs from '../../containers/RRDs/RRDs';
 import BanList from '../Firewalls/Banlist';
 import BanList from '../Firewalls/Banlist';
 import Web from '../../containers/Web/Web';
 import Web from '../../containers/Web/Web';
+import GenerateCSR from '../GenerateCSR';
 import Search from '../Search/Search';
 import Search from '../Search/Search';
 import Logs from '../Logs/Logs';
 import Logs from '../Logs/Logs';
 
 
 import './ControlPanelContent.scss';
 import './ControlPanelContent.scss';
 
 
 const ControlPanelContent = props => {
 const ControlPanelContent = props => {
-  const { userName, session: { look } } = useSelector(state => state.session);
+  const { userName } = useSelector(state => state.session);
   const history = useHistory();
   const history = useHistory();
   const [searchTerm, setSearchTerm] = useState('');
   const [searchTerm, setSearchTerm] = useState('');
   const [hotkeysList, setHotkeysList] = useState(null);
   const [hotkeysList, setHotkeysList] = useState(null);
@@ -71,18 +72,7 @@ const ControlPanelContent = props => {
     } else {
     } else {
       setLoading(false);
       setLoading(false);
     }
     }
-
-    if (look) {
-      const commonUserRoutes = ['package', 'ip', 'rrd', 'updates', 'firewall', 'server'];
-      const splitPath = history.location.pathname.split('/')[2];
-
-      if (history.location.pathname === '/add/user/') return history.push('/');
-
-      if (commonUserRoutes.includes(splitPath)) {
-        return history.push('/');
-      }
-    }
-  }, [userName, look]);
+  }, [userName]);
 
 
   useEffect(() => {
   useEffect(() => {
     dispatch(removeFocusedElement());
     dispatch(removeFocusedElement());
@@ -123,7 +113,6 @@ const ControlPanelContent = props => {
 
 
     if (event.keyCode === 65) {
     if (event.keyCode === 65) {
       switch (history.location.pathname) {
       switch (history.location.pathname) {
-        case '/list/user/': return look ? history.push('/add/web/') : history.push('/add/user/');
         case '/list/web/': return history.push('/add/web/');
         case '/list/web/': return history.push('/add/web/');
         case '/list/dns/': return history.push('/add/dns/');
         case '/list/dns/': return history.push('/add/dns/');
         case '/list/mail/': return history.push('/add/mail/');
         case '/list/mail/': return history.push('/add/mail/');
@@ -201,6 +190,7 @@ const ControlPanelContent = props => {
 
 
                 <Route path="/list/user" component={props => <Users changeSearchTerm={handleSearchTerm} {...props} />} />
                 <Route path="/list/user" component={props => <Users changeSearchTerm={handleSearchTerm} {...props} />} />
                 <Route path="/add/user" component={() => <AddUser />} />
                 <Route path="/add/user" component={() => <AddUser />} />
+                <Route path="/generate/ssl" component={GenerateCSR} />
                 <Route path="/edit/user" component={() => <EditUser />} />
                 <Route path="/edit/user" component={() => <EditUser />} />
                 <Route path="/list/web" component={props => <Web {...props} changeSearchTerm={handleSearchTerm} />} />
                 <Route path="/list/web" component={props => <Web {...props} changeSearchTerm={handleSearchTerm} />} />
                 <Route path="/add/web" component={() => <AddWebDomain />} />
                 <Route path="/add/web" component={() => <AddWebDomain />} />

+ 2 - 2
src/react/src/containers/FileManager/FileManager.js

@@ -182,7 +182,7 @@ class FileManager extends Component {
     const { cursor, currentPath, itemName } = this.state;
     const { cursor, currentPath, itemName } = this.state;
 
 
     if (cursor !== 0) {
     if (cursor !== 0) {
-      window.open('/download/file/?path=' + currentPath + '/' + itemName);
+      window.open('/api/v1/download/file/?path=' + currentPath + '/' + itemName);
     }
     }
   }
   }
 
 
@@ -218,7 +218,7 @@ class FileManager extends Component {
     }
     }
 
 
     this.setState({ loading: true }, () => {
     this.setState({ loading: true }, () => {
-      axios.post(`${window.location.origin}/upload/?dir=${this.state.currentPath}`, formData, {
+      axios.post(`${window.location.origin}/api/v1/upload/?dir=${this.state.currentPath}`, formData, {
         onUploadProgress: progressEvent => {
         onUploadProgress: progressEvent => {
           let uploadPercent = Math.round(progressEvent.loaded / progressEvent.total * 100);
           let uploadPercent = Math.round(progressEvent.loaded / progressEvent.total * 100);
           this.setState({ uploadPercent });
           this.setState({ uploadPercent });

+ 165 - 0
src/react/src/containers/GenerateCSR/index.jsx

@@ -0,0 +1,165 @@
+import React, { useEffect, useState } from 'react';
+import { addActiveElement, removeFocusedElement } from "src/actions/MainNavigation/mainNavigationActions";
+import TextInput from 'src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput';
+import AddItemLayout from 'src/components/ControlPanel/AddItemLayout/AddItemLayout';
+import TextArea from 'src/components/ControlPanel/AddItemLayout/Form/TextArea/TextArea';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import Toolbar from 'src/components/MainNav/Toolbar/Toolbar';
+import { generateCSR, getCsrInitialData } from 'src/ControlPanelService/Web';
+import { useDispatch, useSelector } from 'react-redux';
+import Spinner from 'src/components/Spinner/Spinner';
+import { useHistory } from 'react-router-dom';
+import HtmlParser from 'react-html-parser';
+import { Helmet } from 'react-helmet';
+import QS from 'qs';
+
+const GenerateSSL = props => {
+  const token = localStorage.getItem("token");
+  const { i18n } = useSelector(state => state.session);
+  const history = useHistory();
+  const dispatch = useDispatch();
+  const [errorMessage, setErrorMessage] = useState('');
+  const [okMessage, setOkMessage] = useState('');
+  const [state, setState] = useState({
+    data: {},
+    generatedData: {},
+    loading: false,
+    domain: ''
+  });
+
+  useEffect(() => {
+    let queryParams = QS.parse(history.location.search, { ignoreQueryPrefix: true });
+    const { domain } = queryParams;
+
+    dispatch(addActiveElement('/list/web/'));
+    dispatch(removeFocusedElement());
+
+    if (domain) {
+      fetchData(domain);
+    } else {
+      fetchData();
+    }
+  }, []);
+
+  const fetchData = (domain = '') => {
+    getCsrInitialData(domain)
+      .then(response => {
+        setState({
+          ...state,
+          domain,
+          generatedData: {},
+          data: response.data,
+          loading: false
+        });
+      })
+      .catch(err => {
+        setState({ ...state, loading: false });
+        console.error(err);
+      });
+  }
+
+  const submitFormHandler = event => {
+    event.preventDefault();
+    let newCsr = {};
+
+    for (var [name, value] of (new FormData(event.target)).entries()) {
+      newCsr[name] = value;
+    }
+
+    newCsr['generate'] = 'generate';
+
+    if (Object.keys(newCsr).length !== 0 && newCsr.constructor === Object) {
+      setState({ ...state, loading: true });
+
+      generateCSR(newCsr)
+        .then(result => {
+          if (result.status === 200) {
+            const { error_msg: errorMessage, ok_msg: okMessage, crt, key, csr } = result.data;
+
+            if (errorMessage) {
+              setErrorMessage(errorMessage);
+              setOkMessage('');
+              setState({ ...state, generatedData: {}, loading: false });
+            } else {
+              setErrorMessage('');
+              setOkMessage(okMessage);
+
+              setState({ ...state, generatedData: { crt, key, csr }, loading: false });
+            }
+          }
+        })
+        .catch(err => console.error(err));
+    }
+  }
+
+  return (
+    <div className="edit-template edit-user">
+      <Helmet>
+        <title>{`Vesta - ${i18n.WEB}`}</title>
+      </Helmet>
+      <Toolbar mobile={false}>
+        <div></div>
+        <div className="search-toolbar-name">{i18n['Generating CSR']}</div>
+        <div className="error"><span className="error-message">{errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {errorMessage}</span></div>
+        <div className="success">
+          <span className="ok-message">{okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(okMessage)}</span> </span>
+        </div>
+      </Toolbar>
+      <AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>
+        {state.loading ? <Spinner /> :
+          <form onSubmit={event => submitFormHandler(event)} id="add-user">
+            <input type="hidden" name="token" value={token} />
+
+            {
+              Object.entries(state.generatedData).length
+                ? (<>
+                  <TextArea
+                    id="csr"
+                    name="v_csr"
+                    title={i18n['SSL CSR']}
+                    defaultValue={state.generatedData.csr} />
+
+                  <TextArea
+                    id="crt"
+                    name="v_crt"
+                    title={i18n['SSL Certificate']}
+                    defaultValue={state.generatedData.crt} />
+
+                  <TextArea
+                    id="v_key"
+                    name="key"
+                    title={i18n['SSL Key']}
+                    defaultValue={state.generatedData.key} />
+
+                  <div className="buttons-wrapper">
+                    <button type="button" className="back" onClick={() => history.push(`/edit/web/?domain=${state.domain}`)}>{i18n.Back}</button>
+                  </div>
+                </>)
+                : (<>
+                  <TextInput id="domain" name="v_domain" title={i18n['Domain']} value={state.data.domain} />
+
+                  <TextInput id="email" name="v_email" title={i18n['Email']} value={state.data.email} />
+
+                  <TextInput id="country" name="v_country" title={i18n['Country']} optionalTitle={`(${i18n['2 letter code']})`} value={state.data.country} />
+
+                  <TextInput id="state" name="v_state" title={i18n['State / Province']} value={state.data.state} />
+
+                  <TextInput id="locality" name="v_locality" title={i18n['City / Locality']} value={state.data.locality} />
+
+                  <TextInput id="org" name="v_org" title={i18n['Organization']} value={state.data.org} />
+
+                  <div className="buttons-wrapper">
+                    <button type="submit" className="add">{i18n.Save}</button>
+                    <button type="button" className="back" onClick={() => history.push(`/edit/web/?domain=${state.domain}`)}>{i18n.Back}</button>
+                  </div>
+                </>)
+            }
+
+          </form>
+        }
+      </AddItemLayout>
+    </div >
+  );
+}
+
+export default GenerateSSL;

+ 10 - 3
src/react/src/containers/Mails/Mails.jsx

@@ -18,6 +18,7 @@ import './Mails.scss';
 import { useSelector, useDispatch } from 'react-redux';
 import { useSelector, useDispatch } from 'react-redux';
 import { Helmet } from 'react-helmet';
 import { Helmet } from 'react-helmet';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
+import { Link } from 'react-router-dom';
 
 
 const Mails = props => {
 const Mails = props => {
   const { i18n } = useSelector(state => state.session);
   const { i18n } = useSelector(state => state.session);
@@ -34,7 +35,7 @@ const Mails = props => {
     mails: [],
     mails: [],
     mailFav: [],
     mailFav: [],
     toggledAll: false,
     toggledAll: false,
-    webMail: '',
+    webmail: '',
     sorting: i18n.Date,
     sorting: i18n.Date,
     order: "descending",
     order: "descending",
     selection: [],
     selection: [],
@@ -182,7 +183,7 @@ const Mails = props => {
           setState({
           setState({
             ...state,
             ...state,
             mails: reformatData(result.data.data),
             mails: reformatData(result.data.data),
-            webMail: result.data.webMail,
+            webmail: result.data.webmail,
             mailFav: result.data.mailFav,
             mailFav: result.data.mailFav,
             selection: [],
             selection: [],
             toggledAll: false,
             toggledAll: false,
@@ -394,7 +395,13 @@ const Mails = props => {
         <LeftButton name="Add Mail Domain" href="/add/mail" showLeftMenu={true} />
         <LeftButton name="Add Mail Domain" href="/add/mail" showLeftMenu={true} />
         <div className="r-menu">
         <div className="r-menu">
           <div className="input-group input-group-sm">
           <div className="input-group input-group-sm">
-            <a href={state.webMail} className="button-extra" type="submit">{i18n['open webMail']}</a>
+            <Link
+              to={{ pathname: `${window.location.protocol}//${window.location.hostname}${state.webmail}` }}
+              target="_blank"
+              className="button-extra"
+              type="submit">
+              {i18n['open webmail']}
+            </Link>
             <Checkbox toggleAll={toggleAll} toggled={state.toggledAll} />
             <Checkbox toggleAll={toggleAll} toggled={state.toggledAll} />
             <Select list='mailList' bulkAction={bulk} />
             <Select list='mailList' bulkAction={bulk} />
             <DropdownFilter changeSorting={changeSorting} sorting={state.sorting} order={state.order} list="mailList" />
             <DropdownFilter changeSorting={changeSorting} sorting={state.sorting} order={state.order} list="mailList" />

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

@@ -301,7 +301,8 @@ const Servers = props => {
           setLoading(false);
           setLoading(false);
           return displayModal(res.data.error, '');
           return displayModal(res.data.error, '');
         }
         }
-        fetchData().then(() => refreshMenuCounters())
+
+        fetchData().then(() => refreshMenuCounters());
       })
       })
       .catch(err => { setLoading(false); console.error(err); });
       .catch(err => { setLoading(false); console.error(err); });
   }
   }
@@ -339,7 +340,7 @@ const Servers = props => {
       <Modal
       <Modal
         onSave={modalConfirmHandler}
         onSave={modalConfirmHandler}
         onCancel={modalCancelHandler}
         onCancel={modalCancelHandler}
-        showSaveButton={false}
+        showCancelButton={false}
         show={modal.visible}
         show={modal.visible}
         text={modal.text} />
         text={modal.text} />
     </div>
     </div>

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

@@ -17,12 +17,15 @@ import User from '../../components/User/User';
 import { Helmet } from 'react-helmet';
 import { Helmet } from 'react-helmet';
 import './Users.scss';
 import './Users.scss';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
 import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
+import { useHistory } from 'react-router';
 
 
 const Users = props => {
 const Users = props => {
-  const { userName, i18n, session: { look } } = useSelector(state => state.session);
+  const { userName, i18n } = useSelector(state => state.session);
+  const { session: { look } } = useSelector(state => state.userSession);
   const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent);
   const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent);
   const { focusedElement } = useSelector(state => state.mainNavigation);
   const { focusedElement } = useSelector(state => state.mainNavigation);
   const dispatch = useDispatch();
   const dispatch = useDispatch();
+  const history = useHistory();
   const [loading, setLoading] = useState(false);
   const [loading, setLoading] = useState(false);
   const [modal, setModal] = useState({
   const [modal, setModal] = useState({
     text: '',
     text: '',
@@ -53,13 +56,30 @@ const Users = props => {
   useEffect(() => {
   useEffect(() => {
     window.addEventListener("keydown", handleContentSelection);
     window.addEventListener("keydown", handleContentSelection);
     window.addEventListener("keydown", handleFocusedElementShortcuts);
     window.addEventListener("keydown", handleFocusedElementShortcuts);
+    window.addEventListener("keyup", addNewObject);
 
 
     return () => {
     return () => {
       window.removeEventListener("keydown", handleContentSelection);
       window.removeEventListener("keydown", handleContentSelection);
       window.removeEventListener("keydown", handleFocusedElementShortcuts);
       window.removeEventListener("keydown", handleFocusedElementShortcuts);
+      window.removeEventListener("keyup", addNewObject);
     };
     };
   }, [controlPanelFocusedElement, focusedElement, state.users]);
   }, [controlPanelFocusedElement, focusedElement, state.users]);
 
 
+  const addNewObject = event => {
+    let isSearchInputFocused = document.querySelector('input:focus') || document.querySelector('textarea:focus');
+
+    if (isSearchInputFocused) {
+      return;
+    }
+
+    if (event.keyCode === 65) {
+      switch (history.location.pathname) {
+        case '/list/user/': return look ? history.push('/add/web/') : history.push('/add/user/');
+        default: break;
+      }
+    }
+  }
+
   const fetchData = () => {
   const fetchData = () => {
     setLoading(true);
     setLoading(true);
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {

+ 0 - 5
src/react/src/reducers/Session/sessionReducer.js

@@ -3,7 +3,6 @@ import { LOGGED_OUT_AS, LOGIN, LOGOUT, CHECK_AUTH } from '../../actions/Session/
 const INITIAL_STATE = {
 const INITIAL_STATE = {
   token: '',
   token: '',
   error: '',
   error: '',
-  session: {},
   i18n: {},
   i18n: {},
   userName: '',
   userName: '',
   panel: {}
   panel: {}
@@ -15,7 +14,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => {
       return {
       return {
         ...state,
         ...state,
         token: action.value.token,
         token: action.value.token,
-        session: action.value.session,
         userName: action.value.userName,
         userName: action.value.userName,
         i18n: action.value.i18n || {},
         i18n: action.value.i18n || {},
         panel: action.value.panel,
         panel: action.value.panel,
@@ -26,7 +24,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => {
       return {
       return {
         ...state,
         ...state,
         token: action.value.token,
         token: action.value.token,
-        session: action.value.session,
         userName: action.value.userName,
         userName: action.value.userName,
         i18n: action.value.i18n || {},
         i18n: action.value.i18n || {},
         panel: action.value.panel,
         panel: action.value.panel,
@@ -37,7 +34,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => {
       return {
       return {
         ...state,
         ...state,
         token: action.value.token,
         token: action.value.token,
-        session: action.value.session,
         userName: action.value.userName,
         userName: action.value.userName,
         i18n: action.value.i18n || {},
         i18n: action.value.i18n || {},
         panel: action.value.panel,
         panel: action.value.panel,
@@ -47,7 +43,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => {
     case CHECK_AUTH: return {
     case CHECK_AUTH: return {
       ...state,
       ...state,
       token: action.value.token,
       token: action.value.token,
-      session: action.value.session,
       userName: action.value.userName,
       userName: action.value.userName,
       i18n: action.value.i18n || {},
       i18n: action.value.i18n || {},
       panel: action.value.panel,
       panel: action.value.panel,

+ 19 - 0
src/react/src/reducers/UserSession/userSessionReducer.js

@@ -0,0 +1,19 @@
+import { SET_USER_SESSION } from 'src/actions/UserSession/userSessionTypes';
+
+const INITIAL_STATE = {
+  session: {}
+};
+
+const userSessionReducer = (state = INITIAL_STATE, action) => {
+  switch (action.type) {
+    case SET_USER_SESSION:
+      return {
+        ...state,
+        session: action.value,
+      };
+
+    default: return state;
+  }
+};
+
+export default userSessionReducer;

+ 2 - 0
src/react/src/reducers/rootReducer.js

@@ -3,6 +3,7 @@ import mainNavigationReducer from './MainNavigation/mainNavigationReducer';
 import controlPanelContentReducer from './ControlPanelContent/controlPanelContentReducer';
 import controlPanelContentReducer from './ControlPanelContent/controlPanelContentReducer';
 import notificationReducer from './Notification/notificationReducer';
 import notificationReducer from './Notification/notificationReducer';
 import menuCounterReducer from './MenuCounters/menuCounterReducer';
 import menuCounterReducer from './MenuCounters/menuCounterReducer';
+import userSessionReducer from './UserSession/userSessionReducer';
 import sessionReducer from './Session/sessionReducer';
 import sessionReducer from './Session/sessionReducer';
 
 
 export default combineReducers({
 export default combineReducers({
@@ -10,5 +11,6 @@ export default combineReducers({
   controlPanelContent: controlPanelContentReducer,
   controlPanelContent: controlPanelContentReducer,
   notifications: notificationReducer,
   notifications: notificationReducer,
   menuCounters: menuCounterReducer,
   menuCounters: menuCounterReducer,
+  userSession: userSessionReducer,
   session: sessionReducer,
   session: sessionReducer,
 });
 });