feat: Add main application views and structure
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:
Matt Batchelder
2026-02-18 10:43:27 -05:00
parent 29b8c23dbb
commit 45c94b6536
149 changed files with 6469 additions and 63498 deletions

View File

@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.DependencyInjection;
namespace OTSSignsOrchestrator.Core.Data;
/// <summary>
/// Design-time factory for EF Core migrations tooling.
/// </summary>
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<XiboContext>
{
public XiboContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<XiboContext>();
optionsBuilder.UseSqlite("Data Source=design-time.db");
// Set up a temporary DataProtection provider for design-time use
var services = new ServiceCollection();
services.AddDataProtection()
.SetApplicationName("OTSSignsOrchestrator");
var sp = services.BuildServiceProvider();
var dpProvider = sp.GetRequiredService<IDataProtectionProvider>();
return new XiboContext(optionsBuilder.Options, dpProvider);
}
}

View File

@@ -0,0 +1,95 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using OTSSignsOrchestrator.Core.Models.Entities;
namespace OTSSignsOrchestrator.Core.Data;
public class XiboContext : DbContext
{
private readonly IDataProtectionProvider? _dataProtection;
public XiboContext(DbContextOptions<XiboContext> options, IDataProtectionProvider? dataProtection = null)
: base(options)
{
_dataProtection = dataProtection;
}
public DbSet<CmsInstance> CmsInstances => Set<CmsInstance>();
public DbSet<SshHost> SshHosts => Set<SshHost>();
public DbSet<SecretMetadata> SecretMetadata => Set<SecretMetadata>();
public DbSet<OperationLog> OperationLogs => Set<OperationLog>();
public DbSet<AppSetting> AppSettings => Set<AppSetting>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// --- CmsInstance ---
modelBuilder.Entity<CmsInstance>(entity =>
{
entity.HasIndex(e => e.StackName).IsUnique();
entity.HasIndex(e => e.CustomerName);
entity.HasQueryFilter(e => e.DeletedAt == null);
entity.HasOne(e => e.SshHost)
.WithMany(h => h.Instances)
.HasForeignKey(e => e.SshHostId)
.OnDelete(DeleteBehavior.SetNull);
if (_dataProtection != null)
{
var protector = _dataProtection.CreateProtector("OTSSignsOrchestrator.CmsInstance");
var pwdConverter = new ValueConverter<string?, string?>(
v => v != null ? protector.Protect(v) : null,
v => v != null ? protector.Unprotect(v) : null);
entity.Property(e => e.XiboPassword).HasConversion(pwdConverter);
entity.Property(e => e.XiboUsername).HasConversion(pwdConverter);
entity.Property(e => e.TemplateRepoPat).HasConversion(pwdConverter);
entity.Property(e => e.CifsPassword).HasConversion(pwdConverter);
}
});
// --- SshHost ---
modelBuilder.Entity<SshHost>(entity =>
{
entity.HasIndex(e => e.Label).IsUnique();
if (_dataProtection != null)
{
var protector = _dataProtection.CreateProtector("OTSSignsOrchestrator.SshHost");
var passphraseConverter = new ValueConverter<string?, string?>(
v => v != null ? protector.Protect(v) : null,
v => v != null ? protector.Unprotect(v) : null);
var passwordConverter = new ValueConverter<string?, string?>(
v => v != null ? protector.Protect(v) : null,
v => v != null ? protector.Unprotect(v) : null);
entity.Property(e => e.KeyPassphrase).HasConversion(passphraseConverter);
entity.Property(e => e.Password).HasConversion(passwordConverter);
}
});
// --- SecretMetadata ---
modelBuilder.Entity<SecretMetadata>(entity =>
{
entity.HasIndex(e => e.Name).IsUnique();
});
// --- OperationLog ---
modelBuilder.Entity<OperationLog>(entity =>
{
entity.HasIndex(e => e.Timestamp);
entity.HasIndex(e => e.InstanceId);
entity.HasIndex(e => e.Operation);
});
// --- AppSetting ---
modelBuilder.Entity<AppSetting>(entity =>
{
entity.HasKey(e => e.Key);
entity.HasIndex(e => e.Category);
});
}
}