SettingsForm.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import { Input, Switch, Tooltip, useDisclosure } from "@nextui-org/react";
  2. import React from "react";
  3. import { useTranslation } from "react-i18next";
  4. import { FaEye, FaEyeSlash } from "react-icons/fa";
  5. import { AvailableLanguages } from "../../../i18n";
  6. import { I18nKey } from "../../../i18n/declaration";
  7. import { AutocompleteCombobox } from "./AutocompleteCombobox";
  8. import { Settings } from "#/services/settings";
  9. import { organizeModelsAndProviders } from "#/utils/organizeModelsAndProviders";
  10. import { extractModelAndProvider } from "#/utils/extractModelAndProvider";
  11. import { ModelSelector } from "./ModelSelector";
  12. interface SettingsFormProps {
  13. settings: Settings;
  14. models: string[];
  15. agents: string[];
  16. securityAnalyzers: string[];
  17. disabled: boolean;
  18. onModelChange: (model: string) => void;
  19. onBaseURLChange: (baseURL: string) => void;
  20. onAPIKeyChange: (apiKey: string) => void;
  21. onAgentChange: (agent: string) => void;
  22. onLanguageChange: (language: string) => void;
  23. onConfirmationModeChange: (confirmationMode: boolean) => void;
  24. onSecurityAnalyzerChange: (securityAnalyzer: string) => void;
  25. }
  26. function SettingsForm({
  27. settings,
  28. models,
  29. agents,
  30. securityAnalyzers,
  31. disabled,
  32. onModelChange,
  33. onBaseURLChange,
  34. onAPIKeyChange,
  35. onAgentChange,
  36. onLanguageChange,
  37. onConfirmationModeChange,
  38. onSecurityAnalyzerChange,
  39. }: SettingsFormProps) {
  40. const { t } = useTranslation();
  41. const { isOpen: isVisible, onOpenChange: onVisibleChange } = useDisclosure();
  42. const advancedAlreadyInUse = React.useMemo(() => {
  43. const organizedModels = organizeModelsAndProviders(models);
  44. const { provider, model } = extractModelAndProvider(
  45. settings.LLM_MODEL || "",
  46. );
  47. const isKnownModel =
  48. provider in organizedModels &&
  49. organizedModels[provider].models.includes(model);
  50. return (
  51. !!settings.SECURITY_ANALYZER ||
  52. !!settings.CONFIRMATION_MODE ||
  53. !!settings.LLM_BASE_URL ||
  54. (!!settings.LLM_MODEL && !isKnownModel)
  55. );
  56. }, [settings, models]);
  57. const [enableAdvanced, setEnableAdvanced] =
  58. React.useState(advancedAlreadyInUse);
  59. React.useEffect(() => {
  60. setEnableAdvanced(advancedAlreadyInUse);
  61. }, [advancedAlreadyInUse]);
  62. const handleAdvancedChange = (value: boolean) => {
  63. setEnableAdvanced(value);
  64. };
  65. return (
  66. <>
  67. <Switch
  68. data-testid="advanced-options-toggle"
  69. aria-checked={enableAdvanced}
  70. isSelected={enableAdvanced}
  71. onValueChange={handleAdvancedChange}
  72. >
  73. Advanced Options
  74. </Switch>
  75. {enableAdvanced && (
  76. <>
  77. <Input
  78. data-testid="custom-model-input"
  79. label="Custom Model"
  80. onValueChange={onModelChange}
  81. defaultValue={settings.LLM_MODEL}
  82. />
  83. <Input
  84. data-testid="base-url-input"
  85. label="Base URL"
  86. onValueChange={onBaseURLChange}
  87. defaultValue={settings.LLM_BASE_URL}
  88. />
  89. </>
  90. )}
  91. {!enableAdvanced && (
  92. <ModelSelector
  93. isDisabled={disabled}
  94. models={organizeModelsAndProviders(models)}
  95. currentModel={settings.LLM_MODEL}
  96. />
  97. )}
  98. <Input
  99. label="API Key"
  100. isDisabled={disabled}
  101. aria-label="apikey"
  102. data-testid="apikey"
  103. placeholder={t(I18nKey.SETTINGS$API_KEY_PLACEHOLDER)}
  104. type={isVisible ? "text" : "password"}
  105. value={settings.LLM_API_KEY || ""}
  106. onChange={(e) => {
  107. onAPIKeyChange(e.target.value);
  108. }}
  109. endContent={
  110. <button
  111. className="focus:outline-none"
  112. type="button"
  113. onClick={onVisibleChange}
  114. >
  115. {isVisible ? (
  116. <FaEye className="text-2xl text-default-400 pointer-events-none" />
  117. ) : (
  118. <FaEyeSlash className="text-2xl text-default-400 pointer-events-none" />
  119. )}
  120. </button>
  121. }
  122. />
  123. <AutocompleteCombobox
  124. ariaLabel="language"
  125. items={AvailableLanguages}
  126. defaultKey={settings.LANGUAGE}
  127. onChange={onLanguageChange}
  128. tooltip={t(I18nKey.SETTINGS$LANGUAGE_TOOLTIP)}
  129. disabled={disabled}
  130. />
  131. {enableAdvanced && (
  132. <AutocompleteCombobox
  133. ariaLabel="agent"
  134. items={agents.map((agent) => ({ value: agent, label: agent }))}
  135. defaultKey={settings.AGENT}
  136. onChange={onAgentChange}
  137. tooltip={t(I18nKey.SETTINGS$AGENT_TOOLTIP)}
  138. />
  139. )}
  140. {enableAdvanced && (
  141. <AutocompleteCombobox
  142. ariaLabel="securityanalyzer"
  143. items={securityAnalyzers.map((securityAnalyzer) => ({
  144. value: securityAnalyzer,
  145. label: securityAnalyzer,
  146. }))}
  147. defaultKey={settings.SECURITY_ANALYZER}
  148. onChange={onSecurityAnalyzerChange}
  149. tooltip={t(I18nKey.SETTINGS$SECURITY_ANALYZER)}
  150. disabled={disabled}
  151. />
  152. )}
  153. {enableAdvanced && (
  154. <Switch
  155. aria-label="confirmationmode"
  156. data-testid="confirmationmode"
  157. defaultSelected={
  158. settings.CONFIRMATION_MODE || !!settings.SECURITY_ANALYZER
  159. }
  160. onValueChange={onConfirmationModeChange}
  161. isDisabled={disabled || !!settings.SECURITY_ANALYZER}
  162. isSelected={settings.CONFIRMATION_MODE}
  163. >
  164. <Tooltip
  165. content={t(I18nKey.SETTINGS$CONFIRMATION_MODE_TOOLTIP)}
  166. closeDelay={100}
  167. delay={500}
  168. >
  169. {t(I18nKey.SETTINGS$CONFIRMATION_MODE)}
  170. </Tooltip>
  171. </Switch>
  172. )}
  173. </>
  174. );
  175. }
  176. export default SettingsForm;