feat: Add main application views and structure
Some checks failed
Build and Publish Docker Image / build-and-push (push) Has been cancelled
Some checks failed
Build and Publish Docker Image / build-and-push (push) Has been cancelled
- Implemented CreateInstanceView for creating new instances. - Added HostsView for managing SSH hosts with CRUD operations. - Created InstancesView for displaying and managing instances. - Developed LogsView for viewing operation logs. - Introduced SecretsView for managing secrets associated with hosts. - Established SettingsView for configuring application settings. - Created MainWindow as the main application window with navigation. - Added app manifest and configuration files for logging and settings.
This commit is contained in:
41
OTSSignsOrchestrator.Core/Models/DTOs/CreateInstanceDto.cs
Normal file
41
OTSSignsOrchestrator.Core/Models/DTOs/CreateInstanceDto.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.DTOs;
|
||||
|
||||
public class CreateInstanceDto
|
||||
{
|
||||
[Required, MaxLength(100)]
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Exactly 3 lowercase letters used to derive all resource names.</summary>
|
||||
[Required, MaxLength(3), MinLength(3), RegularExpression("^[a-z]{3}$", ErrorMessage = "Abbreviation must be exactly 3 lowercase letters.")]
|
||||
public string CustomerAbbrev { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>SSH host to deploy to.</summary>
|
||||
public Guid? SshHostId { get; set; }
|
||||
|
||||
/// <summary>Pangolin Newt ID (optional — tunnel service excluded if not provided).</summary>
|
||||
[MaxLength(500)]
|
||||
public string? NewtId { get; set; }
|
||||
|
||||
/// <summary>Pangolin Newt Secret (optional — tunnel service excluded if not provided).</summary>
|
||||
[MaxLength(500)]
|
||||
public string? NewtSecret { get; set; }
|
||||
|
||||
// ── CIFS / SMB credentials (optional — falls back to global settings) ──
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? CifsServer { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsShareBasePath { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? CifsUsername { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsPassword { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsExtraOptions { get; set; }
|
||||
}
|
||||
13
OTSSignsOrchestrator.Core/Models/DTOs/DeploymentResultDto.cs
Normal file
13
OTSSignsOrchestrator.Core/Models/DTOs/DeploymentResultDto.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace OTSSignsOrchestrator.Core.Models.DTOs;
|
||||
|
||||
public class DeploymentResultDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string StackName { get; set; } = string.Empty;
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public string? Output { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
public int ExitCode { get; set; }
|
||||
public long DurationMs { get; set; }
|
||||
public int ServiceCount { get; set; }
|
||||
}
|
||||
8
OTSSignsOrchestrator.Core/Models/DTOs/TemplateConfig.cs
Normal file
8
OTSSignsOrchestrator.Core/Models/DTOs/TemplateConfig.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace OTSSignsOrchestrator.Core.Models.DTOs;
|
||||
|
||||
public class TemplateConfig
|
||||
{
|
||||
public string Yaml { get; set; } = string.Empty;
|
||||
public List<string> EnvLines { get; set; } = new();
|
||||
public DateTime FetchedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
43
OTSSignsOrchestrator.Core/Models/DTOs/UpdateInstanceDto.cs
Normal file
43
OTSSignsOrchestrator.Core/Models/DTOs/UpdateInstanceDto.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.DTOs;
|
||||
|
||||
public class UpdateInstanceDto
|
||||
{
|
||||
[MaxLength(500)]
|
||||
public string? TemplateRepoUrl { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? TemplateRepoPat { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? SmtpServer { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? SmtpUsername { get; set; }
|
||||
|
||||
public List<string>? Constraints { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? XiboUsername { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? XiboPassword { get; set; }
|
||||
|
||||
// ── CIFS / SMB credentials (per-instance) ──
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? CifsServer { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsShareBasePath { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? CifsUsername { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsPassword { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsExtraOptions { get; set; }
|
||||
}
|
||||
23
OTSSignsOrchestrator.Core/Models/Entities/AppSetting.cs
Normal file
23
OTSSignsOrchestrator.Core/Models/Entities/AppSetting.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Key-value application setting persisted in the local database.
|
||||
/// Sensitive values are encrypted at rest via DataProtection.
|
||||
/// </summary>
|
||||
public class AppSetting
|
||||
{
|
||||
[Key, MaxLength(200)]
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(4000)]
|
||||
public string? Value { get; set; }
|
||||
|
||||
[Required, MaxLength(50)]
|
||||
public string Category { get; set; } = string.Empty;
|
||||
|
||||
public bool IsSensitive { get; set; }
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
117
OTSSignsOrchestrator.Core/Models/Entities/CmsInstance.cs
Normal file
117
OTSSignsOrchestrator.Core/Models/Entities/CmsInstance.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.Entities;
|
||||
|
||||
public enum InstanceStatus
|
||||
{
|
||||
Deploying,
|
||||
Active,
|
||||
Error,
|
||||
Deleted
|
||||
}
|
||||
|
||||
public enum XiboApiTestStatus
|
||||
{
|
||||
Unknown,
|
||||
Success,
|
||||
Failed
|
||||
}
|
||||
|
||||
public class CmsInstance
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required, MaxLength(100)]
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Exactly 3 lowercase letters used to derive all resource names.</summary>
|
||||
[MaxLength(3)]
|
||||
public string CustomerAbbrev { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(100)]
|
||||
public string StackName { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(200)]
|
||||
public string CmsServerName { get; set; } = string.Empty;
|
||||
|
||||
[Required, Range(1024, 65535)]
|
||||
public int HostHttpPort { get; set; }
|
||||
|
||||
[Required, MaxLength(500)]
|
||||
public string ThemeHostPath { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(500)]
|
||||
public string LibraryHostPath { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(200)]
|
||||
public string SmtpServer { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(200)]
|
||||
public string SmtpUsername { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// JSON array of placement constraints, e.g. ["node.labels.xibo==true"]
|
||||
/// </summary>
|
||||
[MaxLength(2000)]
|
||||
public string? Constraints { get; set; }
|
||||
|
||||
[Required, MaxLength(500)]
|
||||
public string TemplateRepoUrl { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? TemplateRepoPat { get; set; }
|
||||
|
||||
public DateTime? TemplateLastFetch { get; set; }
|
||||
|
||||
[MaxLength(100)]
|
||||
public string? TemplateCacheKey { get; set; }
|
||||
|
||||
public InstanceStatus Status { get; set; } = InstanceStatus.Deploying;
|
||||
|
||||
/// <summary>Encrypted Xibo admin username for API access.</summary>
|
||||
[MaxLength(500)]
|
||||
public string? XiboUsername { get; set; }
|
||||
|
||||
/// <summary>Encrypted Xibo admin password. Never logged; encrypted at rest.</summary>
|
||||
[MaxLength(1000)]
|
||||
public string? XiboPassword { get; set; }
|
||||
|
||||
public XiboApiTestStatus XiboApiTestStatus { get; set; } = XiboApiTestStatus.Unknown;
|
||||
|
||||
public DateTime? XiboApiTestedAt { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Soft delete marker.</summary>
|
||||
public DateTime? DeletedAt { get; set; }
|
||||
|
||||
// ── CIFS / SMB credentials (per-instance) ─────────────────────────────
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? CifsServer { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsShareBasePath { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? CifsUsername { get; set; }
|
||||
|
||||
/// <summary>Encrypted CIFS password. Never logged; encrypted at rest.</summary>
|
||||
[MaxLength(1000)]
|
||||
public string? CifsPassword { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string? CifsExtraOptions { get; set; }
|
||||
|
||||
/// <summary>ID of the SshHost this instance is deployed to.</summary>
|
||||
public Guid? SshHostId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(SshHostId))]
|
||||
public SshHost? SshHost { get; set; }
|
||||
|
||||
public ICollection<OperationLog> OperationLogs { get; set; } = new List<OperationLog>();
|
||||
}
|
||||
48
OTSSignsOrchestrator.Core/Models/Entities/OperationLog.cs
Normal file
48
OTSSignsOrchestrator.Core/Models/Entities/OperationLog.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.Entities;
|
||||
|
||||
public enum OperationType
|
||||
{
|
||||
Create,
|
||||
Update,
|
||||
Delete,
|
||||
TestXibo,
|
||||
TestIdP,
|
||||
DeploymentStatus,
|
||||
Other
|
||||
}
|
||||
|
||||
public enum OperationStatus
|
||||
{
|
||||
Pending,
|
||||
Success,
|
||||
Failure
|
||||
}
|
||||
|
||||
public class OperationLog
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public OperationType Operation { get; set; }
|
||||
|
||||
public Guid? InstanceId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(InstanceId))]
|
||||
public CmsInstance? Instance { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
public OperationStatus Status { get; set; } = OperationStatus.Pending;
|
||||
|
||||
/// <summary>Human-readable message. NEVER includes secret values.</summary>
|
||||
[MaxLength(2000)]
|
||||
public string? Message { get; set; }
|
||||
|
||||
public long? DurationMs { get; set; }
|
||||
|
||||
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
21
OTSSignsOrchestrator.Core/Models/Entities/SecretMetadata.cs
Normal file
21
OTSSignsOrchestrator.Core/Models/Entities/SecretMetadata.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.Entities;
|
||||
|
||||
public class SecretMetadata
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required, MaxLength(200)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public bool IsGlobal { get; set; }
|
||||
|
||||
[MaxLength(100)]
|
||||
public string? CustomerName { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime? LastRotatedAt { get; set; }
|
||||
}
|
||||
59
OTSSignsOrchestrator.Core/Models/Entities/SshHost.cs
Normal file
59
OTSSignsOrchestrator.Core/Models/Entities/SshHost.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OTSSignsOrchestrator.Core.Models.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a remote Docker Swarm host accessible over SSH.
|
||||
/// SSH key paths or encrypted passwords are stored for authentication.
|
||||
/// </summary>
|
||||
public class SshHost
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required, MaxLength(200)]
|
||||
public string Label { get; set; } = string.Empty;
|
||||
|
||||
[Required, MaxLength(500)]
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
[Range(1, 65535)]
|
||||
public int Port { get; set; } = 22;
|
||||
|
||||
[Required, MaxLength(100)]
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Path to the SSH private key file on the local machine.
|
||||
/// </summary>
|
||||
[MaxLength(1000)]
|
||||
public string? PrivateKeyPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted passphrase for the SSH key (if any). Protected by DataProtection.
|
||||
/// </summary>
|
||||
[MaxLength(2000)]
|
||||
public string? KeyPassphrase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted SSH password (if key-based auth is not used). Protected by DataProtection.
|
||||
/// </summary>
|
||||
[MaxLength(2000)]
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to prefer key-based auth over password.
|
||||
/// </summary>
|
||||
public bool UseKeyAuth { get; set; } = true;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Last time a connection was successfully tested.</summary>
|
||||
public DateTime? LastTestedAt { get; set; }
|
||||
|
||||
public bool? LastTestSuccess { get; set; }
|
||||
|
||||
public ICollection<CmsInstance> Instances { get; set; } = new List<CmsInstance>();
|
||||
}
|
||||
Reference in New Issue
Block a user