mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(settings): render Managed provider as always-on badge, not a locked toggle (#3984)
This commit is contained in:
@@ -612,6 +612,7 @@ const ProviderToggleChip = ({
|
||||
enabled,
|
||||
busy,
|
||||
locked = false,
|
||||
alwaysOn = false,
|
||||
onToggle,
|
||||
}: {
|
||||
slug: string;
|
||||
@@ -619,7 +620,11 @@ const ProviderToggleChip = ({
|
||||
enabled: boolean;
|
||||
busy?: boolean;
|
||||
locked?: boolean;
|
||||
onToggle: () => void;
|
||||
// When true the provider is permanently available (e.g. Managed) and renders
|
||||
// a static "Always on" indicator instead of a toggle. A locked toggle reads
|
||||
// as switchable-but-broken (#3760); a badge has no affordance to fight.
|
||||
alwaysOn?: boolean;
|
||||
onToggle?: () => void;
|
||||
}) => {
|
||||
const { t } = useT();
|
||||
const tone = slugTone(slug);
|
||||
@@ -627,13 +632,20 @@ const ProviderToggleChip = ({
|
||||
<div
|
||||
className={`inline-flex items-center gap-2 rounded-full px-2.5 py-1 text-xs font-medium ring-1 transition-colors dark:ring-neutral-700 ${tone}`}>
|
||||
<span>{label}</span>
|
||||
<SettingsSwitch
|
||||
id={`provider-toggle-${slug}`}
|
||||
checked={enabled}
|
||||
onCheckedChange={onToggle}
|
||||
disabled={busy || locked}
|
||||
aria-label={providerToggleAriaLabel(t, enabled, label)}
|
||||
/>
|
||||
{alwaysOn ? (
|
||||
<span className="inline-flex items-center gap-1 opacity-80">
|
||||
<LuCheck className="h-3 w-3" />
|
||||
{t('settings.ai.routing.managedAlwaysOn')}
|
||||
</span>
|
||||
) : (
|
||||
<SettingsSwitch
|
||||
id={`provider-toggle-${slug}`}
|
||||
checked={enabled}
|
||||
onCheckedChange={() => onToggle?.()}
|
||||
disabled={busy || locked}
|
||||
aria-label={providerToggleAriaLabel(t, enabled, label)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -3162,8 +3174,7 @@ const AIPanel = ({ embedded = false }: AIPanelProps = {}) => {
|
||||
slug="openhuman"
|
||||
label={t('settings.ai.routing.managed')}
|
||||
enabled
|
||||
locked
|
||||
onToggle={() => {}}
|
||||
alwaysOn
|
||||
/>
|
||||
|
||||
{/* Built-in cloud providers */}
|
||||
@@ -3283,6 +3294,13 @@ const AIPanel = ({ embedded = false }: AIPanelProps = {}) => {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* #3760: Managed is always-on and can't be turned off; point users
|
||||
who want a local model at the Routing card below instead of
|
||||
letting them fight the (now badge, formerly locked) Managed chip. */}
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
{t('settings.ai.routing.managedHint')}
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-2 pt-1">
|
||||
{/* Codex — imports the existing Codex CLI login as an OpenAI credential. */}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
|
||||
@@ -279,11 +279,14 @@ describe('AIPanel', () => {
|
||||
await waitFor(() => expect(screen.getAllByText(/OpenHuman/i).length).toBeGreaterThan(0));
|
||||
});
|
||||
|
||||
it('renders the always-on Managed chip', async () => {
|
||||
it('renders Managed as an always-on badge, not a switchable toggle (#3760)', async () => {
|
||||
renderWithProviders(<AIPanel />);
|
||||
const managedSwitch = await screen.findByRole('switch', { name: /Disconnect Managed/i });
|
||||
expect(managedSwitch).toBeDisabled();
|
||||
expect(managedSwitch).toHaveAttribute('aria-checked', 'true');
|
||||
// The Managed chip must show an "Always on" indicator...
|
||||
expect(await screen.findByText(/Always on/i)).toBeInTheDocument();
|
||||
// ...and must NOT render a toggle switch users would try (and fail) to flip.
|
||||
expect(screen.queryByRole('switch', { name: /Managed/i })).toBeNull();
|
||||
// A hint points users wanting a local model at the Routing card below.
|
||||
expect(screen.getByText(/choose a routing mode below/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders Managed, Use Your Own Models, and Advanced routing controls', async () => {
|
||||
|
||||
@@ -3623,6 +3623,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'استطلاعات عاملي الذاكرة',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'المُدارة',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'(Xqx0xx) سيحقق كل شيء في السحابة، ويختار أفضل نموذج للمهمة، ويرفع التكاليف إلى أقصى حد، ويحتفظ بأمن التخلف عن الدفع.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3700,6 +3700,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'মেমরি কর্মী পোল',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'পরিচালিত',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'xq0xqx সমস্ত প্রকার মেঘে রান করা হবে, কর্মের জন্য সেরা মডেল নির্বাচন করুন, খরচের জন্য ব্যবহারযোগ্য ডিফল্ট মান নির্বাচন করুন।',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3789,6 +3789,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Speicher-Worker-Umfragen',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Verwaltet',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Immer aktiv',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Verwaltet ist immer als Fallback verfügbar. Um dein eigenes Modell zu verwenden, wähle unten einen Routing-Modus.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman führt alle Inferenzen in der Cloud aus, wählt das beste Modell für die Aufgabe aus, optimiert die Kosten und behält die sichersten Routing-Standards bei.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -4303,6 +4303,9 @@ const en: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Memory worker polls',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Managed',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman will run all inference in the cloud, choose the best model for the task, optimize for cost, and keep the safest routing defaults.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3765,6 +3765,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Encuestas de trabajadores de la memoria',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Gestionado',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman ejecutará toda la inferencia en la nube, elegirá el mejor modelo para la tarea, optimizará para el costo y mantendrá los valores predeterminados de enrutamiento más seguros.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3779,6 +3779,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Sondages de mémoire',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Géré',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman exécutera toutes les inférences dans le cloud, choisira le meilleur modèle pour la tâche, optimisera les coûts et conservera les paramètres de routage les plus sûrs par défaut.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3706,6 +3706,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'स्मृति कार्यकर्ता सर्वेक्षण',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'प्रबंधित',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman बादल में सभी अनुमान चला जाएगा, कार्य के लिए सबसे अच्छा मॉडल चुनें, लागत के लिए अनुकूलन करें और सबसे सुरक्षित रूटिंग डिफ़ॉल्ट रखें।',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3709,6 +3709,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Jajak pendapat pekerja memori',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Terkelola',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman akan menjalankan semua kesimpulan di awan, memilih model terbaik untuk tugas ini, mengoptimalkan biaya, dan menjaga standar routing teraman.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3756,6 +3756,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Sondaggi del Memory Worker',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Gestiti',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman eseguirà tutte le inferenze nel cloud, sceglierà il miglior modello per il compito, ottimizzerà i costi e manterrà le impostazioni di routing più sicure.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3673,6 +3673,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': '메모리 작업자 설문 조사',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': '관리됨',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman이 모든 추론을 클라우드에서 실행하고, 작업에 가장 적합한 모델을 선택하며, 비용을 최적화하고 가장 안전한 라우팅 기본값을 유지합니다.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3755,6 +3755,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Odpytywania procesu pamięci',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Zarządzane',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman uruchomi całą inferencję w chmurze, wybierze najlepszy model dla zadania, zoptymalizuje koszty i zachowa najbezpieczniejsze domyślne ustawienia routingu.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3761,6 +3761,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Pesquisas de trabalho de memória',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Gerenciadas',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman executará toda a inferência na nuvem, escolherá o melhor modelo para a tarefa, otimizará os custos e manterá os padrões de roteamento mais seguros.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3733,6 +3733,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': 'Опросы работников памяти',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': 'Управляемый',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman выполнит все логические выводы в облаке, выберет лучшую модель для задачи, оптимизирует затраты и сохранит самые безопасные настройки маршрутизации по умолчанию.',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
@@ -3518,6 +3518,9 @@ const messages: TranslationMap = {
|
||||
'settings.ai.memoryWorkerPolls': '内存工作者民意调查',
|
||||
'settings.ai.defaultProviderName': 'OpenHuman',
|
||||
'settings.ai.routing.managed': '托管',
|
||||
'settings.ai.routing.managedAlwaysOn': 'Always on',
|
||||
'settings.ai.routing.managedHint':
|
||||
'Managed is always available as a fallback. To use your own model, choose a routing mode below.',
|
||||
'settings.ai.routing.managedDesc':
|
||||
'OpenHuman 会在云端运行所有推理,为任务选择最佳模型,优化成本,并保持最安全的路由默认值。',
|
||||
'settings.ai.routing.managedMsg':
|
||||
|
||||
Reference in New Issue
Block a user