Pull request 1889: AG-22207 handle rewrite update
Updates #1577
Squashed commit of the following:
commit a07ff51fb3f1eb58ab9a922d7bc11ed1d65ef3a7
Merge: 7db696814 2f515e8d8
Author: Ildar Kamalov <ik@adguard.com>
Date: Fri Jun 23 16:50:09 2023 +0300
Merge branch 'master' into AG-22207
commit 7db696814f2134fd3a3415cbcfa0ffdac1fabda3
Author: Ildar Kamalov <ik@adguard.com>
Date: Fri Jun 23 14:57:09 2023 +0300
fix changelog
commit bf9458b3f18697ca1fc504c51fa443934f76371f
Author: Ildar Kamalov <ik@adguard.com>
Date: Fri Jun 23 14:48:20 2023 +0300
changelog
commit bc2bf3f9507957afe63a654334b6e22858d1e41b
Author: Ildar Kamalov <ik@adguard.com>
Date: Fri Jun 23 13:28:28 2023 +0300
client: handle rewrite edit
This commit is contained in:
parent
2f515e8d8f
commit
e7e638443f
|
@ -31,7 +31,7 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
|||
configuration file ([#951]). The UI changes are coming in the upcoming
|
||||
releases.
|
||||
- The ability to edit rewrite rules via `PUT /control/rewrite/update` HTTP API
|
||||
([#1577]).
|
||||
and the Web UI ([#1577]).
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -478,7 +478,9 @@
|
|||
"setup_dns_notice": "In order to use <1>DNS-over-HTTPS</1> or <1>DNS-over-TLS</1>, you need to <0>configure Encryption</0> in AdGuard Home settings.",
|
||||
"rewrite_added": "DNS rewrite for \"{{key}}\" successfully added",
|
||||
"rewrite_deleted": "DNS rewrite for \"{{key}}\" successfully deleted",
|
||||
"rewrite_updated": "DNS rewrite successfully updated",
|
||||
"rewrite_add": "Add DNS rewrite",
|
||||
"rewrite_edit": "Edit DNS rewrite",
|
||||
"rewrite_not_found": "No DNS rewrites found",
|
||||
"rewrite_confirm_delete": "Are you sure you want to delete DNS rewrite for \"{{key}}\"?",
|
||||
"rewrite_desc": "Allows to easily configure custom DNS response for a specific domain name.",
|
||||
|
|
|
@ -38,6 +38,29 @@ export const addRewrite = (config) => async (dispatch) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const updateRewriteRequest = createAction('UPDATE_REWRITE_REQUEST');
|
||||
export const updateRewriteFailure = createAction('UPDATE_REWRITE_FAILURE');
|
||||
export const updateRewriteSuccess = createAction('UPDATE_REWRITE_SUCCESS');
|
||||
|
||||
/**
|
||||
* @param {Object} config
|
||||
* @param {string} config.target - current DNS rewrite value
|
||||
* @param {string} config.update - updated DNS rewrite value
|
||||
*/
|
||||
export const updateRewrite = (config) => async (dispatch) => {
|
||||
dispatch(updateRewriteRequest());
|
||||
try {
|
||||
await apiClient.updateRewrite(config);
|
||||
dispatch(updateRewriteSuccess());
|
||||
dispatch(toggleRewritesModal());
|
||||
dispatch(getRewritesList());
|
||||
dispatch(addSuccessToast(i18next.t('rewrite_updated', { key: config.domain })));
|
||||
} catch (error) {
|
||||
dispatch(addErrorToast({ error }));
|
||||
dispatch(updateRewriteFailure());
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteRewriteRequest = createAction('DELETE_REWRITE_REQUEST');
|
||||
export const deleteRewriteFailure = createAction('DELETE_REWRITE_FAILURE');
|
||||
export const deleteRewriteSuccess = createAction('DELETE_REWRITE_SUCCESS');
|
||||
|
|
|
@ -455,6 +455,8 @@ class Api {
|
|||
|
||||
REWRITE_ADD = { path: 'rewrite/add', method: 'POST' };
|
||||
|
||||
REWRITE_UPDATE = { path: 'rewrite/update', method: 'PUT' };
|
||||
|
||||
REWRITE_DELETE = { path: 'rewrite/delete', method: 'POST' };
|
||||
|
||||
getRewritesList() {
|
||||
|
@ -470,6 +472,14 @@ class Api {
|
|||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
updateRewrite(config) {
|
||||
const { path, method } = this.REWRITE_UPDATE;
|
||||
const parameters = {
|
||||
data: config,
|
||||
};
|
||||
return this.makeRequest(path, method, parameters);
|
||||
}
|
||||
|
||||
deleteRewrite(config) {
|
||||
const { path, method } = this.REWRITE_DELETE;
|
||||
const parameters = {
|
||||
|
|
|
@ -105,6 +105,7 @@ Form.propTypes = {
|
|||
submitting: PropTypes.bool.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
initialValues: PropTypes.object,
|
||||
};
|
||||
|
||||
export default flow([
|
||||
|
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import ReactModal from 'react-modal';
|
||||
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
import Form from './Form';
|
||||
|
||||
const Modal = (props) => {
|
||||
|
@ -12,6 +13,8 @@ const Modal = (props) => {
|
|||
toggleRewritesModal,
|
||||
processingAdd,
|
||||
processingDelete,
|
||||
modalType,
|
||||
currentRewrite,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
|
@ -24,13 +27,18 @@ const Modal = (props) => {
|
|||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h4 className="modal-title">
|
||||
{modalType === MODAL_TYPE.EDIT_REWRITE ? (
|
||||
<Trans>rewrite_edit</Trans>
|
||||
) : (
|
||||
<Trans>rewrite_add</Trans>
|
||||
)}
|
||||
</h4>
|
||||
<button type="button" className="close" onClick={() => toggleRewritesModal()}>
|
||||
<span className="sr-only">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
<Form
|
||||
initialValues={{ ...currentRewrite }}
|
||||
onSubmit={handleSubmit}
|
||||
toggleRewritesModal={toggleRewritesModal}
|
||||
processingAdd={processingAdd}
|
||||
|
@ -47,6 +55,8 @@ Modal.propTypes = {
|
|||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
processingDelete: PropTypes.bool.isRequired,
|
||||
modalType: PropTypes.string.isRequired,
|
||||
currentRewrite: PropTypes.object,
|
||||
};
|
||||
|
||||
export default withTranslation()(Modal);
|
||||
|
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import ReactTable from 'react-table';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { sortIp } from '../../../helpers/helpers';
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
|
||||
class Table extends Component {
|
||||
cellWrap = ({ value }) => (
|
||||
|
@ -31,16 +32,35 @@ class Table extends Component {
|
|||
maxWidth: 100,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
Cell: (value) => (
|
||||
Cell: (value) => {
|
||||
const currentRewrite = {
|
||||
answer: value.row.answer,
|
||||
domain: value.row.domain,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="logs__row logs__row--center">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-icon--green btn-outline-secondary btn-sm"
|
||||
onClick={() => this.props.handleDelete({
|
||||
answer: value.row.answer,
|
||||
domain: value.row.domain,
|
||||
})
|
||||
}
|
||||
className="btn btn-icon btn-outline-primary btn-sm mr-2"
|
||||
onClick={() => {
|
||||
this.props.toggleRewritesModal({
|
||||
type: MODAL_TYPE.EDIT_REWRITE,
|
||||
currentRewrite,
|
||||
});
|
||||
}}
|
||||
disabled={this.props.processingUpdate}
|
||||
title={this.props.t('edit_table_action')}
|
||||
>
|
||||
<svg className="icons icon12">
|
||||
<use xlinkHref="#edit" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-outline-secondary btn-sm"
|
||||
onClick={() => this.props.handleDelete(currentRewrite)}
|
||||
title={this.props.t('delete_table_action')}
|
||||
>
|
||||
<svg className="icons">
|
||||
|
@ -48,7 +68,8 @@ class Table extends Component {
|
|||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -84,7 +105,9 @@ Table.propTypes = {
|
|||
processing: PropTypes.bool.isRequired,
|
||||
processingAdd: PropTypes.bool.isRequired,
|
||||
processingDelete: PropTypes.bool.isRequired,
|
||||
processingUpdate: PropTypes.bool.isRequired,
|
||||
handleDelete: PropTypes.func.isRequired,
|
||||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(Table);
|
||||
|
|
|
@ -6,16 +6,13 @@ import Table from './Table';
|
|||
import Modal from './Modal';
|
||||
import Card from '../../ui/Card';
|
||||
import PageTitle from '../../ui/PageTitle';
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
|
||||
class Rewrites extends Component {
|
||||
componentDidMount() {
|
||||
this.props.getRewritesList();
|
||||
}
|
||||
|
||||
handleSubmit = (values) => {
|
||||
this.props.addRewrite(values);
|
||||
};
|
||||
|
||||
handleDelete = (values) => {
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(this.props.t('rewrite_confirm_delete', { key: values.domain }))) {
|
||||
|
@ -23,6 +20,19 @@ class Rewrites extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
handleSubmit = (values) => {
|
||||
const { modalType, currentRewrite } = this.props.rewrites;
|
||||
|
||||
if (modalType === MODAL_TYPE.EDIT_REWRITE && currentRewrite) {
|
||||
this.props.updateRewrite({
|
||||
target: currentRewrite,
|
||||
update: values,
|
||||
});
|
||||
} else {
|
||||
this.props.addRewrite(values);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
|
@ -36,6 +46,9 @@ class Rewrites extends Component {
|
|||
processing,
|
||||
processingAdd,
|
||||
processingDelete,
|
||||
processingUpdate,
|
||||
modalType,
|
||||
currentRewrite,
|
||||
} = rewrites;
|
||||
|
||||
return (
|
||||
|
@ -54,13 +67,15 @@ class Rewrites extends Component {
|
|||
processing={processing}
|
||||
processingAdd={processingAdd}
|
||||
processingDelete={processingDelete}
|
||||
processingUpdate={processingUpdate}
|
||||
handleDelete={this.handleDelete}
|
||||
toggleRewritesModal={toggleRewritesModal}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-success btn-standard mt-3"
|
||||
onClick={() => toggleRewritesModal()}
|
||||
onClick={() => toggleRewritesModal({ type: MODAL_TYPE.ADD_REWRITE })}
|
||||
disabled={processingAdd}
|
||||
>
|
||||
<Trans>rewrite_add</Trans>
|
||||
|
@ -68,10 +83,13 @@ class Rewrites extends Component {
|
|||
|
||||
<Modal
|
||||
isModalOpen={isModalOpen}
|
||||
modalType={modalType}
|
||||
toggleRewritesModal={toggleRewritesModal}
|
||||
handleSubmit={this.handleSubmit}
|
||||
processingAdd={processingAdd}
|
||||
processingDelete={processingDelete}
|
||||
processingUpdate={processingUpdate}
|
||||
currentRewrite={currentRewrite}
|
||||
/>
|
||||
</Fragment>
|
||||
</Card>
|
||||
|
@ -86,6 +104,7 @@ Rewrites.propTypes = {
|
|||
toggleRewritesModal: PropTypes.func.isRequired,
|
||||
addRewrite: PropTypes.func.isRequired,
|
||||
deleteRewrite: PropTypes.func.isRequired,
|
||||
updateRewrite: PropTypes.func.isRequired,
|
||||
rewrites: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ class Table extends Component {
|
|||
Header: <Trans>list_url_table_header</Trans>,
|
||||
accessor: 'url',
|
||||
minWidth: 180,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
Cell: ({ value }) => (
|
||||
<div className="logs__row">
|
||||
{isValidAbsolutePath(value) ? value
|
||||
|
|
|
@ -32,6 +32,8 @@ const ProtectionTimer = ({
|
|||
};
|
||||
|
||||
ProtectionTimer.propTypes = {
|
||||
protectionDisabledDuration: PropTypes.number,
|
||||
toggleProtectionSuccess: PropTypes.func.isRequired,
|
||||
setProtectionTimerTime: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ import {
|
|||
} from '../../../helpers/constants';
|
||||
import '../FormButton.css';
|
||||
|
||||
|
||||
const getIntervalTitle = (interval, t) => {
|
||||
switch (interval) {
|
||||
case RETENTION_CUSTOM:
|
||||
|
|
|
@ -7,7 +7,6 @@ import { Trans, withTranslation } from 'react-i18next';
|
|||
import flow from 'lodash/flow';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
|
||||
import {
|
||||
renderRadioField,
|
||||
toNumber,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable react/no-unknown-property */
|
||||
import React from 'react';
|
||||
|
||||
import './Icons.css';
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
getRewritesList,
|
||||
addRewrite,
|
||||
deleteRewrite,
|
||||
updateRewrite,
|
||||
toggleRewritesModal,
|
||||
} from '../actions/rewrites';
|
||||
import Rewrites from '../components/Filters/Rewrites';
|
||||
|
@ -17,6 +18,7 @@ const mapDispatchToProps = {
|
|||
getRewritesList,
|
||||
addRewrite,
|
||||
deleteRewrite,
|
||||
updateRewrite,
|
||||
toggleRewritesModal,
|
||||
};
|
||||
|
||||
|
|
|
@ -173,6 +173,8 @@ export const MODAL_TYPE = {
|
|||
ADD_FILTERS: 'ADD_FILTERS',
|
||||
EDIT_FILTERS: 'EDIT_FILTERS',
|
||||
CHOOSE_FILTERING_LIST: 'CHOOSE_FILTERING_LIST',
|
||||
ADD_REWRITE: 'ADD_REWRITE',
|
||||
EDIT_REWRITE: 'EDIT_REWRITE',
|
||||
};
|
||||
|
||||
export const CLIENT_ID = {
|
||||
|
|
|
@ -845,7 +845,6 @@ export const sortIp = (a, b) => {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} filterId
|
||||
* @returns {string}
|
||||
|
|
|
@ -30,7 +30,27 @@ const rewrites = handleActions(
|
|||
[actions.deleteRewriteFailure]: (state) => ({ ...state, processingDelete: false }),
|
||||
[actions.deleteRewriteSuccess]: (state) => ({ ...state, processingDelete: false }),
|
||||
|
||||
[actions.toggleRewritesModal]: (state) => {
|
||||
[actions.updateRewriteRequest]: (state) => ({ ...state, processingUpdate: true }),
|
||||
[actions.updateRewriteFailure]: (state) => ({ ...state, processingUpdate: false }),
|
||||
[actions.updateRewriteSuccess]: (state) => {
|
||||
const newState = {
|
||||
...state,
|
||||
processingUpdate: false,
|
||||
};
|
||||
return newState;
|
||||
},
|
||||
|
||||
[actions.toggleRewritesModal]: (state, { payload }) => {
|
||||
if (payload) {
|
||||
const newState = {
|
||||
...state,
|
||||
modalType: payload.type || '',
|
||||
isModalOpen: !state.isModalOpen,
|
||||
currentRewrite: payload.currentRewrite,
|
||||
};
|
||||
return newState;
|
||||
}
|
||||
|
||||
const newState = {
|
||||
...state,
|
||||
isModalOpen: !state.isModalOpen,
|
||||
|
@ -42,7 +62,10 @@ const rewrites = handleActions(
|
|||
processing: true,
|
||||
processingAdd: false,
|
||||
processingDelete: false,
|
||||
processingUpdate: false,
|
||||
isModalOpen: false,
|
||||
modalType: '',
|
||||
currentRewrite: {},
|
||||
list: [],
|
||||
},
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue