From de0bcc149b8d74da3dbf2d4ca15f1395d16e0df4 Mon Sep 17 00:00:00 2001 From: Eddasol Date: Tue, 27 Aug 2024 16:19:28 +0200 Subject: [PATCH 1/3] Fix typo --- .../src/components/Pages/MissionHistoryPage/FilterSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Pages/MissionHistoryPage/FilterSection.tsx b/frontend/src/components/Pages/MissionHistoryPage/FilterSection.tsx index fe2201b16..fe43cfc27 100644 --- a/frontend/src/components/Pages/MissionHistoryPage/FilterSection.tsx +++ b/frontend/src/components/Pages/MissionHistoryPage/FilterSection.tsx @@ -26,7 +26,7 @@ const StyledHeader = styled.div` } ` -const StyledSerach = styled(Search)` +const StyledSearch = styled(Search)` display: flex; width: 288px; height: 36px; @@ -85,7 +85,7 @@ export const FilterSection = () => { return ( <> - ) => { From 0fc11fc76d589df232b632ffc903a8f111f41391 Mon Sep 17 00:00:00 2001 From: Eddasol Date: Thu, 29 Aug 2024 15:08:56 +0200 Subject: [PATCH 2/3] Add documentation to robot --- backend/api.test/Client/MissionTests.cs | 12 +- .../api.test/Database/DatabaseUtilities.cs | 1 + backend/api.test/Services/RobotService.cs | 9 + .../Models/CreateDocumentationQuery.cs | 13 + .../Controllers/Models/CreateRobotQuery.cs | 2 + .../api/Controllers/Models/RobotResponse.cs | 3 + backend/api/Database/Context/InitDb.cs | 3 + backend/api/Database/Models/DocumentInfo.cs | 23 + backend/api/Database/Models/Robot.cs | 15 + backend/api/EventHandlers/MqttEventHandler.cs | 1 + .../api/MQTT/MessageModels/IsarRobotInfo.cs | 3 + ...132840_AddDocumentationToRobot.Designer.cs | 1407 +++++++++++++++++ .../20240910132840_AddDocumentationToRobot.cs | 46 + .../FlotillaDbContextModelSnapshot.cs | 32 + backend/api/Services/RobotService.cs | 1 + 15 files changed, 1567 insertions(+), 4 deletions(-) create mode 100644 backend/api/Controllers/Models/CreateDocumentationQuery.cs create mode 100644 backend/api/Database/Models/DocumentInfo.cs create mode 100644 backend/api/Migrations/20240910132840_AddDocumentationToRobot.Designer.cs create mode 100644 backend/api/Migrations/20240910132840_AddDocumentationToRobot.cs diff --git a/backend/api.test/Client/MissionTests.cs b/backend/api.test/Client/MissionTests.cs index 85a633c82..07f2ecf80 100644 --- a/backend/api.test/Client/MissionTests.cs +++ b/backend/api.test/Client/MissionTests.cs @@ -464,7 +464,8 @@ public async Task ScheduleDuplicateCustomMissionDefinitions() CurrentInstallationCode = installationCode, CurrentAreaName = null, RobotCapabilities = [], - VideoStreams = new List() + VideoStreams = new List(), + Documentation = new List() }; string robotUrl = "/robots"; @@ -547,7 +548,8 @@ public async Task GetNextRun() CurrentInstallationCode = installation.InstallationCode, CurrentAreaName = areaName, RobotCapabilities = [], - VideoStreams = new List() + VideoStreams = new List(), + Documentation = new List() }; string robotUrl = "/robots"; @@ -729,7 +731,8 @@ public async Task MissionDoesNotStartIfRobotIsNotInSameInstallationAsMission() CurrentInstallationCode = otherInstallation.InstallationCode, CurrentAreaName = null, RobotCapabilities = [], - VideoStreams = new List() + VideoStreams = new List(), + Documentation = new List() }; string robotUrl = "/robots"; @@ -800,7 +803,8 @@ public async Task MissionFailsIfRobotIsNotInSameDeckAsMission() CurrentInstallationCode = installation.InstallationCode, CurrentAreaName = area1.AreaName, RobotCapabilities = [], - VideoStreams = new List() + VideoStreams = new List(), + Documentation = new List() }; string robotUrl = "/robots"; diff --git a/backend/api.test/Database/DatabaseUtilities.cs b/backend/api.test/Database/DatabaseUtilities.cs index dbd89c6e4..de9635a5d 100644 --- a/backend/api.test/Database/DatabaseUtilities.cs +++ b/backend/api.test/Database/DatabaseUtilities.cs @@ -157,6 +157,7 @@ public async Task NewRobot(RobotStatus status, Installation installation, CurrentInstallationCode = installation.InstallationCode, CurrentAreaName = area?.Name, VideoStreams = new List(), + Documentation = new List(), Host = "localhost", Port = 3000, Status = status, diff --git a/backend/api.test/Services/RobotService.cs b/backend/api.test/Services/RobotService.cs index 7c0489d25..220b51f2b 100644 --- a/backend/api.test/Services/RobotService.cs +++ b/backend/api.test/Services/RobotService.cs @@ -94,6 +94,11 @@ public async Task Create() Url = "localhost:5000", Type = "mjpeg" }; + var documentationQuery = new CreateDocumentationQuery + { + Name = "Some document", + Url = "someURL", + }; var robotQuery = new CreateRobotQuery { Name = "", @@ -103,6 +108,10 @@ public async Task Create() { videoStreamQuery }, + Documentation = new List + { + documentationQuery + }, CurrentInstallationCode = installation.InstallationCode, RobotType = RobotType.Robot, Host = "", diff --git a/backend/api/Controllers/Models/CreateDocumentationQuery.cs b/backend/api/Controllers/Models/CreateDocumentationQuery.cs new file mode 100644 index 000000000..d244c6d95 --- /dev/null +++ b/backend/api/Controllers/Models/CreateDocumentationQuery.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace Api.Controllers.Models +{ + public struct CreateDocumentationQuery + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("url")] + public string Url { get; set; } + } +} diff --git a/backend/api/Controllers/Models/CreateRobotQuery.cs b/backend/api/Controllers/Models/CreateRobotQuery.cs index 61b8aecf9..63d3d2cb5 100644 --- a/backend/api/Controllers/Models/CreateRobotQuery.cs +++ b/backend/api/Controllers/Models/CreateRobotQuery.cs @@ -16,6 +16,8 @@ public struct CreateRobotQuery public string? CurrentAreaName { get; set; } + public IList Documentation { get; set; } + public IList VideoStreams { get; set; } public string Host { get; set; } diff --git a/backend/api/Controllers/Models/RobotResponse.cs b/backend/api/Controllers/Models/RobotResponse.cs index 7d7115f4e..74518a152 100644 --- a/backend/api/Controllers/Models/RobotResponse.cs +++ b/backend/api/Controllers/Models/RobotResponse.cs @@ -22,6 +22,8 @@ public class RobotResponse public float? PressureLevel { get; set; } + public IList Documentation { get; set; } + public IList VideoStreams { get; set; } public string Host { get; set; } @@ -60,6 +62,7 @@ public RobotResponse(Robot robot) CurrentArea = robot.CurrentArea != null ? new AreaResponse(robot.CurrentArea) : null; BatteryLevel = robot.BatteryLevel; PressureLevel = robot.PressureLevel; + Documentation = robot.Documentation; VideoStreams = robot.VideoStreams; Host = robot.Host; Port = robot.Port; diff --git a/backend/api/Database/Context/InitDb.cs b/backend/api/Database/Context/InitDb.cs index 7b86a04b9..98d3c0f64 100644 --- a/backend/api/Database/Context/InitDb.cs +++ b/backend/api/Database/Context/InitDb.cs @@ -286,6 +286,7 @@ private static List GetRobots() Port = 3000, CurrentInstallation = installations[0], VideoStreams = new List(), + Documentation = new List(), Pose = new Pose() }; @@ -299,6 +300,7 @@ private static List GetRobots() Port = 3000, CurrentInstallation = installations[0], VideoStreams = new List(), + Documentation = new List(), Pose = new Pose() }; @@ -312,6 +314,7 @@ private static List GetRobots() Port = 3000, CurrentInstallation = installations[0], VideoStreams = new List(), + Documentation = new List(), Pose = new Pose() }; diff --git a/backend/api/Database/Models/DocumentInfo.cs b/backend/api/Database/Models/DocumentInfo.cs new file mode 100644 index 000000000..7d2f25cb7 --- /dev/null +++ b/backend/api/Database/Models/DocumentInfo.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; + +#pragma warning disable CS8618 +namespace Api.Database.Models +{ + [Owned] + public class DocumentInfo + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public string Id { get; set; } + + [Required] + [MaxLength(200)] + public string Name { get; set; } + + [Required] + [MaxLength(200)] + public string Url { get; set; } + } +} diff --git a/backend/api/Database/Models/Robot.cs b/backend/api/Database/Models/Robot.cs index 0db2063e4..58ab25656 100644 --- a/backend/api/Database/Models/Robot.cs +++ b/backend/api/Database/Models/Robot.cs @@ -8,6 +8,7 @@ public class Robot { public Robot() { + Documentation = new List(); VideoStreams = new List(); IsarId = "defaultIsarId"; Name = "defaultId"; @@ -34,11 +35,23 @@ public Robot(CreateRobotQuery createQuery, Installation installation, RobotModel videoStreams.Add(videoStream); } + var documentation = new List(); + foreach (var documentQuery in createQuery.Documentation) + { + var document = new DocumentInfo + { + Name = documentQuery.Name, + Url = documentQuery.Url + }; + documentation.Add(document); + } + IsarId = createQuery.IsarId; Name = createQuery.Name; SerialNumber = createQuery.SerialNumber; CurrentInstallation = installation; CurrentArea = area; + Documentation = documentation; VideoStreams = videoStreams; Host = createQuery.Host; Port = createQuery.Port; @@ -95,6 +108,8 @@ public bool IsRobotBatteryTooLow() return Model.BatteryWarningThreshold >= BatteryLevel; } + public IList Documentation { get; set; } + public IList VideoStreams { get; set; } [Required] diff --git a/backend/api/EventHandlers/MqttEventHandler.cs b/backend/api/EventHandlers/MqttEventHandler.cs index e68936438..9fc099a33 100644 --- a/backend/api/EventHandlers/MqttEventHandler.cs +++ b/backend/api/EventHandlers/MqttEventHandler.cs @@ -145,6 +145,7 @@ private async void OnIsarRobotInfo(object? sender, MqttReceivedArgs mqttArgs) RobotType = isarRobotInfo.RobotType, SerialNumber = isarRobotInfo.SerialNumber, CurrentInstallationCode = installation.InstallationCode, + Documentation = isarRobotInfo.DocumentationQueries, VideoStreams = isarRobotInfo.VideoStreamQueries, Host = isarRobotInfo.Host, Port = isarRobotInfo.Port, diff --git a/backend/api/MQTT/MessageModels/IsarRobotInfo.cs b/backend/api/MQTT/MessageModels/IsarRobotInfo.cs index 1a87ac925..fa4a676db 100644 --- a/backend/api/MQTT/MessageModels/IsarRobotInfo.cs +++ b/backend/api/MQTT/MessageModels/IsarRobotInfo.cs @@ -22,6 +22,9 @@ public class IsarRobotInfoMessage : MqttMessage [JsonPropertyName("robot_asset")] public string CurrentInstallation { get; set; } + [JsonPropertyName("documentation")] + public List DocumentationQueries { get; set; } + [JsonPropertyName("video_streams")] public List VideoStreamQueries { get; set; } diff --git a/backend/api/Migrations/20240910132840_AddDocumentationToRobot.Designer.cs b/backend/api/Migrations/20240910132840_AddDocumentationToRobot.Designer.cs new file mode 100644 index 000000000..b5fd5aed4 --- /dev/null +++ b/backend/api/Migrations/20240910132840_AddDocumentationToRobot.Designer.cs @@ -0,0 +1,1407 @@ +// +using System; +using Api.Database.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Api.Migrations +{ + [DbContext(typeof(FlotillaDbContext))] + [Migration("20240910132840_AddDocumentationToRobot")] + partial class AddDocumentationToRobot + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Api.Database.Models.AccessRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("AccessLevel") + .IsRequired() + .HasColumnType("text"); + + b.Property("InstallationId") + .HasColumnType("text"); + + b.Property("RoleName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("InstallationId"); + + b.ToTable("AccessRoles"); + }); + + modelBuilder.Entity("Api.Database.Models.Area", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("DeckId") + .IsRequired() + .HasColumnType("text"); + + b.Property("DefaultLocalizationPoseId") + .HasColumnType("text"); + + b.Property("InstallationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DeckId"); + + b.HasIndex("DefaultLocalizationPoseId"); + + b.HasIndex("InstallationId"); + + b.HasIndex("PlantId"); + + b.ToTable("Areas"); + }); + + modelBuilder.Entity("Api.Database.Models.Deck", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("DefaultLocalizationPoseId") + .HasColumnType("text"); + + b.Property("InstallationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PlantId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DefaultLocalizationPoseId"); + + b.HasIndex("InstallationId"); + + b.HasIndex("PlantId"); + + b.ToTable("Decks"); + }); + + modelBuilder.Entity("Api.Database.Models.DefaultLocalizationPose", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("DockingEnabled") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("DefaultLocalizationPoses"); + }); + + modelBuilder.Entity("Api.Database.Models.Inspection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("AnalysisType") + .HasColumnType("text"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("InspectionType") + .IsRequired() + .HasColumnType("text"); + + b.Property("InspectionUrl") + .HasMaxLength(250) + .HasColumnType("character varying(250)"); + + b.Property("IsarStepId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionTaskId") + .HasColumnType("text"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("VideoDuration") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("MissionTaskId"); + + b.ToTable("Inspections"); + }); + + modelBuilder.Entity("Api.Database.Models.InspectionFinding", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("Finding") + .IsRequired() + .HasColumnType("text"); + + b.Property("InspectionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("InspectionId") + .HasColumnType("text"); + + b.Property("IsarStepId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("InspectionId"); + + b.ToTable("InspectionFindings"); + }); + + modelBuilder.Entity("Api.Database.Models.Installation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("InstallationCode") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.HasKey("Id"); + + b.HasIndex("InstallationCode") + .IsUnique(); + + b.ToTable("Installations"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionDefinition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("AreaId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Comment") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("InspectionFrequency") + .HasColumnType("bigint"); + + b.Property("InstallationCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsDeprecated") + .HasColumnType("boolean"); + + b.Property("LastSuccessfulRunId") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SourceId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AreaId"); + + b.HasIndex("LastSuccessfulRunId"); + + b.HasIndex("SourceId"); + + b.ToTable("MissionDefinitions"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionRun", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("AreaId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Comment") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("Description") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.Property("DesiredStartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("EstimatedDuration") + .HasColumnType("bigint"); + + b.Property("InstallationCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsDeprecated") + .HasColumnType("boolean"); + + b.Property("IsarMissionId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("MissionRunType") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("StatusReason") + .HasMaxLength(450) + .HasColumnType("character varying(450)"); + + b.HasKey("Id"); + + b.HasIndex("AreaId"); + + b.HasIndex("RobotId"); + + b.ToTable("MissionRuns"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionTask", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsarTaskId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionRunId") + .HasColumnType("text"); + + b.Property("PoseId") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.Property("TagId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("TagLink") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("TaskOrder") + .HasColumnType("integer"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MissionRunId"); + + b.ToTable("MissionTasks"); + }); + + modelBuilder.Entity("Api.Database.Models.Plant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("InstallationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PlantCode") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.HasKey("Id"); + + b.HasIndex("InstallationId"); + + b.HasIndex("PlantCode") + .IsUnique(); + + b.ToTable("Plants"); + }); + + modelBuilder.Entity("Api.Database.Models.Robot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("BatteryLevel") + .HasColumnType("real"); + + b.Property("CurrentAreaId") + .HasColumnType("text"); + + b.Property("CurrentInstallationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CurrentMissionId") + .HasColumnType("text"); + + b.Property("Deprecated") + .HasColumnType("boolean"); + + b.Property("FlotillaStatus") + .IsRequired() + .HasColumnType("text"); + + b.Property("Host") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsarConnected") + .HasColumnType("boolean"); + + b.Property("IsarId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionQueueFrozen") + .HasColumnType("boolean"); + + b.Property("ModelId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Port") + .HasColumnType("integer"); + + b.Property("PressureLevel") + .HasColumnType("real"); + + b.Property("RobotCapabilities") + .HasColumnType("text"); + + b.Property("SerialNumber") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CurrentAreaId"); + + b.HasIndex("CurrentInstallationId"); + + b.HasIndex("ModelId"); + + b.ToTable("Robots"); + }); + + modelBuilder.Entity("Api.Database.Models.RobotBatteryTimeseries", b => + { + b.Property("BatteryLevel") + .HasColumnType("real"); + + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Time") + .HasColumnType("timestamp with time zone"); + + b.ToTable("RobotBatteryTimeseries"); + }); + + modelBuilder.Entity("Api.Database.Models.RobotModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("AverageDurationPerTag") + .HasColumnType("real"); + + b.Property("BatteryWarningThreshold") + .HasColumnType("real"); + + b.Property("LowerPressureWarningThreshold") + .HasColumnType("real"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpperPressureWarningThreshold") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.HasIndex("Type") + .IsUnique(); + + b.ToTable("RobotModels"); + }); + + modelBuilder.Entity("Api.Database.Models.RobotPoseTimeseries", b => + { + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("OrientationW") + .HasColumnType("real"); + + b.Property("OrientationX") + .HasColumnType("real"); + + b.Property("OrientationY") + .HasColumnType("real"); + + b.Property("OrientationZ") + .HasColumnType("real"); + + b.Property("PositionX") + .HasColumnType("real"); + + b.Property("PositionY") + .HasColumnType("real"); + + b.Property("PositionZ") + .HasColumnType("real"); + + b.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Time") + .HasColumnType("timestamp with time zone"); + + b.ToTable("RobotPoseTimeseries"); + }); + + modelBuilder.Entity("Api.Database.Models.RobotPressureTimeseries", b => + { + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("Pressure") + .HasColumnType("real"); + + b.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Time") + .HasColumnType("timestamp with time zone"); + + b.ToTable("RobotPressureTimeseries"); + }); + + modelBuilder.Entity("Api.Database.Models.SafePosition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("AreaId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AreaId"); + + b.ToTable("SafePositions"); + }); + + modelBuilder.Entity("Api.Database.Models.Source", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("CustomMissionTasks") + .HasColumnType("text"); + + b.Property("SourceId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sources"); + }); + + modelBuilder.Entity("Api.Database.Models.UserInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("Oid") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("UserInfos"); + }); + + modelBuilder.Entity("Api.Database.Models.AccessRole", b => + { + b.HasOne("Api.Database.Models.Installation", "Installation") + .WithMany() + .HasForeignKey("InstallationId"); + + b.Navigation("Installation"); + }); + + modelBuilder.Entity("Api.Database.Models.Area", b => + { + b.HasOne("Api.Database.Models.Deck", "Deck") + .WithMany() + .HasForeignKey("DeckId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Api.Database.Models.DefaultLocalizationPose", "DefaultLocalizationPose") + .WithMany() + .HasForeignKey("DefaultLocalizationPoseId"); + + b.HasOne("Api.Database.Models.Installation", "Installation") + .WithMany() + .HasForeignKey("InstallationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Api.Database.Models.Plant", "Plant") + .WithMany() + .HasForeignKey("PlantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.OwnsOne("Api.Database.Models.MapMetadata", "MapMetadata", b1 => + { + b1.Property("AreaId") + .HasColumnType("text"); + + b1.Property("MapName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.HasKey("AreaId"); + + b1.ToTable("Areas"); + + b1.WithOwner() + .HasForeignKey("AreaId"); + + b1.OwnsOne("Api.Database.Models.Boundary", "Boundary", b2 => + { + b2.Property("MapMetadataAreaId") + .HasColumnType("text"); + + b2.Property("X1") + .HasColumnType("double precision"); + + b2.Property("X2") + .HasColumnType("double precision"); + + b2.Property("Y1") + .HasColumnType("double precision"); + + b2.Property("Y2") + .HasColumnType("double precision"); + + b2.Property("Z1") + .HasColumnType("double precision"); + + b2.Property("Z2") + .HasColumnType("double precision"); + + b2.HasKey("MapMetadataAreaId"); + + b2.ToTable("Areas"); + + b2.WithOwner() + .HasForeignKey("MapMetadataAreaId"); + }); + + b1.OwnsOne("Api.Database.Models.TransformationMatrices", "TransformationMatrices", b2 => + { + b2.Property("MapMetadataAreaId") + .HasColumnType("text"); + + b2.Property("C1") + .HasColumnType("double precision"); + + b2.Property("C2") + .HasColumnType("double precision"); + + b2.Property("D1") + .HasColumnType("double precision"); + + b2.Property("D2") + .HasColumnType("double precision"); + + b2.HasKey("MapMetadataAreaId"); + + b2.ToTable("Areas"); + + b2.WithOwner() + .HasForeignKey("MapMetadataAreaId"); + }); + + b1.Navigation("Boundary") + .IsRequired(); + + b1.Navigation("TransformationMatrices") + .IsRequired(); + }); + + b.Navigation("Deck"); + + b.Navigation("DefaultLocalizationPose"); + + b.Navigation("Installation"); + + b.Navigation("MapMetadata") + .IsRequired(); + + b.Navigation("Plant"); + }); + + modelBuilder.Entity("Api.Database.Models.Deck", b => + { + b.HasOne("Api.Database.Models.DefaultLocalizationPose", "DefaultLocalizationPose") + .WithMany() + .HasForeignKey("DefaultLocalizationPoseId"); + + b.HasOne("Api.Database.Models.Installation", "Installation") + .WithMany() + .HasForeignKey("InstallationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Api.Database.Models.Plant", "Plant") + .WithMany() + .HasForeignKey("PlantId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("DefaultLocalizationPose"); + + b.Navigation("Installation"); + + b.Navigation("Plant"); + }); + + modelBuilder.Entity("Api.Database.Models.DefaultLocalizationPose", b => + { + b.OwnsOne("Api.Database.Models.Pose", "Pose", b1 => + { + b1.Property("DefaultLocalizationPoseId") + .HasColumnType("text"); + + b1.HasKey("DefaultLocalizationPoseId"); + + b1.ToTable("DefaultLocalizationPoses"); + + b1.WithOwner() + .HasForeignKey("DefaultLocalizationPoseId"); + + b1.OwnsOne("Api.Database.Models.Orientation", "Orientation", b2 => + { + b2.Property("PoseDefaultLocalizationPoseId") + .HasColumnType("text"); + + b2.Property("W") + .HasColumnType("real"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseDefaultLocalizationPoseId"); + + b2.ToTable("DefaultLocalizationPoses"); + + b2.WithOwner() + .HasForeignKey("PoseDefaultLocalizationPoseId"); + }); + + b1.OwnsOne("Api.Database.Models.Position", "Position", b2 => + { + b2.Property("PoseDefaultLocalizationPoseId") + .HasColumnType("text"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseDefaultLocalizationPoseId"); + + b2.ToTable("DefaultLocalizationPoses"); + + b2.WithOwner() + .HasForeignKey("PoseDefaultLocalizationPoseId"); + }); + + b1.Navigation("Orientation") + .IsRequired(); + + b1.Navigation("Position") + .IsRequired(); + }); + + b.Navigation("Pose") + .IsRequired(); + }); + + modelBuilder.Entity("Api.Database.Models.Inspection", b => + { + b.HasOne("Api.Database.Models.MissionTask", null) + .WithMany("Inspections") + .HasForeignKey("MissionTaskId"); + + b.OwnsOne("Api.Database.Models.Position", "InspectionTarget", b1 => + { + b1.Property("InspectionId") + .HasColumnType("text"); + + b1.Property("X") + .HasColumnType("real"); + + b1.Property("Y") + .HasColumnType("real"); + + b1.Property("Z") + .HasColumnType("real"); + + b1.HasKey("InspectionId"); + + b1.ToTable("Inspections"); + + b1.WithOwner() + .HasForeignKey("InspectionId"); + }); + + b.Navigation("InspectionTarget") + .IsRequired(); + }); + + modelBuilder.Entity("Api.Database.Models.InspectionFinding", b => + { + b.HasOne("Api.Database.Models.Inspection", null) + .WithMany("InspectionFindings") + .HasForeignKey("InspectionId"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionDefinition", b => + { + b.HasOne("Api.Database.Models.Area", "Area") + .WithMany() + .HasForeignKey("AreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Api.Database.Models.MissionRun", "LastSuccessfulRun") + .WithMany() + .HasForeignKey("LastSuccessfulRunId"); + + b.HasOne("Api.Database.Models.Source", "Source") + .WithMany() + .HasForeignKey("SourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Area"); + + b.Navigation("LastSuccessfulRun"); + + b.Navigation("Source"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionRun", b => + { + b.HasOne("Api.Database.Models.Area", "Area") + .WithMany() + .HasForeignKey("AreaId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Api.Database.Models.Robot", "Robot") + .WithMany() + .HasForeignKey("RobotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Api.Database.Models.MapMetadata", "Map", b1 => + { + b1.Property("MissionRunId") + .HasColumnType("text"); + + b1.Property("MapName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.HasKey("MissionRunId"); + + b1.ToTable("MissionRuns"); + + b1.WithOwner() + .HasForeignKey("MissionRunId"); + + b1.OwnsOne("Api.Database.Models.Boundary", "Boundary", b2 => + { + b2.Property("MapMetadataMissionRunId") + .HasColumnType("text"); + + b2.Property("X1") + .HasColumnType("double precision"); + + b2.Property("X2") + .HasColumnType("double precision"); + + b2.Property("Y1") + .HasColumnType("double precision"); + + b2.Property("Y2") + .HasColumnType("double precision"); + + b2.Property("Z1") + .HasColumnType("double precision"); + + b2.Property("Z2") + .HasColumnType("double precision"); + + b2.HasKey("MapMetadataMissionRunId"); + + b2.ToTable("MissionRuns"); + + b2.WithOwner() + .HasForeignKey("MapMetadataMissionRunId"); + }); + + b1.OwnsOne("Api.Database.Models.TransformationMatrices", "TransformationMatrices", b2 => + { + b2.Property("MapMetadataMissionRunId") + .HasColumnType("text"); + + b2.Property("C1") + .HasColumnType("double precision"); + + b2.Property("C2") + .HasColumnType("double precision"); + + b2.Property("D1") + .HasColumnType("double precision"); + + b2.Property("D2") + .HasColumnType("double precision"); + + b2.HasKey("MapMetadataMissionRunId"); + + b2.ToTable("MissionRuns"); + + b2.WithOwner() + .HasForeignKey("MapMetadataMissionRunId"); + }); + + b1.Navigation("Boundary") + .IsRequired(); + + b1.Navigation("TransformationMatrices") + .IsRequired(); + }); + + b.Navigation("Area"); + + b.Navigation("Map"); + + b.Navigation("Robot"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionTask", b => + { + b.HasOne("Api.Database.Models.MissionRun", null) + .WithMany("Tasks") + .HasForeignKey("MissionRunId"); + + b.OwnsOne("Api.Database.Models.Pose", "RobotPose", b1 => + { + b1.Property("MissionTaskId") + .HasColumnType("text"); + + b1.HasKey("MissionTaskId"); + + b1.ToTable("MissionTasks"); + + b1.WithOwner() + .HasForeignKey("MissionTaskId"); + + b1.OwnsOne("Api.Database.Models.Orientation", "Orientation", b2 => + { + b2.Property("PoseMissionTaskId") + .HasColumnType("text"); + + b2.Property("W") + .HasColumnType("real"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseMissionTaskId"); + + b2.ToTable("MissionTasks"); + + b2.WithOwner() + .HasForeignKey("PoseMissionTaskId"); + }); + + b1.OwnsOne("Api.Database.Models.Position", "Position", b2 => + { + b2.Property("PoseMissionTaskId") + .HasColumnType("text"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseMissionTaskId"); + + b2.ToTable("MissionTasks"); + + b2.WithOwner() + .HasForeignKey("PoseMissionTaskId"); + }); + + b1.Navigation("Orientation") + .IsRequired(); + + b1.Navigation("Position") + .IsRequired(); + }); + + b.Navigation("RobotPose") + .IsRequired(); + }); + + modelBuilder.Entity("Api.Database.Models.Plant", b => + { + b.HasOne("Api.Database.Models.Installation", "Installation") + .WithMany() + .HasForeignKey("InstallationId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Installation"); + }); + + modelBuilder.Entity("Api.Database.Models.Robot", b => + { + b.HasOne("Api.Database.Models.Area", "CurrentArea") + .WithMany() + .HasForeignKey("CurrentAreaId"); + + b.HasOne("Api.Database.Models.Installation", "CurrentInstallation") + .WithMany() + .HasForeignKey("CurrentInstallationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Api.Database.Models.RobotModel", "Model") + .WithMany() + .HasForeignKey("ModelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsMany("Api.Database.Models.DocumentInfo", "Documentation", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b1.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b1.Property("Url") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.HasKey("Id"); + + b1.HasIndex("RobotId"); + + b1.ToTable("DocumentInfo"); + + b1.WithOwner() + .HasForeignKey("RobotId"); + }); + + b.OwnsOne("Api.Database.Models.Pose", "Pose", b1 => + { + b1.Property("RobotId") + .HasColumnType("text"); + + b1.HasKey("RobotId"); + + b1.ToTable("Robots"); + + b1.WithOwner() + .HasForeignKey("RobotId"); + + b1.OwnsOne("Api.Database.Models.Orientation", "Orientation", b2 => + { + b2.Property("PoseRobotId") + .HasColumnType("text"); + + b2.Property("W") + .HasColumnType("real"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseRobotId"); + + b2.ToTable("Robots"); + + b2.WithOwner() + .HasForeignKey("PoseRobotId"); + }); + + b1.OwnsOne("Api.Database.Models.Position", "Position", b2 => + { + b2.Property("PoseRobotId") + .HasColumnType("text"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseRobotId"); + + b2.ToTable("Robots"); + + b2.WithOwner() + .HasForeignKey("PoseRobotId"); + }); + + b1.Navigation("Orientation") + .IsRequired(); + + b1.Navigation("Position") + .IsRequired(); + }); + + b.OwnsMany("Api.Database.Models.VideoStream", "VideoStreams", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b1.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b1.Property("ShouldRotate270Clockwise") + .HasColumnType("boolean"); + + b1.Property("Type") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b1.Property("Url") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.HasKey("Id"); + + b1.HasIndex("RobotId"); + + b1.ToTable("VideoStream"); + + b1.WithOwner() + .HasForeignKey("RobotId"); + }); + + b.Navigation("CurrentArea"); + + b.Navigation("CurrentInstallation"); + + b.Navigation("Documentation"); + + b.Navigation("Model"); + + b.Navigation("Pose") + .IsRequired(); + + b.Navigation("VideoStreams"); + }); + + modelBuilder.Entity("Api.Database.Models.SafePosition", b => + { + b.HasOne("Api.Database.Models.Area", null) + .WithMany("SafePositions") + .HasForeignKey("AreaId"); + + b.OwnsOne("Api.Database.Models.Pose", "Pose", b1 => + { + b1.Property("SafePositionId") + .HasColumnType("text"); + + b1.HasKey("SafePositionId"); + + b1.ToTable("SafePositions"); + + b1.WithOwner() + .HasForeignKey("SafePositionId"); + + b1.OwnsOne("Api.Database.Models.Orientation", "Orientation", b2 => + { + b2.Property("PoseSafePositionId") + .HasColumnType("text"); + + b2.Property("W") + .HasColumnType("real"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseSafePositionId"); + + b2.ToTable("SafePositions"); + + b2.WithOwner() + .HasForeignKey("PoseSafePositionId"); + }); + + b1.OwnsOne("Api.Database.Models.Position", "Position", b2 => + { + b2.Property("PoseSafePositionId") + .HasColumnType("text"); + + b2.Property("X") + .HasColumnType("real"); + + b2.Property("Y") + .HasColumnType("real"); + + b2.Property("Z") + .HasColumnType("real"); + + b2.HasKey("PoseSafePositionId"); + + b2.ToTable("SafePositions"); + + b2.WithOwner() + .HasForeignKey("PoseSafePositionId"); + }); + + b1.Navigation("Orientation") + .IsRequired(); + + b1.Navigation("Position") + .IsRequired(); + }); + + b.Navigation("Pose") + .IsRequired(); + }); + + modelBuilder.Entity("Api.Database.Models.Area", b => + { + b.Navigation("SafePositions"); + }); + + modelBuilder.Entity("Api.Database.Models.Inspection", b => + { + b.Navigation("InspectionFindings"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionRun", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("Api.Database.Models.MissionTask", b => + { + b.Navigation("Inspections"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/api/Migrations/20240910132840_AddDocumentationToRobot.cs b/backend/api/Migrations/20240910132840_AddDocumentationToRobot.cs new file mode 100644 index 000000000..1b7f2b49a --- /dev/null +++ b/backend/api/Migrations/20240910132840_AddDocumentationToRobot.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Api.Migrations +{ + /// + public partial class AddDocumentationToRobot : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "DocumentInfo", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + Url = table.Column(type: "character varying(200)", maxLength: 200, nullable: false), + RobotId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DocumentInfo", x => x.Id); + table.ForeignKey( + name: "FK_DocumentInfo_Robots_RobotId", + column: x => x.RobotId, + principalTable: "Robots", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_DocumentInfo_RobotId", + table: "DocumentInfo", + column: "RobotId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "DocumentInfo"); + } + } +} diff --git a/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs b/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs index d209dec89..e3972ee92 100644 --- a/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs +++ b/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs @@ -1155,6 +1155,36 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.OwnsMany("Api.Database.Models.DocumentInfo", "Documentation", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b1.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.Property("RobotId") + .IsRequired() + .HasColumnType("text"); + + b1.Property("Url") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b1.HasKey("Id"); + + b1.HasIndex("RobotId"); + + b1.ToTable("DocumentInfo"); + + b1.WithOwner() + .HasForeignKey("RobotId"); + }); + b.OwnsOne("Api.Database.Models.Pose", "Pose", b1 => { b1.Property("RobotId") @@ -1263,6 +1293,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("CurrentInstallation"); + b.Navigation("Documentation"); + b.Navigation("Model"); b.Navigation("Pose") diff --git a/backend/api/Services/RobotService.cs b/backend/api/Services/RobotService.cs index b6db02cd3..8ccfe5448 100644 --- a/backend/api/Services/RobotService.cs +++ b/backend/api/Services/RobotService.cs @@ -321,6 +321,7 @@ private IQueryable GetRobotsWithSubModels(bool readOnly = true) var accessibleInstallationCodes = accessRoleService.GetAllowedInstallationCodes(); var query = context.Robots .Include(r => r.VideoStreams) + .Include(r => r.Documentation) .Include(r => r.Model) .Include(r => r.CurrentInstallation) .Include(r => r.CurrentArea) From af2e22fdbf0fbc51dac21eadb4e26b4a4dbcc488 Mon Sep 17 00:00:00 2001 From: Eddasol Date: Thu, 29 Aug 2024 15:09:28 +0200 Subject: [PATCH 3/3] Display documentation info on robot page --- .../Pages/RobotPage/Documentation.tsx | 34 +++++++++++++++++++ .../components/Pages/RobotPage/RobotPage.tsx | 4 +++ frontend/src/language/en.json | 3 +- frontend/src/language/no.json | 3 +- frontend/src/models/DocumentInfo.ts | 4 +++ frontend/src/models/Robot.ts | 2 ++ frontend/src/utils/icons.tsx | 3 ++ 7 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 frontend/src/components/Pages/RobotPage/Documentation.tsx create mode 100644 frontend/src/models/DocumentInfo.ts diff --git a/frontend/src/components/Pages/RobotPage/Documentation.tsx b/frontend/src/components/Pages/RobotPage/Documentation.tsx new file mode 100644 index 000000000..47348a84c --- /dev/null +++ b/frontend/src/components/Pages/RobotPage/Documentation.tsx @@ -0,0 +1,34 @@ +import { Typography, Icon } from '@equinor/eds-core-react' +import { Icons } from 'utils/icons' +import { tokens } from '@equinor/eds-tokens' +import { useLanguageContext } from 'components/Contexts/LanguageContext' +import styled from 'styled-components' +import { DocumentInfo } from 'models/DocumentInfo' + +const DocumentStyle = styled.div` + display: flex; + gap: 1rem; + align-items: center; +` + +export const DocumentationSection = ({ documentation }: { documentation: DocumentInfo[] }) => { + const { TranslateText } = useLanguageContext() + + return ( + <> + {TranslateText('Documentation')} + {documentation.map((documentInfo, index) => ( + + + + {documentInfo.name} + + + ))} + + ) +} diff --git a/frontend/src/components/Pages/RobotPage/RobotPage.tsx b/frontend/src/components/Pages/RobotPage/RobotPage.tsx index cfb4ede8b..48e4f7796 100644 --- a/frontend/src/components/Pages/RobotPage/RobotPage.tsx +++ b/frontend/src/components/Pages/RobotPage/RobotPage.tsx @@ -18,6 +18,7 @@ import { StyledButton, StyledPage } from 'components/Styles/StyledComponents' import { AlertType, useAlertContext } from 'components/Contexts/AlertContext' import { FailedRequestAlertContent, FailedRequestAlertListContent } from 'components/Alerts/FailedRequestAlert' import { AlertCategory } from 'components/Alerts/AlertsBanner' +import { DocumentationSection } from './Documentation' const RobotArmMovementSection = styled.div` display: flex; @@ -155,6 +156,9 @@ export const RobotPage = () => { )} + {selectedRobot.documentation && selectedRobot.documentation.length > 0 && ( + + )} )} diff --git a/frontend/src/language/en.json b/frontend/src/language/en.json index 46291445f..52aeaf153 100644 --- a/frontend/src/language/en.json +++ b/frontend/src/language/en.json @@ -264,5 +264,6 @@ "Alerts": "Alerts", "No alerts": "No alerts", "minutes ago": "minutes ago", - "Failed to retrieve previous mission runs": "Failed to retrieve previous mission runs" + "Failed to retrieve previous mission runs": "Failed to retrieve previous mission runs", + "Documentation": "Documentation" } diff --git a/frontend/src/language/no.json b/frontend/src/language/no.json index c80bc341e..5cfbfa53e 100644 --- a/frontend/src/language/no.json +++ b/frontend/src/language/no.json @@ -264,5 +264,6 @@ "Alerts": "Varsler", "No alerts": "Ingen varsler", "minutes ago": "minutter siden", - "Failed to retrieve previous mission runs": "Kunne ikke hente tildigere oppdragskjøringer" + "Failed to retrieve previous mission runs": "Kunne ikke hente tildigere oppdragskjøringer", + "Documentation": "Dokumentasjon" } diff --git a/frontend/src/models/DocumentInfo.ts b/frontend/src/models/DocumentInfo.ts new file mode 100644 index 000000000..4f9173b09 --- /dev/null +++ b/frontend/src/models/DocumentInfo.ts @@ -0,0 +1,4 @@ +export interface DocumentInfo { + name: string + url: string +} diff --git a/frontend/src/models/Robot.ts b/frontend/src/models/Robot.ts index 2a28c15b2..e140842af 100644 --- a/frontend/src/models/Robot.ts +++ b/frontend/src/models/Robot.ts @@ -1,5 +1,6 @@ import { Area } from './Area' import { BatteryStatus } from './Battery' +import { DocumentInfo } from './DocumentInfo' import { Installation, placeholderInstallation } from './Installation' import { Pose } from './Pose' import { RobotModel, placeholderRobotModel } from './RobotModel' @@ -37,6 +38,7 @@ export interface Robot { host?: string logs?: string port?: number + documentation?: DocumentInfo[] videoStreams?: VideoStream[] isarUri?: string currentArea?: Area diff --git a/frontend/src/utils/icons.tsx b/frontend/src/utils/icons.tsx index 348272b70..91cdc3b60 100644 --- a/frontend/src/utils/icons.tsx +++ b/frontend/src/utils/icons.tsx @@ -42,6 +42,7 @@ import { info_circle, blocked, close_circle_outlined, + file_description, } from '@equinor/eds-icons' Icon.add({ @@ -87,6 +88,7 @@ Icon.add({ info_circle, blocked, close_circle_outlined, + file_description, }) export enum Icons { @@ -132,4 +134,5 @@ export enum Icons { Info = 'info_circle', Blocked = 'blocked', ClosedCircleOutlined = 'close_circle_outlined', + FileDescription = 'file_description', }