+page.svelte 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <script>
  2. import { WEBUI_API_BASE_URL } from '$lib/constants';
  3. import { config, user } from '$lib/stores';
  4. import { goto } from '$app/navigation';
  5. import { onMount } from 'svelte';
  6. import toast from 'svelte-french-toast';
  7. let loaded = false;
  8. let users = [];
  9. const updateUserRole = async (id, role) => {
  10. const res = await fetch(`${WEBUI_API_BASE_URL}/users/update/role`, {
  11. method: 'POST',
  12. headers: {
  13. 'Content-Type': 'application/json',
  14. Authorization: `Bearer ${localStorage.token}`
  15. },
  16. body: JSON.stringify({
  17. id: id,
  18. role: role
  19. })
  20. })
  21. .then(async (res) => {
  22. if (!res.ok) throw await res.json();
  23. return res.json();
  24. })
  25. .catch((error) => {
  26. console.log(error);
  27. toast.error(error.detail);
  28. return null;
  29. });
  30. if (res) {
  31. await getUsers();
  32. }
  33. };
  34. const getUsers = async () => {
  35. const res = await fetch(`${WEBUI_API_BASE_URL}/users/`, {
  36. method: 'GET',
  37. headers: {
  38. 'Content-Type': 'application/json',
  39. Authorization: `Bearer ${localStorage.token}`
  40. }
  41. })
  42. .then(async (res) => {
  43. if (!res.ok) throw await res.json();
  44. return res.json();
  45. })
  46. .catch((error) => {
  47. console.log(error);
  48. toast.error(error.detail);
  49. return null;
  50. });
  51. users = res ? res : [];
  52. };
  53. onMount(async () => {
  54. if ($config === null || !$config.auth || ($config.auth && $user && $user.role !== 'admin')) {
  55. await goto('/');
  56. } else {
  57. await getUsers();
  58. }
  59. loaded = true;
  60. });
  61. </script>
  62. <div
  63. class=" bg-white dark:bg-gray-800 dark:text-gray-100 min-h-screen w-full flex justify-center font-mona"
  64. >
  65. {#if loaded}
  66. <div class="w-full max-w-3xl px-10 md:px-16 min-h-screen flex flex-col">
  67. <div class="py-10 w-full">
  68. <div class=" flex flex-col justify-center">
  69. <div class=" text-2xl font-semibold">Users ({users.length})</div>
  70. <div class=" text-gray-500 text-xs font-medium mt-1">
  71. Click on the user role cell in the table to change a user's role.
  72. </div>
  73. <hr class=" my-3 dark:border-gray-600" />
  74. <div class="scrollbar-hidden relative overflow-x-auto whitespace-nowrap">
  75. <table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
  76. <thead
  77. class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"
  78. >
  79. <tr>
  80. <th scope="col" class="px-6 py-3"> Name </th>
  81. <th scope="col" class="px-6 py-3"> Email </th>
  82. <th scope="col" class="px-6 py-3"> Role </th>
  83. <!-- <th scope="col" class="px-6 py-3"> Action </th> -->
  84. </tr>
  85. </thead>
  86. <tbody>
  87. {#each users as user}
  88. <tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
  89. <th
  90. scope="row"
  91. class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"
  92. >
  93. <div class="flex flex-row">
  94. <img
  95. class=" rounded-full max-w-[30px] max-h-[30px] object-cover mr-4"
  96. src={user.profile_image_url}
  97. />
  98. <div class=" font-semibold md:self-center">{user.name}</div>
  99. </div>
  100. </th>
  101. <td class="px-6 py-4"> {user.email} </td>
  102. <td class="px-6 py-4">
  103. <button
  104. class=" dark:text-white underline"
  105. on:click={() => {
  106. if (user.role === 'user') {
  107. updateUserRole(user.id, 'admin');
  108. } else if (user.role === 'pending') {
  109. updateUserRole(user.id, 'user');
  110. } else {
  111. updateUserRole(user.id, 'pending');
  112. }
  113. }}>{user.role}</button
  114. >
  115. </td>
  116. <!-- <td class="px-6 py-4 text-center">
  117. <button class=" text-white underline"> Edit </button>
  118. </td> -->
  119. </tr>
  120. {/each}
  121. </tbody>
  122. </table>
  123. </div>
  124. </div>
  125. </div>
  126. </div>
  127. {/if}
  128. </div>
  129. <style>
  130. .font-mona {
  131. font-family: 'Mona Sans';
  132. }
  133. .scrollbar-hidden::-webkit-scrollbar {
  134. display: none; /* for Chrome, Safari and Opera */
  135. }
  136. .scrollbar-hidden {
  137. -ms-overflow-style: none; /* IE and Edge */
  138. scrollbar-width: none; /* Firefox */
  139. }
  140. </style>