server-stats-panel.svelte 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <script lang="ts">
  2. import { locale } from '$lib/stores/preferences.store';
  3. import type { ServerStatsResponseDto } from '@api';
  4. import CameraIris from 'svelte-material-icons/CameraIris.svelte';
  5. import Memory from 'svelte-material-icons/Memory.svelte';
  6. import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
  7. import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
  8. import StatsCard from './stats-card.svelte';
  9. export let stats: ServerStatsResponseDto = {
  10. photos: 0,
  11. videos: 0,
  12. usage: 0,
  13. usageByUser: [],
  14. };
  15. $: zeros = (value: number) => {
  16. const maxLength = 13;
  17. const valueLength = value.toString().length;
  18. const zeroLength = maxLength - valueLength;
  19. return '0'.repeat(zeroLength);
  20. };
  21. $: [statsUsage, statsUsageUnit] = getBytesWithUnit(stats.usage, 0);
  22. </script>
  23. <div class="flex flex-col gap-5">
  24. <div>
  25. <p class="text-sm dark:text-immich-dark-fg">TOTAL USAGE</p>
  26. <div class="mt-5 justify-between lg:flex hidden">
  27. <StatsCard logo={CameraIris} title="PHOTOS" value={stats.photos} />
  28. <StatsCard logo={PlayCircle} title="VIDEOS" value={stats.videos} />
  29. <StatsCard logo={Memory} title="STORAGE" value={statsUsage} unit={statsUsageUnit} />
  30. </div>
  31. <div class="mt-5 lg:hidden flex">
  32. <div class="bg-immich-gray dark:bg-immich-dark-gray rounded-3xl p-5 flex flex-col justify-between">
  33. <div class="flex flex-wrap gap-x-12">
  34. <div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
  35. <CameraIris size="25" />
  36. <p>PHOTOS</p>
  37. </div>
  38. <div class="relative text-center font-mono font-semibold text-2xl">
  39. <span class="text-[#DCDADA] dark:text-[#525252]">{zeros(stats.photos)}</span><span
  40. class="text-immich-primary dark:text-immich-dark-primary">{stats.photos}</span
  41. >
  42. </div>
  43. </div>
  44. <div class="flex flex-wrap gap-x-12">
  45. <div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
  46. <PlayCircle size="25" />
  47. <p>VIDEOS</p>
  48. </div>
  49. <div class="relative text-center font-mono font-semibold text-2xl">
  50. <span class="text-[#DCDADA] dark:text-[#525252]">{zeros(stats.videos)}</span><span
  51. class="text-immich-primary dark:text-immich-dark-primary">{stats.videos}</span
  52. >
  53. </div>
  54. </div>
  55. <div class="flex flex-wrap gap-x-7">
  56. <div class="flex place-items-center gap-4 text-immich-primary dark:text-immich-dark-primary">
  57. <Memory size="25" />
  58. <p>STORAGE</p>
  59. </div>
  60. <div class="relative text-center font-mono font-semibold text-2xl flex">
  61. <span class="text-[#DCDADA] dark:text-[#525252]">{zeros(statsUsage)}</span><span
  62. class="text-immich-primary dark:text-immich-dark-primary">{statsUsage}</span
  63. >
  64. <span class="text-center my-auto ml-2 text-base font-light text-gray-400">{statsUsageUnit}</span>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. <div>
  71. <p class="text-sm dark:text-immich-dark-fg">USER USAGE DETAIL</p>
  72. <table class="text-left w-full mt-5">
  73. <thead
  74. class="border rounded-md mb-4 bg-gray-50 dark:bg-immich-dark-gray dark:border-immich-dark-gray flex text-immich-primary dark:text-immich-dark-primary w-full h-12"
  75. >
  76. <tr class="flex w-full place-items-center">
  77. <th class="text-center w-1/4 font-medium text-sm">User</th>
  78. <th class="text-center w-1/4 font-medium text-sm">Photos</th>
  79. <th class="text-center w-1/4 font-medium text-sm">Videos</th>
  80. <th class="text-center w-1/4 font-medium text-sm">Size</th>
  81. </tr>
  82. </thead>
  83. <tbody
  84. class="overflow-y-auto rounded-md w-full max-h-[320px] block border dark:border-immich-dark-gray dark:text-immich-dark-fg"
  85. >
  86. {#each stats.usageByUser as user (user.userId)}
  87. <tr
  88. class="text-center flex place-items-center w-full h-[50px] even:bg-immich-bg even:dark:bg-immich-dark-gray/50 odd:bg-immich-gray odd:dark:bg-immich-dark-gray/75"
  89. >
  90. <td class="text-sm px-2 w-1/4 text-ellipsis">{user.userFirstName} {user.userLastName}</td>
  91. <td class="text-sm px-2 w-1/4 text-ellipsis">{user.photos.toLocaleString($locale)}</td>
  92. <td class="text-sm px-2 w-1/4 text-ellipsis">{user.videos.toLocaleString($locale)}</td>
  93. <td class="text-sm px-2 w-1/4 text-ellipsis">{asByteUnitString(user.usage, $locale)}</td>
  94. </tr>
  95. {/each}
  96. </tbody>
  97. </table>
  98. </div>
  99. </div>