mirror of
https://github.com/serghey-rodin/vesta.git
synced 2025-07-06 04:51:52 -07:00
Merge pull request #2220 from serghey-rodin/release/1.0.0-6-ui
UI 1.0.0-6 release.
This commit is contained in:
commit
653348242f
58 changed files with 374 additions and 151 deletions
|
@ -2,5 +2,6 @@
|
|||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "build"]
|
||||
}
|
||||
|
|
9
src/react/package-lock.json
generated
9
src/react/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 => {
|
||||
|
|
1
src/react/src/actions/Panel/panelTypes.js
Normal file
1
src/react/src/actions/Panel/panelTypes.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const REFRESH_PANEL = 'REFRESH_PANEL';
|
|
@ -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: {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -30,6 +30,7 @@ const Password = ({ defaultValue, onChange = () => { }, id, name, title, showGen
|
|||
}
|
||||
|
||||
setState({ ...state, generatedPassword: result });
|
||||
onChange(result);
|
||||
}
|
||||
|
||||
const passwordInputHandler = value => {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -50,7 +50,7 @@ const InternetProtocol = props => {
|
|||
</Container>
|
||||
<Container className="c-3 w-35">
|
||||
<div>{i18n.Owner}: <span className="stat">{data.OWNER}</span></div>
|
||||
<div>{i18n.Users}: <span className="stat">{data.U_SYS_USERS.replaceAll(',', ', ')}</span></div>
|
||||
<div>{i18n.Users}: <span className="stat">{data.U_SYS_USERS.replace(/,/g, ', ')}</span></div>
|
||||
</Container>
|
||||
</div>
|
||||
</Container>
|
||||
|
|
|
@ -55,7 +55,11 @@ export default function AddMailAccount(props) {
|
|||
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) {
|
|||
|
||||
<TextInput
|
||||
title={i18n['Send login credentials to email address']}
|
||||
name="v_credentials"
|
||||
id="credentials" />
|
||||
name="v_send_email"
|
||||
id="send_email" />
|
||||
</div>
|
||||
|
||||
<div className="buttons-wrapper">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.content .edit-template.add-mail-account {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
form {
|
||||
|
|
|
@ -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) {
|
|||
</div>
|
||||
|
||||
<div className="buttons-wrapper">
|
||||
<button type="submit" className="add">{i18n.Add}</button>
|
||||
<button type="submit" className="add">{i18n.Save}</button>
|
||||
<button type="button" className="back" onClick={goBack}>{i18n.Back}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -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 (
|
||||
<div className="mail-info-block">
|
||||
<div class="form-group select-group">
|
||||
|
@ -109,15 +127,7 @@ export default function MailInfoBlock({ webMail, hostName, domain, userName = ''
|
|||
<span><Link to={{ pathname: `http://${window.location.hostname}${webMail}` }} target="_blank">{webMail}</Link></span>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name={i18n['Username']} value={`@${domain}`} />
|
||||
<input type="hidden" name={i18n['IMAP hostname']} value={state.imapHostName} />
|
||||
<input type="hidden" name={i18n['SMTP hostname']} value={state.smtpHostName} />
|
||||
<input type="hidden" name={i18n['IMAP port']} value={state.imapPort} />
|
||||
<input type="hidden" name={i18n['SMTP port']} value={state.smtpPort} />
|
||||
<input type="hidden" name={i18n['IMAP security']} value={state.imapEncryption} />
|
||||
<input type="hidden" name={i18n['SMTP security']} value={state.smtpEncryption} />
|
||||
<input type="hidden" name={i18n['IMAP auth method']} value={i18n['Normal password']} />
|
||||
<input type="hidden" name={i18n['SMTP auth method']} value={i18n['Normal password']} />
|
||||
<input type="hidden" name="v_credentials" value={getCredentials()} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = () => {
|
|||
<button type="button" className="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<div className="bell">
|
||||
{
|
||||
notifications && notifications.length
|
||||
notifications.length
|
||||
? <BellUnread />
|
||||
: <Bell />
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ import { Link } from "react-router-dom";
|
|||
import './Panel.scss';
|
||||
|
||||
const Panel = props => {
|
||||
const { i18n, userName, panel } = useSelector(state => state.session);
|
||||
const { i18n, userName } = useSelector(state => state.session);
|
||||
const { panel } = useSelector(state => state.panel);
|
||||
const { session } = useSelector(state => state.userSession);
|
||||
const { activeElement, focusedElement } = useSelector(state => state.mainNavigation);
|
||||
const dispatch = useDispatch();
|
||||
|
@ -63,6 +64,40 @@ const Panel = props => {
|
|||
});
|
||||
}
|
||||
|
||||
const renderNotifications = () => {
|
||||
if (panel[userName]) {
|
||||
if (panel[userName]['NOTIFICATIONS'] === 'yes') {
|
||||
return <Notifications />;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const renderSmallNavigation = () => {
|
||||
if (document.documentElement.clientWidth < 900) {
|
||||
return (<div className="top-panel small-device">
|
||||
<div className="container left-menu">
|
||||
<div className="logo">
|
||||
<Link to="/list/user/" onClick={() => dispatch(addActiveElement('/list/user/'))}>
|
||||
<div>
|
||||
<img src="/images/white_logo.png" alt="Logo" />
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container hamburger" onClick={toggleNavigation}>
|
||||
<span className="bar"></span>
|
||||
<span className="bar"></span>
|
||||
<span className="bar"></span>
|
||||
</div>
|
||||
<div className="container profile-menu">
|
||||
{renderNotifications()}
|
||||
<div><Link to={`/edit/user?user=${userName}`}>{userName}</Link></div>
|
||||
<div><button onClick={signOut}>{i18n['Log out']}</button></div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="panel-wrapper">
|
||||
{loading && <Spinner />}
|
||||
|
@ -113,7 +148,7 @@ const Panel = props => {
|
|||
)}
|
||||
</div>
|
||||
<div className="container profile-menu">
|
||||
{panel[userName]['NOTIFICATIONS'] === 'yes' && <Notifications />}
|
||||
{renderNotifications()}
|
||||
<div className="edit-user">
|
||||
<Link to={`/edit/user?user=${userName}`}>
|
||||
{session.look
|
||||
|
@ -130,27 +165,7 @@ const Panel = props => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="top-panel small-device">
|
||||
<div className="container left-menu">
|
||||
<div className="logo">
|
||||
<Link to="/list/user/" onClick={() => dispatch(addActiveElement('/list/user/'))}>
|
||||
<div>
|
||||
<img src="/images/white_logo.png" alt="Logo" />
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container hamburger" onClick={toggleNavigation}>
|
||||
<span className="bar"></span>
|
||||
<span className="bar"></span>
|
||||
<span className="bar"></span>
|
||||
</div>
|
||||
<div className="container profile-menu">
|
||||
{panel[userName]['NOTIFICATIONS'] === 'yes' && <Notifications />}
|
||||
<div><Link to={`/edit/user?user=${userName}`}>{userName}</Link></div>
|
||||
<div><button onClick={signOut}>{i18n['Log out']}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
{renderSmallNavigation()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 <Spinner />;
|
||||
|
||||
return (
|
||||
<div className="menu-wrapper">
|
||||
<div className={className(props.menuHeight)} style={{ height: style(props) }}>
|
||||
|
@ -62,11 +66,21 @@ const Menu = props => {
|
|||
? (<>
|
||||
<div>
|
||||
<span>{i18n.Disk}:</span>
|
||||
<span><span className="value">{user.U_DISK} <span className="unit">{panel[session.look]['U_DISK_MEASURE']}</span></span></span>
|
||||
<span>
|
||||
<span className="value">
|
||||
{panel[session.look]['U_DISK']}
|
||||
<span className="unit">{panel[session.look]['U_DISK_MEASURE']}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{i18n.Bandwidth}:</span>
|
||||
<span><span className="value">{user.U_BANDWIDTH} <span className="unit">{panel[session.look]['U_BANDWIDTH_MEASURE']}</span></span></span>
|
||||
<span>
|
||||
<span className="value">
|
||||
{panel[session.look]['U_BANDWIDTH']}
|
||||
<span className="unit">{panel[session.look]['U_BANDWIDTH_MEASURE']}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</>)
|
||||
: (<>
|
||||
|
|
|
@ -99,10 +99,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.stat.last {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.l-active {
|
||||
border-bottom: 3px solid $primary;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
label.label-wrapper {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
|
||||
span {
|
||||
font-weight: normal;
|
||||
|
|
|
@ -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 => {
|
|||
<div className="stats">
|
||||
<Container className="c-1 w-30">
|
||||
<div>{i18n['Web Template']}: <span><span className="stat">{data.WEB_TEMPLATE}</span></span></div>
|
||||
<div>{i18n['Proxy Template']}: <span><span className="stat">{data.PROXY_TEMPLATE}</span></span></div>
|
||||
{session.PROXY_SYSTEM && <div>{i18n['Proxy Template']}: <span><span className="stat">{data.PROXY_TEMPLATE}</span></span></div>}
|
||||
<div>{i18n['DNS Template']}: <span><span className="stat">{data.DNS_TEMPLATE}</span></span></div>
|
||||
<div>{i18n['SSH Access']}: <span><span className="stat">{data.SHELL}</span></span></div>
|
||||
<div>{i18n['Web Domains']}: <span><span className="stat">{data.WEB_DOMAINS}</span></span></div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.content .edit-template.edit-bind9 {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.content .edit-template.edit-bind9 {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 }) => {
|
|||
<>
|
||||
<TextInput
|
||||
title={i18n['phpMyAdmin URL']}
|
||||
value={data.mail_url}
|
||||
value={DB_PMA_URL}
|
||||
name="v_mysql_url"
|
||||
id="mysql_url" />
|
||||
|
||||
|
@ -108,7 +109,7 @@ const EditDatabaseOption = ({ data, visible }) => {
|
|||
<>
|
||||
<TextInput
|
||||
title={i18n['phpPgAdmin URL']}
|
||||
value={data.pgsql_url}
|
||||
value={DB_PGA_URL}
|
||||
name="v_pgsql_url"
|
||||
id="pgsql_url" />
|
||||
|
||||
|
|
|
@ -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 }) => {
|
|||
<TextInput
|
||||
title={i18n['Webmail URL']}
|
||||
name="v_mail_url"
|
||||
value={data.mail_url}
|
||||
value={MAIL_URL}
|
||||
id="mail-url" />
|
||||
|
||||
<br /><br />
|
||||
|
|
|
@ -167,12 +167,6 @@ const EditServer = props => {
|
|||
name="v_language"
|
||||
id="language" />
|
||||
|
||||
{/* <TextInput
|
||||
value={state.data.port}
|
||||
title={i18n['Default Port'] ?? 'Default Port'}
|
||||
name="port"
|
||||
id="port" /> */}
|
||||
|
||||
<div className="modules">
|
||||
<button type="button" onClick={() => toggleOption('webOption')}>
|
||||
{i18n['WEB']}
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
padding: 7px 15px;
|
||||
text-transform: capitalize;
|
||||
text-decoration: none;
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
margin-right: 10px;
|
||||
|
||||
&:hover {
|
||||
|
|
|
@ -4,7 +4,7 @@ $secondaryLight: #f8b014;
|
|||
.content .edit-template.edit-httpd {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
|
||||
a {
|
||||
color: $secondary;
|
||||
|
@ -17,7 +17,7 @@ $secondaryLight: #f8b014;
|
|||
}
|
||||
|
||||
.link {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
margin-left: 15px;
|
||||
|
||||
a {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.content .edit-template.edit-mysql {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,11 @@ $secondaryLight: #f8b014;
|
|||
.content .edit-template.edit-nginx {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.link {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
margin-left: 15px;
|
||||
|
||||
a {
|
||||
|
|
|
@ -5,13 +5,13 @@ $textColor: #555;
|
|||
.content .edit-template.edit-php {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
color: $textColor;
|
||||
}
|
||||
|
||||
.search-toolbar-name,
|
||||
.link {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.content .edit-template.edit-pgsql {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.content .edit-template.edit-service {
|
||||
.toolbar {
|
||||
.search-toolbar-name {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { logout } from 'src/actions/Session/sessionActions';
|
|||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import Spinner from '../Spinner/Spinner';
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
|
||||
import './TopPanel.scss';
|
||||
|
||||
|
@ -82,9 +83,10 @@ const TopPanel = ({ menuItems = [], extraMenuItems = [] }) => {
|
|||
</Link>
|
||||
</div>
|
||||
|
||||
<PerfectScrollbar>
|
||||
{renderMenuItems()}
|
||||
|
||||
{renderExtraMenuItems()}
|
||||
</PerfectScrollbar>
|
||||
</div>
|
||||
|
||||
<div className="container profile-menu">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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%;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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={<>/ <button type="button" onClick={() => props.setModalVisible(true)} className="generate-csr">{i18n['Generate CSR']}</button></>} />
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ export default function WebDomain(props) {
|
|||
<Container className="r-col w-85">
|
||||
<div className="name">
|
||||
<div>{data.NAME}</div>
|
||||
<div><span className="dns-name-span">{data.ALIAS.replaceAll(',', ', ')}</span></div>
|
||||
<div><span className="dns-name-span">{data.ALIAS.replace(/,/g, ', ')}</span></div>
|
||||
</div>
|
||||
<div>{data.IP}</div>
|
||||
<div className="stats">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -106,7 +106,7 @@ const App = () => {
|
|||
exact
|
||||
component={Preview} />
|
||||
<AuthenticatedRoute
|
||||
path="/list/server/:service"
|
||||
path="/list/server/service/"
|
||||
authenticated={session.userName}
|
||||
component={ServiceInfo} />
|
||||
<AuthenticatedRoute
|
||||
|
|
|
@ -380,7 +380,7 @@ export default function MailAccounts(props) {
|
|||
<LeftButton name={i18n['Add Mail Account']} href={`/add/mail/?domain=${props.domain}`} showLeftMenu={true} />
|
||||
<div className="r-menu">
|
||||
<div className="input-group input-group-sm">
|
||||
<a href={state.webMail} className="button-extra" type="submit">{i18n['open webmail']}</a>
|
||||
{state.webMail && <a href={state.webMail} className="button-extra" type="submit">{i18n['open webmail']}</a>}
|
||||
<Checkbox toggleAll={toggleAll} toggled={state.toggledAll} />
|
||||
<Select list='mailList' bulkAction={bulk} />
|
||||
<DropdownFilter changeSorting={changeSorting} sorting={state.sorting} order={state.order} list="mailAccountList" />
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
div.list-item {
|
||||
.r-col {
|
||||
.stat.email {
|
||||
width: max-content;
|
||||
width: fit-content;
|
||||
text-transform: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ const Servers = props => {
|
|||
<LeftButton href="/edit/server/" list="server" name={i18n.configure} showLeftMenu={true} />
|
||||
<div className="r-menu">
|
||||
<div className="input-group input-group-sm">
|
||||
<Link to="/list/server/cpu" className="button-extra">{i18n['show: CPU / MEM / NET / DISK']}</Link>
|
||||
<Link to="/list/server/service/?srv=cpu" className="button-extra">{i18n['show: CPU / MEM / NET / DISK']}</Link>
|
||||
<Checkbox toggleAll={toggleAll} toggled={state.toggledAll} />
|
||||
<Select list='serverList' bulkAction={bulk} />
|
||||
<SearchInput handleSearchTerm={term => props.changeSearchTerm(term)} />
|
||||
|
|
|
@ -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
|
||||
? <Spinner />
|
||||
: (<pre>
|
||||
{state.data.length && state.data.map(line => (<>{ReactHtmlParser(line)}<br /></>))}
|
||||
{state.data && ReactHtmlParser(state.data)}
|
||||
</pre>)
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -94,7 +94,7 @@ export default function WebLogs() {
|
|||
</Helmet>
|
||||
<TopPanel menuItems={menuItems} extraMenuItems={extraMenuItems} />
|
||||
<div className="content">
|
||||
<h6>{state.prefix}</h6>
|
||||
<h6><b>{state.prefix}</b></h6>
|
||||
<br />
|
||||
{
|
||||
state.loading
|
||||
|
|
|
@ -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;
|
||||
|
||||
@media screen and (min-width: 1067px) {
|
||||
padding-top: 5rem !important;
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
.nav-link:nth-child(3),
|
||||
.nav-link:nth-child(4) {
|
||||
width: 9rem;
|
||||
@media screen and (max-width: 1066px) {
|
||||
padding-top: 5rem !important;
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) => {
|
||||
|
|
19
src/react/src/reducers/Panel/panel.js
Normal file
19
src/react/src/reducers/Panel/panel.js
Normal file
|
@ -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;
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue