ServiceCardComponent.razor 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. @using RackPeek.Domain.Resources.Services
  2. @using RackPeek.Domain.Resources.Services.UseCases
  3. @inject UpdateServiceUseCase UpdateServiceUseCase
  4. @inject GetServiceUseCase GetServiceUseCase
  5. @inject DeleteServiceUseCase DeleteServiceUseCase
  6. @inject CloneServiceUseCase CloneServiceUseCase
  7. @inject NavigationManager Nav
  8. <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
  9. <div class="flex justify-between items-center mb-3">
  10. <NavLink href="@($"/resources/services/{Service.Name}")" class="block">
  11. <div class="text-zinc-100 hover:text-emerald-300">
  12. @Service.Name
  13. </div>
  14. </NavLink>
  15. <div class="flex gap-3 text-xs">
  16. @if (!_isEditing)
  17. {
  18. <button class="text-zinc-400 hover:text-zinc-200"
  19. @onclick="BeginEdit">
  20. Edit
  21. </button>
  22. <button
  23. class="text-xs text-emerald-400 hover:text-emerald-300 transition"
  24. title="Clone service"
  25. @onclick="OpenClone">
  26. Clone
  27. </button>
  28. <button
  29. class="text-xs text-red-400 hover:text-red-300 transition"
  30. title="Delete server"
  31. @onclick="ConfirmDelete">
  32. Delete
  33. </button>
  34. }
  35. else
  36. {
  37. <button class="text-emerald-400 hover:text-emerald-300"
  38. @onclick="Save">
  39. Save
  40. </button>
  41. <button class="text-zinc-500 hover:text-zinc-300"
  42. @onclick="Cancel">
  43. Cancel
  44. </button>
  45. }
  46. </div>
  47. </div>
  48. <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
  49. <!-- IP -->
  50. <div>
  51. <div class="text-zinc-400 mb-1">IP</div>
  52. @if (_isEditing)
  53. {
  54. <input class="input"
  55. @bind="_edit.Ip"/>
  56. }
  57. else if (!string.IsNullOrWhiteSpace(Service.Network?.Ip))
  58. {
  59. <div class="text-zinc-300">@Service.Network!.Ip</div>
  60. }
  61. </div>
  62. <!-- Port -->
  63. <div>
  64. <div class="text-zinc-400 mb-1">Port</div>
  65. @if (_isEditing)
  66. {
  67. <input type="number"
  68. class="input"
  69. @bind="_edit.Port"/>
  70. }
  71. else if (Service.Network?.Port.HasValue == true)
  72. {
  73. <div class="text-zinc-300">@Service.Network.Port</div>
  74. }
  75. </div>
  76. <!-- Protocol -->
  77. <div>
  78. <div class="text-zinc-400 mb-1">Protocol</div>
  79. @if (_isEditing)
  80. {
  81. <input class="input"
  82. @bind="_edit.Protocol"/>
  83. }
  84. else if (!string.IsNullOrWhiteSpace(Service.Network?.Protocol))
  85. {
  86. <div class="text-zinc-300">@Service.Network!.Protocol</div>
  87. }
  88. </div>
  89. <!-- URL -->
  90. <div>
  91. <div class="text-zinc-400 mb-1">URL</div>
  92. @if (_isEditing)
  93. {
  94. <input class="input"
  95. @bind="_edit.Url"/>
  96. }
  97. else if (!string.IsNullOrWhiteSpace(Service.Network?.Url))
  98. {
  99. <a href="@Service.Network!.Url"
  100. target="_blank"
  101. rel="noopener noreferrer"
  102. class="text-emerald-400 hover:underline break-all">
  103. @Service.Network.Url
  104. </a>
  105. }
  106. </div>
  107. <!-- Runs On -->
  108. <div>
  109. <div class="text-zinc-400 mb-1">Runs On</div>
  110. @if (_isEditing)
  111. {
  112. <button
  113. class="hover:text-emerald-400"
  114. title="Edit Runs On"
  115. @onclick="() => _selectParentOpen = true">
  116. @if (!string.IsNullOrWhiteSpace(Service.RunsOn))
  117. {
  118. @($"{Service.RunsOn} +")
  119. }
  120. else
  121. {
  122. @("Edit parent")
  123. }
  124. </button>
  125. }
  126. else if (!string.IsNullOrWhiteSpace(Service.RunsOn))
  127. {
  128. <NavLink href="@($"/resources/systems/{Service.RunsOn}")"
  129. class="text-emerald-400">
  130. @Service.RunsOn
  131. </NavLink>
  132. }
  133. </div>
  134. </div>
  135. </div>
  136. <SystemSelectionModal
  137. IsOpen="@_selectParentOpen"
  138. IsOpenChanged="v => _selectParentOpen = v"
  139. Title="Select a parent"
  140. Value="@SelectedParentName"
  141. OnAccept="HandleParentSelected"/>
  142. <ConfirmModal
  143. IsOpen="_confirmDeleteOpen"
  144. IsOpenChanged="v => _confirmDeleteOpen = v"
  145. Title="Delete server"
  146. ConfirmText="Delete"
  147. ConfirmClass="bg-red-600 hover:bg-red-500"
  148. OnConfirm="DeleteServer">
  149. Are you sure you want to delete <strong>@Service.Name</strong>?
  150. </ConfirmModal>
  151. <StringValueModal
  152. IsOpen="_cloneOpen"
  153. IsOpenChanged="v => _cloneOpen = v"
  154. Title="Clone service"
  155. Description="Enter a name for the cloned service"
  156. Label="New service name"
  157. Value="@($"{Service.Name}-copy")"
  158. OnSubmit="HandleCloneSubmit" />
  159. @code
  160. {
  161. bool _cloneOpen;
  162. void OpenClone()
  163. {
  164. _cloneOpen = true;
  165. }
  166. async Task HandleCloneSubmit(string newName)
  167. {
  168. await CloneServiceUseCase.ExecuteAsync(Service.Name, newName);
  169. Nav.NavigateTo($"/resources/services/{newName}");
  170. }
  171. }
  172. @code {
  173. [Parameter] [EditorRequired] public Service Service { get; set; } = default!;
  174. [Parameter] public EventCallback<ServiceEditModel> OnSave { get; set; }
  175. private bool _isEditing;
  176. private ServiceEditModel _edit = new();
  177. void BeginEdit()
  178. {
  179. _edit = ServiceEditModel.From(Service);
  180. _isEditing = true;
  181. }
  182. async Task Save()
  183. {
  184. _isEditing = false;
  185. await OnSave.InvokeAsync(_edit);
  186. }
  187. void Cancel()
  188. {
  189. _isEditing = false;
  190. }
  191. bool _selectParentOpen;
  192. string? SelectedParentName;
  193. async Task HandleParentSelected(string? name)
  194. {
  195. SelectedParentName = name;
  196. await UpdateServiceUseCase.ExecuteAsync(
  197. Service.Name,
  198. Service.Network?.Ip,
  199. Service.Network?.Port,
  200. Service.Network?.Protocol,
  201. Service.Network?.Url,
  202. name);
  203. Service = await GetServiceUseCase.ExecuteAsync(Service.Name);
  204. _edit = ServiceEditModel.From(Service);
  205. }
  206. }
  207. <ConfirmModal
  208. IsOpen="_confirmDeleteOpen"
  209. IsOpenChanged="v => _confirmDeleteOpen = v"
  210. Title="Delete service"
  211. ConfirmText="Delete"
  212. ConfirmClass="bg-red-600 hover:bg-red-500"
  213. OnConfirm="DeleteServer">
  214. Are you sure you want to delete <strong>@Service.Name</strong>?
  215. <br/>
  216. </ConfirmModal>
  217. @code {
  218. private bool _confirmDeleteOpen;
  219. [Parameter] public EventCallback<string> OnDeleted { get; set; }
  220. void ConfirmDelete()
  221. {
  222. _confirmDeleteOpen = true;
  223. }
  224. async Task DeleteServer()
  225. {
  226. _confirmDeleteOpen = false;
  227. await DeleteServiceUseCase.ExecuteAsync(Service.Name);
  228. if (OnDeleted.HasDelegate)
  229. await OnDeleted.InvokeAsync(Service.Name);
  230. }
  231. }