Merge pull request #2071 from serghey-rodin/feature/new-react-ui

Updated react UI and UX part.
This commit is contained in:
Serghey Rodin 2021-10-28 22:52:55 +03:00 committed by GitHub
commit f832525f65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
122 changed files with 1622 additions and 899 deletions

View file

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

View file

@ -19,13 +19,26 @@ export const getDNSRecordInfo = (domain, recordId) => {
return axios.get(`${BASE_URL}${updateDNSUri}?domain=${domain}&record_id=${recordId}`);
}
export const bulkAction = (action, domainNameSystems) => {
export const bulkDomainAction = (action, domains) => {
const formData = new FormData();
formData.append("action", action);
formData.append("token", getAuthToken());
domainNameSystems.forEach(domainNameSystem => {
formData.append("domain[]", domainNameSystem);
domains.forEach(record => {
formData.append("domain[]", record);
});
return axios.post(BASE_URL + '/api/v1/bulk/dns/', formData);
};
export const bulkAction = (action, records, domain) => {
const formData = new FormData();
formData.append("action", action);
formData.append("token", getAuthToken());
formData.append("domain", domain);
records.forEach(record => {
formData.append("record[]", record);
});
return axios.post(BASE_URL + '/api/v1/bulk/dns/', formData);

View file

@ -17,16 +17,17 @@ export const getBanList = () => {
return axios.get(BASE_URL + banListUri);
}
export const bulkAction = (action, firewalls) => {
export const bulkAction = (action, ips, banIps) => {
const formData = new FormData();
formData.append("action", action);
formData.append("token", getAuthToken());
firewalls.forEach(firewall => {
formData.append("rule[]", firewall);
ips.forEach(ip => {
const banIp = banIps.find(banIp => banIp.NAME === ip);
formData.append("ipchain[]", `${ip}:${banIp['CHAIN']}`);
});
return axios.post(BASE_URL + '/api/v1/bulk/firewall/', formData);
return axios.post(BASE_URL + '/api/v1/bulk/firewall/banlist/', formData);
};
export const handleAction = uri => {
@ -54,11 +55,13 @@ export const getBanIps = data => {
export const addBanIp = (data) => {
let formDataObject = new FormData();
formDataObject.append('token', getAuthToken());
for (let key in data) {
formDataObject.append(key, data[key]);
}
return axios.get(BASE_URL + addBanIpsUri, {
return axios.post(BASE_URL + addBanIpsUri, formDataObject, {
params: {
token: getAuthToken()
}

View file

@ -2,7 +2,7 @@ import axios from "axios";
import { getAuthToken } from "src/utils/token";
const BASE_URL = window.location.origin;
const webApiUri = '/search/search.php';
const webApiUri = '/api/v1/search/';
export const getSearchResultsList = term => {
return axios.get(BASE_URL + webApiUri + '?q=' + term);

View file

@ -1,8 +1,8 @@
import axios from "axios";
import { getAuthToken } from "src/utils/token";
const deleteAutoUpdateUri = '/delete/cron/autoupdate/';
const addAutoUpdateUri = '/add/cron/autoupdate/';
const deleteAutoUpdateUri = '/api/v1/delete/cron/autoupdate/';
const addAutoUpdateUri = '/api/v1/add/cron/autoupdate/';
const webApiUri = '/api/v1/list/updates/index.php';
const BASE_URL = window.location.origin;

View file

@ -0,0 +1,27 @@
import { REFRESH_COUNTERS } from './menuCounterTypes';
import { checkAuth } from 'src/services/session';
import { setAuthToken } from 'src/utils/token';
export const refreshCounters = () => (dispatch, getState) => {
return new Promise((resolve, reject) => {
checkAuth()
.then(res => {
const { data, token } = res.data;
if (token) setAuthToken(token);
dispatch({
type: REFRESH_COUNTERS,
value: {
user: data
}
});
resolve(token);
})
.catch(err => {
reject();
console.error(err);
});
});
}

View file

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

View file

@ -2,6 +2,7 @@ import { LOGIN, LOGOUT, LOGGED_OUT_AS, CHECK_AUTH, RESET_PASSWORD } from './sess
import { checkAuth, signIn, signInAs, signOut } from 'src/services/session';
import { resetPassword } from 'src/ControlPanelService/ResetPassword';
import { resetAuthToken, setAuthToken } from 'src/utils/token';
import { REFRESH_COUNTERS } from '../MenuCounters/menuCounterTypes';
const LOGOUT_RESPONSE = 'logged_out';
const LOGOUT_AS_RESPONSE = 'logged_out_as';
@ -21,10 +22,15 @@ export const login = (user, password) => dispatch => {
session,
i18n: i18n || {},
userName: user,
user: data,
error
},
});
dispatch({
type: REFRESH_COUNTERS,
value: {
user: data,
}
});
resolve(token);
}, (error) => {
reject(error);
@ -44,10 +50,15 @@ export const reset = ({ user = '', code = '', password = '', password_confirm =
panel,
session,
userName: user,
user: {},
error
},
});
dispatch({
type: REFRESH_COUNTERS,
value: {
user: {},
}
});
resolve(token);
}, (error) => {
reject(error);
@ -65,7 +76,6 @@ export const loginAs = username => dispatch => {
type: LOGIN,
value: {
userName: user,
user: data,
i18n,
session,
panel,
@ -73,6 +83,12 @@ export const loginAs = username => dispatch => {
error
}
});
dispatch({
type: REFRESH_COUNTERS,
value: {
user: data,
}
});
resolve(token);
}, (error) => {
@ -94,7 +110,6 @@ export const logout = () => (dispatch, getState) => {
type: LOGOUT,
value: {
userName: '',
user: {},
token: '',
panel: {},
session: {},
@ -102,6 +117,12 @@ export const logout = () => (dispatch, getState) => {
error,
},
});
dispatch({
type: REFRESH_COUNTERS,
value: {
user: {},
}
});
resolve();
} else if (logout_response === LOGOUT_AS_RESPONSE) {
@ -109,7 +130,6 @@ export const logout = () => (dispatch, getState) => {
type: LOGGED_OUT_AS,
value: {
userName,
user,
session,
panel,
token: '',
@ -117,6 +137,12 @@ export const logout = () => (dispatch, getState) => {
error,
},
});
dispatch({
type: REFRESH_COUNTERS,
value: {
user,
}
});
resolve();
} else {
@ -135,11 +161,12 @@ export const checkAuthHandler = () => (dispatch, getState) => {
.then(res => {
const { user, data, session, panel, error, i18n, token } = res.data;
if (token) setAuthToken(token);
dispatch({
type: CHECK_AUTH,
value: {
userName: user,
user: data,
i18n,
session,
panel,
@ -147,6 +174,12 @@ export const checkAuthHandler = () => (dispatch, getState) => {
error
}
});
dispatch({
type: REFRESH_COUNTERS,
value: {
user: data,
}
});
resolve(token);
})

View file

@ -57,7 +57,7 @@ const Backup = props => {
{data.UPDATED === 'no' && <div><a href={`/update/vesta/?pkg=${data.NAME}`}>{i18n.update} <FontAwesomeIcon icon="wrench" /></a></div>}
<div>
<a className="link-download" href={`/download/backup/?backup=${data.NAME}&token=${token}`}>
<a className="link-download" href={`/api/v1/download/backup/?backup=${data.NAME}&token=${token}`}>
{i18n.download}
{data.FOCUSED ? <span className="shortcut-button">D</span> : <FontAwesomeIcon icon={faFileDownload} />}
</a>

View file

@ -11,6 +11,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { Helmet } from 'react-helmet';
import './style.scss';
import HtmlParser from 'react-html-parser';
const EditBackupExclusions = () => {
const token = localStorage.getItem("token");
@ -90,7 +91,7 @@ const EditBackupExclusions = () => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -32,7 +32,7 @@ $errorColor: #BE5ABF;
div.error,
div.success {
width: fit-content !important;
width: max-content !important;
span {
font-weight: bold;
@ -40,6 +40,7 @@ $errorColor: #BE5ABF;
svg {
font-size: 13px;
margin-right: 10px;
}
}
@ -151,10 +152,24 @@ $errorColor: #BE5ABF;
}
}
textarea {
&:focus {
background: #D7F9FF;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
background-color: $primaryLight;
border-color: $primaryActive;
filter: none;
box-shadow: none;
}
input:autofill,
input:autofill:hover,
input:autofill:focus,
input:autofill:active {
background-color: $primaryLight;
border-color: $primaryActive;
filter: none;
box-shadow: none;
}
button {
@ -180,7 +195,7 @@ $errorColor: #BE5ABF;
&:active {
box-shadow: unset;
border-color: $primaryActive;
background: #D7F9FF;
background: #d7dcef9e;
}
}
@ -192,7 +207,7 @@ $errorColor: #BE5ABF;
label.label-wrapper {
display: flex;
align-items: flex-end;
width: fit-content;
width: max-content;
span {
font-weight: normal;

View file

@ -7,11 +7,7 @@ const TextInputWithExtraButton = props => {
});
useEffect(() => {
if (props.value !== 'unlimited') {
setState({ ...state, value: state.previousValue });
} else {
setState({ ...state, value: props.value });
}
setState({ ...state, value: props.value });
}, [props.value]);
useEffect(() => {

View file

@ -27,7 +27,7 @@ const TextInputWithTextOnTheRight = ({ id, title, name, defaultValue = '', optio
onChange={event => setInputValue(event.target.value)}
disabled={disabled}
name={name} />
<span><i>{`admin_${inputValue}`}</i></span>
<span><i>{`${inputValue}`}</i></span>
</div>
</div>
);

View file

@ -12,6 +12,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddCronJob.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddCronJob = props => {
const { i18n } = useSelector(state => state.session);
@ -46,18 +48,17 @@ const AddCronJob = props => {
if (Object.keys(newCronJob).length !== 0 && newCronJob.constructor === Object) {
setState({ ...state, loading: true });
addCronJob(newCronJob)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false })
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -100,7 +101,7 @@ const AddCronJob = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -25,11 +25,11 @@ const CronJob = props => {
const handleSuspend = () => {
let suspendedStatus = data.SUSPENDED === 'yes' ? 'unsuspend' : 'suspend' === 'yes' ? 'unsuspend' : 'suspend';
props.handleModal(data.suspend_conf, `/${suspendedStatus}/cron/index.php?job=${data.NAME}`);
props.handleModal(data.suspend_conf, `/api/v1/${suspendedStatus}/cron/index.php?job=${data.NAME}`);
}
const handleDelete = () => {
props.handleModal(data.delete_conf, `/delete/cron/index.php?job=${data.NAME}`);
props.handleModal(data.delete_conf, `/api/v1/delete/cron/index.php?job=${data.NAME}`);
}
return (

View file

@ -13,6 +13,9 @@ import QS from 'qs';
import './EditCronJob.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditMail = props => {
const token = localStorage.getItem("token");
@ -79,14 +82,14 @@ const EditMail = props => {
updateCronJob(updatedJob, state.data.job)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -128,7 +131,7 @@ const EditMail = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -5,7 +5,6 @@ import SelectInput from 'src/components/ControlPanel/AddItemLayout/Form/SelectIn
import TextInput from 'src/components/ControlPanel/AddItemLayout/Form/TextInput/TextInput';
import AddItemLayout from '../../ControlPanel/AddItemLayout/AddItemLayout';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { addMail } from '../../../ControlPanelService/Mail';
import { addDomainNameSystemRecord } from '../../../ControlPanelService/Dns';
import Toolbar from '../../MainNav/Toolbar/Toolbar';
import { useHistory } from 'react-router-dom';
@ -14,6 +13,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddDNSRecord.scss'
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
export default function AddDNSRecord(props) {
const { i18n } = useSelector(state => state.session);
@ -61,16 +62,18 @@ export default function AddDNSRecord(props) {
newDnsRecord['v_domain'] = props.domain;
if (Object.keys(newDnsRecord).length !== 0 && newDnsRecord.constructor === Object) {
setState({ loading: true });
setState({ ...state, loading: true });
addDomainNameSystemRecord(newDnsRecord)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -94,7 +97,7 @@ export default function AddDNSRecord(props) {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -7,7 +7,6 @@ import { useSelector } from 'react-redux';
export default function DnsRecord({ data, domain, handleModal, ...props }) {
const { i18n } = useSelector(state => state.session);
const token = localStorage.getItem("token");
const toggleFav = (starred) => {
if (starred) {
@ -25,6 +24,10 @@ export default function DnsRecord({ data, domain, handleModal, ...props }) {
handleModal(data.delete_conf, `/api/v1/delete/dns/?domain=${domain}&record_id=${data.ID}`);
}
const handleSuspend = () => {
handleModal(data.suspend_conf, `/api/v1/${data.suspend_action}/dns/?domain=${domain}&record_id=${data.ID}`);
}
return (
<ListItem
id={data.NAME}
@ -62,6 +65,15 @@ export default function DnsRecord({ data, domain, handleModal, ...props }) {
</Link>
</div>
<div>
<button
className="link-gray"
onClick={handleSuspend}>
{data.suspend_action}
{data.FOCUSED ? <span className="shortcut-button">S</span> : <FontAwesomeIcon icon={data.SUSPENDED === 'yes' ? 'unlock' : 'lock'} />}
</button>
</div>
<div>
<button className="link-delete" onClick={() => handleDelete()}>
{i18n.Delete}

View file

@ -11,6 +11,9 @@ import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import QS from 'qs';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
export default function EditDNSRecord(props) {
const token = localStorage.getItem("token");
@ -81,14 +84,14 @@ export default function EditDNSRecord(props) {
updateDNS(updatedRecord, props.domain, props.record_id)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -111,7 +114,7 @@ export default function EditDNSRecord(props) {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { memo, useEffect, useState } from 'react';
import { addActiveElement, removeFocusedElement } from "../../../actions/MainNavigation/mainNavigationActions";
import { dbCharsets, addDatabase, getDbOptionalInfo } from '../../../ControlPanelService/Db';
@ -9,11 +9,12 @@ import Toolbar from '../../MainNav/Toolbar/Toolbar';
import { useHistory } from 'react-router-dom';
import Spinner from '../../Spinner/Spinner';
import { useDispatch, useSelector } from 'react-redux';
import './AddDatabase.scss'
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
import './AddDatabase.scss'
const AddDatabase = props => {
const AddDatabase = memo(props => {
const { i18n } = useSelector(state => state.session);
const token = localStorage.getItem("token");
const dispatch = useDispatch();
@ -91,23 +92,22 @@ const AddDatabase = props => {
newDatabase[name] = value;
}
newDatabase['v_database'] = `${state.user}_${state.databaseInputValue}`;
newDatabase['v_dbuser'] = `${state.user}_${state.databaseUserInputValue}`;
newDatabase['v_database'] = state.databaseInputValue;
newDatabase['v_dbuser'] = state.databaseUserInputValue;
if (Object.keys(newDatabase).length !== 0 && newDatabase.constructor === Object) {
setState({ ...state, loading: true });
addDatabase(newDatabase)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage: '', loading: false });
} else {
setState({ ...state, loading: false })
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -131,7 +131,7 @@ const AddDatabase = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>
@ -141,7 +141,7 @@ const AddDatabase = props => {
<input type="hidden" name="ok" value="add" />
<input type="hidden" name="token" value={token} />
<span className="prefix" dangerouslySetInnerHTML={{ __html: state.prefixI18N }}></span>
<span className="prefix">{HtmlParser(state.prefixI18N)}</span>
<div className="form-group database">
<label htmlFor="database">{i18n.Database}</label>
@ -215,6 +215,6 @@ const AddDatabase = props => {
</AddItemLayout>
</div>
);
}
});
export default AddDatabase;
export default AddDatabase;

View file

@ -14,15 +14,18 @@ import QS from 'qs';
import './EditDatabase.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditDatabase = props => {
const token = localStorage.getItem("token");
const { i18n } = useSelector(state => state.session);
const { i18n, userName } = useSelector(state => state.session);
const history = useHistory();
const dispatch = useDispatch();
const [state, setState] = useState({
data: {},
loading: false,
databaseUserInputValue: '',
errorMessage: '',
okMessage: ''
});
@ -42,6 +45,7 @@ const EditDatabase = props => {
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
@ -60,6 +64,7 @@ const EditDatabase = props => {
}
updatedDatabase['v_database'] = state.data.database;
updatedDatabase['v_dbuser'] = `${userName}_${state.databaseUserInputValue}`;
if (Object.keys(updatedDatabase).length !== 0 && updatedDatabase.constructor === Object) {
setState({ ...state, loading: true });
@ -67,14 +72,14 @@ const EditDatabase = props => {
updateDatabase(updatedDatabase, state.data.database)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -82,6 +87,10 @@ const EditDatabase = props => {
}
}
const databaseUserInputHandler = value => {
setState({ ...state, databaseUserInputValue: value });
}
return (
<div className="edit-template edit-db">
<Helmet>
@ -97,7 +106,7 @@ const EditDatabase = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>
@ -109,7 +118,21 @@ const EditDatabase = props => {
<TextInputWithTextOnTheRight id="database" name="v_database" title={i18n['Database']} defaultValue={state.data.database} disabled />
<TextInputWithTextOnTheRight id="username" name="v_dbuser" title={i18n['User']} defaultValue={state.data.dbuser} />
<div className="form-group">
<div className="label-wrapper">
<label htmlFor="user">{i18n.User}</label>
</div>
<div className="input-wrapper">
<input
type="text"
className="form-control"
id="user"
value={state.databaseUserInputValue}
onChange={event => databaseUserInputHandler(event.target.value)}
name="v_dbuser" />
<span className="italic"><i>{`${userName}_${state.databaseUserInputValue}`}</i></span>
</div>
</div>
<Password name="v_password" defaultValue={state.data.password} />

View file

@ -0,0 +1,9 @@
.input-wrapper {
display: flex;
align-items: center;
span.italic {
margin-left: 15px;
color: #777;
}
}

View file

@ -13,6 +13,8 @@ import './AddDomainNameSystem.scss';
import AdvancedOptions from './AdvancedOptions/AdvancedOptions';
import { addDomainNameSystem } from '../../../ControlPanelService/Dns';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddDomainNameSystem = props => {
const { i18n } = useSelector(state => state.session);
@ -33,7 +35,6 @@ const AddDomainNameSystem = props => {
dispatch(removeFocusedElement());
setState({ ...state, loading: true });
getUserNS()
.then(result => {
if (result.data.length) {
@ -53,18 +54,17 @@ const AddDomainNameSystem = props => {
if (Object.keys(domainNameSystem).length !== 0 && domainNameSystem.constructor === Object) {
setState({ ...state, loading: true });
addDomainNameSystem(domainNameSystem)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -98,7 +98,7 @@ const AddDomainNameSystem = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -13,6 +13,9 @@ import QS from 'qs';
import './EditDomainNameSystem.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditDomainNameSystem = props => {
const token = localStorage.getItem("token");
@ -66,14 +69,14 @@ const EditDomainNameSystem = props => {
updateDNS(updatedDomain, state.data.domain)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -96,7 +99,7 @@ const EditDomainNameSystem = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -12,6 +12,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddFirewall.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddFirewall = props => {
const token = localStorage.getItem("token");
@ -48,18 +50,17 @@ const AddFirewall = props => {
if (Object.keys(newFirewall).length !== 0 && newFirewall.constructor === Object) {
setState({ ...state, loading: true });
addFirewall(newFirewall)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false })
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -83,7 +84,7 @@ const AddFirewall = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,6 +1,6 @@
.content .edit-template.add-firewall {
.toolbar .search-toolbar-name {
width: fit-content;
width: max-content;
}
label.label-wrapper[for=ip] span {

View file

@ -8,6 +8,7 @@ import Toolbar from '../../../MainNav/Toolbar/Toolbar';
import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const AddBanIP = () => {
const { i18n } = useSelector(state => state.session);
@ -42,15 +43,18 @@ const AddBanIP = () => {
}
if (Object.keys(newUser).length !== 0 && newUser.constructor === Object) {
setState({ ...state, loading: true });
addBanIp(newUser)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
if (error_msg) {
setState({ ...state, errorMessage: error_msg, okMessage: '' });
setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
} else if (ok_msg) {
setState({ ...state, errorMessage: '', okMessage: ok_msg });
setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
} else {
setState({ ...state, loading: false });
}
}
})
@ -74,12 +78,14 @@ const AddBanIP = () => {
<div className="search-toolbar-name">{i18n['Adding IP Address to Banlist']}</div>
<div className="error"><span className="error-message">{state.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}</span></div>
<div className="success">
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span> </span>
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span> </span>
</div>
</Toolbar>
<AddItemLayout>
{state.loading ? <Spinner /> :
<form onSubmit={event => submitFormHandler(event)} id="add-user">
<input type="hidden" name="ok" value="add" />
<div class="form-group">
<label htmlFor="chain">{i18n.Banlist}</label>
<select class="form-control" id="chain" name="v_chain">

View file

@ -6,14 +6,13 @@ import { useSelector } from 'react-redux';
const Ban = ({ data, ...props }) => {
const { i18n } = useSelector(state => state.session);
const token = localStorage.getItem("token");
const checkItem = () => {
props.checkItem(data.NAME);
}
const handleDelete = () => {
props.handleModal(data.delete_conf, `/api/v1/delete/firewall/banlist/?ip=${data.NAME}&chain=${data.CHAIN}`);
props.handleModal(data.delete_confirmation, `/api/v1/delete/firewall/banlist/?ip=${data.NAME}&chain=${data.CHAIN}`);
}
return (
@ -32,10 +31,10 @@ const Ban = ({ data, ...props }) => {
<div></div>
</Container>
<Container className="c-2 w-30">
<div>{data.CHAIN}</div>
<div><b>{data.CHAIN}</b></div>
</Container>
<Container className="c-2 w-30">
<div>{data.NAME}</div>
<div><b>{data.NAME}</b></div>
</Container>
</div>
</Container>

View file

@ -13,6 +13,7 @@ import QS from 'qs';
import './EditFirewall.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const EditFirewall = props => {
const token = localStorage.getItem("token");
@ -34,22 +35,26 @@ const EditFirewall = props => {
dispatch(removeFocusedElement());
if (rule) {
setState({ ...state, loading: true });
getFirewallInfo(rule)
.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(rule);
}
}, []);
const fetchData = rule => {
setState({ ...state, loading: true });
getFirewallInfo(rule)
.then(response => {
setState({
...state,
data: response.data,
errorMessage: response.data['error_msg'],
okMessage: response.data['ok_msg'],
loading: false
});
})
.catch(err => console.error(err));
}
const submitFormHandler = event => {
event.preventDefault();
let updatedDomain = {};
@ -61,20 +66,19 @@ const EditFirewall = props => {
if (Object.keys(updatedDomain).length !== 0 && updatedDomain.constructor === Object) {
setState({ ...state, loading: true });
updateFirewall(updatedDomain, state.data.domain)
updateFirewall(updatedDomain, state.data.rule)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
setState({ ...state, okMessage, errorMessage: '', loading: false });
}
}
})
.then(() => fetchData(state.data.rule))
.catch(err => console.error(err));
}
}
@ -94,7 +98,7 @@ const EditFirewall = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -7,19 +7,18 @@ import './Firewall.scss';
import { useSelector } from 'react-redux';
const Firewall = ({ data, ...props }) => {
const token = localStorage.getItem("token");
const { i18n } = useSelector(state => state.session);
const toggleFav = (starred) => {
if (starred) {
props.toggleFav(props.data.NAME, 'add');
props.toggleFav(data.NAME, 'add');
} else {
props.toggleFav(props.data.NAME, 'delete');
props.toggleFav(data.NAME, 'delete');
}
}
const checkItem = () => {
props.checkItem(props.data.NAME);
props.checkItem(data.NAME);
}
const handleSuspend = () => {

View file

@ -14,6 +14,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddInternetProtocol.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddInternetProtocol = props => {
const token = localStorage.getItem("token");
@ -49,18 +51,17 @@ const AddInternetProtocol = props => {
if (Object.keys(newIp).length !== 0 && newIp.constructor === Object) {
setState({ ...state, loading: true });
addInternetProtocol(newIp)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false })
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -96,7 +97,7 @@ const AddInternetProtocol = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -15,6 +15,9 @@ import QS from 'qs';
import './EditInternetProtocol.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditInternetProtocol = () => {
const token = localStorage.getItem("token");
@ -72,8 +75,15 @@ const EditInternetProtocol = () => {
updateInternetProtocol(updatedIP, state.data.ip)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
setState({ ...state, errorMessage: error_msg || '', okMessage: ok_msg || '', loading: false });
const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
.catch(err => console.error(err));
@ -99,7 +109,7 @@ const EditInternetProtocol = () => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -169,8 +169,8 @@ li.inactive {
background: rgb(220, 220, 220);
}
@media (max-width: 1200px){
@media (max-width: 1320px){
.fPermissions, .fOwner {
display: none;
}
}
}

View file

@ -1,4 +1,8 @@
.logs-list {
.toolbar {
padding: 6px 13%;
}
.statistic-item {
.l-col {
font-size: 13px;
@ -25,4 +29,10 @@
color: #5edad0;
}
}
}
@media (max-width: 1350px) {
.logs-list .toolbar {
padding: 6px 9.5%;
}
}

View file

@ -11,6 +11,9 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddMail.scss'
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddMail = props => {
const { i18n } = useSelector(state => state.session);
@ -40,15 +43,18 @@ const AddMail = props => {
}
if (Object.keys(newMailDomain).length !== 0 && newMailDomain.constructor === Object) {
setState({ ...state, loading: true });
addMail(newMailDomain)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
if (error_msg) {
setState({ ...state, errorMessage: error_msg, okMessage: '' });
} else if (ok_msg) {
setState({ ...state, errorMessage: '', okMessage: ok_msg });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -72,7 +78,7 @@ const AddMail = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -13,6 +13,9 @@ import QS from 'qs';
import './EditMail.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditMail = props => {
const token = localStorage.getItem("token");
@ -66,14 +69,14 @@ const EditMail = props => {
updateMail(updatedDomain, state.data.domain)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -96,7 +99,7 @@ const EditMail = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -62,7 +62,7 @@ const Mail = props => {
</Container>
<Container className="c-3">
{printStat(i18n['AntiSpam Support'], data.ANTISPAM)}
<div>{i18n['Catchall email']}: <span className="stat">{data.CATCHALL}</span></div>
<div>{i18n['Catchall email']}: <span className="stat catchall-mail">{data.CATCHALL}</span></div>
</Container>
</div>
</Container>

View file

@ -1,3 +1,7 @@
.crossed {
text-decoration: line-through;
}
}
.catchall-mail {
text-transform: none;
}

View file

@ -17,6 +17,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddMailAccount.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
export default function AddMailAccount(props) {
const { i18n } = useSelector(state => state.session);
@ -26,6 +28,7 @@ export default function AddMailAccount(props) {
const [state, setState] = useState({
data: {},
advancedOptions: false,
autoreplyChecked: false,
quotaValue: '',
loading: false,
password: '',
@ -54,15 +57,18 @@ export default function AddMailAccount(props) {
newMailDomain['Password'] = newMailDomain['v_password'];
if (Object.keys(newMailDomain).length !== 0 && newMailDomain.constructor === Object) {
setState({ ...state, loading: true });
addMailAccount(newMailDomain, props.domain)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
if (error_msg) {
setState({ ...state, errorMessage: error_msg, okMessage: '' });
} else if (ok_msg) {
setState({ ...state, errorMessage: '', okMessage: ok_msg });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -114,7 +120,7 @@ export default function AddMailAccount(props) {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,6 +1,6 @@
.content .edit-template.add-mail-account {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
form {
@ -21,10 +21,25 @@
}
}
}
.form-group:nth-child(3) {
> div {
display: flex;
input {
width: 100%;
}
input + button {
padding-left: 10px;
}
}
}
}
.c-2 {
width: 45%;
height: 100%;
border: 1px solid #d9d9d9;
padding: 0px 5px 12px 20px;
}

View file

@ -15,6 +15,9 @@ import { useHistory } from 'react-router-dom';
import Spinner from '../../Spinner/Spinner';
import { useDispatch, useSelector } from 'react-redux';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
export default function EditMailAccount(props) {
const [autoreplyChecked, setAutoreplyChecked] = useState(false);
@ -56,13 +59,14 @@ export default function EditMailAccount(props) {
editMailAccount(newMailDomain, props.domain, props.account)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
if (error_msg) {
setState({ ...state, errorMessage: error_msg, okMessage: '', loading: false });
} else if (ok_msg) {
goBack();
setState({ ...state, errorMessage: '', okMessage: ok_msg, loading: false });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -88,12 +92,9 @@ export default function EditMailAccount(props) {
.catch(err => console.error(err));
}
const toggleQuotaValue = () => {
if (state.quotaValue !== 'unlimited') {
setState({ ...state, quotaValue: 'unlimited' });
} else {
setState({ ...state, quotaValue: '' });
}
const toggleQuota = () => {
const value = state.data.quota === 'unlimited' ? '1000' : 'unlimited';
setState({ ...state, data: { ...state.data, quota: value } });
}
const goBack = () => {
@ -116,7 +117,7 @@ export default function EditMailAccount(props) {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>
@ -135,13 +136,58 @@ export default function EditMailAccount(props) {
id="domain"
disabled />
<TextInput
title={i18n['Account']}
value={props.account}
name="v_account"
id="account" />
<Password name="v_password" onChange={password => setState({ ...state, password })} />
<TextInputWithExtraButton title={i18n['Quota']} optionalTitle={i18n['in megabytes']} id="quota" name="v_quota" value={state.data.quota}>
<button type="button" onClick={toggleQuota}>
<FontAwesomeIcon icon="infinity" />
</button>
</TextInputWithExtraButton>
<TextArea
optionalTitle={`${i18n['use local-part']}`}
defaultValue={state.data.aliases}
title={i18n['Aliases']}
name="v_aliases"
id="aliases" />
<TextArea
optionalTitle={`${i18n['one or more email addresses']}`}
defaultValue={state.data.fwd}
title={i18n['Forward to']}
name="v_fwd"
id="fwd" />
<Checkbox
title={i18n['Do not store forwarded mail']}
defaultChecked={state.data.fwd_only === 'yes'}
name="v_fwd_only"
id="fwd_only" />
<Checkbox
title={i18n['Autoreply']}
checked={autoreplyChecked}
onChange={checked => setAutoreplyChecked(checked)}
name="v_autoreply"
id="autoreply" />
{
autoreplyChecked && (
<div style={{ transform: 'translateX(3rem)' }}>
<TextArea
defaultValue={state.data.autoreply_message}
title={i18n['Message']}
name="v_autoreply_message"
id="autoreply_message" />
</div>
)
}
<TextInput
title={i18n['Send login credentials to email address']}
value={state.data.send_email}
name="v_credentials"
id="credentials" />
</div>
<div className="c-2">
@ -153,59 +199,6 @@ export default function EditMailAccount(props) {
</div>
</div>
<div className="r-2">
<TextInputWithExtraButton title={i18n['Quota']} optionalTitle={i18n['in megabytes']} id="quota" name="v_quota" value={state.data.quota}>
<button type="button" onClick={toggleQuotaValue}>
<FontAwesomeIcon icon="infinity" />
</button>
</TextInputWithExtraButton>
<TextArea
optionalTitle={`${i18n['use local-part']}`}
defaultValue={state.data.aliases}
title={i18n['Aliases']}
name="v_aliases"
id="aliases" />
<TextArea
optionalTitle={`${i18n['one or more email addresses']}`}
defaultValue={state.data.fwd}
title={i18n['Forward to']}
name="v_fwd"
id="fwd" />
<Checkbox
title={i18n['Do not store forwarded mail']}
defaultChecked={state.data.fwd_only === 'yes'}
name="v_fwd_only"
id="fwd_only" />
<Checkbox
title={i18n['Autoreply']}
checked={autoreplyChecked}
onChange={checked => setAutoreplyChecked(checked)}
name="v_fwd_only"
id="fwd_only" />
{
autoreplyChecked && (
<div style={{ transform: 'translateX(3rem)' }}>
<TextArea
defaultValue={state.data.autoreply_message}
title={i18n['Message']}
name="v_autoreply_message"
id="autoreply_message" />
</div>
)
}
<TextInput
title={i18n['Send login credentials to email address']}
value={state.data.send_email}
name="v_credentials"
id="credentials" />
</div>
<div className="buttons-wrapper">
<button type="submit" className="add">{i18n.Add}</button>
<button type="button" className="back" onClick={goBack}>{i18n.Back}</button>

View file

@ -1,3 +1,5 @@
$primary: #2c54ac;
.mail-info-block {
.select-group {
select {
@ -5,7 +7,7 @@
margin-top: 5px;
padding: 0;
border: none;
color: #2c9491;
color: $primary;
text-transform: uppercase;
font-size: 11px;
font-weight: bold;

View file

@ -18,7 +18,8 @@ const MainNav = () => {
showTopNav: false
});
const { userName, user, session: { look } } = useSelector(state => state.session);
const { userName, session: { look } } = useSelector(state => state.session);
const { user } = useSelector(state => state.menuCounters);
const { activeElement, focusedElement, adminMenuTabs, userMenuTabs } = useSelector(state => state.mainNavigation);
const { controlPanelFocusedElement } = useSelector(state => state.controlPanelContent);
const dispatch = useDispatch();

View file

@ -5,6 +5,7 @@ import Bell from './Bell';
import BellUnread from './BellUnread';
import { useDispatch, useSelector } from 'react-redux';
import './Notifications.scss';
import HtmlParser from 'react-html-parser';
const Notifications = () => {
const { i18n } = useSelector(state => state.session);
@ -13,8 +14,10 @@ const Notifications = () => {
const [loading, setLoading] = useState(false);
useEffect(() => {
fetchData();
}, []);
if (!notifications) {
fetchData();
}
}, [notifications]);
const fetchData = () => {
setLoading(true);
@ -32,7 +35,7 @@ const Notifications = () => {
.catch(err => {
console.error(err);
setLoading(false);
})
});
}
const removeNotification = id => {
@ -44,7 +47,7 @@ const Notifications = () => {
}
const renderOptions = () => {
if (notifications.length) {
if (notifications && notifications.length) {
return notifications.map(item => {
return (
<>
@ -52,7 +55,7 @@ const Notifications = () => {
<span className="title"><b>{item.TOPIC}</b></span>
<span className="delete-notification" onClick={() => removeNotification(item.ID)}></span>
</div>
<div dangerouslySetInnerHTML={{ __html: item.NOTICE }}></div>
<div>{HtmlParser(item.NOTICE)}</div>
<div className="dropdown-divider"></div>
</>
);
@ -71,7 +74,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.length
notifications && notifications.length
? <BellUnread />
: <Bell />
}

View file

@ -56,7 +56,6 @@ const Panel = props => {
dispatch(logout())
.then(() => {
history.push('/login/');
setLoading(false);
},
error => {
@ -69,7 +68,7 @@ const Panel = props => {
<div className="panel-wrapper">
{loading && <Spinner />}
<div className={`top-panel ${user ? 'long-profile' : ''}`}>
<div className={`top-panel ${look ? 'long-profile' : ''}`}>
<div className="container left-menu">
<div className="logo">
<Link to="/list/user/" onClick={() => dispatch(addActiveElement('/list/user/'))}>
@ -103,7 +102,7 @@ const Panel = props => {
<Link to="/list/firewall/" onClick={event => handleState("/list/firewall/", event)} onKeyPress={event => event.preventDefault()}>{i18n.Firewall}</Link>
</div>}
</>)}
{session.session.FILEMANAGER_KEY && <div className={className("/list/directory/", "fm")}>
{session.session.FILEMANAGER_KEY && <div className={className("/list/directory/")}>
<Link to="/list/directory/">{i18n['File Manager']}</Link>
</div>}
{session.session.SOFTACULOUS === "yes" && <div className={className("/softaculous/")}><a href="/softaculous/">{i18n.Apps ?? 'Apps'}</a>

View file

@ -52,7 +52,7 @@ $textColor: #555;
display: flex;
justify-content: center;
align-items: center;
padding: 0 5px;
padding: 0 10px !important;
width: 100%;
height: 100%;
text-decoration: none;
@ -93,14 +93,15 @@ $textColor: #555;
}
.left-menu {
width: 80%;
width: 75%;
padding-left: 0;
margin-left: 0;
justify-content: space-between;
div {
width: 7rem;
flex: 1 1 auto;
height: 100%;
transform: translateX(-5px);
padding-right: 5px;
&:hover {
background: $secondaryLight;
@ -108,8 +109,19 @@ $textColor: #555;
}
div.logo {
img {
width: 90%;
width: 7rem;
padding-left: 0;
a {
div {
padding: 0;
width: 6rem;
flex: none;
img {
width: 90%;
}
}
}
&:hover {
@ -129,7 +141,7 @@ $textColor: #555;
}
.profile-menu {
width: 20%;
width: auto;
div {
width: 4rem;
@ -189,11 +201,24 @@ $textColor: #555;
.top-panel.long-profile {
.left-menu {
width: 75%;
justify-content: start;
> div {
width: max-content;
flex: unset;
padding: 0 1rem;
}
.logo {
width: 7rem;
padding: 0;
margin-right: 1rem;
}
}
.profile-menu {
width: 25%;
justify-content: space-between;
align-items: center;
> div + div {
width: max-content;

View file

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

View file

@ -81,12 +81,6 @@ $textColor: #555;
.servers-list,
.exclusions-list {
.l-menu {
&.server-icon {
a, span.add {
background: $primary;
}
}
&.backup-details-icon {
transform: translateX(2px);
}

View file

@ -20,6 +20,14 @@ const SearchInput = props => {
return () => window.removeEventListener("keyup", focusInput);
}, []);
const onSubmit = e => {
e.preventDefault();
if (searchTerm) {
handleClick();
}
}
const focusInput = event => {
if (event.keyCode === 70) {
return inputElement.current.focus();
@ -27,11 +35,13 @@ const SearchInput = props => {
}
return (
<div className="search-input-form">
<input type="text" className="form-control" onChange={e => setSearchTerm(e.target.value)} ref={inputElement} />
<button className="btn btn-outline-secondary" type="submit" onClick={() => handleClick()}><FontAwesomeIcon icon="search" /></button>
</div>
<form onSubmit={onSubmit}>
<div className="search-input-form">
<input type="text" className="form-control" onChange={e => setSearchTerm(e.target.value)} ref={inputElement} />
<button className="btn btn-outline-secondary" type="submit" onClick={() => handleClick()}><FontAwesomeIcon icon="search" /></button>
</div>
</form>
);
}
export default SearchInput;
export default SearchInput;

View file

@ -4,7 +4,7 @@ import { values } from '../../../../ControlPanelService/Select';
import { useSelector } from 'react-redux';
import './Select.scss';
const Select = props => {
const Select = ({ cronReports, ...props }) => {
const { i18n } = useSelector(state => state.session);
const listValues = values(i18n);
@ -44,6 +44,14 @@ const Select = props => {
const { list } = props;
let activeList = state[list];
if (list === 'cronList') {
if (cronReports) {
activeList = activeList.filter((item, index) => index !== 0);
} else {
activeList = activeList.filter((item, index) => index !== 1);
}
}
if (list === 'statisticsList') {
return props.users.map((item, index) => { return <option key={index} value={item}>{item}</option> });
} else {

View file

@ -1,3 +1,16 @@
$primary: #2c54ac;
$whiteBackground: #ececec;
$primary: #2c54ac;
$primaryLight: #d7dcef;
$primaryActive: #1e5cb2;
$secondary: #fcac04;
$secondaryLight: #f8b014;
$danger: #b00e5b;
$secondaryActive: #fdb51c;
$hoverButtonText: #2c54ac;
$activeButtonText: #fff;
$textColor: #555;
.toolbar {
display: flex;
flex-direction: row;
@ -8,16 +21,17 @@
left: 0;
width: 100%;
z-index: 1;
padding: 0 13%;
padding: 3px 13% 1px;
border-top: 1px solid #e0e0e0;
border-bottom: 1px solid #e0e0e0;
padding-top: 5px;
.r-menu {
display: flex;
justify-content: center;
align-items: center;
a.button-extra, button.button-extra {
a.button-extra,
button.button-extra {
background: none;
border: none;
padding: 0 0.75rem;
@ -27,9 +41,17 @@
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
border-radius: 3px;
&:hover {
color: rgb(78, 76, 76);
background: $primaryLight;
color: $hoverButtonText;
}
&:active {
background: $primaryActive;
color: $activeButtonText;
}
}
@ -131,7 +153,7 @@
@media (max-width: 1350px) {
.toolbar {
padding: 5px 10% 0;
padding: 3px 10% 1px;
}
}

View file

@ -36,6 +36,8 @@ $black: #000;
margin-top: 100px;
.modal-body {
overflow-wrap: anywhere;
font-size: 17px;
margin-bottom: 40px;
input {

View file

@ -15,6 +15,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddPackage.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddPackage = props => {
const token = localStorage.getItem("token");
@ -89,18 +91,17 @@ const AddPackage = props => {
if (Object.keys(newPackage).length !== 0 && newPackage.constructor === Object) {
setState({ ...state, loading: true });
addPackage(newPackage)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false })
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -141,7 +142,7 @@ const AddPackage = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -3,7 +3,7 @@
label.label-wrapper {
display: flex;
align-items: flex-end;
width: fit-content;
width: max-content;
span {
font-weight: normal;

View file

@ -16,6 +16,9 @@ import QS from 'qs';
import './EditPackage.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditPackage = props => {
const token = localStorage.getItem("token");
@ -70,9 +73,15 @@ const EditPackage = props => {
updatePackage(updatedPackage, state.data.package)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
setState({ ...state, errorMessage: error_msg || '', okMessage: ok_msg || '', loading: false });
history.push('/list/package/');
const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
.catch(err => console.error(err));
@ -113,7 +122,7 @@ const EditPackage = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -9,7 +9,6 @@ import { useSelector } from 'react-redux';
const Package = props => {
const { data } = props;
const { i18n } = useSelector(state => state.session);
const token = localStorage.getItem("token");
const printNameServers = servers => {
let serversArray = servers.split(',');
@ -32,7 +31,7 @@ const Package = props => {
}
const handleDelete = () => {
props.handleModal(data.delete_conf, `/api/v1/delete/package?package=${data.NAME}`);
props.handleModal(data.delete_conf, `/api/v1/delete/package/index.php?package=${data.NAME}`);
}
return (

View file

@ -5,13 +5,13 @@ import Dropdown from './Dropdown/Dropdown';
import './Path.scss';
const Path = ({ path, isActive, className, openDirectory, changeSorting, sorting, order }) => {
const session = useSelector(state => state.session);
const { user } = useSelector(state => state.menuCounters);
const clickablePath = () => {
let splitPath = path.split('/');
splitPath.splice(0, 3);
if (path !== session.user.HOME) {
if (path !== user.HOME) {
return (
splitPath.map((item, index) => <span className="clickable" key={index} onClick={() => openDirectoryHandler(index)}>&nbsp;/&nbsp;{item}</span>)
);
@ -36,7 +36,7 @@ const Path = ({ path, isActive, className, openDirectory, changeSorting, sorting
<div className={className}>
<div className="clickable-wrapper">
<span className="clickable-path">
<span className="clickable" onClick={() => openDirectory(session.user.HOME)}>{session.user.HOME}</span>
<span className="clickable" onClick={() => openDirectory(user.HOME)}>{user.HOME}</span>
{clickablePath()}
</span>
</div>

View file

@ -17,7 +17,7 @@ const RRD = props => {
let year = newDate.getFullYear();
let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
return <div className="date">{day} &nbsp; {months[month - 1]} &nbsp; {year}</div>;
return <div className="date">{day} &nbsp; {months[month]} &nbsp; {year}</div>;
}
return (

View file

@ -1,13 +1,54 @@
import React from 'react';
import { loginAs, logout } from 'src/actions/Session/sessionActions';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import ListItem from '../ControlPanel/ListItem/ListItem';
import Container from '../ControlPanel/Container/Container';
import { useSelector } from 'react-redux';
import ListItem from '../ControlPanel/ListItem/ListItem';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useHistory } from 'react-router-dom';
import './SearchItem.scss';
import { Link } from 'react-router-dom';
const SearchItem = ({ data, handleModal }) => {
const { i18n } = useSelector(state => state.session);
const { i18n, userName } = useSelector(state => state.session);
const dispatch = useDispatch();
const history = useHistory()
const signInAs = user => {
dispatch(loginAs(user)).then(() => history.push('/'));
}
const signOut = () => {
dispatch(logout()).then(() => history.push('/'));
}
const handleDelete = () => {
handleModal(data.delete_confirmation, `/api/v1/${data.TYPE === 'user' ? `/api/v1/delete/user/index.php?user=${data.USER}` : data.delete_link}`);
}
const handleSuspend = () => {
handleModal(data.spnd_confirmation, `/api/v1/${data.TYPE === 'user' ? `${data.spnd_action}/user/index.php?user=${data.USER}` : data.spnd_link}`);
}
const printLoginActionButton = () => {
if (data.TYPE !== 'user') return;
if (userName === data.USER) {
return (
<div>
<button onClick={signOut}>{i18n['Log out']}
{data.FOCUSED ? <span className="shortcut-button">L</span> : <FontAwesomeIcon icon="user-lock" />}
</button>
</div>
);
} else {
return (
<div>
<button onClick={() => signInAs(data.USER)}>{i18n['login as']} {data.USER}
{data.FOCUSED ? <span className="shortcut-button">L</span> : <FontAwesomeIcon icon="user-lock" />}
</button>
</div>
);
}
}
return (
<ListItem date={data.DATE} suspended={data.SUSPENDED === 'yes'}>
@ -15,7 +56,7 @@ const SearchItem = ({ data, handleModal }) => {
<div className="name">{data.RESULT}</div>
<div className="stats">
<Container className="c-1">
<div className="object">{i18n[data.object]}</div>
<div className="object">{data.TYPE === 'user' ? i18n['USER'] : i18n[data.object]}</div>
</Container>
<Container className="c-2">
<div className="owner">{i18n.Owner}: <span>{data.USER}</span></div>
@ -26,17 +67,20 @@ const SearchItem = ({ data, handleModal }) => {
</div>
</Container>
<div className="actions">
{printLoginActionButton()}
<div><Link className="link-edit" to={data.edit_link}>{i18n.edit} <FontAwesomeIcon icon="pen" /></Link></div>
<div>
<button
className="link-gray"
onClick={() => handleModal(data.spnd_confirmation, '/api/v1' + data.spnd_link)}>
onClick={handleSuspend}>
{data.spnd_action}
<FontAwesomeIcon icon={data.SUSPENDED === 'yes' ? 'unlock' : 'lock'} />
</button>
</div>
<div>
<button className="link-delete" onClick={() => this.props.handleModal(data.delete_confirmation, data, data.delete_link)}>
<button
className="link-delete"
onClick={handleDelete}>
{i18n.Delete}
<FontAwesomeIcon icon="times" />
</button>

View file

@ -12,6 +12,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './Bind9.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const Bind9 = () => {
const token = localStorage.getItem("token");
@ -94,7 +95,7 @@ const Bind9 = () => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,7 +1,7 @@
.content .edit-template.edit-bind9 {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
}

View file

@ -12,6 +12,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './Dovecot.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const Dovecot = () => {
const token = localStorage.getItem("token");
@ -94,7 +95,7 @@ const Dovecot = () => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,7 +1,7 @@
.content .edit-template.edit-bind9 {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
}

View file

@ -19,6 +19,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './EditServer.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const EditServer = props => {
const token = localStorage.getItem("token");
@ -106,7 +107,7 @@ const EditServer = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -121,7 +121,7 @@ $textColor: #555;
padding: 7px 15px;
text-transform: capitalize;
text-decoration: none;
width: fit-content;
width: max-content;
margin-right: 10px;
&:hover {

View file

@ -12,6 +12,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './EditHttpd.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const EditHttpd = props => {
const token = localStorage.getItem("token");
@ -89,7 +90,7 @@ const EditHttpd = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -4,7 +4,7 @@ $secondaryLight: #f8b014;
.content .edit-template.edit-httpd {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
a {
color: $secondary;
@ -17,7 +17,7 @@ $secondaryLight: #f8b014;
}
.link {
width: fit-content;
width: max-content;
margin-left: 15px;
a {

View file

@ -13,6 +13,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './Mysql.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const Mysql = ({ serviceName = '' }) => {
const token = localStorage.getItem("token");
@ -107,7 +108,7 @@ const Mysql = ({ serviceName = '' }) => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,7 +1,7 @@
.content .edit-template.edit-mysql {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
}

View file

@ -13,6 +13,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './EditServerNginx.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const EditServerNginx = props => {
const token = localStorage.getItem("token");
@ -100,7 +101,7 @@ const EditServerNginx = props => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -3,11 +3,11 @@ $secondaryLight: #f8b014;
.content .edit-template.edit-nginx {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
.link {
width: fit-content;
width: max-content;
margin-left: 15px;
a {

View file

@ -13,6 +13,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './EditPhp.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const EditPhp = ({ serviceName = '' }) => {
const token = localStorage.getItem("token");
@ -104,7 +105,7 @@ const EditPhp = ({ serviceName = '' }) => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -5,13 +5,13 @@ $textColor: #555;
.content .edit-template.edit-php {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
color: $textColor;
}
.search-toolbar-name,
.link {
width: fit-content;
width: max-content;
a {
text-decoration: none;

View file

@ -12,6 +12,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './Postgresql.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const Postgresql = () => {
const token = localStorage.getItem("token");
@ -94,7 +95,7 @@ const Postgresql = () => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,7 +1,7 @@
.content .edit-template.edit-pgsql {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
}

View file

@ -12,6 +12,7 @@ import { useDispatch, useSelector } from 'react-redux';
import './Service.scss';
import { Helmet } from 'react-helmet';
import HtmlParser from 'react-html-parser';
const Service = ({ serviceName = '' }) => {
const token = localStorage.getItem("token");
@ -100,7 +101,7 @@ const Service = ({ serviceName = '' }) => {
</div>
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -1,7 +1,7 @@
.content .edit-template.edit-service {
.toolbar {
.search-toolbar-name {
width: fit-content;
width: max-content;
}
}

View file

@ -10,12 +10,6 @@ const Server = props => {
const { data } = props;
const { i18n } = useSelector(state => state.session);
const printTime = seconds => {
let hours = seconds / 60;
let days = Math.floor(hours / 24);
return days;
}
const checkItem = () => {
props.checkItem(data.NAME);
}
@ -41,7 +35,7 @@ const Server = props => {
<div><span>{i18n.Memory}: <span className="stat">{data.MEM} {i18n.mb}</span></span></div>
</Container>
<Container className="c-3">
<div><span>{i18n.Uptime}: <span className="stat">{printTime(data.RTIME)} {i18n.days}</span></span></div>
<div><span>{i18n.Uptime}: <span className="stat">{data.RTIME}</span></span></div>
</Container>
<Container className="c-1" />
</div>

View file

@ -9,13 +9,6 @@ import { useSelector } from 'react-redux';
const Server = props => {
const { data } = props;
const { i18n } = useSelector(state => state.session);
const token = localStorage.getItem("token");
const printTime = seconds => {
let hours = seconds / 60;
let days = Math.floor(hours / 24);
return days;
}
const checkItem = () => {
props.checkItem(props.data.HOSTNAME);
@ -39,7 +32,7 @@ const Server = props => {
<div>{i18n['Load Average']}: <span><span className="stat">{data.LOADAVERAGE}</span></span></div>
</Container>
<Container className="c-3">
<div><span>{i18n.Uptime}: <span className="stat">{printTime(data.UPTIME)} {i18n.days}</span></span></div>
<div><span>{i18n.Uptime}: <span className="stat">{data.UPTIME}</span></span></div>
</Container>
</div>
</Container>

View file

@ -10,10 +10,9 @@ import './TopPanel.scss';
const TopPanel = ({ menuItems = [], extraMenuItems = [] }) => {
const mainNavigation = useSelector(state => state.mainNavigation);
const [loading, setLoading] = useState(false);
const { i18n } = useSelector(state => state.session);
const { i18n, userName } = useSelector(state => state.session);
const dispatch = useDispatch();
const history = useHistory();
const { userName } = useSelector(state => state.session);
const className = cls => {
let className = 'nav-link';

View file

@ -13,6 +13,9 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddUser.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddUser = props => {
const { i18n } = useSelector(state => state.session);
@ -71,19 +74,23 @@ const AddUser = props => {
}
if (Object.keys(newUser).length !== 0 && newUser.constructor === Object) {
setState({ ...state, loading: true });
addUser(newUser)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = result.data;
if (error_msg) {
setState({ ...state, errorMessage: error_msg, okMessage: '' });
} else if (ok_msg) {
setState({ ...state, errorMessage: '', okMessage: ok_msg });
}
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
})
.catch(err => console.error(err));
.catch(err => {
setState({ ...state, loading: false });
console.error(err);
});
}
}
@ -133,7 +140,7 @@ const AddUser = props => {
<div className="search-toolbar-name">{i18n['Adding User']}</div>
<div className="error"><span className="error-message">{state.errorMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} {state.errorMessage}</span></div>
<div className="success">
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span> </span>
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span> </span>
</div>
</Toolbar>
<AddItemLayout>

View file

@ -15,6 +15,9 @@ import QS from 'qs';
import './EditUser.scss';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditUser = props => {
const token = localStorage.getItem("token");
@ -68,14 +71,14 @@ const EditUser = props => {
updateUser(updatedUser, state.username)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -103,7 +106,7 @@ const EditUser = props => {
<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="success">
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span> </span>
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span> </span>
</div>
</Toolbar>
<AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>

View file

@ -9,9 +9,8 @@ import { Link } from 'react-router-dom';
import './User.scss';
const User = ({ data, toggleFav, handleModal, checkItem }) => {
const { i18n } = useSelector(state => state.session);
const { i18n, userName } = useSelector(state => state.session);
const session = useSelector(state => state.session);
const token = localStorage.getItem("token");
const dispatch = useDispatch();
const printNameServers = servers => {

View file

@ -39,6 +39,7 @@ $textColor: #555;
span.stat.email{
display: block;
width: max-content;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;

View file

@ -13,6 +13,8 @@ import { useDispatch, useSelector } from 'react-redux';
import './AddWebDomain.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const AddWebDomain = props => {
const { i18n } = useSelector(state => state.session);
@ -37,7 +39,6 @@ const AddWebDomain = props => {
dispatch(removeFocusedElement());
setState({ ...state, loading: true });
Promise.all([getWebStats(), getIpList()])
.then(result => {
const [webStats, internetProtocols] = result;
@ -94,12 +95,14 @@ const AddWebDomain = props => {
addWeb(newWebDomain)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -123,7 +126,7 @@ const AddWebDomain = props => {
<div className="success">
<span className="ok-message">
{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''}
<span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span>
<span>{HtmlParser(state.okMessage)}</span>
</span>
</div>
</Toolbar>

View file

@ -5,10 +5,10 @@ import Password from '../../../../components/ControlPanel/AddItemLayout/Form/Pas
import './AdditionalFtpForEditing.scss';
const AdditionalFtpForEditing = ({ domain, data = {}, onDeleteAdditionalFtp, prefixI18N, prePath, checked }) => {
const { userName, i18n } = useSelector(state => state.session);
const AdditionalFtpForEditing = ({ domain, data = {}, onDeleteAdditionalFtp, prefixI18N, prePath, checked, ...props }) => {
const { i18n, userName } = useSelector(state => state.session);
const [state, setState] = useState({
username: data.v_ftp_user,
username: data.v_ftp_user || '',
path: ''
});
@ -29,72 +29,73 @@ const AdditionalFtpForEditing = ({ domain, data = {}, onDeleteAdditionalFtp, pre
return <></>;
}
return (<div className="additional-ftp">
<div className="title">
<input type="hidden" name={`v_ftp_user[${data.id}][delete]`} value="0" />
<input type="hidden" name={`v_ftp_user[${data.id}][is_new]`} value="1" />
return (
<div className="additional-ftp">
<div className="title">
<input type="hidden" name={`v_ftp_user[${data.id}][delete]`} value="0" />
<input type="hidden" name={`v_ftp_user[${data.id}][is_new]`} value="1" />
<span className="data.indexed-name">{i18n.FTP} #{data.id + 1}</span>
<span>
&nbsp;
<button
type="button"
onClick={() => onDeleteAdditionalFtp(data.id)}>
({i18n.Delete ?? 'Delete'})
</button>
</span>
</div>
<div className="form-transform">
<div className="form-group username">
<label htmlFor={`ftp_user_${data.id}`}>{i18n.Username}</label>
<span className="prefix-note">{prefixI18N}</span>
<div className="input-wrapper">
<input
defaultValue={state.username}
onChange={event => setState({ ...state, username: event.target.value })}
type="text"
disabled={data.v_ftp_user}
className="form-control"
id={`ftp_user_${data.id}`}
name={`v_ftp_user[${data.id}][v_ftp_user]`} />
<span>{`${userName}_${state.username}`}</span>
</div>
<span className="data.indexed-name">{i18n.FTP} #{data.id + 1}</span>
<span>
&nbsp;
<button
type="button"
onClick={() => onDeleteAdditionalFtp(data.id)}>
({i18n.Delete ?? 'Delete'})
</button>
</span>
</div>
<Password name={`v_ftp_user[${data.id}][v_ftp_password]`} id={data.id} />
<div className="form-group">
<input type="hidden" name="v_ftp_pre_path" value={prePath} />
<input type="hidden" name={`v_ftp_user[${data.id}][v_ftp_path_prev]`} value={data.v_ftp_path !== '/' ? '/' : ''} />
<label htmlFor={`path${data.id}`}>{i18n.Path}</label>
<input
type="text"
value={state.path}
onChange={event => setState({ ...state, path: event.target.value })}
className="form-control"
id={`path${data.id}`}
name={`v_ftp_user[${data.id}][v_ftp_path]`} />
<span className="path-note">{`${data.v_ftp_pre_path ? data.v_ftp_pre_path : ''}/${state.path}`}</span>
</div>
{
data.is_new === 1 && (
<div className="form-group">
<label htmlFor={`sendLoginCredentialsToEmailAddress_${data.id}`}>{i18n['Send login credentials to email address']}</label>
<div className="form-transform">
<div className="form-group username">
<label htmlFor={`ftp_user_${data.id}`}>{i18n.Username}</label>
<span className="prefix-note">{prefixI18N}</span>
<div className="input-wrapper">
<input
type="email"
defaultValue={state.username}
onChange={event => setState({ ...state, username: event.target.value })}
type="text"
disabled={data.v_ftp_user}
className="form-control"
id={`sendLoginCredentialsToEmailAddress_${data.id}`}
defaultValue={data.v_ftp_email}
name={`v_ftp_user[${data.id}][v_ftp_email]`} />
id={`ftp_user_${data.id}`}
name={`v_ftp_user[${data.id}][v_ftp_user]`} />
<span>{data.v_ftp_user ? data.v_ftp_user : `${userName}_${state.username}`}</span>
</div>
)
}
</div>
</div>
</div >);
<Password name={`v_ftp_user[${data.id}][v_ftp_password]`} id={data.id} />
<div className="form-group">
<input type="hidden" name="v_ftp_pre_path" value={prePath} />
<input type="hidden" name={`v_ftp_user[${data.id}][v_ftp_path_prev]`} value={data.v_ftp_path !== '/' ? '/' : ''} />
<label htmlFor={`path${data.id}`}>{i18n.Path}</label>
<input
type="text"
value={state.path}
onChange={event => setState({ ...state, path: event.target.value })}
className="form-control"
id={`path${data.id}`}
name={`v_ftp_user[${data.id}][v_ftp_path]`} />
<span className="path-note">{prePath}</span>
</div>
{
data.is_new === 1 && (
<div className="form-group">
<label htmlFor={`sendLoginCredentialsToEmailAddress_${data.id}`}>{i18n['Send login credentials to email address']}</label>
<input
type="email"
className="form-control"
id={`sendLoginCredentialsToEmailAddress_${data.id}`}
defaultValue={data.v_ftp_email}
name={`v_ftp_user[${data.id}][v_ftp_email]`} />
</div>
)
}
</div>
</div >);
}
return <></>;

View file

@ -1,34 +1,35 @@
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import AdditionalFtp from '../AdditionalFtp/AdditionalFtp';
import AdditionalFtpForEditing from '../AdditionalFtpForEditing/AdditionalFtpForEditing';
import './AdditionalFtpWrapper.scss';
const AdditionalFtpWrapper = props => {
const AdditionalFtpWrapper = ({ checked, ftps, unCheckAdditionalFtpBox, prefixI18N, ftpUserPrePath, domain, ...props }) => {
const { i18n } = useSelector(state => state.session);
const [state, setState] = useState({
additionalFtp: []
});
useEffect(() => {
if (props.ftps) {
const data = props.ftps.map((item, index) => {
item['deleted'] = false;
if (ftps) {
const data = ftps.map((item, index) => {
item['deleted'] = !checked;
item['id'] = index;
return item;
});
setState({ ...state, additionalFtp: data });
}
}, [props.ftps]);
}, [checked, ftps]);
const renderAdditionalFtps = () => {
return state.additionalFtp.map(ftp => {
return <AdditionalFtpForEditing
key={ftp.id}
prefixI18N={props.prefixI18N}
prefixI18N={prefixI18N}
data={ftp}
checked={props.checked}
prePath={props.ftpUserPrePath}
domain={props.domain}
checked={checked}
prePath={ftpUserPrePath}
domain={domain}
onDeleteAdditionalFtp={id => onDeleteFtp(id)} />;
});
}
@ -45,7 +46,7 @@ const AdditionalFtpWrapper = props => {
});
if (!updatedAdditionalFtps.length) {
props.unCheckAdditionalFtpBox();
unCheckAdditionalFtpBox();
}
setState({ ...state, additionalFtp: updatedAdditionalFtps });
@ -64,7 +65,7 @@ const AdditionalFtpWrapper = props => {
<div>
{renderAdditionalFtps()}
{props.checked && (
{checked && (
<button type="button" onClick={() => addAdditionalFtp()}>
{i18n['Add one more FTP Account'] ?? 'Add'}
</button>)}

View file

@ -0,0 +1,48 @@
.additional-ftp {
.title {
span:nth-child(1) {
color: #555;
font-size: 15px;
font-weight: bold;
}
}
.form-transform {
margin-top: 15px;
transform: translateX(3rem);
.form-group.username {
display: flex;
flex-direction: column;
label {
margin: 0;
}
span {
font-size: 10pt;
color: #777;
font-weight: bold;
margin-bottom: 10px;
}
.input-wrapper {
display: flex;
align-items: center;
span {
color: #777;
font-size: 15px;
font-style: italic;
font-weight: normal;
margin-left: 15px;
}
}
}
}
.path-note {
font-weight: bold;
color: #555;
}
}

View file

@ -18,6 +18,9 @@ import QS from 'qs';
import './EditWeb.scss';
import TextArea from '../../ControlPanel/AddItemLayout/Form/TextArea/TextArea';
import { Helmet } from 'react-helmet';
import { checkAuthHandler } from 'src/actions/Session/sessionActions';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
import HtmlParser from 'react-html-parser';
const EditWeb = props => {
const token = localStorage.getItem("token");
@ -83,14 +86,14 @@ const EditWeb = props => {
updateWebDomain(updatedDomain, state.domain)
.then(result => {
if (result.status === 200) {
const { error_msg, ok_msg } = result.data;
const { error_msg: errorMessage, ok_msg: okMessage } = 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 });
if (errorMessage) {
setState({ ...state, errorMessage, okMessage, loading: false });
} else {
setState({ ...state, loading: false });
dispatch(refreshCounters()).then(() => {
setState({ ...state, okMessage, errorMessage: '', loading: false });
});
}
}
})
@ -134,7 +137,7 @@ const EditWeb = props => {
<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="success">
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span dangerouslySetInnerHTML={{ __html: state.okMessage }}></span> </span>
<span className="ok-message">{state.okMessage ? <FontAwesomeIcon icon="long-arrow-alt-right" /> : ''} <span>{HtmlParser(state.okMessage)}</span> </span>
</div>
</Toolbar>
<AddItemLayout date={state.data.date} time={state.data.time} status={state.data.status}>

View file

@ -19,7 +19,7 @@ $textColor: #555;
}
&:nth-child(2) {
width: fit-content;
width: max-content;
}
}
}

View file

@ -93,10 +93,10 @@ export default function WebDomain(props) {
</Link>
</div>
<div>
<a className="link-gray" href={`/list/web-log?domain=${data.NAME}&type=access`}>
<Link className="link-gray" to={`/list/web-log?domain=${data.NAME}&type=access`}>
{i18n['view logs']}
{data.FOCUSED ? <span className="shortcut-button">L</span> : <FontAwesomeIcon icon="list" />}
</a>
</Link>
</div>
{
data.STATS && (

View file

@ -22,7 +22,7 @@
align-items: center;
> div:nth-child(1) {
width: 34%;
margin-right: 2rem;
}
.dns-name-span {

View file

@ -71,10 +71,6 @@ const App = () => {
useEffect(() => {
if (!Object.entries(session.i18n).length) {
dispatch(checkAuthHandler()).then(token => {
if (token) {
setAuthToken(token);
}
setLoading(false);
});
}

View file

@ -10,6 +10,10 @@ $hoverButtonText: #2c54ac;
$activeButtonText: #fff;
$textColor: #555;
html {
overflow-y: scroll;
}
.App {
font-size: 25px;
font-family: Arial;

View file

@ -16,13 +16,14 @@ import Backup from '../../components/Backup/Backup';
import { Helmet } from 'react-helmet';
import { Link } from 'react-router-dom';
import './Backups.scss';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
const Backups = 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();
const [loading, setLoading] = useState(false);
const [modal, setModal] = useState({
text: '',
visible: false,
@ -31,7 +32,6 @@ const Backups = props => {
const [state, setState] = useState({
backups: [],
backupFav: [],
loading: true,
toggledAll: false,
selection: [],
totalAmount: ''
@ -41,7 +41,7 @@ const Backups = props => {
dispatch(addActiveElement('/list/backup/'));
dispatch(removeFocusedElement());
dispatch(removeControlPanelContentFocusedElement());
fetchData();
fetchData().then(() => setLoading(false));
return () => {
dispatch(removeControlPanelContentFocusedElement());
@ -146,7 +146,7 @@ const Backups = props => {
}
const download = () => {
props.history.push(`/download/backup?backup=${controlPanelFocusedElement}`);
window.open(`/api/v1/download/backup?backup=${controlPanelFocusedElement}`);
}
const handleDelete = () => {
@ -157,19 +157,22 @@ const Backups = props => {
}
const fetchData = () => {
getBackupList()
.then(result => {
setState({
...state,
backups: reformatData(result.data.data),
backupFav: result.data.backup_fav,
totalAmount: result.data.totalAmount,
selection: [],
toggledAll: false,
loading: false
});
})
.catch(err => console.error(err));
setLoading(true);
return new Promise((resolve, reject) => {
getBackupList()
.then(result => {
setState({
...state,
backups: reformatData(result.data.data),
backupFav: result.data.backup_fav,
totalAmount: result.data.totalAmount,
selection: [],
toggledAll: false
});
resolve();
})
.catch(err => console.error(err));
});
}
const reformatData = data => {
@ -278,12 +281,12 @@ const Backups = props => {
const { selection } = state;
if (selection.length && action) {
setState({ ...state, loading: true });
setLoading(true);
bulkAction(action, selection)
.then(result => {
if (result.status === 200) {
fetchData();
toggleAll(false);
fetchData().then(() => refreshMenuCounters());
}
})
.catch(err => console.error(err));
@ -291,7 +294,7 @@ const Backups = props => {
}
const displayModal = (text, url) => {
setState({ ...state, loading: false });
setLoading(false);
setModal({
...modal,
visible: true,
@ -301,13 +304,25 @@ const Backups = props => {
}
const modalConfirmHandler = () => {
if (!modal.actionUrl) return;
if (!modal.actionUrl) {
return modalCancelHandler();
}
modalCancelHandler();
setLoading(true);
handleAction(modal.actionUrl)
.then(() => fetchData())
.catch(err => console.error(err));
.then(res => {
if (res.data.error) {
setLoading(false);
return displayModal(res.data.error, '');
}
fetchData().then(() => refreshMenuCounters())
})
.catch(err => { setLoading(false); console.error(err); });
}
const refreshMenuCounters = () => {
dispatch(refreshCounters()).then(() => setLoading(false));
}
const modalCancelHandler = () => {
@ -320,10 +335,15 @@ const Backups = props => {
}
const scheduleBackupButton = () => {
setState({ ...state, loading: true });
setLoading(true);
scheduleBackup()
.then(result => displayModal(result.data.error_msg, ''))
.then(result => {
if (result.data.error) {
displayModal(result.data.error, '');
} else {
displayModal(result.data.ok, '');
}
})
.catch(err => console.error(err));
}
@ -349,9 +369,13 @@ const Backups = props => {
</div>
</Toolbar>
<div className="backups-wrapper">
{state.loading ? <Spinner /> : backups()}
{loading
? <Spinner />
: (<>
{backups()}
<div className="total">{state.totalAmount}</div>
</>)}
</div>
<div className="total">{state.totalAmount}</div>
<Modal
onSave={modalConfirmHandler}
onCancel={modalCancelHandler}

View file

@ -66,10 +66,10 @@ const ControlPanelContent = props => {
const dispatch = useDispatch();
useEffect(() => {
if (userName) {
setLoading(false);
if (!userName) {
return history.push('/login');
} else {
history.push('/login');
setLoading(false);
}
if (look) {
@ -102,7 +102,6 @@ const ControlPanelContent = props => {
return;
}
console.log(event);
switch (event.keyCode) {
case 49: return history.push('/list/user/');
case 50: return history.push('/list/web/');
@ -200,7 +199,7 @@ const ControlPanelContent = props => {
})
}
<Route path="/list/user" component={props => <Users changeSearchTerm={handleSearchTerm} loading={loading} {...props} />} />
<Route path="/list/user" component={props => <Users changeSearchTerm={handleSearchTerm} {...props} />} />
<Route path="/add/user" component={() => <AddUser />} />
<Route path="/edit/user" component={() => <EditUser />} />
<Route path="/list/web" component={props => <Web {...props} changeSearchTerm={handleSearchTerm} />} />

View file

@ -16,13 +16,14 @@ import Spinner from '../../components/Spinner/Spinner';
import { useSelector, useDispatch } from 'react-redux';
import './CronJobs.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
const CronJobs = 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();
const [loading, setLoading] = useState(false);
const [modal, setModal] = useState({
text: '',
visible: false,
@ -31,7 +32,6 @@ const CronJobs = props => {
const [state, setState] = useState({
cronJobs: [],
cronFav: [],
loading: true,
toggledAll: false,
cronReports: '',
sorting: i18n.Date,
@ -44,7 +44,7 @@ const CronJobs = props => {
dispatch(addActiveElement('/list/cron/'));
dispatch(removeFocusedElement());
dispatch(removeControlPanelContentFocusedElement());
fetchData();
fetchData().then(() => setLoading(false));
return () => {
dispatch(removeControlPanelContentFocusedElement());
@ -164,20 +164,23 @@ const CronJobs = props => {
}
const fetchData = () => {
getCronList()
.then(result => {
setState({
...state,
cronJobs: reformatData(result.data.data),
cronReports: result.data.cron_reports,
cronFav: result.data.cron_fav,
selection: [],
toggledAll: false,
totalAmount: result.data.totalAmount,
loading: false
});
})
.catch(err => console.error(err));
setLoading(true);
return new Promise((resolve, reject) => {
getCronList()
.then(result => {
setState({
...state,
cronJobs: reformatData(result.data.data),
cronReports: result.data.cron_reports,
cronFav: result.data.cron_fav,
selection: [],
toggledAll: false,
totalAmount: result.data.totalAmount
});
resolve();
})
.catch(err => console.error(err));
});
}
const reformatData = data => {
@ -316,13 +319,19 @@ const CronJobs = props => {
const bulk = action => {
const { selection } = state;
const notifications = state.cronReports === 'yes' ? 'delete-cron-reports' : 'add-cron-reports';
if (action === notifications) {
return handleCronNotifications();
}
if (selection.length && action) {
setLoading(true);
bulkAction(action, selection)
.then(result => {
if (result.status === 200) {
fetchData();
toggleAll(false);
fetchData().then(() => refreshMenuCounters());
}
})
.catch(err => console.error(err));
@ -340,15 +349,24 @@ const CronJobs = props => {
const modalConfirmHandler = () => {
if (!modal.actionUrl) {
modalCancelHandler();
return modalCancelHandler();
}
setState({ ...state, loading: true });
modalCancelHandler();
setLoading(true);
handleAction(modal.actionUrl)
.then(() => fetchData())
.catch(err => console.error(err));
.then(res => {
if (res.data.error) {
setLoading(false);
return displayModal(res.data.error, '');
}
fetchData().then(() => refreshMenuCounters())
})
.catch(err => { setLoading(false); console.error(err); });
}
const refreshMenuCounters = () => {
dispatch(refreshCounters()).then(() => setLoading(false));
}
const modalCancelHandler = () => {
@ -385,16 +403,20 @@ const CronJobs = props => {
{state.cronReports === 'yes' ? i18n['turn off notifications'] : i18n['turn on notifications']}
</button>
<Checkbox toggleAll={toggleAll} toggled={state.toggledAll} />
<Select list='cronList' bulkAction={bulk} />
<Select list='cronList' bulkAction={bulk} cronReports={state.cronReports === 'yes'} />
<DropdownFilter changeSorting={changeSorting} sorting={state.sorting} order={state.order} list="cronList" />
<SearchInput handleSearchTerm={term => props.changeSearchTerm(term)} />
</div>
</div>
</Toolbar>
<div className="cron-wrapper">
{state.loading ? <Spinner /> : cronJobs()}
{loading
? <Spinner />
: (<>
{cronJobs()}
<div className="total">{state.totalAmount}</div>
</>)}
</div>
<div className="total">{state.totalAmount}</div>
<Modal
showCancelButton={modal.actionUrl}
onCancel={modalCancelHandler}

View file

@ -17,14 +17,15 @@ import QueryString from 'qs';
import './DNSRecords.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
export default function DnsRecords(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();
const history = useHistory();
const [loading, setLoading] = useState(false);
const [modal, setModal] = useState({
text: '',
visible: false,
@ -34,7 +35,6 @@ export default function DnsRecords(props) {
dnsRecords: [],
dnsRecordFav: [],
domain: '',
loading: true,
toggledAll: false,
sorting: i18n.Date,
order: "descending",
@ -44,7 +44,7 @@ export default function DnsRecords(props) {
useEffect(() => {
dispatch(removeControlPanelContentFocusedElement());
fetchData();
fetchData().then(() => setLoading(false));
return () => {
dispatch(removeControlPanelContentFocusedElement());
@ -156,23 +156,23 @@ export default function DnsRecords(props) {
const fetchData = () => {
let parsedQueryString = QueryString.parse(history.location.search, { ignoreQueryPrefix: true });
setState({ ...state, loading: true });
getDNSRecordsList(parsedQueryString.domain || '')
.then(result => {
setState({
...state,
dnsRecords: reformatData(result.data.data),
dnsRecordFav: result.data.dnsRecordsFav,
totalAmount: result.data.totalAmount,
domain: parsedQueryString.domain,
toggledAll: false,
selection: [],
loading: false
});
})
.catch(err => console.error(err));
setLoading(true);
return new Promise((resolve, reject) => {
getDNSRecordsList(parsedQueryString.domain || '')
.then(result => {
setState({
...state,
dnsRecords: reformatData(result.data.data),
dnsRecordFav: result.data.dnsRecordsFav,
totalAmount: result.data.totalAmount,
domain: parsedQueryString.domain,
toggledAll: false,
selection: []
});
resolve();
})
.catch(err => console.error(err));
});
}
const reformatData = data => {
@ -281,11 +281,12 @@ export default function DnsRecords(props) {
const { selection } = state;
if (selection.length && action) {
bulkAction(action, selection)
setLoading(true);
bulkAction(action, selection, state.domain)
.then(result => {
if (result.status === 200) {
fetchData();
toggleAll(false);
fetchData().then(() => refreshMenuCounters());
}
})
.catch(err => console.error(err));
@ -302,12 +303,25 @@ export default function DnsRecords(props) {
}
const modalConfirmHandler = () => {
if (!modal.actionUrl) {
return modalCancelHandler();
}
modalCancelHandler();
setLoading(true);
handleAction(modal.actionUrl)
.then(() => {
fetchData();
modalCancelHandler();
.then(res => {
if (res.data.error) {
setLoading(false);
return displayModal(res.data.error, '');
}
fetchData().then(() => refreshMenuCounters())
})
.catch(err => console.error(err));
.catch(err => { setLoading(false); console.error(err); });
}
const refreshMenuCounters = () => {
dispatch(refreshCounters()).then(() => setLoading(false));
}
const modalCancelHandler = () => {
@ -334,7 +348,7 @@ export default function DnsRecords(props) {
</div>
</div>
</Toolbar>
{state.loading
{loading
? <Spinner />
: (
<>

View file

@ -70,6 +70,7 @@ $textColor: #555;
display: flex;
align-items: center;
margin-top: 2rem;
padding-bottom: 1.5rem;
.total {
margin: 0 3.5rem 0 14.3%;

View file

@ -16,13 +16,14 @@ import { useSelector, useDispatch } from 'react-redux';
import Spinner from '../../components/Spinner/Spinner';
import './Databases.scss';
import { Helmet } from 'react-helmet';
import { refreshCounters } from 'src/actions/MenuCounters/menuCounterActions';
const Databases = 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();
const [loading, setLoading] = useState(false);
const [modal, setModal] = useState({
text: '',
visible: false,
@ -31,7 +32,6 @@ const Databases = props => {
const [state, setState] = useState({
databases: [],
dbFav: [],
loading: true,
toggledAll: false,
dbAdmin: '',
dbAdminLink: '',
@ -45,7 +45,7 @@ const Databases = props => {
dispatch(addActiveElement('/list/db/'));
dispatch(removeFocusedElement());
dispatch(removeControlPanelContentFocusedElement());
fetchData();
fetchData().then(() => setLoading(false));
return () => {
dispatch(removeControlPanelContentFocusedElement());
@ -165,21 +165,24 @@ const Databases = props => {
}
const fetchData = () => {
getDatabaseList()
.then(result => {
setState({
...state,
databases: reformatData(result.data.data),
dbAdmin: result.data.db_admin,
dbAdminLink: result.data.db_admin_link,
dbFav: result.data.dbFav,
selection: [],
toggledAll: false,
totalAmount: result.data.totalAmount,
loading: false
});
})
.catch(err => console.error(err));
setLoading(true);
return new Promise((resolve, reject) => {
getDatabaseList()
.then(result => {
setState({
...state,
databases: reformatData(result.data.data),
dbAdmin: result.data.db_admin,
dbAdminLink: result.data.db_admin_link,
dbFav: result.data.dbFav,
selection: [],
toggledAll: false,
totalAmount: result.data.totalAmount
});
resolve();
})
.catch(err => console.error(err));
});
}
const reformatData = data => {
@ -323,12 +326,12 @@ const Databases = props => {
const { selection } = state;
if (selection.length && action) {
setState({ ...state, loading: true });
setLoading(true);
bulkAction(action, selection)
.then(result => {
if (result.status === 200) {
fetchData();
toggleAll(false);
fetchData().then(() => refreshMenuCounters());
}
})
.catch(err => console.error(err));
@ -345,13 +348,25 @@ const Databases = props => {
}
const modalConfirmHandler = () => {
setState({ ...state, loading: true });
if (!modal.actionUrl) {
return modalCancelHandler();
}
modalCancelHandler();
setLoading(true);
handleAction(modal.actionUrl)
.then(() => {
fetchData();
modalCancelHandler();
.then(res => {
if (res.data.error) {
setLoading(false);
return displayModal(res.data.error, '');
}
fetchData().then(() => refreshMenuCounters())
})
.catch(err => console.error(err));
.catch(err => { setLoading(false); console.error(err); });
}
const refreshMenuCounters = () => {
dispatch(refreshCounters()).then(() => setLoading(false));
}
const modalCancelHandler = () => {
@ -381,7 +396,7 @@ const Databases = props => {
</div>
</Toolbar>
<div className="mails-wrapper">
{state.loading
{loading
? <Spinner />
: (<>
{databases()}

Some files were not shown because too many files have changed in this diff Show more