diff --git a/backend/api/Controllers/Models/RobotResponse.cs b/backend/api/Controllers/Models/RobotResponse.cs index a553d3b8c..f3c6aebd8 100644 --- a/backend/api/Controllers/Models/RobotResponse.cs +++ b/backend/api/Controllers/Models/RobotResponse.cs @@ -14,7 +14,7 @@ public class RobotResponse public string SerialNumber { get; set; } - public Installation? CurrentInstallation { get; } + public Installation CurrentInstallation { get; } public AreaResponse? CurrentArea { get; set; } diff --git a/backend/api/Database/Models/Area.cs b/backend/api/Database/Models/Area.cs index 2cb4f86f9..3fae39d93 100644 --- a/backend/api/Database/Models/Area.cs +++ b/backend/api/Database/Models/Area.cs @@ -10,10 +10,13 @@ public class Area [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } - public virtual Deck? Deck { get; set; } + [Required] + public virtual Deck Deck { get; set; } + [Required] public virtual Plant Plant { get; set; } + [Required] public virtual Installation Installation { get; set; } [Required] @@ -23,7 +26,6 @@ public class Area [Required] public MapMetadata MapMetadata { get; set; } - public DefaultLocalizationPose? DefaultLocalizationPose { get; set; } public IList SafePositions { get; set; } diff --git a/backend/api/Database/Models/Deck.cs b/backend/api/Database/Models/Deck.cs index dd9e3ec12..48414a9e6 100644 --- a/backend/api/Database/Models/Deck.cs +++ b/backend/api/Database/Models/Deck.cs @@ -10,8 +10,10 @@ public class Deck [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } + [Required] public virtual Plant Plant { get; set; } + [Required] public virtual Installation Installation { get; set; } public DefaultLocalizationPose? DefaultLocalizationPose { get; set; } diff --git a/backend/api/Database/Models/DefaultLocalizationPose.cs b/backend/api/Database/Models/DefaultLocalizationPose.cs index cc212f4a1..ea2f81cd5 100644 --- a/backend/api/Database/Models/DefaultLocalizationPose.cs +++ b/backend/api/Database/Models/DefaultLocalizationPose.cs @@ -10,6 +10,7 @@ public class DefaultLocalizationPose [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } + [Required] public Pose Pose { get; set; } public DefaultLocalizationPose() diff --git a/backend/api/Database/Models/Inspection.cs b/backend/api/Database/Models/Inspection.cs index 11e59edd3..b8b3ba6b4 100644 --- a/backend/api/Database/Models/Inspection.cs +++ b/backend/api/Database/Models/Inspection.cs @@ -50,11 +50,12 @@ public Inspection(Inspection copy, InspectionStatus? inspectionStatus = null) [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } + [Required] [MaxLength(200)] // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Local - public string? IsarStepId { get; private set; } = Guid.NewGuid().ToString(); + public string IsarStepId { get; private set; } = Guid.NewGuid().ToString(); - public Position InspectionTarget { get; set; } + public Position? InspectionTarget { get; set; } [Required] public InspectionStatus Status diff --git a/backend/api/Database/Models/InspectionFinding.cs b/backend/api/Database/Models/InspectionFinding.cs index 2feb20373..188355096 100644 --- a/backend/api/Database/Models/InspectionFinding.cs +++ b/backend/api/Database/Models/InspectionFinding.cs @@ -10,10 +10,13 @@ public class InspectionFinding [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } + [Required] public DateTime InspectionDate { get; set; } + [Required] public string IsarStepId { get; set; } + [Required] public string Finding { get; set; } public InspectionFinding(InspectionFindingQuery createInspectionFindingQuery) diff --git a/backend/api/Database/Models/MissionRun.cs b/backend/api/Database/Models/MissionRun.cs index d437cea7e..7bcb81a7b 100644 --- a/backend/api/Database/Models/MissionRun.cs +++ b/backend/api/Database/Models/MissionRun.cs @@ -10,6 +10,7 @@ public class MissionRun : SortableRecord private MissionStatus _status; private IList _tasks; + [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } diff --git a/backend/api/Database/Models/MissionTask.cs b/backend/api/Database/Models/MissionTask.cs index e5a245e20..1b9517848 100644 --- a/backend/api/Database/Models/MissionTask.cs +++ b/backend/api/Database/Models/MissionTask.cs @@ -99,6 +99,7 @@ public MissionTask(MissionTask copy, TaskStatus? status = null) [Required] public int TaskOrder { get; set; } + [Required] public MissionTaskType Type { get; set; } [MaxLength(200)] diff --git a/backend/api/Database/Models/Plant.cs b/backend/api/Database/Models/Plant.cs index 806d3caf8..7a7141bb3 100644 --- a/backend/api/Database/Models/Plant.cs +++ b/backend/api/Database/Models/Plant.cs @@ -10,6 +10,7 @@ public class Plant [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public string Id { get; set; } + [Required] public virtual Installation Installation { get; set; } [Required] diff --git a/backend/api/Database/Models/Pose.cs b/backend/api/Database/Models/Pose.cs index 13f15b015..aa1a49900 100644 --- a/backend/api/Database/Models/Pose.cs +++ b/backend/api/Database/Models/Pose.cs @@ -8,7 +8,6 @@ namespace Api.Database.Models [Owned] public class Orientation { - public Orientation() { X = 0; @@ -32,9 +31,14 @@ public Orientation(float x = 0, float y = 0, float z = 0, float w = 1) Z = z; W = w; } + + [Required] public float X { get; set; } + [Required] public float Y { get; set; } + [Required] public float Z { get; set; } + [Required] public float W { get; set; } public override bool Equals(object obj) @@ -80,8 +84,11 @@ public Position(float x = 0, float y = 0, float z = 0) Z = z; } + [Required] public float X { get; set; } + [Required] public float Y { get; set; } + [Required] public float Z { get; set; } public override bool Equals(object obj) diff --git a/backend/api/Database/Models/Robot.cs b/backend/api/Database/Models/Robot.cs index 0d3c350bb..84ac3e786 100644 --- a/backend/api/Database/Models/Robot.cs +++ b/backend/api/Database/Models/Robot.cs @@ -6,7 +6,6 @@ namespace Api.Database.Models { public class Robot { - public Robot() { VideoStreams = new List(); @@ -65,7 +64,8 @@ public Robot(CreateRobotQuery createQuery, Installation installation, Area? area [MaxLength(200)] public string SerialNumber { get; set; } - public Installation? CurrentInstallation { get; set; } + [Required] + public Installation CurrentInstallation { get; set; } public Area? CurrentArea { get; set; } diff --git a/backend/api/Database/Models/SortableRecord.cs b/backend/api/Database/Models/SortableRecord.cs index 33127dc6c..f0350238f 100644 --- a/backend/api/Database/Models/SortableRecord.cs +++ b/backend/api/Database/Models/SortableRecord.cs @@ -1,5 +1,4 @@ -#pragma warning disable CS8618 -namespace Api.Database.Models +namespace Api.Database.Models { public interface SortableRecord { diff --git a/backend/api/EventHandlers/MissionEventHandler.cs b/backend/api/EventHandlers/MissionEventHandler.cs index edbfb16fd..377f34a61 100644 --- a/backend/api/EventHandlers/MissionEventHandler.cs +++ b/backend/api/EventHandlers/MissionEventHandler.cs @@ -166,12 +166,10 @@ private async void OnRobotAvailable(object? sender, RobotAvailableEventArgs e) private void ReportFailureToSignalR(Robot robot, string message) { - var installation = robot.CurrentInstallation; - if (installation != null) - _ = SignalRService.SendMessageAsync( - "Alert", - installation, - new AlertResponse("safezoneFailure", "Safezone failure", message, installation.InstallationCode, robot.Id)); + _ = SignalRService.SendMessageAsync( + "Alert", + robot.CurrentInstallation, + new AlertResponse("safezoneFailure", "Safezone failure", message, robot.CurrentInstallation.InstallationCode, robot.Id)); } private async void OnEmergencyButtonPressedForRobot(object? sender, EmergencyButtonPressedForRobotEventArgs e) diff --git a/backend/api/Migrations/20240104142156_MakeDeckInAreaRequired.Designer.cs b/backend/api/Migrations/20240104142156_MakeDeckInAreaRequired.Designer.cs new file mode 100644 index 000000000..448c05190 --- /dev/null +++ b/backend/api/Migrations/20240104142156_MakeDeckInAreaRequired.Designer.cs @@ -0,0 +1,1366 @@ +// +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("20240104142156_MakeDeckInAreaRequired")] + partial class MakeDeckInAreaRequired + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .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.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") + .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("IsarMissionId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("MissionRunPriority") + .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("EchoPoseId") + .HasColumnType("integer"); + + b.Property("EchoTagLink") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsarTaskId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionRunId") + .HasColumnType("text"); + + 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("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") + .HasColumnType("text"); + + b.Property("CurrentMissionId") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Host") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + 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("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("SourceId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sources"); + }); + + 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.Position", "InspectionTarget", b1 => + { + b1.Property("MissionTaskId") + .HasColumnType("text"); + + b1.Property("X") + .HasColumnType("real"); + + b1.Property("Y") + .HasColumnType("real"); + + b1.Property("Z") + .HasColumnType("real"); + + b1.HasKey("MissionTaskId"); + + b1.ToTable("MissionTasks"); + + b1.WithOwner() + .HasForeignKey("MissionTaskId"); + }); + + 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("InspectionTarget") + .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"); + + b.HasOne("Api.Database.Models.RobotModel", "Model") + .WithMany() + .HasForeignKey("ModelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + 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("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/20240104142156_MakeDeckInAreaRequired.cs b/backend/api/Migrations/20240104142156_MakeDeckInAreaRequired.cs new file mode 100644 index 000000000..d51cfbc49 --- /dev/null +++ b/backend/api/Migrations/20240104142156_MakeDeckInAreaRequired.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Api.Migrations +{ + /// + public partial class MakeDeckInAreaRequired : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "DeckId", + table: "Areas", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "DeckId", + table: "Areas", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/backend/api/Migrations/20240104143242_MakeCurrentRobotInstallationRequired.Designer.cs b/backend/api/Migrations/20240104143242_MakeCurrentRobotInstallationRequired.Designer.cs new file mode 100644 index 000000000..9ee1c53ae --- /dev/null +++ b/backend/api/Migrations/20240104143242_MakeCurrentRobotInstallationRequired.Designer.cs @@ -0,0 +1,1369 @@ +// +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("20240104143242_MakeCurrentRobotInstallationRequired")] + partial class MakeCurrentRobotInstallationRequired + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .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.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") + .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("IsarMissionId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("MissionRunPriority") + .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("EchoPoseId") + .HasColumnType("integer"); + + b.Property("EchoTagLink") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsarTaskId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionRunId") + .HasColumnType("text"); + + 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("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("Enabled") + .HasColumnType("boolean"); + + b.Property("Host") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + 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("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("SourceId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sources"); + }); + + 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.Position", "InspectionTarget", b1 => + { + b1.Property("MissionTaskId") + .HasColumnType("text"); + + b1.Property("X") + .HasColumnType("real"); + + b1.Property("Y") + .HasColumnType("real"); + + b1.Property("Z") + .HasColumnType("real"); + + b1.HasKey("MissionTaskId"); + + b1.ToTable("MissionTasks"); + + b1.WithOwner() + .HasForeignKey("MissionTaskId"); + }); + + 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("InspectionTarget") + .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.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("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/20240104143242_MakeCurrentRobotInstallationRequired.cs b/backend/api/Migrations/20240104143242_MakeCurrentRobotInstallationRequired.cs new file mode 100644 index 000000000..1cfc7073e --- /dev/null +++ b/backend/api/Migrations/20240104143242_MakeCurrentRobotInstallationRequired.cs @@ -0,0 +1,59 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Api.Migrations +{ + /// + public partial class MakeCurrentRobotInstallationRequired : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Robots_Installations_CurrentInstallationId", + table: "Robots"); + + migrationBuilder.AlterColumn( + name: "CurrentInstallationId", + table: "Robots", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + + migrationBuilder.AddForeignKey( + name: "FK_Robots_Installations_CurrentInstallationId", + table: "Robots", + column: "CurrentInstallationId", + principalTable: "Installations", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Robots_Installations_CurrentInstallationId", + table: "Robots"); + + migrationBuilder.AlterColumn( + name: "CurrentInstallationId", + table: "Robots", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AddForeignKey( + name: "FK_Robots_Installations_CurrentInstallationId", + table: "Robots", + column: "CurrentInstallationId", + principalTable: "Installations", + principalColumn: "Id"); + } + } +} diff --git a/backend/api/Migrations/20240112094731_AddRequiredFieldsToInspectionAndPoses.Designer.cs b/backend/api/Migrations/20240112094731_AddRequiredFieldsToInspectionAndPoses.Designer.cs new file mode 100644 index 000000000..d90938647 --- /dev/null +++ b/backend/api/Migrations/20240112094731_AddRequiredFieldsToInspectionAndPoses.Designer.cs @@ -0,0 +1,1369 @@ +// +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("20240112094731_AddRequiredFieldsToInspectionAndPoses")] + partial class AddRequiredFieldsToInspectionAndPoses + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .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.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("IsarMissionId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionId") + .HasColumnType("text"); + + b.Property("MissionRunPriority") + .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("EchoPoseId") + .HasColumnType("integer"); + + b.Property("EchoTagLink") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsarTaskId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("MissionRunId") + .HasColumnType("text"); + + 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("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("Enabled") + .HasColumnType("boolean"); + + b.Property("Host") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + 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("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("SourceId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sources"); + }); + + 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"); + }); + + 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.Position", "InspectionTarget", b1 => + { + b1.Property("MissionTaskId") + .HasColumnType("text"); + + b1.Property("X") + .HasColumnType("real"); + + b1.Property("Y") + .HasColumnType("real"); + + b1.Property("Z") + .HasColumnType("real"); + + b1.HasKey("MissionTaskId"); + + b1.ToTable("MissionTasks"); + + b1.WithOwner() + .HasForeignKey("MissionTaskId"); + }); + + 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("InspectionTarget") + .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.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("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/20240112094731_AddRequiredFieldsToInspectionAndPoses.cs b/backend/api/Migrations/20240112094731_AddRequiredFieldsToInspectionAndPoses.cs new file mode 100644 index 000000000..c051d4ba3 --- /dev/null +++ b/backend/api/Migrations/20240112094731_AddRequiredFieldsToInspectionAndPoses.cs @@ -0,0 +1,94 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Api.Migrations +{ + /// + public partial class AddRequiredFieldsToInspectionAndPoses : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "IsarStepId", + table: "Inspections", + type: "character varying(200)", + maxLength: 200, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "character varying(200)", + oldMaxLength: 200, + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "InspectionTarget_Z", + table: "Inspections", + type: "real", + nullable: true, + oldClrType: typeof(float), + oldType: "real"); + + migrationBuilder.AlterColumn( + name: "InspectionTarget_Y", + table: "Inspections", + type: "real", + nullable: true, + oldClrType: typeof(float), + oldType: "real"); + + migrationBuilder.AlterColumn( + name: "InspectionTarget_X", + table: "Inspections", + type: "real", + nullable: true, + oldClrType: typeof(float), + oldType: "real"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "IsarStepId", + table: "Inspections", + type: "character varying(200)", + maxLength: 200, + nullable: true, + oldClrType: typeof(string), + oldType: "character varying(200)", + oldMaxLength: 200); + + migrationBuilder.AlterColumn( + name: "InspectionTarget_Z", + table: "Inspections", + type: "real", + nullable: false, + defaultValue: 0f, + oldClrType: typeof(float), + oldType: "real", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "InspectionTarget_Y", + table: "Inspections", + type: "real", + nullable: false, + defaultValue: 0f, + oldClrType: typeof(float), + oldType: "real", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "InspectionTarget_X", + table: "Inspections", + type: "real", + nullable: false, + defaultValue: 0f, + oldClrType: typeof(float), + oldType: "real", + oldNullable: true); + } + } +} diff --git a/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs b/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs index bea0cb50a..cbd17575b 100644 --- a/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs +++ b/backend/api/Migrations/FlotillaDbContextModelSnapshot.cs @@ -53,6 +53,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("text"); b.Property("DeckId") + .IsRequired() .HasColumnType("text"); b.Property("DefaultLocalizationPoseId") @@ -149,6 +150,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character varying(250)"); b.Property("IsarStepId") + .IsRequired() .HasMaxLength(200) .HasColumnType("character varying(200)"); @@ -437,6 +439,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("text"); b.Property("CurrentInstallationId") + .IsRequired() .HasColumnType("text"); b.Property("CurrentMissionId") @@ -644,7 +647,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("Api.Database.Models.Deck", "Deck") .WithMany() .HasForeignKey("DeckId") - .OnDelete(DeleteBehavior.Restrict); + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); b.HasOne("Api.Database.Models.DefaultLocalizationPose", "DefaultLocalizationPose") .WithMany() @@ -879,8 +883,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("InspectionId"); }); - b.Navigation("InspectionTarget") - .IsRequired(); + b.Navigation("InspectionTarget"); }); modelBuilder.Entity("Api.Database.Models.InspectionFinding", b => @@ -1136,7 +1139,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("Api.Database.Models.Installation", "CurrentInstallation") .WithMany() - .HasForeignKey("CurrentInstallationId"); + .HasForeignKey("CurrentInstallationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.HasOne("Api.Database.Models.RobotModel", "Model") .WithMany() diff --git a/backend/api/Services/LocalizationService.cs b/backend/api/Services/LocalizationService.cs index 74ed5a779..f848e4313 100644 --- a/backend/api/Services/LocalizationService.cs +++ b/backend/api/Services/LocalizationService.cs @@ -21,9 +21,9 @@ public async Task EnsureRobotIsOnSameInstallationAsMission(Robot robot, MissionD { var missionInstallation = await installationService.ReadByName(missionDefinition.InstallationCode); - if (missionInstallation is null || robot.CurrentInstallation is null) + if (missionInstallation is null) { - string errorMessage = $"Could not find installation for installation code {missionDefinition.InstallationCode} or the robot has no current installation"; + string errorMessage = $"Could not find installation for installation code {missionDefinition.InstallationCode}"; logger.LogError("{Message}", errorMessage); throw new InstallationNotFoundException(errorMessage); } diff --git a/backend/api/Services/Models/IsarMissionDefinition.cs b/backend/api/Services/Models/IsarMissionDefinition.cs index 34eac19d6..bc37a2968 100644 --- a/backend/api/Services/Models/IsarMissionDefinition.cs +++ b/backend/api/Services/Models/IsarMissionDefinition.cs @@ -73,7 +73,7 @@ public struct IsarInspectionDefinition public string Type { get; set; } [JsonPropertyName("inspection_target")] - public IsarPosition InspectionTarget { get; set; } + public IsarPosition? InspectionTarget { get; set; } [JsonPropertyName("duration")] public float? Duration { get; set; } @@ -85,12 +85,12 @@ public IsarInspectionDefinition(Inspection inspection, MissionRun missionRun) { Id = inspection.IsarStepId; Type = inspection.InspectionType.ToString(); - InspectionTarget = new IsarPosition( + InspectionTarget = inspection.InspectionTarget != null ? new IsarPosition( inspection.InspectionTarget.X, inspection.InspectionTarget.Y, inspection.InspectionTarget.Z, "asset" - ); + ) : null; Duration = inspection.VideoDuration; var metadata = new Dictionary { diff --git a/backend/api/Services/ReturnToHomeService.cs b/backend/api/Services/ReturnToHomeService.cs index 46063f929..076112e07 100644 --- a/backend/api/Services/ReturnToHomeService.cs +++ b/backend/api/Services/ReturnToHomeService.cs @@ -31,13 +31,6 @@ public async Task IsRobotHome(string robotId) throw new RobotNotFoundException(errorMessage); } - if (robot.CurrentInstallation is null) - { - string errorMessage = $"Unable to schedule a return to home mission as the robot {robot.Id} is not linked to an installation"; - logger.LogError("{Message}", errorMessage); - throw new InstallationNotFoundException(errorMessage); - } - if (robot.CurrentArea is null) { string errorMessage = $"Unable to schedule a return to home mission as the robot {robot.Id} is not linked to an area";