mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 22:17:14 +00:00
fix(ui): move agy power-user mode to proxy settings
- move Antigravity power-user toggle from Settings > Auth to Settings > Proxy - keep Add Account messaging consistent with the new location - retain issue #509 risk framing for AGY flows
This commit is contained in:
@@ -340,7 +340,7 @@ export function AddAccountDialog({
|
|||||||
<ShieldAlert className="h-3.5 w-3.5" />
|
<ShieldAlert className="h-3.5 w-3.5" />
|
||||||
Power user mode enabled
|
Power user mode enabled
|
||||||
</div>
|
</div>
|
||||||
AGY responsibility checklist is skipped from Settings {'>'} Auth. You accept full
|
AGY responsibility checklist is skipped from Settings {'>'} Proxy. You accept full
|
||||||
responsibility for OAuth/account risk.
|
responsibility for OAuth/account risk.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
* Settings section for CLIProxy auth tokens (API key and management secret)
|
* Settings section for CLIProxy auth tokens (API key and management secret)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useState, useCallback, useRef } from 'react';
|
import { useEffect, useState, useCallback } from 'react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
import { Switch } from '@/components/ui/switch';
|
|
||||||
import {
|
import {
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
@@ -21,7 +20,6 @@ import {
|
|||||||
Check,
|
Check,
|
||||||
KeyRound,
|
KeyRound,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
ShieldAlert,
|
|
||||||
Save,
|
Save,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useRawConfig } from '../hooks';
|
import { useRawConfig } from '../hooks';
|
||||||
@@ -53,10 +51,6 @@ export default function AuthSection() {
|
|||||||
const [editedSecret, setEditedSecret] = useState<string | null>(null);
|
const [editedSecret, setEditedSecret] = useState<string | null>(null);
|
||||||
const [copiedApiKey, setCopiedApiKey] = useState(false);
|
const [copiedApiKey, setCopiedApiKey] = useState(false);
|
||||||
const [copiedSecret, setCopiedSecret] = useState(false);
|
const [copiedSecret, setCopiedSecret] = useState(false);
|
||||||
const [agyAckBypass, setAgyAckBypass] = useState(false);
|
|
||||||
const [agyAckBypassLoading, setAgyAckBypassLoading] = useState(true);
|
|
||||||
const [agyAckBypassSaving, setAgyAckBypassSaving] = useState(false);
|
|
||||||
const agyAckBypassSavingRef = useRef(false);
|
|
||||||
|
|
||||||
// Fetch tokens
|
// Fetch tokens
|
||||||
const fetchTokens = useCallback(async () => {
|
const fetchTokens = useCallback(async () => {
|
||||||
@@ -77,28 +71,11 @@ export default function AuthSection() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchAgyAckBypass = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
setAgyAckBypassLoading(true);
|
|
||||||
const response = await fetch('/api/settings/auth/antigravity-risk');
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to load Antigravity power user settings');
|
|
||||||
}
|
|
||||||
const data = (await response.json()) as { antigravityAckBypass?: boolean };
|
|
||||||
setAgyAckBypass(data.antigravityAckBypass === true);
|
|
||||||
} catch (err) {
|
|
||||||
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
||||||
} finally {
|
|
||||||
setAgyAckBypassLoading(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Load on mount
|
// Load on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTokens();
|
fetchTokens();
|
||||||
fetchAgyAckBypass();
|
|
||||||
fetchRawConfig();
|
fetchRawConfig();
|
||||||
}, [fetchTokens, fetchAgyAckBypass, fetchRawConfig]);
|
}, [fetchTokens, fetchRawConfig]);
|
||||||
|
|
||||||
// Clear success after timeout
|
// Clear success after timeout
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -118,8 +95,6 @@ export default function AuthSection() {
|
|||||||
|
|
||||||
// Save all changes
|
// Save all changes
|
||||||
const saveChanges = async () => {
|
const saveChanges = async () => {
|
||||||
if (agyAckBypassSaving) return;
|
|
||||||
|
|
||||||
const hasApiKeyChange = editedApiKey !== null && editedApiKey !== tokens?.apiKey.value;
|
const hasApiKeyChange = editedApiKey !== null && editedApiKey !== tokens?.apiKey.value;
|
||||||
const hasSecretChange =
|
const hasSecretChange =
|
||||||
editedSecret !== null && editedSecret !== tokens?.managementSecret.value;
|
editedSecret !== null && editedSecret !== tokens?.managementSecret.value;
|
||||||
@@ -159,8 +134,6 @@ export default function AuthSection() {
|
|||||||
|
|
||||||
// Regenerate management secret
|
// Regenerate management secret
|
||||||
const regenerateSecret = async () => {
|
const regenerateSecret = async () => {
|
||||||
if (agyAckBypassSaving) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -185,8 +158,6 @@ export default function AuthSection() {
|
|||||||
|
|
||||||
// Reset to defaults
|
// Reset to defaults
|
||||||
const resetToDefaults = async () => {
|
const resetToDefaults = async () => {
|
||||||
if (agyAckBypassSaving) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -226,50 +197,11 @@ export default function AuthSection() {
|
|||||||
setTimeout(() => setCopiedSecret(false), 2000);
|
setTimeout(() => setCopiedSecret(false), 2000);
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveAgyAckBypass = async (nextValue: boolean) => {
|
|
||||||
if (agyAckBypassSavingRef.current || agyAckBypassSaving || saving) return;
|
|
||||||
|
|
||||||
if (nextValue) {
|
|
||||||
const confirmed = window.confirm(
|
|
||||||
'Enable AGY power user mode?\n\nThis skips AGY safety prompts. You accept the OAuth risk.'
|
|
||||||
);
|
|
||||||
if (!confirmed) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
agyAckBypassSavingRef.current = true;
|
|
||||||
setAgyAckBypassSaving(true);
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
const response = await fetch('/api/settings/auth/antigravity-risk', {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ antigravityAckBypass: nextValue }),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = (await response.json()) as { error?: string };
|
|
||||||
throw new Error(data.error || 'Failed to update Antigravity power user mode');
|
|
||||||
}
|
|
||||||
|
|
||||||
setAgyAckBypass(nextValue);
|
|
||||||
setSuccess(
|
|
||||||
nextValue ? 'Antigravity power user mode enabled.' : 'Antigravity power user mode disabled.'
|
|
||||||
);
|
|
||||||
await fetchRawConfig();
|
|
||||||
} catch (err) {
|
|
||||||
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
||||||
} finally {
|
|
||||||
agyAckBypassSavingRef.current = false;
|
|
||||||
setAgyAckBypassSaving(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshAll = async () => {
|
const refreshAll = async () => {
|
||||||
if (loading || saving || agyAckBypassSaving) return;
|
if (loading || saving) return;
|
||||||
setError(null);
|
setError(null);
|
||||||
setSuccess(null);
|
setSuccess(null);
|
||||||
await Promise.all([fetchTokens(), fetchAgyAckBypass(), fetchRawConfig()]);
|
await Promise.all([fetchTokens(), fetchRawConfig()]);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading || !tokens) {
|
if (loading || !tokens) {
|
||||||
@@ -344,7 +276,7 @@ export default function AuthSection() {
|
|||||||
value={displayApiKey}
|
value={displayApiKey}
|
||||||
onChange={(e) => setEditedApiKey(e.target.value)}
|
onChange={(e) => setEditedApiKey(e.target.value)}
|
||||||
placeholder="API key"
|
placeholder="API key"
|
||||||
disabled={saving || agyAckBypassSaving}
|
disabled={saving}
|
||||||
className="pr-20 font-mono text-sm"
|
className="pr-20 font-mono text-sm"
|
||||||
/>
|
/>
|
||||||
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex gap-1">
|
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex gap-1">
|
||||||
@@ -395,7 +327,7 @@ export default function AuthSection() {
|
|||||||
value={displaySecret}
|
value={displaySecret}
|
||||||
onChange={(e) => setEditedSecret(e.target.value)}
|
onChange={(e) => setEditedSecret(e.target.value)}
|
||||||
placeholder="Management secret"
|
placeholder="Management secret"
|
||||||
disabled={saving || agyAckBypassSaving}
|
disabled={saving}
|
||||||
className="pr-20 font-mono text-sm"
|
className="pr-20 font-mono text-sm"
|
||||||
/>
|
/>
|
||||||
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex gap-1">
|
<div className="absolute right-2 top-1/2 -translate-y-1/2 flex gap-1">
|
||||||
@@ -426,7 +358,7 @@ export default function AuthSection() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={regenerateSecret}
|
onClick={regenerateSecret}
|
||||||
disabled={saving || agyAckBypassSaving}
|
disabled={saving}
|
||||||
title="Generate new secure secret"
|
title="Generate new secure secret"
|
||||||
>
|
>
|
||||||
<Sparkles className="w-4 h-4" />
|
<Sparkles className="w-4 h-4" />
|
||||||
@@ -434,48 +366,12 @@ export default function AuthSection() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Actions */}
|
|
||||||
<div className="space-y-3 rounded-lg border border-amber-400/35 bg-amber-50/70 p-4 dark:border-amber-800/60 dark:bg-amber-950/25">
|
|
||||||
<div className="flex items-start justify-between gap-4">
|
|
||||||
<div className="space-y-1">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<ShieldAlert className="w-4 h-4 text-amber-700 dark:text-amber-300" />
|
|
||||||
<h3 className="text-base font-medium">Antigravity Power User Mode</h3>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
Skip AGY responsibility checklists in Add Account and `ccs agy` flows.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Switch
|
|
||||||
aria-labelledby="agy-power-user-mode-label"
|
|
||||||
aria-describedby="agy-power-user-mode-description"
|
|
||||||
checked={agyAckBypass}
|
|
||||||
disabled={agyAckBypassLoading || agyAckBypassSaving || saving}
|
|
||||||
onCheckedChange={saveAgyAckBypass}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
id="agy-power-user-mode-description"
|
|
||||||
className="text-xs text-amber-800/90 dark:text-amber-200/90"
|
|
||||||
>
|
|
||||||
Use only if you fully understand the OAuth suspension/ban risk pattern (#509). CCS
|
|
||||||
cannot assume responsibility for account loss.
|
|
||||||
</p>
|
|
||||||
<span id="agy-power-user-mode-label" className="sr-only">
|
|
||||||
Toggle AGY power user mode
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="pt-4 border-t">
|
<div className="pt-4 border-t">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={resetToDefaults}
|
onClick={resetToDefaults}
|
||||||
disabled={
|
disabled={saving || (!tokens.apiKey.isCustom && !tokens.managementSecret.isCustom)}
|
||||||
saving ||
|
|
||||||
agyAckBypassSaving ||
|
|
||||||
(!tokens.apiKey.isCustom && !tokens.managementSecret.isCustom)
|
|
||||||
}
|
|
||||||
className="gap-2"
|
className="gap-2"
|
||||||
>
|
>
|
||||||
<RotateCcw className="w-4 h-4" />
|
<RotateCcw className="w-4 h-4" />
|
||||||
@@ -494,7 +390,7 @@ export default function AuthSection() {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={refreshAll}
|
onClick={refreshAll}
|
||||||
disabled={loading || saving || agyAckBypassSaving}
|
disabled={loading || saving}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
>
|
>
|
||||||
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />
|
||||||
@@ -504,7 +400,7 @@ export default function AuthSection() {
|
|||||||
variant="default"
|
variant="default"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={saveChanges}
|
onClick={saveChanges}
|
||||||
disabled={!hasChanges || saving || agyAckBypassSaving}
|
disabled={!hasChanges || saving}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
>
|
>
|
||||||
<Save className={`w-4 h-4 mr-2 ${saving ? 'animate-pulse' : ''}`} />
|
<Save className={`w-4 h-4 mr-2 ${saving ? 'animate-pulse' : ''}`} />
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Settings section for CLIProxyAPI configuration (local/remote)
|
* Settings section for CLIProxyAPI configuration (local/remote)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useState, useCallback } from 'react';
|
import { useEffect, useState, useCallback, useRef } from 'react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
Bug,
|
Bug,
|
||||||
Box,
|
Box,
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
|
ShieldAlert,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useProxyConfig, useRawConfig } from '../../hooks';
|
import { useProxyConfig, useRawConfig } from '../../hooks';
|
||||||
import { useUpdateBackend, useProxyStatus } from '@/hooks/use-cliproxy';
|
import { useUpdateBackend, useProxyStatus } from '@/hooks/use-cliproxy';
|
||||||
@@ -67,6 +68,10 @@ export default function ProxySection() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const [agyAckBypass, setAgyAckBypass] = useState(false);
|
||||||
|
const [agyAckBypassLoading, setAgyAckBypassLoading] = useState(true);
|
||||||
|
const [agyAckBypassSaving, setAgyAckBypassSaving] = useState(false);
|
||||||
|
const agyAckBypassSavingRef = useRef(false);
|
||||||
|
|
||||||
const handleDebugModeChange = (enabled: boolean) => {
|
const handleDebugModeChange = (enabled: boolean) => {
|
||||||
setDebugMode(enabled);
|
setDebugMode(enabled);
|
||||||
@@ -77,6 +82,62 @@ export default function ProxySection() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchAgyAckBypass = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
setAgyAckBypassLoading(true);
|
||||||
|
const response = await fetch('/api/settings/auth/antigravity-risk');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to load AGY power user mode');
|
||||||
|
}
|
||||||
|
const data = (await response.json()) as { antigravityAckBypass?: boolean };
|
||||||
|
setAgyAckBypass(data.antigravityAckBypass === true);
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(err instanceof Error ? err.message : 'Failed to load AGY power user mode');
|
||||||
|
setAgyAckBypass(false);
|
||||||
|
} finally {
|
||||||
|
setAgyAckBypassLoading(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const saveAgyAckBypass = useCallback(
|
||||||
|
async (nextValue: boolean) => {
|
||||||
|
if (agyAckBypassSavingRef.current || agyAckBypassSaving || saving) return;
|
||||||
|
|
||||||
|
if (nextValue) {
|
||||||
|
const confirmed = window.confirm(
|
||||||
|
'Enable AGY power user mode?\n\nThis skips AGY safety prompts. You accept the OAuth risk.'
|
||||||
|
);
|
||||||
|
if (!confirmed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
agyAckBypassSavingRef.current = true;
|
||||||
|
setAgyAckBypassSaving(true);
|
||||||
|
|
||||||
|
const response = await fetch('/api/settings/auth/antigravity-risk', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ antigravityAckBypass: nextValue }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = (await response.json()) as { error?: string };
|
||||||
|
throw new Error(data.error || 'Failed to update AGY power user mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
setAgyAckBypass(nextValue);
|
||||||
|
toast.success(nextValue ? 'AGY power user mode enabled.' : 'AGY power user mode disabled.');
|
||||||
|
await fetchRawConfig();
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(err instanceof Error ? err.message : 'Failed to update AGY power user mode');
|
||||||
|
} finally {
|
||||||
|
agyAckBypassSavingRef.current = false;
|
||||||
|
setAgyAckBypassSaving(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[agyAckBypassSaving, fetchRawConfig, saving]
|
||||||
|
);
|
||||||
|
|
||||||
// Backend state (loaded from API) + mutation hook for proper query invalidation
|
// Backend state (loaded from API) + mutation hook for proper query invalidation
|
||||||
const [backend, setBackend] = useState<'original' | 'plus'>('plus');
|
const [backend, setBackend] = useState<'original' | 'plus'>('plus');
|
||||||
const [hasKiroGhcpVariants, setHasKiroGhcpVariants] = useState(false);
|
const [hasKiroGhcpVariants, setHasKiroGhcpVariants] = useState(false);
|
||||||
@@ -138,12 +199,13 @@ export default function ProxySection() {
|
|||||||
// Load data on mount
|
// Load data on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchConfig();
|
fetchConfig();
|
||||||
|
void fetchAgyAckBypass();
|
||||||
fetchRawConfig();
|
fetchRawConfig();
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- Async data fetching on mount is intended
|
|
||||||
void fetchBackend();
|
void fetchBackend();
|
||||||
|
|
||||||
void checkPlusOnlyVariants();
|
void checkPlusOnlyVariants();
|
||||||
}, [fetchConfig, fetchRawConfig, fetchBackend, checkPlusOnlyVariants]);
|
}, [fetchConfig, fetchAgyAckBypass, fetchRawConfig, fetchBackend, checkPlusOnlyVariants]);
|
||||||
|
|
||||||
if (loading || !config) {
|
if (loading || !config) {
|
||||||
return (
|
return (
|
||||||
@@ -403,6 +465,41 @@ export default function ProxySection() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Safety */}
|
||||||
|
<div className="space-y-3">
|
||||||
|
<h3 className="text-base font-medium flex items-center gap-2">
|
||||||
|
<ShieldAlert className="w-4 h-4 text-amber-700 dark:text-amber-300" />
|
||||||
|
Safety
|
||||||
|
</h3>
|
||||||
|
<div className="space-y-3 rounded-lg border border-amber-400/35 bg-amber-50/70 p-4 dark:border-amber-800/60 dark:bg-amber-950/25">
|
||||||
|
<div className="flex items-start justify-between gap-4">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="font-medium text-sm">Antigravity Power User Mode</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Skip AGY responsibility checklist in Add Account and `ccs agy` flows.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Switch
|
||||||
|
aria-labelledby="agy-power-user-mode-label"
|
||||||
|
aria-describedby="agy-power-user-mode-description"
|
||||||
|
checked={agyAckBypass}
|
||||||
|
disabled={agyAckBypassLoading || agyAckBypassSaving || saving}
|
||||||
|
onCheckedChange={saveAgyAckBypass}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
id="agy-power-user-mode-description"
|
||||||
|
className="text-xs text-amber-800/90 dark:text-amber-200/90"
|
||||||
|
>
|
||||||
|
Use only if you fully understand the OAuth suspension/ban risk pattern (#509). CCS
|
||||||
|
cannot assume responsibility for account loss.
|
||||||
|
</p>
|
||||||
|
<span id="agy-power-user-mode-label" className="sr-only">
|
||||||
|
Toggle AGY power user mode
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Remote Settings - Show when remote mode is enabled */}
|
{/* Remote Settings - Show when remote mode is enabled */}
|
||||||
{isRemoteMode && (
|
{isRemoteMode && (
|
||||||
<RemoteProxyCard
|
<RemoteProxyCard
|
||||||
@@ -517,11 +614,12 @@ export default function ProxySection() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
fetchConfig();
|
fetchConfig();
|
||||||
|
fetchAgyAckBypass();
|
||||||
fetchRawConfig();
|
fetchRawConfig();
|
||||||
fetchBackend();
|
fetchBackend();
|
||||||
checkPlusOnlyVariants();
|
checkPlusOnlyVariants();
|
||||||
}}
|
}}
|
||||||
disabled={loading || saving}
|
disabled={loading || saving || agyAckBypassSaving}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />
|
<RefreshCw className={`w-4 h-4 mr-2 ${loading ? 'animate-spin' : ''}`} />
|
||||||
|
|||||||
Reference in New Issue
Block a user