Valves.svelte 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <script lang="ts">
  2. import { toast } from 'svelte-sonner';
  3. import { config, functions, models, settings, tools, user } from '$lib/stores';
  4. import { createEventDispatcher, onMount, getContext, tick } from 'svelte';
  5. import {
  6. getUserValvesSpecById as getToolUserValvesSpecById,
  7. getUserValvesById as getToolUserValvesById,
  8. updateUserValvesById as updateToolUserValvesById,
  9. getTools
  10. } from '$lib/apis/tools';
  11. import {
  12. getUserValvesSpecById as getFunctionUserValvesSpecById,
  13. getUserValvesById as getFunctionUserValvesById,
  14. updateUserValvesById as updateFunctionUserValvesById,
  15. getFunctions
  16. } from '$lib/apis/functions';
  17. import Tooltip from '$lib/components/common/Tooltip.svelte';
  18. import Spinner from '$lib/components/common/Spinner.svelte';
  19. import Valves from '$lib/components/common/Valves.svelte';
  20. const dispatch = createEventDispatcher();
  21. const i18n = getContext('i18n');
  22. export let show = false;
  23. let tab = 'tools';
  24. let selectedId = '';
  25. let loading = false;
  26. let valvesSpec = null;
  27. let valves = {};
  28. let debounceTimer;
  29. const debounceSubmitHandler = async () => {
  30. if (debounceTimer) {
  31. clearTimeout(debounceTimer);
  32. }
  33. // Set a new timer
  34. debounceTimer = setTimeout(() => {
  35. submitHandler();
  36. }, 500); // 0.5 second debounce
  37. };
  38. const getUserValves = async () => {
  39. loading = true;
  40. if (tab === 'tools') {
  41. valves = await getToolUserValvesById(localStorage.token, selectedId);
  42. valvesSpec = await getToolUserValvesSpecById(localStorage.token, selectedId);
  43. } else if (tab === 'functions') {
  44. valves = await getFunctionUserValvesById(localStorage.token, selectedId);
  45. valvesSpec = await getFunctionUserValvesSpecById(localStorage.token, selectedId);
  46. }
  47. if (valvesSpec) {
  48. // Convert array to string
  49. for (const property in valvesSpec.properties) {
  50. if (valvesSpec.properties[property]?.type === 'array') {
  51. valves[property] = (valves[property] ?? []).join(',');
  52. }
  53. }
  54. }
  55. loading = false;
  56. };
  57. const submitHandler = async () => {
  58. if (valvesSpec) {
  59. // Convert string to array
  60. for (const property in valvesSpec.properties) {
  61. if (valvesSpec.properties[property]?.type === 'array') {
  62. valves[property] = (valves[property] ?? '').split(',').map((v) => v.trim());
  63. }
  64. }
  65. if (tab === 'tools') {
  66. const res = await updateToolUserValvesById(localStorage.token, selectedId, valves).catch(
  67. (error) => {
  68. toast.error(`${error}`);
  69. return null;
  70. }
  71. );
  72. if (res) {
  73. toast.success($i18n.t('Valves updated'));
  74. valves = res;
  75. }
  76. } else if (tab === 'functions') {
  77. const res = await updateFunctionUserValvesById(
  78. localStorage.token,
  79. selectedId,
  80. valves
  81. ).catch((error) => {
  82. toast.error(`${error}`);
  83. return null;
  84. });
  85. if (res) {
  86. toast.success($i18n.t('Valves updated'));
  87. valves = res;
  88. }
  89. }
  90. }
  91. };
  92. $: if (tab) {
  93. selectedId = '';
  94. }
  95. $: if (selectedId) {
  96. getUserValves();
  97. }
  98. $: if (show) {
  99. init();
  100. }
  101. const init = async () => {
  102. loading = true;
  103. if ($functions === null) {
  104. functions.set(await getFunctions(localStorage.token));
  105. }
  106. if ($tools === null) {
  107. tools.set(await getTools(localStorage.token));
  108. }
  109. loading = false;
  110. };
  111. </script>
  112. {#if show && !loading}
  113. <form
  114. class="flex flex-col h-full justify-between space-y-3 text-sm"
  115. on:submit|preventDefault={() => {
  116. submitHandler();
  117. dispatch('save');
  118. }}
  119. >
  120. <div class="flex flex-col">
  121. <div class="space-y-1">
  122. <div class="flex gap-2">
  123. <div class="flex-1">
  124. <select
  125. class=" w-full rounded-sm text-xs py-2 px-1 bg-transparent outline-hidden"
  126. bind:value={tab}
  127. placeholder="Select"
  128. >
  129. <option value="tools" class="bg-gray-100 dark:bg-gray-800">{$i18n.t('Tools')}</option>
  130. <option value="functions" class="bg-gray-100 dark:bg-gray-800"
  131. >{$i18n.t('Functions')}</option
  132. >
  133. </select>
  134. </div>
  135. <div class="flex-1">
  136. <select
  137. class="w-full rounded-sm py-2 px-1 text-xs bg-transparent outline-hidden"
  138. bind:value={selectedId}
  139. on:change={async () => {
  140. await tick();
  141. }}
  142. >
  143. {#if tab === 'tools'}
  144. <option value="" selected disabled class="bg-gray-100 dark:bg-gray-800"
  145. >{$i18n.t('Select a tool')}</option
  146. >
  147. {#each $tools as tool, toolIdx}
  148. <option value={tool.id} class="bg-gray-100 dark:bg-gray-800">{tool.name}</option>
  149. {/each}
  150. {:else if tab === 'functions'}
  151. <option value="" selected disabled class="bg-gray-100 dark:bg-gray-800"
  152. >{$i18n.t('Select a function')}</option
  153. >
  154. {#each $functions as func, funcIdx}
  155. <option value={func.id} class="bg-gray-100 dark:bg-gray-800">{func.name}</option>
  156. {/each}
  157. {/if}
  158. </select>
  159. </div>
  160. </div>
  161. </div>
  162. {#if selectedId}
  163. <hr class="dark:border-gray-800 my-1 w-full" />
  164. <div class="my-2 text-xs">
  165. {#if !loading}
  166. <Valves
  167. {valvesSpec}
  168. bind:valves
  169. on:change={() => {
  170. debounceSubmitHandler();
  171. }}
  172. />
  173. {:else}
  174. <Spinner className="size-5" />
  175. {/if}
  176. </div>
  177. {/if}
  178. </div>
  179. </form>
  180. {:else}
  181. <Spinner className="size-4" />
  182. {/if}