Skip to content

Commit

Permalink
Add working schedule mission from GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindsjovold committed Sep 22, 2022
1 parent 7cc497b commit ce87279
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 166 deletions.
71 changes: 2 additions & 69 deletions backend/api/Controllers/EchoMissionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ public EchoMissionController(ILogger<EchoMissionController> logger, IEchoService
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<IList<EchoMission>>> GetEchoMissions()
public async Task<ActionResult<IList<EchoMission>>> GetEchoMissions(string? installationCode)
{
try
{
var missions = await _echoService.GetMissions();
var missions = await _echoService.GetMissions(installationCode);
return Ok(missions);
}
catch (HttpRequestException e)
Expand Down Expand Up @@ -95,71 +95,4 @@ public async Task<ActionResult<EchoMission>> GetEchoMission([FromRoute] int miss
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
[HttpGet]
[Route("installation/{installationCode}")]
[ProducesResponseType(typeof(EchoMission), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<EchoMission>> GetEchoMissionsFromInstallation([FromRoute] string installationCode)
{
try
{
var mission = await _echoService.GetMissionsByInstallation(installationCode);
return Ok(mission);
}
catch (HttpRequestException e)
{
if (e.StatusCode.HasValue && (int)e.StatusCode.Value == 404)
{
_logger.LogWarning("Could not find echo mission from installation with installationCode={installationCode}", installationCode);
return NotFound("Echo mission not found");
}

_logger.LogError(e, "Error getting mission from Echo");
return new StatusCodeResult(StatusCodes.Status502BadGateway);
}
catch (JsonException e)
{
_logger.LogError(e, "Error deserializing mission from Echo");
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}

[HttpGet]
[Route("echo-plant-info")]
[ProducesResponseType(typeof(List<EchoPlantInfo>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<EchoMission>> GetEchoPlantInfos()
{
try
{
var echoPlantInfos = await _echoService.GetEchoPlantInfos();
return Ok(echoPlantInfos);
}
catch (HttpRequestException e)
{
if (e.StatusCode.HasValue && (int)e.StatusCode.Value == 404)
{
_logger.LogWarning("Could not get plant info from Echo");
return NotFound("Echo plant info not found");
}

_logger.LogError(e, "Error getting plant info from Echo");
return new StatusCodeResult(StatusCodes.Status502BadGateway);
}
catch (JsonException e)
{
_logger.LogError(e, "Error deserializing plant info response from Echo");
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
}
54 changes: 54 additions & 0 deletions backend/api/Controllers/EchoPlantController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Text.Json;
using Api.Controllers.Models;
using Api.Services;
using Microsoft.AspNetCore.Mvc;

namespace Api.Controllers;
[ApiController]
[Route("echo-plant")]
public class EchoPlantController : ControllerBase
{
private readonly ILogger<EchoPlantController> _logger;
private readonly IEchoService _echoService;
public EchoPlantController(ILogger<EchoPlantController> logger, IEchoService echoService)
{
_logger = logger;
_echoService = echoService;
}

[HttpGet]
[Route("/all-plants-info")]
[ProducesResponseType(typeof(List<EchoPlantInfo>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<EchoMission>> GetEchoPlantInfos()
{
try
{
var echoPlantInfos = await _echoService.GetEchoPlantInfos();
return Ok(echoPlantInfos);
}
catch (HttpRequestException e)
{
if (e.StatusCode.HasValue && (int)e.StatusCode.Value == 404)
{
_logger.LogWarning("Could not get plant info from Echo");
return NotFound("Echo plant info not found");
}

_logger.LogError(e, "Error getting plant info from Echo");
return new StatusCodeResult(StatusCodes.Status502BadGateway);
}
catch (JsonException e)
{
_logger.LogError(e, "Error deserializing plant info response from Echo");
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
}


4 changes: 2 additions & 2 deletions backend/api/Controllers/Models/EchoPlantInfo.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#nullable disable
#nullable disable
namespace Api.Controllers.Models
{
public class EchoPlantInfo
{
public string InstallationCode { get; set; }
public string ProjectDescription { get; set; }
}
}
}
4 changes: 2 additions & 2 deletions backend/api/Controllers/Models/EchoPlantInfoResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System.Text.Json.Serialization;
namespace Api.Controllers.Models
{
Expand All @@ -14,7 +14,7 @@ public class EchoPlantInfoResponse
public string? ProjectDescription { get; set; }

[JsonPropertyName("plantDirectory")]
public string? plantDirectory { get; set; }
public string? PlantDirectory { get; set; }

[JsonPropertyName("availableInEcho3D")]
public bool AvailableInEcho3D { get; set; }
Expand Down
35 changes: 6 additions & 29 deletions backend/api/Services/EchoService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ namespace Api.Services
{
public interface IEchoService
{
public abstract Task<IList<EchoMission>> GetMissions();
public abstract Task<IList<EchoMission>> GetMissions(string? installationCode);

public abstract Task<EchoMission> GetMissionById(int missionId);

public abstract Task<IList<EchoMission>> GetMissionsByInstallation(string installationCode);
public abstract Task<IList<EchoPlantInfo>> GetEchoPlantInfos();
}

Expand All @@ -28,9 +27,11 @@ public EchoService(IConfiguration config, IDownstreamWebApi downstreamWebApi)
_installationCode = config.GetValue<string>("InstallationCode");
}

public async Task<IList<EchoMission>> GetMissions()
public async Task<IList<EchoMission>> GetMissions(string? installationCode)
{
string relativePath = $"robots/robot-plan";
string relativePath = string.IsNullOrEmpty(installationCode) ?
$"robots/robot-plan" :
$"robots/robot-plan?InstallationCode={installationCode}";

var response = await _echoApi.CallWebApiForAppAsync(
ServiceName,
Expand All @@ -51,31 +52,7 @@ public async Task<IList<EchoMission>> GetMissions()
throw new JsonException("Failed to deserialize missions from Echo");

var missions = ProcessEchoMissions(echoMissions);
return missions;
}
public async Task<IList<EchoMission>> GetMissionsByInstallation(string installationCode)
{
string relativePath = $"robots/robot-plan?InstallationCode={installationCode}";

var response = await _echoApi.CallWebApiForAppAsync(
ServiceName,
options =>
{
options.HttpMethod = HttpMethod.Get;
options.RelativePath = relativePath;
}
);

response.EnsureSuccessStatusCode();

var echoMissions = await response.Content.ReadFromJsonAsync<
List<EchoMissionResponse>
>();

if (echoMissions is null)
throw new JsonException("Failed to deserialize missions from Echo");

var missions = ProcessEchoMissions(echoMissions);
return missions;
}

Expand Down Expand Up @@ -201,7 +178,7 @@ private EchoMission ProcessEchoMission(EchoMissionResponse echoMission)
return mission;
}

private List<EchoPlantInfo> ProcessEchoPlantInfos(List<EchoPlantInfoResponse> echoPlantInfoResponse)
private static List<EchoPlantInfo> ProcessEchoPlantInfos(List<EchoPlantInfoResponse> echoPlantInfoResponse)
{
var echoPlantInfos = new List<EchoPlantInfo>();
foreach (var plant in echoPlantInfoResponse)
Expand Down
2 changes: 1 addition & 1 deletion backend/api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@
"Database": {
"ConnectionString": ""
}
}
}
36 changes: 17 additions & 19 deletions frontend/src/api/ApiCaller.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { AccessTokenContext } from 'components/Pages/FlotillaSite'
import { config } from 'config'
import { EchoMission } from 'models/EchoMission'
import { EchoMission, EchoPlantInfo } from 'models/EchoMission'
import { Mission, MissionStatus } from 'models/Mission'
import { EchoPlantInfo } from 'models/EchoPlantInfo'
import { Report } from 'models/Report'
import { Robot } from 'models/Robot'
import { VideoStream } from 'models/VideoStream'
import { useContext, useEffect, useRef } from 'react'
import { filterRobots } from 'utils/scheduleMission'

export class BackendAPICaller {
/* Implements the request sent to the backend api.
Expand Down Expand Up @@ -86,25 +85,14 @@ export class BackendAPICaller {
return result.body
}

async getAllEchoMissions(): Promise<Mission[]> {
const path: string = 'echo-missions'
const result = await this.GET<Mission[]>(path).catch((e) => {
async getEchoMissions(installationCode: string = ''): Promise<EchoMission[]> {
const path: string = 'echo-missions?installationCode=' + installationCode
const result = await this.GET<EchoMission[]>(path).catch((e) => {
throw new Error(`Failed to GET /${path}: ` + e)
})
return result.body
}

async getEchoMissionsForPlant(installationCode: string): Promise<Mission[]> {
if (installationCode) {
const path: string = 'echo-missions/installation/' + installationCode;
const result = await this.GET<Mission[]>(path).catch((e) => {
throw new Error(`Failed to GET /${path}: ` + e)
})
return result.body
}
else
return this.getAllEchoMissions()
}
async getMissionById(missionId: string): Promise<Mission> {
const path: string = 'missions/' + missionId
const result = await this.GET<Mission>(path).catch((e) => {
Expand All @@ -121,12 +109,22 @@ export class BackendAPICaller {
return result.body
}
async getEchoPlantInfo(): Promise<EchoPlantInfo[]> {
const path: string = "echo-missions/echo-plant-info";
const result = await this.GET<EchoPlantInfo[]>(path).catch((e) => {
const path: string = 'all-plants-info'
const result = await this.GET<EchoPlantInfo[]>(path).catch((e: Error) => {
throw new Error(`Failed to GET /${path}: ` + e)
})
return result.body
}
async postMission(echoMissionId: number, startTime: Date) {
const path: string = 'missions'
const robots: Robot[] = await this.getRobots()
const desiredRobot = filterRobots(robots, 'R2-D2')
const body = { robotId: desiredRobot[0].id, echoMissionId: echoMissionId, startTime: startTime }
const result = await this.POST<unknown>(path, body).catch((e) => {
throw new Error(`Failed to POST /${path}: ` + e)
})
return result.body
}
}

export const useApi = () => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Contexts/AssetContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Props {

const defaultAsset = {
asset: 'test',
switchAsset: (newAsset: string) => { },
switchAsset: (newAsset: string) => {},
}

export const assetOptions = new Map<string, string>([
Expand Down
33 changes: 18 additions & 15 deletions frontend/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Button, Icon, Search, TopBar, Autocomplete } from '@equinor/eds-core-react'
import { accessible, account_circle, notifications } from '@equinor/eds-icons'
import { useApi } from 'api/ApiCaller'
import { assetOptions, useAssetContext } from 'components/Contexts/AssetContext'
import { EchoPlantInfo } from 'models/EchoPlantInfo'
import { useAssetContext } from 'components/Contexts/AssetContext'
import { EchoPlantInfo } from 'models/EchoMission'
import { useEffect, useState } from 'react'
import styled from 'styled-components'

Expand Down Expand Up @@ -55,17 +55,14 @@ export function Header() {
}

function AssetPicker() {
const apiCaller = useApi();
const [allPlantsMap, setAllPlantsMap] = useState<Map<string, string>>();
const apiCaller = useApi()
const [allPlantsMap, setAllPlantsMap] = useState<Map<string, string>>()
const { asset, switchAsset } = useAssetContext()
useEffect(() => {
apiCaller.getEchoPlantInfo().then((response: EchoPlantInfo[]) => {
var temporaryMap = new Map<string, string>()
response.map((echoPlantInfo: EchoPlantInfo) => {
temporaryMap.set(echoPlantInfo.projectDescription, echoPlantInfo.installationCode)
})
setAllPlantsMap(temporaryMap);
});
const mapping = mapAssetCodeToName(response)
setAllPlantsMap(mapping)
})
}, [])
let savedAsset = sessionStorage.getItem('assetString')
let initialOption = ''
Expand All @@ -82,11 +79,17 @@ function AssetPicker() {
placeholder="Select asset"
onOptionsChange={({ selectedItems }) => {
const mapKey = mappedOptions.get(selectedItems[0])
if (mapKey != undefined)
switchAsset(mapKey)
else
switchAsset("")
if (mapKey != undefined) switchAsset(mapKey)
else switchAsset('')
}}
/>
)
}
}

const mapAssetCodeToName = (echoPlantInfoArray: EchoPlantInfo[]): Map<string, string> => {
var mapping = new Map<string, string>()
echoPlantInfoArray.map((echoPlantInfo: EchoPlantInfo) => {
mapping.set(echoPlantInfo.projectDescription, echoPlantInfo.installationCode)
})
return mapping
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ export function OngoingMissionView() {
const apiCaller = useApi()
const [ongoingMissions, setOngoingMissions] = useState<Mission[]>([])
useEffect(() => {
// Temporarily using the upcoming dummy missions for ongoing dummy missions
apiCaller.getMissionsByStatus(MissionStatus.Pending).then((missions) => {
apiCaller.getMissionsByStatus(MissionStatus.Ongoing).then((missions) => {
setOngoingMissions(missions)
})
}, [])
Expand Down
Loading

0 comments on commit ce87279

Please sign in to comment.