From e1bb428a6a32e43ffad711ab641cd37eeec91769 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 16 Jan 2019 14:51:17 +0300 Subject: [PATCH] Only allow single click on buttons Closes #544 --- client/src/actions/index.js | 4 +-- client/src/components/App/index.css | 4 ++- client/src/components/Dashboard/index.js | 10 ++++-- client/src/components/Filters/index.js | 22 +++++++++++-- client/src/components/Logs/index.js | 9 ++++-- client/src/components/Settings/Dhcp/index.js | 5 +-- client/src/components/ui/Modal.js | 34 ++++++++++++++------ client/src/reducers/index.js | 16 +++++++-- 8 files changed, 80 insertions(+), 24 deletions(-) diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 949e3a5d..e6a2a6c8 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -352,11 +352,11 @@ export const refreshFiltersFailure = createAction('FILTERING_REFRESH_FAILURE'); export const refreshFiltersSuccess = createAction('FILTERING_REFRESH_SUCCESS'); export const refreshFilters = () => async (dispatch) => { - dispatch(refreshFiltersRequest); + dispatch(refreshFiltersRequest()); dispatch(showLoading()); try { const refreshText = await apiClient.refreshFilters(); - dispatch(refreshFiltersSuccess); + dispatch(refreshFiltersSuccess()); if (refreshText.includes('OK')) { if (refreshText.includes('OK 0')) { diff --git a/client/src/components/App/index.css b/client/src/components/App/index.css index fe3d81d3..61ee53a4 100644 --- a/client/src/components/App/index.css +++ b/client/src/components/App/index.css @@ -19,7 +19,9 @@ body { } .loading-bar { - position: absolute; + position: fixed; + top: 0; + left: 0; z-index: 103; height: 3px; background: linear-gradient(45deg, rgba(99, 125, 120, 1) 0%, rgba(88, 177, 101, 1) 100%); diff --git a/client/src/components/Dashboard/index.js b/client/src/components/Dashboard/index.js index 767e8d1a..2016b16f 100644 --- a/client/src/components/Dashboard/index.js +++ b/client/src/components/Dashboard/index.js @@ -25,12 +25,17 @@ class Dashboard extends Component { } getToggleFilteringButton = () => { - const { protectionEnabled } = this.props.dashboard; + const { protectionEnabled, processingProtection } = this.props.dashboard; const buttonText = protectionEnabled ? 'disable_protection' : 'enable_protection'; const buttonClass = protectionEnabled ? 'btn-gray' : 'btn-success'; return ( - ); @@ -125,6 +130,7 @@ Dashboard.propTypes = { isCoreRunning: PropTypes.bool, getFiltering: PropTypes.func, toggleProtection: PropTypes.func, + processingProtection: PropTypes.bool, t: PropTypes.func, }; diff --git a/client/src/components/Filters/index.js b/client/src/components/Filters/index.js index dd690e7e..339bc673 100644 --- a/client/src/components/Filters/index.js +++ b/client/src/components/Filters/index.js @@ -68,7 +68,7 @@ class Filters extends Component { render() { const { t } = this.props; - const { filters, userRules } = this.props.filtering; + const { filters, userRules, processingRefreshFilters } = this.props.filtering; return (
@@ -95,8 +95,21 @@ class Filters extends Component { noDataText={ t('no_filters_added') } />
- - + +
@@ -114,6 +127,7 @@ class Filters extends Component { toggleModal={this.props.toggleFilteringModal} addFilter={this.props.addFilter} isFilterAdded={this.props.filtering.isFilterAdded} + processingAddFilter={this.props.filtering.processingAddFilter} title={ t('new_filter_btn') } inputDescription={ t('enter_valid_filter_url') } /> @@ -130,6 +144,8 @@ Filters.propTypes = { filters: PropTypes.array, isFilteringModalOpen: PropTypes.bool.isRequired, isFilterAdded: PropTypes.bool, + processingAddFilter: PropTypes.bool, + processingRefreshFilters: PropTypes.bool, }), removeFilter: PropTypes.func.isRequired, toggleFilterStatus: PropTypes.func.isRequired, diff --git a/client/src/components/Logs/index.js b/client/src/components/Logs/index.js index 6d1c9ac4..2499c1f1 100644 --- a/client/src/components/Logs/index.js +++ b/client/src/components/Logs/index.js @@ -77,6 +77,7 @@ class Logs extends Component { type="button" className={`btn btn-sm ${buttonClass}`} onClick={() => this.toggleBlocking(buttonType, domain)} + disabled={this.props.filtering.processingRules} > {buttonText} @@ -269,7 +270,7 @@ class Logs extends Component { saveAs(dataBlob, DOWNLOAD_LOG_FILENAME); }; - renderButtons(queryLogEnabled) { + renderButtons(queryLogEnabled, logStatusProcessing) { if (queryLogEnabled) { return ( @@ -277,6 +278,7 @@ class Logs extends Component { className="btn btn-gray btn-sm mr-2" type="submit" onClick={() => this.props.toggleLogStatus(queryLogEnabled)} + disabled={logStatusProcessing} >disabled_log_btn ); } @@ -308,7 +311,7 @@ class Logs extends Component {
- {this.renderButtons(queryLogEnabled)} + {this.renderButtons(queryLogEnabled, dashboard.logStatusProcessing)}
@@ -332,6 +335,8 @@ Logs.propTypes = { userRules: PropTypes.string, setRules: PropTypes.func, addSuccessToast: PropTypes.func, + processingRules: PropTypes.bool, + logStatusProcessing: PropTypes.bool, t: PropTypes.func, }; diff --git a/client/src/components/Settings/Dhcp/index.js b/client/src/components/Settings/Dhcp/index.js index 3beb136f..eed256a6 100644 --- a/client/src/components/Settings/Dhcp/index.js +++ b/client/src/components/Settings/Dhcp/index.js @@ -23,7 +23,7 @@ class Dhcp extends Component { } getToggleDhcpButton = () => { - const { config, active } = this.props.dhcp; + const { config, active, processingDhcp } = this.props.dhcp; const activeDhcpFound = active && active.found; const filledConfig = Object.keys(config).every((key) => { if (key === 'enabled') { @@ -39,6 +39,7 @@ class Dhcp extends Component { type="button" className="btn btn-standart mr-2 btn-gray" onClick={() => this.props.toggleDhcp(config)} + disabled={processingDhcp} > dhcp_disable @@ -50,7 +51,7 @@ class Dhcp extends Component { type="button" className="btn btn-standart mr-2 btn-success" onClick={() => this.handleToggle(config)} - disabled={!filledConfig || activeDhcpFound} + disabled={!filledConfig || activeDhcpFound || processingDhcp} > dhcp_enable diff --git a/client/src/components/ui/Modal.js b/client/src/components/ui/Modal.js index 3c93c257..a19ed3ac 100644 --- a/client/src/components/ui/Modal.js +++ b/client/src/components/ui/Modal.js @@ -55,6 +55,7 @@ class Modal extends Component { isOpen, title, inputDescription, + processingAddFilter, } = this.props; const { isUrlValid, url, name } = this.state; const inputUrlClass = classnames({ @@ -71,8 +72,8 @@ class Modal extends Component { if (!this.props.isFilterAdded) { return ( - - + + {inputDescription &&
{inputDescription} @@ -93,7 +94,7 @@ class Modal extends Component {
@@ -106,14 +107,26 @@ class Modal extends Component {
- { renderBody()} + {renderBody()}
- { - !this.props.isFilterAdded && -
- - -
+ {!this.props.isFilterAdded && +
+ + +
}
@@ -128,6 +141,7 @@ Modal.propTypes = { inputDescription: PropTypes.string, addFilter: PropTypes.func.isRequired, isFilterAdded: PropTypes.bool, + processingAddFilter: PropTypes.bool, t: PropTypes.func, }; diff --git a/client/src/reducers/index.js b/client/src/reducers/index.js index fc202a0b..1b770adc 100644 --- a/client/src/reducers/index.js +++ b/client/src/reducers/index.js @@ -140,8 +140,14 @@ const dashboard = handleActions({ return newState; }, + [actions.toggleProtectionRequest]: state => ({ ...state, processingProtection: true }), + [actions.toggleProtectionFailure]: state => ({ ...state, processingProtection: false }), [actions.toggleProtectionSuccess]: (state) => { - const newState = { ...state, protectionEnabled: !state.protectionEnabled }; + const newState = { + ...state, + protectionEnabled: !state.protectionEnabled, + processingProtection: false, + }; return newState; }, @@ -164,6 +170,7 @@ const dashboard = handleActions({ processingFiltering: true, upstreamDns: [], protectionEnabled: false, + processingProtection: false, }); const queryLogs = handleActions({ @@ -228,6 +235,8 @@ const filtering = handleActions({ isFilteringModalOpen: false, processingFilters: false, processingRules: false, + processingAddFilter: false, + processingRefreshFilters: false, filters: [], userRules: '', }); @@ -291,16 +300,19 @@ const dhcp = handleActions({ processingStatus: false, }), + [actions.toggleDhcpRequest]: state => ({ ...state, processingDhcp: true }), + [actions.toggleDhcpFailure]: state => ({ ...state, processingDhcp: false }), [actions.toggleDhcpSuccess]: (state) => { const { config } = state; const newConfig = { ...config, enabled: !config.enabled }; - const newState = { ...state, config: newConfig }; + const newState = { ...state, config: newConfig, processingDhcp: false }; return newState; }, }, { processing: true, processingStatus: false, processingInterfaces: false, + processingDhcp: false, config: { enabled: false, },