Valves.svelte 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. } from '$lib/apis/tools';
  10. import {
  11. getUserValvesSpecById as getFunctionUserValvesSpecById,
  12. getUserValvesById as getFunctionUserValvesById,
  13. updateUserValvesById as updateFunctionUserValvesById
  14. } from '$lib/apis/functions';
  15. import ManageModal from './Personalization/ManageModal.svelte';
  16. import Tooltip from '$lib/components/common/Tooltip.svelte';
  17. import Spinner from '$lib/components/common/Spinner.svelte';
  18. const dispatch = createEventDispatcher();
  19. const i18n = getContext('i18n');
  20. export let saveSettings: Function;
  21. let tab = 'tools';
  22. let selectedId = '';
  23. let loading = false;
  24. let valvesSpec = null;
  25. let valves = {};
  26. const getUserValves = async () => {
  27. loading = true;
  28. if (tab === 'tools') {
  29. valves = await getToolUserValvesById(localStorage.token, selectedId);
  30. valvesSpec = await getToolUserValvesSpecById(localStorage.token, selectedId);
  31. } else if (tab === 'functions') {
  32. valves = await getFunctionUserValvesById(localStorage.token, selectedId);
  33. valvesSpec = await getFunctionUserValvesSpecById(localStorage.token, selectedId);
  34. }
  35. if (valvesSpec) {
  36. // Convert array to string
  37. for (const property in valvesSpec.properties) {
  38. if (valvesSpec.properties[property]?.type === 'array') {
  39. valves[property] = (valves[property] ?? []).join(',');
  40. }
  41. }
  42. }
  43. loading = false;
  44. };
  45. const submitHandler = async () => {
  46. if (valvesSpec) {
  47. // Convert string to array
  48. for (const property in valvesSpec.properties) {
  49. if (valvesSpec.properties[property]?.type === 'array') {
  50. valves[property] = (valves[property] ?? '').split(',').map((v) => v.trim());
  51. }
  52. }
  53. if (tab === 'tools') {
  54. const res = await updateToolUserValvesById(localStorage.token, selectedId, valves).catch(
  55. (error) => {
  56. toast.error(error);
  57. return null;
  58. }
  59. );
  60. if (res) {
  61. toast.success('Valves updated');
  62. valves = res;
  63. }
  64. } else if (tab === 'functions') {
  65. const res = await updateFunctionUserValvesById(
  66. localStorage.token,
  67. selectedId,
  68. valves
  69. ).catch((error) => {
  70. toast.error(error);
  71. return null;
  72. });
  73. if (res) {
  74. toast.success('Valves updated');
  75. valves = res;
  76. }
  77. }
  78. }
  79. };
  80. $: if (tab) {
  81. selectedId = '';
  82. }
  83. $: if (selectedId) {
  84. getUserValves();
  85. }
  86. </script>
  87. <form
  88. class="flex flex-col h-full justify-between space-y-3 text-sm"
  89. on:submit|preventDefault={() => {
  90. submitHandler();
  91. dispatch('save');
  92. }}
  93. >
  94. <div class="flex flex-col pr-1.5 overflow-y-scroll max-h-[25rem]">
  95. <div>
  96. <div class="flex items-center justify-between mb-2">
  97. <Tooltip content="">
  98. <div class="text-sm font-medium">
  99. {$i18n.t('Manage Valves')}
  100. </div>
  101. </Tooltip>
  102. <div class=" self-end">
  103. <select
  104. class=" dark:bg-gray-900 w-fit pr-8 rounded text-xs bg-transparent outline-none text-right"
  105. bind:value={tab}
  106. placeholder="Select"
  107. >
  108. <option value="tools">{$i18n.t('Tools')}</option>
  109. <option value="functions">{$i18n.t('Functions')}</option>
  110. </select>
  111. </div>
  112. </div>
  113. </div>
  114. <div class="space-y-1">
  115. <div class="flex gap-2">
  116. <div class="flex-1">
  117. <select
  118. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  119. bind:value={selectedId}
  120. on:change={async () => {
  121. await tick();
  122. }}
  123. >
  124. {#if tab === 'tools'}
  125. <option value="" selected disabled class="bg-gray-100 dark:bg-gray-700"
  126. >{$i18n.t('Select a tool')}</option
  127. >
  128. {#each $tools as tool, toolIdx}
  129. <option value={tool.id} class="bg-gray-100 dark:bg-gray-700">{tool.name}</option>
  130. {/each}
  131. {:else if tab === 'functions'}
  132. <option value="" selected disabled class="bg-gray-100 dark:bg-gray-700"
  133. >{$i18n.t('Select a function')}</option
  134. >
  135. {#each $functions as func, funcIdx}
  136. <option value={func.id} class="bg-gray-100 dark:bg-700">{func.name}</option>
  137. {/each}
  138. {/if}
  139. </select>
  140. </div>
  141. </div>
  142. </div>
  143. {#if selectedId}
  144. <hr class="dark:border-gray-800 my-3 w-full" />
  145. <div>
  146. {#if !loading}
  147. {#if valvesSpec}
  148. {#each Object.keys(valvesSpec.properties) as property, idx}
  149. <div class=" py-0.5 w-full justify-between">
  150. <div class="flex w-full justify-between">
  151. <div class=" self-center text-xs font-medium">
  152. {valvesSpec.properties[property].title}
  153. {#if (valvesSpec?.required ?? []).includes(property)}
  154. <span class=" text-gray-500">*required</span>
  155. {/if}
  156. </div>
  157. <button
  158. class="p-1 px-3 text-xs flex rounded transition"
  159. type="button"
  160. on:click={() => {
  161. valves[property] = (valves[property] ?? null) === null ? '' : null;
  162. }}
  163. >
  164. {#if (valves[property] ?? null) === null}
  165. <span class="ml-2 self-center"> {$i18n.t('None')} </span>
  166. {:else}
  167. <span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
  168. {/if}
  169. </button>
  170. </div>
  171. {#if (valves[property] ?? null) !== null}
  172. <div class="flex mt-0.5 space-x-2">
  173. <div class=" flex-1">
  174. <input
  175. class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
  176. type="text"
  177. placeholder={valvesSpec.properties[property].title}
  178. bind:value={valves[property]}
  179. autocomplete="off"
  180. required={(valvesSpec?.required ?? []).includes(property)}
  181. />
  182. </div>
  183. </div>
  184. {/if}
  185. </div>
  186. {/each}
  187. {:else}
  188. <div>No valves</div>
  189. {/if}
  190. {:else}
  191. <Spinner className="size-5" />
  192. {/if}
  193. </div>
  194. {/if}
  195. </div>
  196. <div class="flex justify-end text-sm font-medium">
  197. <button
  198. class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
  199. type="submit"
  200. >
  201. {$i18n.t('Save')}
  202. </button>
  203. </div>
  204. </form>