Skip to content
This repository has been archived by the owner on Feb 6, 2023. It is now read-only.

Commit

Permalink
Merge pull request #344 from makky3939/feature/undo_button_for_update…
Browse files Browse the repository at this point in the history
…d_results

Undo button for updated results
  • Loading branch information
ofk authored Dec 23, 2019
2 parents ad78998 + eaac13f commit 758fc89
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 15 deletions.
13 changes: 12 additions & 1 deletion frontend/src/actions/status.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */

import { CHART_DOWNLOAD_STATUS } from '../constants';
import { ProjectId, ResultId } from '../store/types';
import { ProjectId, ResultId, LastBulkUpdateTarget } from '../store/types';

export const RESULT_SELECT_UPDATE = 'RESULT_SELECT_UPDATE';
export const updateResultSelect = (
Expand Down Expand Up @@ -61,3 +61,14 @@ export const updateChartDownloadStatus = (
chartDownloadStatus,
});
export type ChartDownloadStatusAction = ReturnType<typeof updateChartDownloadStatus>;

export const LAST_BULK_UPDATE_TARGET_UPDATE = 'LAST_BULK_UPDATE_TARGET_UPDATE';
export const updateLastBulkUpdateTarget = (
projectId: ProjectId,
results: LastBulkUpdateTarget
) => ({
type: LAST_BULK_UPDATE_TARGET_UPDATE as typeof LAST_BULK_UPDATE_TARGET_UPDATE,
projectId,
results,
});
export type LastBulkUpdateTargetAction = ReturnType<typeof updateLastBulkUpdateTarget>;
85 changes: 72 additions & 13 deletions frontend/src/components/SelectedResultTools.jsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,82 @@
import React from 'react';
import { Button, ButtonGroup } from 'reactstrap';
import React, { useEffect, useState } from 'react';
import { Button, ButtonGroup, Toast, ToastBody } from 'reactstrap';
import PropTypes from 'prop-types';
import * as uiPropTypes from '../store/uiPropTypes';
import { fetchResultTypes } from '../constants/index';

const TOAST_LIFE_TIME = 1000 * 20;

const SelectedResultTools = (props) => {
const {
project,
results,
resultsStatus,
resultTypeId,
lastBulkUpdateTarget,
onResultsPatch,
onResultCheckBulkUpdate,
onTableExpandedUpdate,
onLastBulkUpdateTargetUpdate,
onHandleGetResultList,
} = props;

const [toastTimier, setToastTimer] = useState(null);

useEffect(() => {
return () => clearInterval(toastTimier);
}, [toastTimier]);

const checkedResults = Object.keys(results).filter(
(key) => resultsStatus[key] && resultsStatus[key].checked
);

const handleDeleteResults = (isUnregistered) => {
if (toastTimier) {
clearInterval(toastTimier);
}

onTableExpandedUpdate(project.id, {});

const targetResultKeys = Object.keys(resultsStatus).filter((resultStatusId) => {
const result = results[resultStatusId];
const resultStatus = resultsStatus[resultStatusId];
const targetResultKeys = Object.keys(resultsStatus)
.map(Number)
.filter((resultStatusId) => {
const result = results[resultStatusId];
const resultStatus = resultsStatus[resultStatusId];

if (!result) {
return false;
}
if (!result) {
return false;
}

if (!resultStatus.checked) {
return false;
}
if (!resultStatus.checked) {
return false;
}

return true;
});
return true;
});

const requestBody = targetResultKeys.map((id) => ({ id, isUnregistered }));
onResultsPatch(project.id, requestBody);
const resultStatusList = targetResultKeys.map((id) => ({ id, checked: false }));
onResultCheckBulkUpdate(project.id, resultStatusList);
onLastBulkUpdateTargetUpdate(project.id, requestBody);

setToastTimer(setTimeout(() => onLastBulkUpdateTargetUpdate(project.id, {}), TOAST_LIFE_TIME));
};

const handleUndo = () => {
const requestBody = Object.keys(lastBulkUpdateTarget).map((key) => {
return {
id: lastBulkUpdateTarget[key].id,
isUnregistered: !lastBulkUpdateTarget[key].isUnregistered,
};
});
onResultsPatch(project.id, requestBody);
onLastBulkUpdateTargetUpdate(project.id, {});
onHandleGetResultList();
};

const handleCloseToast = () => {
onLastBulkUpdateTargetUpdate(project.id, {});
};

return (
Expand All @@ -56,6 +92,25 @@ const SelectedResultTools = (props) => {
Restore results
</Button>
) : null}

{Object.keys(lastBulkUpdateTarget).length !== 0 ? (
<div style={{ position: 'fixed', bottom: '1em', left: '2em', zIndex: 10000 }}>
<Toast className="bg-dark text-white">
<ToastBody>
Selected results removed/restored.
<Button className="ml-1 mb-1" color="link" size="sm" onClick={() => handleUndo()}>
Undo
</Button>
<Button
className="ml-1 text-white"
style={{ 'margin-top': '0.1em' }}
onClick={() => handleCloseToast()}
close
/>
</ToastBody>
</Toast>
</div>
) : null}
</ButtonGroup>
);
};
Expand All @@ -65,13 +120,17 @@ SelectedResultTools.propTypes = {
results: uiPropTypes.results.isRequired,
resultsStatus: uiPropTypes.resultsStatus,
resultTypeId: PropTypes.string.isRequired,
lastBulkUpdateTarget: uiPropTypes.lastBulkUpdateTarget,
onResultsPatch: PropTypes.func.isRequired,
onResultCheckBulkUpdate: PropTypes.func.isRequired,
onTableExpandedUpdate: PropTypes.func.isRequired,
onLastBulkUpdateTargetUpdate: PropTypes.func.isRequired,
onHandleGetResultList: PropTypes.func.isRequired,
};

