change UI set Endpoint
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
ShieldCheck,
|
||||
Trash2,
|
||||
WifiOff,
|
||||
X,
|
||||
XCircle
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
@@ -159,6 +160,7 @@ function App() {
|
||||
const [toast, setToast] = useState(null);
|
||||
const [busyAction, setBusyAction] = useState('');
|
||||
const [activeTask, setActiveTask] = useState(null);
|
||||
const [endpointDialogOpen, setEndpointDialogOpen] = useState(false);
|
||||
|
||||
const packageBaseUrl = settings.packageBaseUrl;
|
||||
const agentBaseUrl = settings.agentBaseUrl;
|
||||
@@ -425,13 +427,25 @@ function App() {
|
||||
}
|
||||
}, [agentBaseUrl, agentHealth, notify, packageBaseUrl, startPreflightFailedTask, startTask]);
|
||||
|
||||
const openEndpointDialog = useCallback(() => {
|
||||
setDraftSettings(settings);
|
||||
setEndpointDialogOpen(true);
|
||||
}, [settings]);
|
||||
|
||||
const closeEndpointDialog = useCallback(() => {
|
||||
setDraftSettings(settings);
|
||||
setEndpointDialogOpen(false);
|
||||
}, [settings]);
|
||||
|
||||
const applySettings = useCallback(() => {
|
||||
const nextSettings = {
|
||||
packageBaseUrl: normalizeUrl(draftSettings.packageBaseUrl || DEFAULT_PACKAGE_BASE_URL),
|
||||
agentBaseUrl: normalizeUrl(draftSettings.agentBaseUrl || DEFAULT_AGENT_BASE_URL)
|
||||
};
|
||||
setSettings(nextSettings);
|
||||
setDraftSettings(nextSettings);
|
||||
saveSettings(nextSettings);
|
||||
setEndpointDialogOpen(false);
|
||||
notify('info', 'Đã cập nhật endpoint test');
|
||||
}, [draftSettings, notify]);
|
||||
|
||||
@@ -507,6 +521,19 @@ function App() {
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [toast]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!endpointDialogOpen) return undefined;
|
||||
|
||||
function onKeyDown(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeEndpointDialog();
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', onKeyDown);
|
||||
return () => window.removeEventListener('keydown', onKeyDown);
|
||||
}, [closeEndpointDialog, endpointDialogOpen]);
|
||||
|
||||
return (
|
||||
<div className="app-shell">
|
||||
<aside className="sidebar">
|
||||
@@ -536,29 +563,19 @@ function App() {
|
||||
/>
|
||||
|
||||
<div className="nav-label">Endpoint</div>
|
||||
<label className="settings-field">
|
||||
<span>Package server</span>
|
||||
<input
|
||||
value={draftSettings.packageBaseUrl}
|
||||
onChange={(event) => setDraftSettings((current) => ({
|
||||
...current,
|
||||
packageBaseUrl: event.target.value
|
||||
}))}
|
||||
/>
|
||||
</label>
|
||||
<label className="settings-field">
|
||||
<span>Local Agent</span>
|
||||
<input
|
||||
value={draftSettings.agentBaseUrl}
|
||||
onChange={(event) => setDraftSettings((current) => ({
|
||||
...current,
|
||||
agentBaseUrl: event.target.value
|
||||
}))}
|
||||
/>
|
||||
</label>
|
||||
<button className="btn btn-secondary full" type="button" onClick={applySettings}>
|
||||
<div className="endpoint-summary" aria-label="Current endpoints">
|
||||
<div className="endpoint-summary-row">
|
||||
<span>Package server</span>
|
||||
<strong title={packageBaseUrl}>{packageBaseUrl}</strong>
|
||||
</div>
|
||||
<div className="endpoint-summary-row">
|
||||
<span>Local Agent</span>
|
||||
<strong title={agentBaseUrl}>{agentBaseUrl}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<button className="btn btn-secondary full" type="button" onClick={openEndpointDialog}>
|
||||
<Settings size={15} aria-hidden="true" />
|
||||
Apply
|
||||
Endpoint settings
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
@@ -814,6 +831,78 @@ function App() {
|
||||
</main>
|
||||
|
||||
{toast && <Toast toast={toast} />}
|
||||
{endpointDialogOpen && (
|
||||
<EndpointDialog
|
||||
draftSettings={draftSettings}
|
||||
onApply={applySettings}
|
||||
onCancel={closeEndpointDialog}
|
||||
onChange={setDraftSettings}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function EndpointDialog({ draftSettings, onApply, onCancel, onChange }) {
|
||||
return (
|
||||
<div className="dialog-backdrop">
|
||||
<section
|
||||
aria-labelledby="endpoint-dialog-title"
|
||||
aria-modal="true"
|
||||
className="dialog-panel"
|
||||
role="dialog"
|
||||
>
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
onApply();
|
||||
}}
|
||||
>
|
||||
<div className="dialog-header">
|
||||
<div>
|
||||
<h2 id="endpoint-dialog-title">Endpoint settings</h2>
|
||||
<p>Changes only apply after you press Apply.</p>
|
||||
</div>
|
||||
<button className="icon-button subtle" type="button" title="Close" onClick={onCancel}>
|
||||
<X size={16} aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="dialog-body">
|
||||
<label className="settings-field">
|
||||
<span>Package server</span>
|
||||
<input
|
||||
autoFocus
|
||||
value={draftSettings.packageBaseUrl}
|
||||
onChange={(event) => onChange((current) => ({
|
||||
...current,
|
||||
packageBaseUrl: event.target.value
|
||||
}))}
|
||||
/>
|
||||
</label>
|
||||
<label className="settings-field">
|
||||
<span>Local Agent</span>
|
||||
<input
|
||||
value={draftSettings.agentBaseUrl}
|
||||
onChange={(event) => onChange((current) => ({
|
||||
...current,
|
||||
agentBaseUrl: event.target.value
|
||||
}))}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="dialog-actions">
|
||||
<button className="btn btn-secondary" type="button" onClick={onCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
<button className="btn btn-primary" type="submit">
|
||||
<Settings size={15} aria-hidden="true" />
|
||||
Apply endpoints
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user