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

Commit e63edb3

Browse files
authored
Merge pull request #334 from makky3939/feature/patch_results_api
Feature/patch results api
2 parents d99ac7e + 0fd78a4 commit e63edb3

File tree

7 files changed

+139
-9
lines changed

7 files changed

+139
-9
lines changed

chainerui/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def output_log(response):
120120
defaults={'id': None}, view_func=result_resource, methods=['GET'])
121121
app.add_url_rule(
122122
'/api/v1/projects/<int:project_id>/results',
123-
view_func=result_resource, methods=['POST'])
123+
view_func=result_resource, methods=['POST', 'PATCH'])
124124
app.add_url_rule(
125125
'/api/v1/projects/<int:project_id>/results/<int:id>',
126126
view_func=result_resource, methods=['GET', 'PUT', 'DELETE'])

chainerui/views/result.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@ def put(self, id, project_id=None):
138138

139139
return jsonify({'result': result.serialize})
140140

141+
def patch(self, project_id=None):
142+
request_json = request.get_json()
143+
request_results = request_json.get('results')
144+
responses = []
145+
146+
for request_item in request_results:
147+
id = request_item.get('id', None)
148+
if id is None:
149+
continue
150+
151+
result = db.session.query(Result).filter_by(id=id).first()
152+
if result is None:
153+
continue
154+
155+
is_unregistered = request_item.get('isUnregistered', None)
156+
if is_unregistered is not None:
157+
result.is_unregistered = is_unregistered
158+
159+
db.session.add(result)
160+
responses.append({
161+
'id': result.id,
162+
'is_unregistered': result.is_unregistered,
163+
})
164+
165+
db.session.commit()
166+
return jsonify({'results': responses})
167+
141168
def delete(self, id, project_id=None):
142169
"""delete."""
143170
result = db.session.query(Result).filter_by(id=id).first()

frontend/src/actions/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ export const RESULT_UPDATE_FAILURE = 'RESULT_UPDATE_FAILURE';
7272
export const RESULT_DELETE_REQUEST = 'RESULT_DELETE_REQUEST';
7373
export const RESULT_DELETE_SUCCESS = 'RESULT_DELETE_SUCCESS';
7474
export const RESULT_DELETE_FAILURE = 'RESULT_DELETE_FAILURE';
75+
export const RESULTS_PATCH_REQUEST = 'RESULTS_PATCH_REQUEST';
76+
export const RESULTS_PATCH_SUCCESS = 'RESULTS_PATCH_SUCCESS';
77+
export const RESULTS_PATCH_FAILURE = 'RESULTS_PATCH_FAILURE';
7578
export const RESULT_LIST_CLEAR = 'RESULT_LIST_CLEAR';
7679
export const RESULT_ASSET_REQUEST = 'RESULT_ASSET_REQUEST';
7780
export const RESULT_ASSET_SUCCESS = 'RESULT_ASSET_SUCCESS';
@@ -123,6 +126,17 @@ export const deleteResult = (projectId, resultId) => {
123126
};
124127
};
125128

129+
export const patchResults = (projectId, results = []) => {
130+
return {
131+
[CALL_API]: {
132+
types: [RESULTS_PATCH_REQUEST, RESULTS_PATCH_SUCCESS, RESULTS_PATCH_FAILURE],
133+
endpoint: `projects/${projectId}/results`,
134+
method: 'PATCH',
135+
body: { results },
136+
},
137+
};
138+
};
139+
126140
export const clearResultList = () => ({
127141
type: RESULT_LIST_CLEAR,
128142
});

