import { CONFIG_DEFAULT, CONFIG_INFO } from '../Config';
import { isDev } from '../Config';
import StorageUtils from '../utils/storage';
+import { isBoolean, isNumeric, isString } from '../utils/misc';
type SettKey = keyof typeof CONFIG_DEFAULT;
};
const handleSave = () => {
- saveConfig(localConfig);
+ // copy the local config to prevent direct mutation
+ const newConfig: typeof CONFIG_DEFAULT = JSON.parse(
+ JSON.stringify(localConfig)
+ );
+ // validate the config
+ for (const key in newConfig) {
+ const value = newConfig[key as SettKey];
+ const mustBeBoolean = isBoolean(CONFIG_DEFAULT[key as SettKey]);
+ const mustBeString = isString(CONFIG_DEFAULT[key as SettKey]);
+ const mustBeNumeric = isNumeric(CONFIG_DEFAULT[key as SettKey]);
+ if (mustBeString) {
+ if (!isString(value)) {
+ alert(`Value for ${key} must be string`);
+ return;
+ }
+ } else if (mustBeNumeric) {
+ const trimedValue = value.toString().trim();
+ const numVal = Number(trimedValue);
+ if (isNaN(numVal) || !isNumeric(numVal) || trimedValue.length === 0) {
+ alert(`Value for ${key} must be numeric`);
+ return;
+ }
+ // force conversion to number
+ // @ts-expect-error this is safe
+ newConfig[key] = numVal;
+ } else if (mustBeBoolean) {
+ if (!isBoolean(value)) {
+ alert(`Value for ${key} must be boolean`);
+ return;
+ }
+ } else {
+ console.error(`Unknown default type for key ${key}`);
+ }
+ }
+ if (isDev) console.log('Saving config', newConfig);
+ saveConfig(newConfig);
onClose();
};
onClose();
};
+ const onChange = (key: SettKey) => (value: string | boolean) => {
+ // note: we do not perform validation here, because we may get incomplete value as user is still typing it
+ setLocalConfig({ ...localConfig, [key]: value });
+ };
+
return (
<dialog className={`modal ${show ? 'modal-open' : ''}`}>
<div className="modal-box">
configKey="apiKey"
configDefault={CONFIG_DEFAULT}
value={localConfig.apiKey}
- onChange={(value) =>
- setLocalConfig({ ...localConfig, apiKey: value })
- }
+ onChange={onChange('apiKey')}
/>
<label className="form-control mb-2">
className="textarea textarea-bordered h-24"
placeholder={`Default: ${CONFIG_DEFAULT.systemMessage}`}
value={localConfig.systemMessage}
- onChange={(e) =>
- setLocalConfig({
- ...localConfig,
- systemMessage: e.target.value,
- })
- }
+ onChange={(e) => onChange('systemMessage')(e.target.value)}
/>
</label>
configKey={key}
configDefault={CONFIG_DEFAULT}
value={localConfig[key]}
- onChange={(value) =>
- setLocalConfig({ ...localConfig, [key]: value })
- }
+ onChange={onChange(key)}
/>
))}
configKey="samplers"
configDefault={CONFIG_DEFAULT}
value={localConfig.samplers}
- onChange={(value) =>
- setLocalConfig({ ...localConfig, samplers: value })
- }
+ onChange={onChange('samplers')}
/>
{OTHER_SAMPLER_KEYS.map((key) => (
<SettingsModalShortInput
configKey={key}
configDefault={CONFIG_DEFAULT}
value={localConfig[key]}
- onChange={(value) =>
- setLocalConfig({ ...localConfig, [key]: value })
- }
+ onChange={onChange(key)}
/>
))}
</div>
configKey={key}
configDefault={CONFIG_DEFAULT}
value={localConfig[key]}
- onChange={(value) =>
- setLocalConfig({ ...localConfig, [key]: value })
- }
+ onChange={onChange(key)}
/>
))}
</div>
className="checkbox"
checked={localConfig.showThoughtInProgress}
onChange={(e) =>
- setLocalConfig({
- ...localConfig,
- showThoughtInProgress: e.target.checked,
- })
+ onChange('showThoughtInProgress')(e.target.checked)
}
/>
<span className="ml-4">
className="checkbox"
checked={localConfig.excludeThoughtOnReq}
onChange={(e) =>
- setLocalConfig({
- ...localConfig,
- excludeThoughtOnReq: e.target.checked,
- })
+ onChange('excludeThoughtOnReq')(e.target.checked)
}
/>
<span className="ml-4">
className="checkbox"
checked={localConfig.showTokensPerSecond}
onChange={(e) =>
- setLocalConfig({
- ...localConfig,
- showTokensPerSecond: e.target.checked,
- })
+ onChange('showTokensPerSecond')(e.target.checked)
}
/>
<span className="ml-4">Show tokens per second</span>
className="textarea textarea-bordered h-24"
placeholder='Example: { "mirostat": 1, "min_p": 0.1 }'
value={localConfig.custom}
- onChange={(e) =>
- setLocalConfig({ ...localConfig, custom: e.target.value })
- }
+ onChange={(e) => onChange('custom')(e.target.value)}
/>
</label>
</div>