badguardhome/client/src/components/Settings/Clients/ClientsTable.js

341 lines
12 KiB
JavaScript
Raw Normal View History

import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { Trans, withNamespaces } from 'react-i18next';
import ReactTable from 'react-table';
import { MODAL_TYPE } from '../../../helpers/constants';
import { normalizeTextarea } from '../../../helpers/helpers';
import Card from '../../ui/Card';
import Modal from './Modal';
import CellWrap from '../../ui/CellWrap';
2019-09-26 09:17:58 +00:00
class ClientsTable extends Component {
handleFormAdd = (values) => {
this.props.addClient(values);
};
handleFormUpdate = (values, name) => {
this.props.updateClient(values, name);
};
handleSubmit = (values) => {
const config = values;
if (values) {
if (values.blocked_services) {
config.blocked_services = Object
.keys(values.blocked_services)
.filter(service => values.blocked_services[service]);
}
if (values.upstreams && typeof values.upstreams === 'string') {
config.upstreams = normalizeTextarea(values.upstreams);
} else {
config.upstreams = [];
}
2020-01-28 11:07:47 +00:00
if (values.tags) {
config.tags = values.tags.map(tag => tag.value);
} else {
config.tags = [];
2020-01-28 11:07:47 +00:00
}
2019-07-18 11:52:47 +00:00
}
if (this.props.modalType === MODAL_TYPE.EDIT) {
2019-07-18 11:52:47 +00:00
this.handleFormUpdate(config, this.props.modalClientName);
} else {
2019-07-18 11:52:47 +00:00
this.handleFormAdd(config);
}
};
2020-01-28 11:07:47 +00:00
getOptionsWithLabels = options => (
options.map(option => ({ value: option, label: option }))
);
getClient = (name, clients) => {
const client = clients.find(item => name === item.name);
if (client) {
2020-01-28 11:07:47 +00:00
const {
upstreams, tags, whois_info, ...values
} = client;
return {
upstreams: (upstreams && upstreams.join('\n')) || '',
2020-01-28 11:07:47 +00:00
tags: (tags && this.getOptionsWithLabels(tags)) || [],
...values,
};
}
return {
ids: [''],
2020-01-28 11:07:47 +00:00
tags: [],
use_global_settings: true,
2019-07-18 11:52:47 +00:00
use_global_blocked_services: true,
};
};
handleDelete = (data) => {
// eslint-disable-next-line no-alert
if (window.confirm(this.props.t('client_confirm_delete', { key: data.name }))) {
this.props.deleteClient(data);
this.props.getStats();
}
};
columns = [
{
Header: this.props.t('table_client'),
accessor: 'ids',
minWidth: 150,
Cell: (row) => {
const { value } = row;
return (
<div className="logs__row logs__row--overflow">
<span className="logs__text">
{value.map(address => (
<div key={address} title={address}>
{address}
</div>
))}
</span>
</div>
);
},
},
{
Header: this.props.t('table_name'),
accessor: 'name',
minWidth: 120,
Cell: CellWrap,
},
{
Header: this.props.t('settings'),
accessor: 'use_global_settings',
minWidth: 120,
Cell: ({ value }) => {
const title = value ? (
<Trans>settings_global</Trans>
) : (
<Trans>settings_custom</Trans>
);
return (
<div className="logs__row logs__row--overflow">
<div className="logs__text">{title}</div>
</div>
);
},
},
2019-07-18 11:52:47 +00:00
{
Header: this.props.t('blocked_services'),
accessor: 'blocked_services',
minWidth: 180,
2019-07-18 11:52:47 +00:00
Cell: (row) => {
const { value, original } = row;
if (original.use_global_blocked_services) {
return <Trans>settings_global</Trans>;
}
return (
<div className="logs__row logs__row--icons">
2019-09-24 12:28:59 +00:00
{value && value.length > 0
? value.map(service => (
<svg
className="service__icon service__icon--table"
title={service}
key={service}
>
<use xlinkHref={`#service_${service}`} />
</svg>
2019-09-24 12:28:59 +00:00
))
: ''}
2019-07-18 11:52:47 +00:00
</div>
);
},
},
{
Header: this.props.t('upstreams'),
accessor: 'upstreams',
minWidth: 120,
Cell: ({ value }) => {
const title = value && value.length > 0 ? (
<Trans>settings_custom</Trans>
) : (
<Trans>settings_global</Trans>
);
return (
<div className="logs__row logs__row--overflow">
<div className="logs__text">{title}</div>
</div>
);
},
},
2020-01-28 11:07:47 +00:00
{
Header: this.props.t('tags_title'),
accessor: 'tags',
minWidth: 140,
Cell: (row) => {
const { value } = row;
if (!value || value.length < 1) {
return '';
}
return (
<div className="logs__row logs__row--overflow">
<span className="logs__text">
{value.map(tag => (
<div key={tag} title={tag} className="small">
{tag}
</div>
))}
</span>
</div>
);
},
},
{
Header: this.props.t('requests_count'),
id: 'statistics',
accessor: row => this.props.normalizedTopClients.configured[row.name] || 0,
sortMethod: (a, b) => b - a,
minWidth: 120,
Cell: CellWrap,
},
{
Header: this.props.t('actions_table_header'),
accessor: 'actions',
maxWidth: 100,
Cell: (row) => {
const clientName = row.original.name;
const {
toggleClientModal, processingDeleting, processingUpdating, t,
} = this.props;
return (
<div className="logs__row logs__row--center">
<button
type="button"
className="btn btn-icon btn-outline-primary btn-sm mr-2"
onClick={() =>
toggleClientModal({
type: MODAL_TYPE.EDIT,
name: clientName,
})
}
disabled={processingUpdating}
title={t('edit_table_action')}
>
<svg className="icons">
<use xlinkHref="#edit" />
</svg>
</button>
<button
type="button"
className="btn btn-icon btn-outline-secondary btn-sm"
onClick={() => this.handleDelete({ name: clientName })}
disabled={processingDeleting}
title={t('delete_table_action')}
>
<svg className="icons">
<use xlinkHref="#delete" />
</svg>
</button>
</div>
);
},
},
];
render() {
const {
t,
clients,
isModalOpen,
modalType,
modalClientName,
toggleClientModal,
processingAdding,
processingUpdating,
2020-01-28 11:07:47 +00:00
supportedTags,
} = this.props;
const currentClientData = this.getClient(modalClientName, clients);
2020-01-28 11:07:47 +00:00
const tagsOptions = this.getOptionsWithLabels(supportedTags);
return (
<Card
title={t('clients_title')}
subtitle={t('clients_desc')}
bodyType="card-body box-body--settings"
>
<Fragment>
<ReactTable
data={clients || []}
columns={this.columns}
defaultSorted={[
{
id: 'statistics',
asc: true,
},
]}
className="-striped -highlight card-table-overflow"
showPagination={true}
defaultPageSize={10}
minRows={5}
previousText={t('previous_btn')}
nextText={t('next_btn')}
loadingText={t('loading_table_status')}
pageText={t('page_table_footer_text')}
ofText="/"
rowsText={t('rows_table_footer_text')}
noDataText={t('clients_not_found')}
/>
<button
type="button"
className="btn btn-success btn-standard mt-3"
onClick={() => toggleClientModal(MODAL_TYPE.ADD)}
disabled={processingAdding}
>
<Trans>client_add</Trans>
</button>
<Modal
isModalOpen={isModalOpen}
modalType={modalType}
toggleClientModal={toggleClientModal}
currentClientData={currentClientData}
handleSubmit={this.handleSubmit}
processingAdding={processingAdding}
processingUpdating={processingUpdating}
2020-01-28 11:07:47 +00:00
tagsOptions={tagsOptions}
/>
</Fragment>
</Card>
);
}
}
ClientsTable.propTypes = {
t: PropTypes.func.isRequired,
clients: PropTypes.array.isRequired,
normalizedTopClients: PropTypes.object.isRequired,
toggleClientModal: PropTypes.func.isRequired,
deleteClient: PropTypes.func.isRequired,
addClient: PropTypes.func.isRequired,
updateClient: PropTypes.func.isRequired,
isModalOpen: PropTypes.bool.isRequired,
modalType: PropTypes.string.isRequired,
modalClientName: PropTypes.string.isRequired,
processingAdding: PropTypes.bool.isRequired,
processingDeleting: PropTypes.bool.isRequired,
processingUpdating: PropTypes.bool.isRequired,
getStats: PropTypes.func.isRequired,
2020-01-28 11:07:47 +00:00
supportedTags: PropTypes.array.isRequired,
};
export default withNamespaces()(ClientsTable);