Skip to content

Commit

Permalink
[OGUI-1442] Use new PUT endpoint for controlling environment (#2204)
Browse files Browse the repository at this point in the history
* Update front-end to use the new PUT endpoint for controlling an environment
* Update method to accept specified parameters rather than an undescribed object
  • Loading branch information
graduta authored Nov 21, 2023
1 parent 253edc7 commit e54a523
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Control/public/common/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default (model) => h('.absolute-fill scroll-y.flex-column', [
model.sideBarMenu ? 'Environments' : 'ENVS'),
menuItem(model, 'Global Runs', 'newEnvironment', iconPlus()),
menuItem(model, 'Calibration Runs', 'calibrationRuns', iconWrench()),
menuItem(model, 'Active Runs', 'environments', iconGridTwoUp()),
menuItem(model, 'Active Environments', 'environments', iconGridTwoUp()),
menuItem(model, 'Create', 'newEnvironmentAdvanced', iconPlus()),
menuItem(model, 'Task list', 'taskList', iconGridThreeUp()),
h('h5.menu-title-large.mh1',
Expand Down
25 changes: 17 additions & 8 deletions Control/public/environment/Environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/

import {Observable, RemoteData} from '/js/src/index.js';
import {jsonPut} from './../utilities/jsonPut.js';
import Task from './Task.js';

/**
Expand Down Expand Up @@ -140,17 +141,25 @@ export default class Environment extends Observable {
}

/**
* Control a remote environment, store action result into `itemControl` as RemoteData
* @param {Object} body - See protobuf definition for properties
* Request the control of an environment to transition to a new state.
* In case of success, the user will be redirected to the environment details page with the new state
* In case of failure, an error message which be stored in `itemControl` and displayed under the button action panel
* @param {String} id - environmentId that the user whishes to control
* @param {String} type - type of the transition that the user whishes to apply
* @param {Number} runNumber - current run number if the environment is in RUNNING state
* @return {void}
*/
async controlEnvironment(body) {
async controlEnvironment(id, type, runNumber) {
this.itemControl = RemoteData.loading();
this.notify();

const {result, ok} = await this.model.loader.post(`/api/ControlEnvironment`, body);
this.itemControl = !ok ? RemoteData.failure(result.message) : RemoteData.success(result);
this.itemNew = RemoteData.notAsked();
this.model.router.go(`?page=environment&id=${result.id}`);
try {(id, type)
const result = await jsonPut(`/api/environment/${id}`, {body: {id, type, runNumber}});
this.itemControl = RemoteData.success(result);
this.model.router.go(`?page=environment&id=${result.id}`);
} catch (error) {
this.itemControl = RemoteData.failure(error);
}
this.notify();
}

Expand All @@ -162,7 +171,7 @@ export default class Environment extends Observable {
async newEnvironment(itemForm) {
this.itemNew = RemoteData.loading();
this.notify();

const {result, ok} = await this.model.loader.post(`/api/core/request`, itemForm);
this.itemNew = !ok ? RemoteData.failure(result.message) : RemoteData.notAsked();
this.model.router.go(`?page=environments`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const controlEnvironmentPanel = (environment, item, isAllowedToControl =
NotAsked: () => null,
Loading: () => null,
Success: (_data) => null,
Failure: (error) => h('p.danger', error),
Failure: ({message}) => h('p.danger.text-right', message),
})
]);
};
Expand Down Expand Up @@ -90,7 +90,7 @@ const controlButton = (buttonType, environment, item, label, type, stateToHide,
style: item.state !== stateToHide ? 'display: none;' : '',
onclick: () => {
confirm(`Are you sure you want to ${label} this ${item.state} environment?`)
&& environment.controlEnvironment({id: item.id, type, runNumber: item.currentRunNumber});
&& environment.controlEnvironment(item.id, type, item.currentRunNumber);
},
title
},
Expand Down
53 changes: 20 additions & 33 deletions Control/public/utilities/jsonFetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,34 @@
* or submit itself to any jurisdiction.
*/

import { fetchClient } from '/js/src/index.js';
import {fetchClient} from '/js/src/index.js';

/**
* @source {Bookkeeping} - https://github.com/AliceO2Group/Bookkeeping/blob/main/lib/public/utilities/fetch/jsonFetch.js
* Send a request to a remote endpoint, and extract the response. If errors occurred, an array of errors containing title and detail is thrown
* Send a request to a remote endpoint, and extract the response. If errors occurred, an error containing a message field will be returned
*
* The endpoint is expected to follow some conventions:
* - If request is valid but no data must be sent, it must return a 204
* - If data must be returned, the json response must contain a top level "data" key
* - If an error occurred, NO "data" key must be present, and there can be one of the following keys:
* - errors: a list of errors containing title and detail
* - error and message describing the error that occurred
* - If an error occurred, there can be error with a message field describing the error that occurred
*
* @param {string} endpoint the remote endpoint to send request to
* @param {RequestInit} options the request options, see {@see fetch} native function
* @return {Promise<*>} resolve with the result of the request or reject with the list of errors if any error occurred
* @param {String} endpoint - the remote endpoint to send request to
* @param {RequestInit} options - the request options, see {@see fetch } native function
* @return {Promise<Resolve<Object>.Error<{message: String}>>} resolve with the result of the request or reject with the error message
*/
export const jsonFetch = async (endpoint, options) => {
let result;
let response;
try {
const response = await fetchClient(endpoint, options);

// 204 means no data and the response do not have a body
if (response.status === 204) {
result = null;
} else {
result = await response.json();
}
} catch (e) {
result = {
detail: e.message,
};
response = await fetchClient(endpoint, options);
} catch (error) {
return Promise.reject({message: 'Connection to server failed, please try again'});
}
if (result === null || result) {
return result;
try {
const result = response.status === 204 // case in which response is empty
? null
: await response.json();
return response.ok
? result
: Promise.reject({message: result.message || 'Unknown error received'});
} catch (error) {
return Promise.reject({message: 'Parsing result from server failed'});
}

return Promise.reject(result.errors || [
{
title: result.error || 'Request failure',
detail: result.message || 'An error occurred while fetching data',
},
]);
};
}
39 changes: 39 additions & 0 deletions Control/public/utilities/jsonPut.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

import {jsonFetch} from './jsonFetch.js';

/**
* Build and send a PUT request to a remote endpoint, and extract the response.
* @param {String} endpoint - the remote endpoint to send request to
* @param {RequestInit} options - the request options, see {@see fetch } native function
* @return {Promise<Resolve<Object>.Error<{message: String}>>} resolve with the result of the request or reject with the error message
*/
export const jsonPut = async (endpoint, options) => {
if (options.body && typeof options.body === 'object') {
options.body = JSON.stringify(options.body);
}
try {
const result = await jsonFetch(endpoint, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
...options
});
return result;
} catch (error) {
return Promise.reject({message: error.message || error});
}
}

0 comments on commit e54a523

Please sign in to comment.