155 lines
4.7 KiB
TypeScript
155 lines
4.7 KiB
TypeScript
/**
|
|
* WorkspaceGeneralSettings -- Per-user workspace settings (e.g. max agent rounds).
|
|
*
|
|
* The user can override the instance default. Setting a field to null reverts to the default.
|
|
*/
|
|
|
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
import { useApiRequest } from '../../../hooks/useApi';
|
|
import styles from './WorkspaceGeneralSettings.module.css';
|
|
|
|
interface GeneralSettingsProps {
|
|
instanceId: string;
|
|
}
|
|
|
|
interface MaxAgentRoundsInfo {
|
|
effective: number;
|
|
userOverride: number | null;
|
|
instanceDefault: number;
|
|
}
|
|
|
|
export const WorkspaceGeneralSettings: React.FC<GeneralSettingsProps> = ({ instanceId }) => {
|
|
const { request } = useApiRequest();
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
const [saving, setSaving] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [success, setSuccess] = useState<string | null>(null);
|
|
|
|
const [maxRoundsInfo, setMaxRoundsInfo] = useState<MaxAgentRoundsInfo>({
|
|
effective: 25,
|
|
userOverride: null,
|
|
instanceDefault: 25,
|
|
});
|
|
const [inputValue, setInputValue] = useState<string>('');
|
|
|
|
const _loadSettings = useCallback(async () => {
|
|
if (!instanceId) return;
|
|
setLoading(true);
|
|
try {
|
|
const data = await request({
|
|
url: `/api/workspace/${instanceId}/settings/general`,
|
|
method: 'get',
|
|
});
|
|
const info = (data as any)?.maxAgentRounds;
|
|
if (info) {
|
|
setMaxRoundsInfo(info);
|
|
setInputValue(info.userOverride != null ? String(info.userOverride) : '');
|
|
}
|
|
} catch (err: any) {
|
|
setError(err?.message || 'Fehler beim Laden der Einstellungen');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [instanceId, request]);
|
|
|
|
useEffect(() => {
|
|
_loadSettings();
|
|
}, [_loadSettings]);
|
|
|
|
const _handleSave = async () => {
|
|
setSaving(true);
|
|
setError(null);
|
|
setSuccess(null);
|
|
try {
|
|
const val = inputValue.trim() === '' ? null : parseInt(inputValue, 10);
|
|
if (val !== null && (isNaN(val) || val < 1 || val > 100)) {
|
|
setError('Wert muss zwischen 1 und 100 liegen.');
|
|
setSaving(false);
|
|
return;
|
|
}
|
|
const data = await request({
|
|
url: `/api/workspace/${instanceId}/settings/general`,
|
|
method: 'put',
|
|
data: { maxAgentRounds: val },
|
|
});
|
|
const info = (data as any)?.maxAgentRounds;
|
|
if (info) {
|
|
setMaxRoundsInfo(info);
|
|
setInputValue(info.userOverride != null ? String(info.userOverride) : '');
|
|
}
|
|
setSuccess('Einstellungen gespeichert.');
|
|
setTimeout(() => setSuccess(null), 3000);
|
|
} catch (err: any) {
|
|
setError(err?.message || 'Fehler beim Speichern');
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const _handleReset = () => {
|
|
setInputValue('');
|
|
};
|
|
|
|
if (loading) {
|
|
return <div className={styles.loading}>Lade Einstellungen...</div>;
|
|
}
|
|
|
|
const hasOverride = inputValue.trim() !== '';
|
|
|
|
return (
|
|
<div className={styles.settings}>
|
|
<h2 className={styles.heading}>Generelle Einstellungen</h2>
|
|
|
|
{error && <div className={styles.error}>{error}</div>}
|
|
{success && <div className={styles.success}>{success}</div>}
|
|
|
|
<div className={styles.section}>
|
|
<h3 className={styles.sectionTitle}>Agenten-Konfiguration</h3>
|
|
|
|
<div className={styles.field}>
|
|
<label className={styles.label}>
|
|
Max. Agenten-Runden
|
|
</label>
|
|
<div style={{ display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
|
|
<input
|
|
type="number"
|
|
className={styles.input}
|
|
style={{ maxWidth: 120 }}
|
|
value={inputValue}
|
|
onChange={e => setInputValue(e.target.value)}
|
|
placeholder={String(maxRoundsInfo.instanceDefault)}
|
|
min={1}
|
|
max={100}
|
|
/>
|
|
{hasOverride && (
|
|
<button
|
|
type="button"
|
|
className={styles.removeBtn}
|
|
onClick={_handleReset}
|
|
title="Auf Standard zurücksetzen"
|
|
>
|
|
Zurücksetzen
|
|
</button>
|
|
)}
|
|
</div>
|
|
<span style={{ fontSize: '0.8rem', color: 'var(--text-secondary, #888)', marginTop: 4, display: 'block' }}>
|
|
Standard der Instanz: {maxRoundsInfo.instanceDefault}.
|
|
{maxRoundsInfo.userOverride != null && (
|
|
<> Ihr Override: {maxRoundsInfo.userOverride}.</>
|
|
)}
|
|
{' '}Effektiv: {maxRoundsInfo.effective}.
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
className={styles.saveBtn}
|
|
onClick={_handleSave}
|
|
disabled={saving}
|
|
>
|
|
{saving ? 'Speichern...' : 'Einstellungen speichern'}
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|