Unify Harbor error handling across server and client
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useReducer, useRef, useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import './styles.css';
|
||||
import { api } from './api.js';
|
||||
import { api, HarborApiError } from './api.js';
|
||||
import { ClientOverviewPage } from './components/ClientOverviewPage.jsx';
|
||||
import { BootStatePage, StaleBanner } from './components/SyncStatus.jsx';
|
||||
import {
|
||||
@@ -18,7 +18,7 @@ function App() {
|
||||
);
|
||||
const [subscriptionUrl, setSubscriptionUrl] = useState('');
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [error, setError] = useState(null);
|
||||
const pollGeneration = useRef(0);
|
||||
|
||||
function setPendingTag(serverId) {
|
||||
@@ -60,14 +60,21 @@ function App() {
|
||||
: '/harbor-connect.svg?v=2';
|
||||
}, [state?.mode]);
|
||||
|
||||
async function run(action) {
|
||||
async function run(action, context) {
|
||||
setBusy(true);
|
||||
setError('');
|
||||
setError(null);
|
||||
try {
|
||||
return await applyMutation(action);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
throw err;
|
||||
const safeError = err instanceof HarborApiError ? err : new HarborApiError();
|
||||
setError({
|
||||
context,
|
||||
message: safeError.message,
|
||||
code: safeError.code,
|
||||
correlationId: safeError.correlationId,
|
||||
retry: safeError.retryable ? () => run(action, context) : null,
|
||||
});
|
||||
return false;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
@@ -91,11 +98,11 @@ function App() {
|
||||
const data = await api.subscription.fetch(subscriptionUrl);
|
||||
dispatch({ type: 'clear-pending-server' });
|
||||
return data;
|
||||
});
|
||||
}, 'subscription');
|
||||
}
|
||||
|
||||
async function refreshSubscription() {
|
||||
return applyMutation(api.subscription.refresh);
|
||||
return run(api.subscription.refresh, 'subscription');
|
||||
}
|
||||
|
||||
async function forgetSubscription() {
|
||||
@@ -104,7 +111,7 @@ function App() {
|
||||
setSubscriptionUrl('');
|
||||
dispatch({ type: 'clear-pending-server' });
|
||||
return data;
|
||||
});
|
||||
}, 'subscription');
|
||||
}
|
||||
|
||||
if (!state) return <BootStatePage transport={transport} onRetry={() => loadState({ retry: true })} />;
|
||||
@@ -126,10 +133,10 @@ function App() {
|
||||
onFetchSubscription={fetchSubscription}
|
||||
onRefreshSubscription={refreshSubscription}
|
||||
onForgetSubscription={forgetSubscription}
|
||||
onApply={(tag) => run(() => api.apply(tag))}
|
||||
onRestart={() => run(api.singbox.restart)}
|
||||
onStop={() => run(api.singbox.stop)}
|
||||
onSetGatewayAuto={(enabled) => run(() => api.gatewayAuto.setEnabled(enabled))}
|
||||
onApply={(tag) => run(() => api.apply(tag), 'connection')}
|
||||
onRestart={() => run(api.singbox.restart, 'connection')}
|
||||
onStop={() => run(api.singbox.stop, 'connection')}
|
||||
onSetGatewayAuto={(enabled) => run(() => api.gatewayAuto.setEnabled(enabled), 'connection')}
|
||||
/>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user