HostsExport.razor 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. @page "/hosts/export"
  2. @using RackPeek.Domain.UseCases.Hosts
  3. @inject HostsFileExportUseCase HostsUseCase
  4. <div class="border border-zinc-800 rounded p-4 bg-zinc-900 max-w-5xl mx-auto"
  5. data-testid="hosts-export-page">
  6. <div class="flex justify-between items-center mb-4">
  7. <div class="text-zinc-100 text-lg">
  8. Hosts File Export
  9. </div>
  10. <button class="text-sm bg-emerald-600 hover:bg-emerald-500 px-3 py-1 rounded text-white transition"
  11. data-testid="generate-hosts-button"
  12. @onclick="GenerateExport">
  13. Generate
  14. </button>
  15. </div>
  16. <!-- Options -->
  17. <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
  18. <!-- Include Tags -->
  19. <div>
  20. <div class="text-zinc-400 mb-1">Include Tags</div>
  21. <input class="w-full bg-zinc-800 text-zinc-200 p-2 rounded border border-zinc-700"
  22. placeholder="prod, staging"
  23. data-testid="hosts-include-tags-input"
  24. @bind="_includeTagsRaw"/>
  25. <div class="text-xs text-zinc-500 mt-1">
  26. Only include resources with these tags (optional)
  27. </div>
  28. </div>
  29. <!-- Domain Suffix -->
  30. <div>
  31. <div class="text-zinc-400 mb-1">Domain Suffix</div>
  32. <input class="w-full bg-zinc-800 text-zinc-200 p-2 rounded border border-zinc-700"
  33. placeholder="home.local"
  34. data-testid="hosts-domain-suffix-input"
  35. @bind="_domainSuffix"/>
  36. <div class="text-xs text-zinc-500 mt-1">
  37. Appends .domain to host names (optional)
  38. </div>
  39. </div>
  40. <!-- Include Localhost Defaults -->
  41. <div class="flex items-center space-x-2">
  42. <input type="checkbox"
  43. class="accent-emerald-600"
  44. data-testid="hosts-include-localhost-checkbox"
  45. @bind="_includeLocalhost"/>
  46. <label class="text-zinc-300">
  47. Include localhost defaults (127.0.0.1 / ::1)
  48. </label>
  49. </div>
  50. </div>
  51. <!-- Warnings -->
  52. @if (_warnings.Any())
  53. {
  54. <div class="border border-red-700 bg-red-900/40 text-red-300 p-3 rounded mb-4"
  55. data-testid="hosts-warnings">
  56. <div class="font-semibold mb-1">Warnings</div>
  57. <ul class="list-disc ml-5 text-sm">
  58. @foreach (var warning in _warnings)
  59. {
  60. <li>@warning</li>
  61. }
  62. </ul>
  63. </div>
  64. }
  65. <!-- Output -->
  66. <div>
  67. <div class="text-zinc-400 mb-1">Generated Hosts File</div>
  68. <textarea class="w-full bg-black text-emerald-400 p-3 rounded border border-zinc-800 font-mono text-sm"
  69. rows="18"
  70. readonly
  71. data-testid="hosts-output">
  72. @_hostsText
  73. </textarea>
  74. </div>
  75. </div>
  76. @code {
  77. private string _includeTagsRaw = string.Empty;
  78. private string? _domainSuffix = "home.local";
  79. private bool _includeLocalhost = true;
  80. private string _hostsText = string.Empty;
  81. private List<string> _warnings = new();
  82. private async Task GenerateExport()
  83. {
  84. try
  85. {
  86. _warnings.Clear();
  87. _hostsText = string.Empty;
  88. var options = new HostsExportOptions
  89. {
  90. IncludeTags = ParseCsv(_includeTagsRaw),
  91. DomainSuffix = string.IsNullOrWhiteSpace(_domainSuffix)
  92. ? null
  93. : _domainSuffix,
  94. IncludeLocalhostDefaults = _includeLocalhost
  95. };
  96. var result = await HostsUseCase.ExecuteAsync(options);
  97. if (result is null)
  98. {
  99. _warnings.Add("Hosts export returned null.");
  100. return;
  101. }
  102. _hostsText = result.HostsText;
  103. _warnings = result.Warnings.ToList();
  104. }
  105. catch (Exception ex)
  106. {
  107. _warnings.Clear();
  108. _warnings.Add($"Unexpected error: {ex.Message}");
  109. }
  110. }
  111. private static IReadOnlyList<string> ParseCsv(string raw)
  112. {
  113. if (string.IsNullOrWhiteSpace(raw))
  114. return [];
  115. return raw.Split(',', StringSplitOptions.RemoveEmptyEntries)
  116. .Select(x => x.Trim())
  117. .Where(x => !string.IsNullOrWhiteSpace(x))
  118. .ToArray();
  119. }
  120. }