diff --git a/src/react/jsconfig.json b/src/react/jsconfig.json index 30b25afe5..97f4bc227 100644 --- a/src/react/jsconfig.json +++ b/src/react/jsconfig.json @@ -2,5 +2,6 @@ "compilerOptions": { "baseUrl": "." }, - "include": ["src"] + "include": ["src"], + "exclude": ["node_modules", "build"] } diff --git a/src/react/package-lock.json b/src/react/package-lock.json index 2409be918..749fd541c 100644 --- a/src/react/package-lock.json +++ b/src/react/package-lock.json @@ -11526,6 +11526,15 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-perfect-scrollbar": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/react-perfect-scrollbar/-/react-perfect-scrollbar-1.5.8.tgz", + "integrity": "sha512-bQ46m70gp/HJtiBOF3gRzBISSZn8FFGNxznTdmTG8AAwpxG1bJCyn7shrgjEvGSQ5FJEafVEiosY+ccER11OSA==", + "requires": { + "perfect-scrollbar": "^1.5.0", + "prop-types": "^15.6.1" + } + }, "react-redux": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz", diff --git a/src/react/package.json b/src/react/package.json index f371616ad..e992f9e70 100644 --- a/src/react/package.json +++ b/src/react/package.json @@ -25,6 +25,7 @@ "react-dom": "^16.10.2", "react-helmet": "^6.1.0", "react-html-parser": "^2.0.2", + "react-perfect-scrollbar": "^1.5.8", "react-redux": "^7.2.1", "react-router-dom": "^5.1.2", "react-scripts": "^3.4.1", diff --git a/src/react/src/actions/MenuCounters/menuCounterActions.js b/src/react/src/actions/MenuCounters/menuCounterActions.js index 8dc5fcf5b..5d4255dc0 100644 --- a/src/react/src/actions/MenuCounters/menuCounterActions.js +++ b/src/react/src/actions/MenuCounters/menuCounterActions.js @@ -1,12 +1,13 @@ import { REFRESH_COUNTERS } from './menuCounterTypes'; import { checkAuth } from 'src/services/session'; import { setAuthToken } from 'src/utils/token'; +import { REFRESH_PANEL } from '../Panel/panelTypes'; export const refreshCounters = () => (dispatch, getState) => { return new Promise((resolve, reject) => { checkAuth() .then(res => { - const { data, token } = res.data; + const { data, token, panel } = res.data; if (token) setAuthToken(token); @@ -17,6 +18,13 @@ export const refreshCounters = () => (dispatch, getState) => { } }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel + } + }); + resolve(token); }) .catch(err => { diff --git a/src/react/src/actions/Panel/panelTypes.js b/src/react/src/actions/Panel/panelTypes.js new file mode 100644 index 000000000..3c5615340 --- /dev/null +++ b/src/react/src/actions/Panel/panelTypes.js @@ -0,0 +1 @@ +export const REFRESH_PANEL = 'REFRESH_PANEL'; diff --git a/src/react/src/actions/Session/sessionActions.js b/src/react/src/actions/Session/sessionActions.js index c28a30e49..5f1823c57 100644 --- a/src/react/src/actions/Session/sessionActions.js +++ b/src/react/src/actions/Session/sessionActions.js @@ -4,6 +4,7 @@ import { resetPassword } from 'src/ControlPanelService/ResetPassword'; import { resetAuthToken, setAuthToken } from 'src/utils/token'; import { REFRESH_COUNTERS } from '../MenuCounters/menuCounterTypes'; import { SET_USER_SESSION } from '../UserSession/userSessionTypes'; +import { REFRESH_PANEL } from '../Panel/panelTypes'; const LOGOUT_RESPONSE = 'logged_out'; const LOGOUT_AS_RESPONSE = 'logged_out_as'; @@ -19,12 +20,17 @@ export const login = (user, password) => dispatch => { type: LOGIN, value: { token: token || '', - panel, i18n: i18n || {}, userName: user, error }, }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel + } + }); dispatch({ type: REFRESH_COUNTERS, value: { @@ -51,11 +57,16 @@ export const reset = ({ user = '', code = '', password = '', password_confirm = type: RESET_PASSWORD, value: { token, - panel, userName: user, error }, }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel + } + }); dispatch({ type: REFRESH_COUNTERS, value: { @@ -84,11 +95,16 @@ export const loginAs = username => dispatch => { value: { userName: user, i18n, - panel, token, error } }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel + } + }); dispatch({ type: REFRESH_COUNTERS, value: { @@ -121,12 +137,17 @@ export const logout = () => (dispatch, getState) => { value: { userName: '', token: '', - panel: {}, session: {}, i18n: [], error, }, }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel: {} + } + }); dispatch({ type: REFRESH_COUNTERS, value: { @@ -144,12 +165,17 @@ export const logout = () => (dispatch, getState) => { type: LOGGED_OUT_AS, value: { userName, - panel, token: '', i18n, error, }, }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel + } + }); dispatch({ type: REFRESH_COUNTERS, value: { @@ -185,11 +211,16 @@ export const checkAuthHandler = () => (dispatch, getState) => { value: { userName: user, i18n, - panel, token, error } }); + dispatch({ + type: REFRESH_PANEL, + value: { + panel + } + }); dispatch({ type: REFRESH_COUNTERS, value: { diff --git a/src/react/src/components/Backup/RestoreSettings/BackupRestoreSettings.jsx b/src/react/src/components/Backup/RestoreSettings/BackupRestoreSettings.jsx index 7043d56f7..ffb3e808a 100644 --- a/src/react/src/components/Backup/RestoreSettings/BackupRestoreSettings.jsx +++ b/src/react/src/components/Backup/RestoreSettings/BackupRestoreSettings.jsx @@ -18,7 +18,6 @@ import './BackupRestoreSettings.scss'; export default function BackupRestoreSettings(props) { const { i18n } = useSelector(state => state.session); - const token = localStorage.getItem("token"); const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent); const { focusedElement } = useSelector(state => state.mainNavigation); const dispatch = useDispatch(); diff --git a/src/react/src/components/ControlPanel/AddItemLayout/AddItemLayout.scss b/src/react/src/components/ControlPanel/AddItemLayout/AddItemLayout.scss index 403f0b28c..12b4c548d 100644 --- a/src/react/src/components/ControlPanel/AddItemLayout/AddItemLayout.scss +++ b/src/react/src/components/ControlPanel/AddItemLayout/AddItemLayout.scss @@ -23,7 +23,7 @@ $errorColor: #BE5ABF; div.error, div.success { - width: max-content !important; + width: fit-content !important; span { font-weight: bold; @@ -58,6 +58,7 @@ $errorColor: #BE5ABF; width: auto !important; padding: 10px 0; margin-left: 0; + margin-right: 10px; } } } @@ -211,7 +212,7 @@ $errorColor: #BE5ABF; label.label-wrapper { display: flex; align-items: flex-end; - width: max-content; + width: fit-content; span { font-weight: normal; diff --git a/src/react/src/components/ControlPanel/AddItemLayout/Form/Password/Password.jsx b/src/react/src/components/ControlPanel/AddItemLayout/Form/Password/Password.jsx index 839e4f8ad..9c89a98f1 100644 --- a/src/react/src/components/ControlPanel/AddItemLayout/Form/Password/Password.jsx +++ b/src/react/src/components/ControlPanel/AddItemLayout/Form/Password/Password.jsx @@ -30,6 +30,7 @@ const Password = ({ defaultValue, onChange = () => { }, id, name, title, showGen } setState({ ...state, generatedPassword: result }); + onChange(result); } const passwordInputHandler = value => { diff --git a/src/react/src/components/Firewall/Add/AddFirewall.scss b/src/react/src/components/Firewall/Add/AddFirewall.scss index 05d56dc08..aff53e9fd 100644 --- a/src/react/src/components/Firewall/Add/AddFirewall.scss +++ b/src/react/src/components/Firewall/Add/AddFirewall.scss @@ -1,6 +1,6 @@ .content .edit-template.add-firewall { .toolbar .search-toolbar-name { - width: max-content; + width: fit-content; } label.label-wrapper[for=ip] span { diff --git a/src/react/src/components/InternetProtocol/InternetProtocol.jsx b/src/react/src/components/InternetProtocol/InternetProtocol.jsx index 6b4e88dce..fbdda12e6 100644 --- a/src/react/src/components/InternetProtocol/InternetProtocol.jsx +++ b/src/react/src/components/InternetProtocol/InternetProtocol.jsx @@ -50,7 +50,7 @@ const InternetProtocol = props => {
{i18n.Owner}: {data.OWNER}
-
{i18n.Users}: {data.U_SYS_USERS.replaceAll(',', ', ')}
+
{i18n.Users}: {data.U_SYS_USERS.replace(/,/g, ', ')}
diff --git a/src/react/src/components/MailAccount/Add/AddMailAccount.jsx b/src/react/src/components/MailAccount/Add/AddMailAccount.jsx index 1413eb595..8e68af96f 100644 --- a/src/react/src/components/MailAccount/Add/AddMailAccount.jsx +++ b/src/react/src/components/MailAccount/Add/AddMailAccount.jsx @@ -48,14 +48,18 @@ export default function AddMailAccount(props) { event.preventDefault(); let newMailDomain = {}; - for (var [name, value] of (new FormData(event.target)).entries()) { + for (var [name, value] of (new FormData(event.target)).entries()) { newMailDomain[name] = value; } newMailDomain['ok_acc'] = 'add'; newMailDomain['token'] = token; newMailDomain['v_domain'] = props.domain; - newMailDomain['Password'] = newMailDomain['v_password']; + newMailDomain['v_password'] = state.password; + + if (!newMailDomain['v_quota']) newMailDomain['v_quota'] = ''; + if (!newMailDomain['v_aliases']) newMailDomain['v_aliases'] = ''; + if (!newMailDomain['v_fwd']) newMailDomain['v_fwd'] = ''; if (Object.keys(newMailDomain).length !== 0 && newMailDomain.constructor === Object) { setState({ ...state, loading: true }); @@ -195,8 +199,8 @@ export default function AddMailAccount(props) { + name="v_send_email" + id="send_email" />
diff --git a/src/react/src/components/MailAccount/Add/AddMailAccount.scss b/src/react/src/components/MailAccount/Add/AddMailAccount.scss index 5d4e5a606..f09dd23d7 100644 --- a/src/react/src/components/MailAccount/Add/AddMailAccount.scss +++ b/src/react/src/components/MailAccount/Add/AddMailAccount.scss @@ -1,6 +1,6 @@ .content .edit-template.add-mail-account { .search-toolbar-name { - width: max-content; + width: fit-content; } form { diff --git a/src/react/src/components/MailAccount/Edit/EditMailAccount.jsx b/src/react/src/components/MailAccount/Edit/EditMailAccount.jsx index 0457af439..d0d8ca4c1 100644 --- a/src/react/src/components/MailAccount/Edit/EditMailAccount.jsx +++ b/src/react/src/components/MailAccount/Edit/EditMailAccount.jsx @@ -63,10 +63,12 @@ export default function EditMailAccount(props) { if (error_msg) { setErrorMessage(error_msg); setOkMessage(''); + setState({ ...state, loading: false }); } else { dispatch(refreshCounters()).then(() => { setErrorMessage(''); setOkMessage(ok_msg); + setState({ ...state, loading: false }); }); } } @@ -200,7 +202,7 @@ export default function EditMailAccount(props) {
- +
diff --git a/src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx b/src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx index 9a233a435..efd02a7b3 100644 --- a/src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx +++ b/src/react/src/components/MailAccount/MailInfoBlock/MailInfoBlock.jsx @@ -46,6 +46,24 @@ export default function MailInfoBlock({ webMail, hostName, domain, userName = '' ); } + const getCredentials = () => { + let result = ''; + + result += `${i18n['Username']}:${userName}@${domain}\n`; + result += `${i18n['Password']}:${password}\n`; + result += `${i18n['IMAP hostname']}:${state.imapHostName}\n`; + result += `${i18n['IMAP port']}:${state.imapPort}\n`; + result += `${i18n['IMAP security']}:${state.imapEncryption}\n`; + result += `${i18n['IMAP auth method']}:${i18n['Normal password']}\n`; + result += `${i18n['SMTP hostname']}:${state.smtpHostName}\n`; + result += `${i18n['SMTP port']}:${state.smtpPort}\n`; + result += `${i18n['SMTP security']}:${state.smtpEncryption}\n`; + result += `${i18n['SMTP auth method']}:${i18n['Normal password']}\n`; + result += `${i18n['Webmail URL']}:${`http://${window.location.hostname}${webMail}`}\n`; + + return result; + } + return (
@@ -109,15 +127,7 @@ export default function MailInfoBlock({ webMail, hostName, domain, userName = '' {webMail}
- - - - - - - - - +
diff --git a/src/react/src/components/MainNav/Mobile/MobileTopNav.scss b/src/react/src/components/MainNav/Mobile/MobileTopNav.scss index 33d40a183..a84541eb8 100644 --- a/src/react/src/components/MainNav/Mobile/MobileTopNav.scss +++ b/src/react/src/components/MainNav/Mobile/MobileTopNav.scss @@ -45,7 +45,7 @@ justify-content: center; align-items: center; padding: 0 10px !important; - width: max-content; + width: fit-content; height: 100%; text-decoration: none; color: $black; diff --git a/src/react/src/components/MainNav/Panel/Notifications/Notifications.jsx b/src/react/src/components/MainNav/Panel/Notifications/Notifications.jsx index c5517f945..09644996f 100644 --- a/src/react/src/components/MainNav/Panel/Notifications/Notifications.jsx +++ b/src/react/src/components/MainNav/Panel/Notifications/Notifications.jsx @@ -14,7 +14,8 @@ const Notifications = () => { const [loading, setLoading] = useState(false); useEffect(() => { - if (!notifications) { + if (!notifications.length) { + console.log(notifications); fetchData(); } }, [notifications]); @@ -47,7 +48,7 @@ const Notifications = () => { } const renderOptions = () => { - if (notifications && notifications.length) { + if (notifications.length) { return notifications.map(item => { return ( <> @@ -74,7 +75,7 @@ const Notifications = () => { + + ); + } + } + return (
{loading && } @@ -113,7 +148,7 @@ const Panel = props => { )}
- {panel[userName]['NOTIFICATIONS'] === 'yes' && } + {renderNotifications()}
{session.look @@ -130,27 +165,7 @@ const Panel = props => {
-
-
-
- dispatch(addActiveElement('/list/user/'))}> -
- Logo -
- -
-
-
- - - -
-
- {panel[userName]['NOTIFICATIONS'] === 'yes' && } -
{userName}
-
-
-
+ {renderSmallNavigation()} ); } diff --git a/src/react/src/components/MainNav/Panel/Panel.scss b/src/react/src/components/MainNav/Panel/Panel.scss index 9a93f84b0..2a2ce1fdb 100644 --- a/src/react/src/components/MainNav/Panel/Panel.scss +++ b/src/react/src/components/MainNav/Panel/Panel.scss @@ -46,7 +46,7 @@ justify-content: center; align-items: center; padding: 0 10px !important; - width: max-content; + width: fit-content; height: 100%; text-decoration: none; color: white; @@ -91,7 +91,8 @@ padding: 0; justify-content: space-between; - div { + div.top-link, + div.nav-link { flex: 1 1 auto; height: 100%; transform: translateX(-5px); @@ -150,8 +151,8 @@ svg { border-radius: 30px; - width: 100%; - height: 100%; + width: 40px; + height: 30px; padding: 3px; &:hover { @@ -199,7 +200,7 @@ justify-content: start; > div { - width: max-content; + width: fit-content; flex: unset; padding: 0 1rem; } @@ -212,11 +213,10 @@ } .profile-menu { - justify-content: space-between; align-items: center; > .edit-user { - width: max-content; + width: fit-content; } .long-username { @@ -236,7 +236,7 @@ } } -@media screen and (min-width: $desktopMax) { +@media screen and (max-width: 1350px) { .top-panel { padding: 0 10%; } @@ -248,13 +248,7 @@ } } -@media screen and (max-width: 1200px) { - .top-panel { - padding: 0 10%; - } -} - -@media (max-width: 1065px) { +@media (max-width: 900px) { .top-panel { display: none; } diff --git a/src/react/src/components/MainNav/Stat-menu/Menu.jsx b/src/react/src/components/MainNav/Stat-menu/Menu.jsx index 4d7c20162..1e84b9c83 100644 --- a/src/react/src/components/MainNav/Stat-menu/Menu.jsx +++ b/src/react/src/components/MainNav/Stat-menu/Menu.jsx @@ -4,6 +4,7 @@ import { useSelector, useDispatch } from "react-redux"; import { Link } from "react-router-dom"; import './Menu.scss'; +import Spinner from 'src/components/Spinner/Spinner'; const className = height => { if (height === 35) { @@ -27,7 +28,8 @@ const style = ({ menuHeight, mobile }) => { const Menu = props => { const { activeElement, focusedElement } = useSelector(state => state.mainNavigation); - const { i18n, panel, userName } = useSelector(state => state.session); + const { i18n, userName } = useSelector(state => state.session); + const { panel } = useSelector(state => state.panel); const { session } = useSelector(state => state.userSession); const { user } = useSelector(state => state.menuCounters); const dispatch = useDispatch(); @@ -50,6 +52,8 @@ const Menu = props => { return `stat ${activeName === activeElement && 'l-active'} ${activeName === focusedElement && 'focus'}`; } + if (!panel[userName]) return ; + return (
@@ -62,11 +66,21 @@ const Menu = props => { ? (<>
{i18n.Disk}: - {user.U_DISK} {panel[session.look]['U_DISK_MEASURE']} + + + {panel[session.look]['U_DISK']} + {panel[session.look]['U_DISK_MEASURE']} + +
{i18n.Bandwidth}: - {user.U_BANDWIDTH} {panel[session.look]['U_BANDWIDTH_MEASURE']} + + + {panel[session.look]['U_BANDWIDTH']} + {panel[session.look]['U_BANDWIDTH_MEASURE']} + +
) : (<> diff --git a/src/react/src/components/MainNav/Stat-menu/Menu.scss b/src/react/src/components/MainNav/Stat-menu/Menu.scss index 194eb4f68..e7ebccb20 100644 --- a/src/react/src/components/MainNav/Stat-menu/Menu.scss +++ b/src/react/src/components/MainNav/Stat-menu/Menu.scss @@ -99,10 +99,6 @@ } } - .stat.last { - flex: 1; - } - .l-active { border-bottom: 3px solid $primary; diff --git a/src/react/src/components/MainNav/Toolbar/Toolbar.scss b/src/react/src/components/MainNav/Toolbar/Toolbar.scss index 084112bf6..5291709ac 100644 --- a/src/react/src/components/MainNav/Toolbar/Toolbar.scss +++ b/src/react/src/components/MainNav/Toolbar/Toolbar.scss @@ -23,18 +23,23 @@ flex-wrap: unset; width: 100%; align-items: center; + justify-content: flex-end; } a.button-extra, button.button-extra { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + justify-content: flex-start; + padding: 5px 10px; background: none; border: none; - padding: 0 0.75rem; text-decoration: none; color: rgb(129, 125, 125); font-size: 14px; display: flex; - justify-content: center; align-items: center; margin-right: 10px; border-radius: 3px; @@ -152,11 +157,28 @@ } } +@media (max-width: 1250px) { + .toolbar { + .r-menu { + a.button-extra, + button.button-extra { + max-width: 30%; + } + } + } +} + @media (max-width: 900px) { .toolbar { .r-menu { overflow: scroll; + a.button-extra, + button.button-extra { + overflow: unset; + max-width: 100%; + } + > div { margin-left: 3rem; position: relative; @@ -164,6 +186,7 @@ flex-wrap: unset; width: 100%; align-items: center; + justify-content: flex-start; } .select-wrapper + div { diff --git a/src/react/src/components/Package/Add/AddPackage.scss b/src/react/src/components/Package/Add/AddPackage.scss index d312a70c6..b91b760d2 100644 --- a/src/react/src/components/Package/Add/AddPackage.scss +++ b/src/react/src/components/Package/Add/AddPackage.scss @@ -3,7 +3,7 @@ label.label-wrapper { display: flex; align-items: flex-end; - width: max-content; + width: fit-content; span { font-weight: normal; diff --git a/src/react/src/components/Package/Package.jsx b/src/react/src/components/Package/Package.jsx index 9a92efe56..f5dd9ae6c 100644 --- a/src/react/src/components/Package/Package.jsx +++ b/src/react/src/components/Package/Package.jsx @@ -9,6 +9,7 @@ import { useSelector } from 'react-redux'; const Package = props => { const { data } = props; const { i18n } = useSelector(state => state.session); + const { session } = useSelector(state => state.userSession); const printNameServers = servers => { let serversArray = servers.split(','); @@ -50,7 +51,7 @@ const Package = props => {
{i18n['Web Template']}: {data.WEB_TEMPLATE}
-
{i18n['Proxy Template']}: {data.PROXY_TEMPLATE}
+ {session.PROXY_SYSTEM &&
{i18n['Proxy Template']}: {data.PROXY_TEMPLATE}
}
{i18n['DNS Template']}: {data.DNS_TEMPLATE}
{i18n['SSH Access']}: {data.SHELL}
{i18n['Web Domains']}: {data.WEB_DOMAINS}
diff --git a/src/react/src/components/Server/Edit/Bind9/Bind9.scss b/src/react/src/components/Server/Edit/Bind9/Bind9.scss index 3762c0a66..612d1a073 100644 --- a/src/react/src/components/Server/Edit/Bind9/Bind9.scss +++ b/src/react/src/components/Server/Edit/Bind9/Bind9.scss @@ -1,7 +1,7 @@ .content .edit-template.edit-bind9 { .toolbar { .search-toolbar-name { - width: max-content; + width: fit-content; } } diff --git a/src/react/src/components/Server/Edit/Dovecot/Dovecot.scss b/src/react/src/components/Server/Edit/Dovecot/Dovecot.scss index 3762c0a66..612d1a073 100644 --- a/src/react/src/components/Server/Edit/Dovecot/Dovecot.scss +++ b/src/react/src/components/Server/Edit/Dovecot/Dovecot.scss @@ -1,7 +1,7 @@ .content .edit-template.edit-bind9 { .toolbar { .search-toolbar-name { - width: max-content; + width: fit-content; } } diff --git a/src/react/src/components/Server/Edit/EditDatabaseOption.jsx b/src/react/src/components/Server/Edit/EditDatabaseOption.jsx index 9d6529d4e..447770c68 100644 --- a/src/react/src/components/Server/Edit/EditDatabaseOption.jsx +++ b/src/react/src/components/Server/Edit/EditDatabaseOption.jsx @@ -6,6 +6,7 @@ import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; const EditDatabaseOption = ({ data, visible }) => { + const { DB_PMA_URL, DB_PGA_URL } = useSelector(state => state.userSession.session); const { i18n } = useSelector(state => state.session); const printPhpMyAdminHosts = () => { @@ -85,7 +86,7 @@ const EditDatabaseOption = ({ data, visible }) => { <> @@ -108,7 +109,7 @@ const EditDatabaseOption = ({ data, visible }) => { <> diff --git a/src/react/src/components/Server/Edit/EditMailOption.jsx b/src/react/src/components/Server/Edit/EditMailOption.jsx index e398a5958..fb5a2b260 100644 --- a/src/react/src/components/Server/Edit/EditMailOption.jsx +++ b/src/react/src/components/Server/Edit/EditMailOption.jsx @@ -7,6 +7,7 @@ import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; const EditMailOption = ({ data, visible }) => { + const { MAIL_URL } = useSelector(state => state.userSession.session); const { i18n } = useSelector(state => state.session); const [mailCertificateSystem, setMailCertificateSystem] = useState(false); @@ -58,7 +59,7 @@ const EditMailOption = ({ data, visible }) => {

diff --git a/src/react/src/components/Server/Edit/EditServer.jsx b/src/react/src/components/Server/Edit/EditServer.jsx index c694ff3ff..23ea1cac1 100644 --- a/src/react/src/components/Server/Edit/EditServer.jsx +++ b/src/react/src/components/Server/Edit/EditServer.jsx @@ -167,12 +167,6 @@ const EditServer = props => { name="v_language" id="language" /> - {/* */} -
- {renderMenuItems()} - - {renderExtraMenuItems()} + + {renderMenuItems()} + {renderExtraMenuItems()} +
diff --git a/src/react/src/components/TopPanel/TopPanel.scss b/src/react/src/components/TopPanel/TopPanel.scss index 3831ff641..43944e77b 100644 --- a/src/react/src/components/TopPanel/TopPanel.scss +++ b/src/react/src/components/TopPanel/TopPanel.scss @@ -16,6 +16,24 @@ } .left-menu { + justify-content: unset; + + .logo { + width: fit-content; + flex: unset; + } + + .scrollbar-container { + &:hover { + background: none; + } + + .nav-link { + flex: unset; + padding: 0 5px; + } + } + a, button { padding: 0 !important; outline: none; diff --git a/src/react/src/components/User/User.scss b/src/react/src/components/User/User.scss index 799959c71..82e730256 100644 --- a/src/react/src/components/User/User.scss +++ b/src/react/src/components/User/User.scss @@ -29,7 +29,7 @@ span.stat.email{ display: block; - width: max-content; + width: fit-content; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; @@ -208,7 +208,7 @@ span.stat.email{ @media (max-width: 850px) { > div { - width: max-content; + width: fit-content; a, button { width: 100%; diff --git a/src/react/src/components/WebDomain/Add/AddWebDomain.jsx b/src/react/src/components/WebDomain/Add/AddWebDomain.jsx index 703afab58..d9b7fc12c 100644 --- a/src/react/src/components/WebDomain/Add/AddWebDomain.jsx +++ b/src/react/src/components/WebDomain/Add/AddWebDomain.jsx @@ -20,7 +20,8 @@ import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions'; import HtmlParser from 'react-html-parser'; const AddWebDomain = props => { - const { i18n, panel, userName } = useSelector(state => state.session); + const { i18n, userName } = useSelector(state => state.session); + const { panel } = useSelector(state => state.panel); const { session } = useSelector(state => state.userSession); const dispatch = useDispatch(); const token = localStorage.getItem("token"); diff --git a/src/react/src/components/WebDomain/Add/SslSupport/SslSupport.jsx b/src/react/src/components/WebDomain/Add/SslSupport/SslSupport.jsx index 125e2ea81..8d9aa1a76 100644 --- a/src/react/src/components/WebDomain/Add/SslSupport/SslSupport.jsx +++ b/src/react/src/components/WebDomain/Add/SslSupport/SslSupport.jsx @@ -1,6 +1,5 @@ import React, { useState } from 'react'; import { useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; import TextArea from 'src/components/ControlPanel/AddItemLayout/Form/TextArea/TextArea'; import './SslSupport.scss'; @@ -30,7 +29,6 @@ const SslSupport = props => { id="ssl-certificate" name="v_ssl_crt" title={i18n['SSL Certificate']} - value={props.sslCertificate} disabled={letsEncrypt} optionalTitle={<>/ } /> diff --git a/src/react/src/components/WebDomain/Edit/SslSupport/SslSupport.scss b/src/react/src/components/WebDomain/Edit/SslSupport/SslSupport.scss index 378dfc8b1..fb0a9c773 100644 --- a/src/react/src/components/WebDomain/Edit/SslSupport/SslSupport.scss +++ b/src/react/src/components/WebDomain/Edit/SslSupport/SslSupport.scss @@ -13,7 +13,7 @@ } &:nth-child(2) { - width: max-content; + width: fit-content; } } } diff --git a/src/react/src/components/WebDomain/WebDomain.jsx b/src/react/src/components/WebDomain/WebDomain.jsx index 823840aa0..2c55a116f 100644 --- a/src/react/src/components/WebDomain/WebDomain.jsx +++ b/src/react/src/components/WebDomain/WebDomain.jsx @@ -72,7 +72,7 @@ export default function WebDomain(props) {
{data.NAME}
-
{data.ALIAS.replaceAll(',', ', ')}
+
{data.ALIAS.replace(/,/g, ', ')}
{data.IP}
diff --git a/src/react/src/components/WebDomain/WebDomain.scss b/src/react/src/components/WebDomain/WebDomain.scss index 0e1ee3b9d..42afea54e 100644 --- a/src/react/src/components/WebDomain/WebDomain.scss +++ b/src/react/src/components/WebDomain/WebDomain.scss @@ -19,12 +19,16 @@ .name { display: flex; - align-items: center; > div:nth-child(1) { margin-right: 2rem; } + > div + div { + line-height: 10px; + margin-top: .75rem; + } + .dns-name-span { font-style: italic; color: #858585; diff --git a/src/react/src/containers/App/App.js b/src/react/src/containers/App/App.js index 3be606931..fc06cf21a 100755 --- a/src/react/src/containers/App/App.js +++ b/src/react/src/containers/App/App.js @@ -106,7 +106,7 @@ const App = () => { exact component={Preview} />
- {i18n['open webmail']} + {state.webMail && {i18n['open webmail']}} props.changeSearchTerm(term)} /> diff --git a/src/react/src/containers/ServiceInfo/index.jsx b/src/react/src/containers/ServiceInfo/index.jsx index 6c169ea4b..f6b9fe2df 100644 --- a/src/react/src/containers/ServiceInfo/index.jsx +++ b/src/react/src/containers/ServiceInfo/index.jsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { addActiveElement } from 'src/actions/MainNavigation/mainNavigationActions'; import TopPanel from 'src/components/TopPanel/TopPanel'; -import { useParams, useHistory } from 'react-router-dom'; +import { useHistory } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import { getServiceLogs } from 'src/ControlPanelService/Server'; @@ -11,13 +11,12 @@ import { Helmet } from 'react-helmet'; import ReactHtmlParser from 'react-html-parser'; import './styles.scss'; +import QueryString from 'qs'; const ServiceInfo = () => { const { i18n, userName } = useSelector(state => state.session); const dispatch = useDispatch(); - const { activeElement } = useSelector(state => state.mainNavigation); const history = useHistory(); - const { service } = useParams(); const [state, setState] = useState({ data: "", loading: false @@ -30,14 +29,28 @@ const ServiceInfo = () => { }, [userName]); useEffect(() => { - fetchData(); - dispatch(addActiveElement(`/list/server/${service}`)); - }, [activeElement]); + let queryParams = QueryString.parse(history.location.search, { ignoreQueryPrefix: true }); - const fetchData = () => { + if (!queryParams.srv) { + fetchData('cpu'); + dispatch(addActiveElement('/list/server/service/?srv=cpu')); + return; + } + + if (!menuItems.find(item => item.service === queryParams.srv)) { + dispatch(addActiveElement('/list/server/service/?srv=cpu')); + history.push('/list/server/service/?srv=cpu'); + return; + } + + fetchData(queryParams.srv); + dispatch(addActiveElement(`/list/server/service/?srv=${queryParams.srv}`)); + }, [history.location.search]); + + const fetchData = serviceName => { setState({ ...state, loading: true }); - getServiceLogs(service) + getServiceLogs(serviceName) .then(result => { setState({ ...state, data: result.data.service_log, loading: false }); }) @@ -49,35 +62,43 @@ const ServiceInfo = () => { const menuItems = [ { - route: '/list/server/cpu', + route: '/list/server/service/?srv=cpu', + service: 'cpu', name: i18n['CPU'] }, { - route: '/list/server/mem', + route: '/list/server/service/?srv=mem', + service: 'mem', name: i18n['MEMORY'] }, { - route: '/list/server/disk', + route: '/list/server/service/?srv=disk', + service: 'disk', name: i18n['DISK'] }, { - route: '/list/server/net', + route: '/list/server/service/?srv=net', + service: 'net', name: i18n['NETWORK'] }, { - route: '/list/server/web', + route: '/list/server/service/?srv=web', + service: 'web', name: i18n['WEB'] }, { - route: '/list/server/dns', + route: '/list/server/service/?srv=dns', + service: 'dns', name: i18n['DNS'] }, { - route: '/list/server/mail', + route: '/list/server/service/?srv=mail', + service: 'mail', name: i18n['MAIL'] }, { - route: '/list/server/db', + route: '/list/server/service/?srv=db', + service: 'db', name: i18n['DB'] } ]; @@ -93,7 +114,7 @@ const ServiceInfo = () => { state.loading ? : (
-              {state.data.length && state.data.map(line => (<>{ReactHtmlParser(line)}
))} + {state.data && ReactHtmlParser(state.data)}
) }
diff --git a/src/react/src/containers/ServiceInfo/styles.scss b/src/react/src/containers/ServiceInfo/styles.scss index 64d26c5e0..ea27fc579 100644 --- a/src/react/src/containers/ServiceInfo/styles.scss +++ b/src/react/src/containers/ServiceInfo/styles.scss @@ -1,7 +1,36 @@ -.service-info { +.App .service-info { + @media screen and (max-width: 1066px) { + .top-panel { + display: flex; + } + } + + @media screen and (min-width: 1200px) { + .top-panel { + padding: 0 13%; + } + } + .content { font-size: 14px; color: #555; padding-top: 4rem; + + @media screen and (min-width: 1067px) { + padding-top: 5rem !important; + margin-top: 0px !important; + } + + @media screen and (max-width: 1066px) { + padding-top: 5rem !important; + margin-top: 0px !important; + } + + table { + td,th { + padding: 5px 10px; + border: 1px solid black; + } + } } } diff --git a/src/react/src/containers/Web/Web.jsx b/src/react/src/containers/Web/Web.jsx index f16838b66..fb8c427a6 100644 --- a/src/react/src/containers/Web/Web.jsx +++ b/src/react/src/containers/Web/Web.jsx @@ -17,12 +17,16 @@ import { useDispatch, useSelector } from 'react-redux'; import { Helmet } from 'react-helmet'; import './Web.scss'; import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions'; +import { useHistory } from 'react-router-dom'; const Web = props => { const { i18n } = useSelector(state => state.session); const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent); const { focusedElement } = useSelector(state => state.mainNavigation); + const { panel } = useSelector(state => state.panel); + const { userName } = useSelector(state => state.session); const dispatch = useDispatch(); + const history = useHistory(); const [loading, setLoading] = useState(false); const [modal, setModal] = useState({ text: '', @@ -40,6 +44,10 @@ const Web = props => { }); useEffect(() => { + if (panel[userName]['WEB_DOMAINS'] === '0') { + return history.push('/'); + } + dispatch(addActiveElement('/list/web/')); dispatch(removeFocusedElement()); dispatch(removeControlPanelContentFocusedElement()); diff --git a/src/react/src/containers/WebLogs/WebLogs.jsx b/src/react/src/containers/WebLogs/WebLogs.jsx index 038b5ee61..d97193159 100644 --- a/src/react/src/containers/WebLogs/WebLogs.jsx +++ b/src/react/src/containers/WebLogs/WebLogs.jsx @@ -94,7 +94,7 @@ export default function WebLogs() {
-
{state.prefix}
+
{state.prefix}

{ state.loading diff --git a/src/react/src/containers/WebLogs/WebLogs.scss b/src/react/src/containers/WebLogs/WebLogs.scss index 17e8bf0c2..f00f61bc0 100644 --- a/src/react/src/containers/WebLogs/WebLogs.scss +++ b/src/react/src/containers/WebLogs/WebLogs.scss @@ -1,12 +1,30 @@ -.web-logs { +.App .web-logs { + .top-panel { + .left-menu { + .logo { + justify-content: start; + margin: 0; + + a { + padding: 0 !important; + } + } + } + } + .content { font-size: 14px; color: #555; padding-top: 4rem; - } - .nav-link:nth-child(3), - .nav-link:nth-child(4) { - width: 9rem; + @media screen and (min-width: 1067px) { + padding-top: 5rem !important; + margin-top: 0px !important; + } + + @media screen and (max-width: 1066px) { + padding-top: 5rem !important; + margin-top: 0px !important; + } } -} \ No newline at end of file +} diff --git a/src/react/src/reducers/Notification/notificationReducer.js b/src/react/src/reducers/Notification/notificationReducer.js index c15f96a53..0e3a269eb 100644 --- a/src/react/src/reducers/Notification/notificationReducer.js +++ b/src/react/src/reducers/Notification/notificationReducer.js @@ -1,7 +1,7 @@ import { ADD_NOTIFICATIONS, REMOVE_NOTIFICATIONS } from 'src/actions/Notification/notificationTypes'; const INITIAL_STATE = { - notifications: null + notifications: [] }; const notificationReducer = (state = INITIAL_STATE, action) => { diff --git a/src/react/src/reducers/Panel/panel.js b/src/react/src/reducers/Panel/panel.js new file mode 100644 index 000000000..36ee5b39e --- /dev/null +++ b/src/react/src/reducers/Panel/panel.js @@ -0,0 +1,19 @@ +import { REFRESH_PANEL } from '../../actions/Panel/panelTypes'; + +const INITIAL_STATE = { + panel: {} +}; + +const panelReducer = (state = INITIAL_STATE, action) => { + switch (action.type) { + case REFRESH_PANEL: + return { + ...state, + panel: action.value.panel + }; + + default: return state; + } +}; + +export default panelReducer; diff --git a/src/react/src/reducers/Session/sessionReducer.js b/src/react/src/reducers/Session/sessionReducer.js index 5c82c6c24..c05888534 100644 --- a/src/react/src/reducers/Session/sessionReducer.js +++ b/src/react/src/reducers/Session/sessionReducer.js @@ -4,8 +4,7 @@ const INITIAL_STATE = { token: '', error: '', i18n: {}, - userName: '', - panel: {} + userName: '' }; const sessionReducer = (state = INITIAL_STATE, action) => { @@ -16,7 +15,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => { token: action.value.token, userName: action.value.userName, i18n: action.value.i18n || {}, - panel: action.value.panel, error: action.value.error }; @@ -26,7 +24,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => { token: action.value.token, userName: action.value.userName, i18n: action.value.i18n || {}, - panel: action.value.panel, error: action.value.error }; @@ -36,7 +33,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => { token: action.value.token, userName: action.value.userName, i18n: action.value.i18n || {}, - panel: action.value.panel, error: action.value.error }; @@ -45,7 +41,6 @@ const sessionReducer = (state = INITIAL_STATE, action) => { token: action.value.token, userName: action.value.userName, i18n: action.value.i18n || {}, - panel: action.value.panel, error: action.value.error }; diff --git a/src/react/src/reducers/rootReducer.js b/src/react/src/reducers/rootReducer.js index 6fc6ce145..c3fde2017 100644 --- a/src/react/src/reducers/rootReducer.js +++ b/src/react/src/reducers/rootReducer.js @@ -5,6 +5,7 @@ import notificationReducer from './Notification/notificationReducer'; import menuCounterReducer from './MenuCounters/menuCounterReducer'; import userSessionReducer from './UserSession/userSessionReducer'; import sessionReducer from './Session/sessionReducer'; +import panelReducer from './Panel/panel'; export default combineReducers({ mainNavigation: mainNavigationReducer, @@ -13,4 +14,5 @@ export default combineReducers({ menuCounters: menuCounterReducer, userSession: userSessionReducer, session: sessionReducer, + panel: panelReducer, }); \ No newline at end of file