LaptopCardComponent.razor 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. @using RackPeek.Domain.Resources.Hardware.Laptops
  2. @using RackPeek.Domain.Resources.Hardware.Laptops.Cpus
  3. @using RackPeek.Domain.Resources.Hardware.Laptops.Drives
  4. @using RackPeek.Domain.Resources.Hardware.Laptops.Gpus
  5. @using RackPeek.Domain.Resources.Hardware.Models
  6. @using RackPeek.Web.Components.Modals
  7. @inject GetLaptopUseCase GetLaptopUseCase
  8. @inject UpdateLaptopUseCase UpdateLaptopUseCase
  9. @inject DeleteLaptopUseCase DeleteLaptopUseCase
  10. @inject AddLaptopCpuUseCase AddCpuUseCase
  11. @inject UpdateLaptopCpuUseCase UpdateCpuUseCase
  12. @inject RemoveLaptopCpuUseCase RemoveCpuUseCase
  13. @inject AddLaptopDriveUseCase AddDriveUseCase
  14. @inject UpdateLaptopDriveUseCase UpdateDriveUseCase
  15. @inject RemoveLaptopDriveUseCase RemoveDriveUseCase
  16. @inject AddLaptopGpuUseCase AddGpuUseCase
  17. @inject UpdateLaptopGpuUseCase UpdateGpuUseCase
  18. @inject RemoveLaptopGpuUseCase RemoveGpuUseCase
  19. <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
  20. <div class="flex justify-between items-center mb-3">
  21. <div class="text-zinc-100 hover:text-emerald-300">
  22. <NavLink href="@($"/resources/hardware/{Laptop.Name}")" class="block">
  23. @Laptop.Name
  24. </NavLink>
  25. </div>
  26. <div class="flex justify-between items-center mb-3">
  27. @if (!string.IsNullOrWhiteSpace(Laptop.Model))
  28. {
  29. <span class="text-xs text-zinc-400">
  30. @Laptop.Model
  31. </span>
  32. }
  33. <div class="flex items-center gap-2">
  34. <button
  35. class="text-xs text-red-400 hover:text-red-300 transition"
  36. title="Delete server"
  37. @onclick="ConfirmDelete">
  38. Delete
  39. </button>
  40. </div>
  41. </div>
  42. </div>
  43. <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
  44. <!-- CPU -->
  45. <div>
  46. <div class="flex items-center justify-between mb-1 group">
  47. <div class="text-zinc-400">
  48. CPU
  49. <button
  50. class="hover:text-emerald-400 transition"
  51. title="Add CPU"
  52. @onclick="OpenAddCpu">
  53. +
  54. </button>
  55. </div>
  56. </div>
  57. @if (Laptop.Cpus?.Any() == true)
  58. {
  59. @foreach (var cpu in Laptop.Cpus)
  60. {
  61. <div
  62. class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
  63. <button
  64. class="hover:text-emerald-400"
  65. title="Edit CPU"
  66. @onclick="() => OpenEditCpu(cpu)">
  67. @cpu.Model — @cpu.Cores cores / @cpu.Threads threads
  68. </button>
  69. </div>
  70. }
  71. }
  72. </div>
  73. <!-- RAM -->
  74. <div>
  75. <div class="text-zinc-400 mb-1">
  76. RAM
  77. <button
  78. class="hover:text-emerald-400 transition"
  79. title="Edit RAM"
  80. @onclick="EditRam">
  81. +
  82. </button>
  83. </div>
  84. @if (Laptop.Ram is not null)
  85. {
  86. <div
  87. class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
  88. <button
  89. class="hover:text-emerald-400"
  90. @onclick="EditRam">
  91. @($"{Laptop.Ram.Size} GB {Laptop.Ram.Mts} MT/s")
  92. </button>
  93. </div>
  94. }
  95. </div>
  96. <!-- Drives -->
  97. <div>
  98. <div class="flex items-center justify-between mb-1 group">
  99. <div class="text-zinc-400">
  100. Drives
  101. <button
  102. class="hover:text-emerald-400 transition"
  103. title="Add Drive"
  104. @onclick="OpenAddDrive">
  105. +
  106. </button>
  107. </div>
  108. </div>
  109. @if (Laptop.Drives?.Any() == true)
  110. {
  111. @foreach (var drive in Laptop.Drives)
  112. {
  113. <div
  114. class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
  115. <button
  116. class="hover:text-emerald-400"
  117. @onclick="() => OpenEditDrive(drive)">
  118. @drive.Type — @drive.Size GB
  119. </button>
  120. </div>
  121. }
  122. }
  123. </div>
  124. <!-- GPUs -->
  125. <div>
  126. <div class="flex items-center justify-between mb-1 group">
  127. <div class="text-zinc-400">
  128. GPUs
  129. <button
  130. class="hover:text-emerald-400 transition"
  131. title="Add GPU"
  132. @onclick="OpenAddGpu">
  133. +
  134. </button>
  135. </div>
  136. </div>
  137. @if (Laptop.Gpus?.Any() == true)
  138. {
  139. @foreach (var gpu in Laptop.Gpus)
  140. {
  141. <div
  142. class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
  143. <button
  144. class="hover:text-emerald-400"
  145. @onclick="() => OpenEditGpu(gpu)">
  146. @gpu.Model — @gpu.Vram GB VRAM
  147. </button>
  148. </div>
  149. }
  150. }
  151. </div>
  152. </div>
  153. </div>
  154. <CpuModal
  155. IsOpen="@_cpuModalOpen"
  156. IsOpenChanged="v => _cpuModalOpen = v"
  157. Value="@_editingCpu"
  158. OnSubmit="HandleCpuSubmit"
  159. OnDelete="HandleCpuDelete"/>
  160. <RamModal
  161. IsOpen="@_isRamModalOpen"
  162. IsOpenChanged="v => _isRamModalOpen = v"
  163. Value="@Laptop.Ram"
  164. OnSubmit="HandleRamSubmit"/>
  165. <DriveModal
  166. IsOpen="@_driveModalOpen"
  167. IsOpenChanged="v => _driveModalOpen = v"
  168. Value="@_editingDrive"
  169. OnSubmit="HandleDriveSubmit"
  170. OnDelete="HandleDriveDelete"/>
  171. <GpuModal
  172. IsOpen="@_gpuModalOpen"
  173. IsOpenChanged="v => _gpuModalOpen = v"
  174. Value="@_editingGpu"
  175. OnSubmit="HandleGpuSubmit"
  176. OnDelete="HandleGpuDelete"/>
  177. <ConfirmModal
  178. IsOpen="_confirmDeleteOpen"
  179. IsOpenChanged="v => _confirmDeleteOpen = v"
  180. Title="Delete server"
  181. ConfirmText="Delete"
  182. ConfirmClass="bg-red-600 hover:bg-red-500"
  183. OnConfirm="DeleteServer">
  184. Are you sure you want to delete <strong>@Laptop.Name</strong>?
  185. <br/>
  186. This will detach all dependent systems.
  187. </ConfirmModal>
  188. @code {
  189. [Parameter] [EditorRequired] public Laptop Laptop { get; set; } = default!;
  190. #region RAM
  191. private bool _isRamModalOpen;
  192. private void EditRam()
  193. {
  194. _isRamModalOpen = true;
  195. }
  196. private async Task HandleRamSubmit(Ram value)
  197. {
  198. _isRamModalOpen = false;
  199. await UpdateLaptopUseCase.ExecuteAsync(Laptop.Name, Laptop.Model, value.Size, value.Mts);
  200. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  201. }
  202. #endregion
  203. #region CPU
  204. bool _cpuModalOpen;
  205. int _editingCpuIndex;
  206. Cpu? _editingCpu;
  207. void OpenAddCpu()
  208. {
  209. _editingCpuIndex = -1;
  210. _editingCpu = null;
  211. _cpuModalOpen = true;
  212. }
  213. void OpenEditCpu(Cpu cpu)
  214. {
  215. _editingCpu = cpu;
  216. Laptop.Cpus ??= new List<Cpu>();
  217. _editingCpuIndex = Laptop.Cpus.IndexOf(cpu);
  218. ;
  219. _cpuModalOpen = true;
  220. }
  221. async Task HandleCpuSubmit(Cpu cpu)
  222. {
  223. Laptop.Cpus ??= new List<Cpu>();
  224. if (_editingCpuIndex < 0)
  225. {
  226. await AddCpuUseCase.ExecuteAsync(Laptop.Name, cpu.Model, cpu.Cores, cpu.Threads);
  227. }
  228. else
  229. {
  230. await UpdateCpuUseCase.ExecuteAsync(Laptop.Name, _editingCpuIndex, cpu.Model, cpu.Cores, cpu.Threads);
  231. }
  232. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  233. }
  234. async Task HandleCpuDelete(Cpu cpu)
  235. {
  236. await RemoveCpuUseCase.ExecuteAsync(Laptop.Name, _editingCpuIndex);
  237. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  238. }
  239. #endregion
  240. #region Drives
  241. bool _driveModalOpen;
  242. int _editingDriveIndex;
  243. Drive? _editingDrive;
  244. void OpenAddDrive()
  245. {
  246. _editingDriveIndex = -1;
  247. _editingDrive = null;
  248. _driveModalOpen = true;
  249. }
  250. void OpenEditDrive(Drive drive)
  251. {
  252. _editingDrive = drive;
  253. Laptop.Drives ??= new List<Drive>();
  254. _editingDriveIndex = Laptop.Drives.IndexOf(drive);
  255. ;
  256. _driveModalOpen = true;
  257. }
  258. async Task HandleDriveSubmit(Drive drive)
  259. {
  260. Laptop.Drives ??= new List<Drive>();
  261. if (_editingDriveIndex < 0)
  262. {
  263. await AddDriveUseCase.ExecuteAsync(Laptop.Name, drive.Type, drive.Size);
  264. }
  265. else
  266. {
  267. await UpdateDriveUseCase.ExecuteAsync(Laptop.Name, _editingDriveIndex, drive.Type, drive.Size);
  268. }
  269. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  270. StateHasChanged();
  271. }
  272. async Task HandleDriveDelete(Drive drive)
  273. {
  274. await RemoveDriveUseCase.ExecuteAsync(Laptop.Name, _editingDriveIndex);
  275. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  276. StateHasChanged();
  277. }
  278. #endregion
  279. #region GPUs
  280. bool _gpuModalOpen;
  281. int _editingGpuIndex;
  282. Gpu? _editingGpu;
  283. void OpenAddGpu()
  284. {
  285. _editingGpuIndex = -1;
  286. _editingGpu = null;
  287. _gpuModalOpen = true;
  288. }
  289. void OpenEditGpu(Gpu gpu)
  290. {
  291. Laptop.Gpus ??= new List<Gpu>();
  292. _editingGpuIndex = Laptop.Gpus.IndexOf(gpu);
  293. _editingGpu = gpu;
  294. _gpuModalOpen = true;
  295. }
  296. async Task HandleGpuSubmit(Gpu gpu)
  297. {
  298. Laptop.Gpus ??= new List<Gpu>();
  299. if (_editingGpuIndex < 0)
  300. {
  301. await AddGpuUseCase.ExecuteAsync(
  302. Laptop.Name,
  303. gpu.Model,
  304. gpu.Vram);
  305. }
  306. else
  307. {
  308. await UpdateGpuUseCase.ExecuteAsync(
  309. Laptop.Name,
  310. _editingGpuIndex,
  311. gpu.Model,
  312. gpu.Vram);
  313. }
  314. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  315. }
  316. async Task HandleGpuDelete(Gpu gpu)
  317. {
  318. await RemoveGpuUseCase.ExecuteAsync(Laptop.Name, _editingGpuIndex);
  319. Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
  320. }
  321. #endregion
  322. }
  323. @code {
  324. private bool _confirmDeleteOpen;
  325. [Parameter] public EventCallback<string> OnDeleted { get; set; }
  326. void ConfirmDelete()
  327. {
  328. _confirmDeleteOpen = true;
  329. }
  330. async Task DeleteServer()
  331. {
  332. _confirmDeleteOpen = false;
  333. await DeleteLaptopUseCase.ExecuteAsync(Laptop.Name);
  334. if (OnDeleted.HasDelegate)
  335. await OnDeleted.InvokeAsync(Laptop.Name);
  336. }
  337. }