frontend/src/components/SelectedResultTools.jsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const SelectedResultTools = (props) => {
1010
results,
1111
resultsStatus,
1212
resultTypeId,
13-
onResultUpdate,
13+
onResultsPatch,
1414
onCheckedOfResultStatusUpdate,
1515
onTableExpandedUpdate,
1616
} = props;
@@ -22,20 +22,26 @@ const SelectedResultTools = (props) => {
2222
const handleDeleteResults = (isUnregistered) => {
2323
onTableExpandedUpdate(project.id, {});
2424

25-
Object.keys(resultsStatus).forEach((resultStatusId) => {
25+
const targetResultKeys = Object.keys(resultsStatus).filter((resultStatusId) => {
2626
const result = results[resultStatusId];
2727
const resultStatus = resultsStatus[resultStatusId];
2828

2929
if (!result) {
30-
return;
30+
return false;
3131
}
3232

3333
if (!resultStatus.checked) {
34-
return;
34+
return false;
3535
}
3636

37-
onResultUpdate(project.id, { ...result, isUnregistered });
38-
onCheckedOfResultStatusUpdate(project.id, result.id, false);
37+
return true;
38+
});
39+
40+
const requestBody = targetResultKeys.map((id) => ({ id, isUnregistered }));
41+
onResultsPatch(project.id, requestBody);
42+
43+
targetResultKeys.forEach((resultKey) => {
44+
onCheckedOfResultStatusUpdate(project.id, results[resultKey].id, false);
3945
});
4046
};
4147

@@ -61,7 +67,7 @@ SelectedResultTools.propTypes = {
6167
results: uiPropTypes.results.isRequired,
6268
resultsStatus: uiPropTypes.resultsStatus,
6369
resultTypeId: PropTypes.string.isRequired,
64-
onResultUpdate: PropTypes.func.isRequired,
70+
onResultsPatch: PropTypes.func.isRequired,
6571
onCheckedOfResultStatusUpdate: PropTypes.func.isRequired,
6672
onTableExpandedUpdate: PropTypes.func.isRequired,
6773
};

frontend/src/containers/PlotContainer.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getProject,
99
getResultList,
1010
updateResult,
11+
patchResults,
1112
clearResultList,
1213
resetProjectConfig,
1314
updateLineInAxis,
@@ -150,7 +151,7 @@ class PlotContainer extends React.Component {
150151
results={results}
151152
resultTypeId={projectConfig.resultType}
152153
resultsStatus={projectStatus.resultsStatus}
153-
onResultUpdate={this.props.updateResult}
154+
onResultsPatch={this.props.patchResults}
154155
onTableExpandedUpdate={this.props.updateTableExpanded}
155156
onCheckedOfResultStatusUpdate={this.props.updateCheckedOfResultStatus}
156157
/>
@@ -202,6 +203,7 @@ PlotContainer.propTypes = {
202203
getProject: PropTypes.func.isRequired,
203204
getResultList: PropTypes.func.isRequired,
204205
updateResult: PropTypes.func.isRequired,
206+
patchResults: PropTypes.func.isRequired,
205207
clearResultList: PropTypes.func.isRequired,
206208
createCommand: PropTypes.func.isRequired,
207209
resetProjectConfig: PropTypes.func.isRequired,
@@ -278,6 +280,7 @@ export default connect(
278280
getProject,
279281
getResultList,
280282
updateResult,
283+
patchResults,
281284
clearResultList,
282285
createCommand,
283286
resetProjectConfig,

frontend/src/reducers/index.jsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ const resultsReducer = (state = {}, action) => {
151151
return removePartialState(state, result.id);
152152
}
153153
return state;
154+
case ActionTypes.RESULTS_PATCH_SUCCESS:
155+
if (action.response && action.response.results) {
156+
const { results } = action.response;
157+
let currentState = state;
158+
results.forEach((result) => {
159+
currentState = removePartialState(currentState, result.id);
160+
});
161+
return currentState;
162+
}
163+
return state;
154164
case ActionTypes.COMMAND_CREATE_SUCCESS:
155165
if (action.response && action.response.commands) {
156166
const result = state[action.body.resultId];

tests/test_api.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,3 +791,73 @@ def test_get_assets(func_dir, app):
791791
assert len(data) == 2
792792
assert isinstance(data['message'], string_types)
793793
assert data['asset'] is None
794+
795+
796+
# PATCH /api/v1/projects/<int:project_id>/results/
797+
def test_patch_results(project, app):
798+
# simplest case
799+
request_json = {
800+
"results": [
801+
{
802+
"id": 1,
803+
"isUnregistered": 0
804+
},
805+
{
806+
"id": 2,
807+
"isUnregistered": 1
808+
}
809+
]
810+
}
811+
resp = app.patch(
812+
'/api/v1/projects/1/results', data=json.dumps(request_json),
813+
content_type='application/json')
814+
data = assert_json_api(resp)
815+
assert len(data) == 1
816+
assert 'results' in data
817+
assert len(data['results']) == len(request_json["results"])
818+
819+
# The API will return no response for the part of the request
820+
# that id(s) is not given.
821+
request_json = {
822+
"results": [
823+
{
824+
"id": 1,
825+
"isUnregistered": 0
826+
},
827+
{
828+
"isUnregistered": 1
829+
}
830+
]
831+
}
832+
resp = app.patch(
833+
'/api/v1/projects/1/results', data=json.dumps(request_json),
834+
content_type='application/json')
835+
data = assert_json_api(resp)
836+
assert len(data) == 1
837+
assert 'results' in data
838+
assert len(data['results']) == len(request_json["results"]) - 1
839+
840+
# The API will return no response for the part of the request
841+
# that couldn't find the result on the table by id.
842+
request_json = {
843+
"results": [
844+
{
845+
"id": 1,
846+
"isUnregistered": 0
847+
},
848+
{
849+
"id": 9999,
850+
"isUnregistered": 1
851+
}
852+
]
853+
}
854+
resp = app.patch(
855+
'/api/v1/projects/1/results', data=json.dumps(request_json),
856+
content_type='application/json')
857+
data = assert_json_api(resp)
858+
assert len(data) == 1
859+
assert 'results' in data
860+
assert len(data['results']) == len(request_json["results"]) - 1
861+
862+
# not raise an exception
863+
# when PATCH /api/v1/projects/12345/results/

0 commit comments

Comments
 (0)