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

This commit is contained in:
Alexander 2021-11-06 17:47:44 +02:00
parent eb5a045252
commit 5b2c180d86
36 changed files with 310 additions and 243 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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