SelectedResultTools.defaultProps = {
resultsStatus: {},
lastBulkUpdateTarget: {},
};

export default SelectedResultTools;
16 changes: 16 additions & 0 deletions frontend/src/containers/PlotContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
updateChartDownloadStatus,
updateTargetResultType,
updateResultCheckBulk,
updateLastBulkUpdateTarget,
} from '../actions';
import NavigationBar from './NavigationBar';
import BreadcrumbLink from '../components/BreadcrumbLink';
Expand Down Expand Up @@ -63,6 +64,7 @@ class PlotContainer extends React.Component {
this.handleExperimentsTableColumnsVisibilityUpdate = this.handleExperimentsTableColumnsVisibilityUpdate.bind(
this
);
this.handleGetResultList = this.handleGetResultList.bind(this);
}

componentWillReceiveProps(nextProps) {
Expand Down Expand Up @@ -102,6 +104,15 @@ class PlotContainer extends React.Component {
this.props.updateTableColumnsVisibility(projectId, hiddenLogKeys, hiddenArgKeys, isGrouped);
}

handleGetResultList() {
const { projectId, globalConfig, projectConfig } = this.props;
const { logsLimit } = globalConfig;
const { resultType } = projectConfig;

this.props.clearResultList();
this.props.getResultList(projectId, logsLimit, resultType);
}

render() {
const {
projectId,
Expand Down Expand Up @@ -155,9 +166,12 @@ class PlotContainer extends React.Component {
results={results}
resultTypeId={projectConfig.resultType}
resultsStatus={projectStatus.resultsStatus}
lastBulkUpdateTarget={projectStatus.lastBulkUpdateTarget}
onResultsPatch={this.props.patchResults}
onTableExpandedUpdate={this.props.updateTableExpanded}
onResultCheckBulkUpdate={this.props.updateResultCheckBulk}
onLastBulkUpdateTargetUpdate={this.props.updateLastBulkUpdateTarget}
onHandleGetResultList={this.handleGetResultList}
/>
<ResultTypeSelector
projectId={projectId}
Expand Down Expand Up @@ -227,6 +241,7 @@ PlotContainer.propTypes = {
updateChartDownloadStatus: PropTypes.func.isRequired,
updateTargetResultType: PropTypes.func.isRequired,
updateResultCheckBulk: PropTypes.func.isRequired,
updateLastBulkUpdateTarget: PropTypes.func.isRequired,
};

const getTargetTextForFilter = (project, result, filterKey) => {
Expand Down Expand Up @@ -306,5 +321,6 @@ export default connect(
updateChartDownloadStatus,
updateTargetResultType,
updateResultCheckBulk,
updateLastBulkUpdateTarget,
}
)(PlotContainer);
23 changes: 22 additions & 1 deletion frontend/src/reducers/statusReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ResultStatus,
ResultsStatus,
ResultFilter,
LastBulkUpdateTarget,
ProjectStatus,
ProjectsStatus,
Stats,
Expand All @@ -17,11 +18,13 @@ import {
RESULT_CHECK_UPDATE,
RESULT_CHECK_BULK_UPDATE,
RESULT_FILTER_UPDATE,
LAST_BULK_UPDATE_TARGET_UPDATE,
ChartDownloadStatusAction,
ResultSelectAction,
ResultCheckAction,
ResultStatusAction,
ResultFilterAction,
LastBulkUpdateTargetAction,
} from '../actions/status';
import { updatePartialState } from './utils';

Expand Down Expand Up @@ -106,13 +109,31 @@ const resultFilterReducer: Reducer<ResultFilter, ResultFilterAction> = (state =
}
};

const lastBulkUpdateTargetReducer: Reducer<LastBulkUpdateTarget, LastBulkUpdateTargetAction> = (
state = {},
action
) => {
const { results } = action;
switch (action.type) {
case LAST_BULK_UPDATE_TARGET_UPDATE:
return { ...results };
default:
return state;
}
};

const projectStatusReducer: Reducer<ProjectStatus> = combineReducers({
chartDownloadStatus: chartDownloadStatusReducer,
resultsStatus: resultsStatusReducer,
resultFilter: resultFilterReducer,
lastBulkUpdateTarget: lastBulkUpdateTargetReducer,
});

type ProjectsStatusAction = ChartDownloadStatusAction | ResultStatusAction | ResultFilterAction;
type ProjectsStatusAction =
| ChartDownloadStatusAction
| ResultStatusAction
| ResultFilterAction
| LastBulkUpdateTargetAction;
const projectsStatusReducer: Reducer<ProjectsStatus, ProjectsStatusAction> = (
state = {},
action
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,18 @@ export interface ResultFilter {
[filterKey: string]: string;
}

export interface LastBulkUpdateTarget {
[k: number]: {
id: ResultId;
isUnregistered: boolean;
};
}

export interface ProjectStatus {
chartDownloadStatus: CHART_DOWNLOAD_STATUS;
resultsStatus: ResultsStatus;
resultFilter: ResultFilter;
lastBulkUpdateTarget: LastBulkUpdateTarget;
}

export interface ProjectsStatus {
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/store/uiPropTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,10 @@ export const projectsStatus = PropTypes.objectOf(projectStatus);
export const status = PropTypes.shape({
projectsStatus,
});

export const lastBulkUpdateTarget = PropTypes.objectOf(
PropTypes.shape({
id: resultId,
isUnregistered: PropTypes.bool,
})
);

0 comments on commit 758fc89

Please sign in to comment.