refactor(dashboard): use onError on server actions

This commit is contained in:
Nicolas Meienberger 2023-12-06 21:52:49 +01:00
parent 25c39b92e5
commit 76f9637d77
12 changed files with 106 additions and 83 deletions

View file

@ -1,4 +1,4 @@
import { SocketEvent } from '@runtipi/shared';
import { SocketEvent } from '@runtipi/shared/src/schemas/socket';
import { Socket } from 'socket.io';
import { logger } from '../logger';

View file

@ -3,7 +3,8 @@
import fs from 'fs';
import path from 'path';
import pg from 'pg';
import { execAsync, pathExists, SocketEvent } from '@runtipi/shared';
import { execAsync, pathExists } from '@runtipi/shared';
import { SocketEvent } from '@runtipi/shared/src/schemas/socket';
import { copyDataDir, generateEnvFile } from './app.helpers';
import { logger } from '@/lib/logger';
import { compose } from '@/lib/docker';
@ -34,7 +35,7 @@ export class AppExecutors {
this.logger = logger;
}
private handleAppError = (err: unknown, appId: string, event: SocketEvent['event']) => {
private handleAppError = (err: unknown, appId: string, event: Extract<SocketEvent, { type: 'app' }>['event']) => {
if (err instanceof Error) {
SocketManager.emit({ type: 'app', event, data: { appId, error: err.message } });
this.logger.error(`An error occurred: ${err.message}`);

View file

@ -4209,6 +4209,11 @@ packages:
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
/base64id@2.0.0:
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
engines: {node: ^4.5.0 || >= 5.9}
dev: false
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@ -4673,6 +4678,14 @@ packages:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: true
/cors@2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
dependencies:
object-assign: 4.1.1
vary: 1.1.2
dev: false
/cosmiconfig@7.1.0:
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
engines: {node: '>=10'}

View file

@ -14,10 +14,11 @@ export function LoginContainer() {
const router = useRouter();
const loginMutation = useAction(loginAction, {
onError: (e) => {
if (e.serverError) toast.error(e.serverError);
},
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
} else if (data.success && data.totpSessionId) {
if (data.success && data.totpSessionId) {
setTotpSessionId(data.totpSessionId);
} else {
router.push('/dashboard');
@ -26,18 +27,27 @@ export function LoginContainer() {
});
const verifyTotpMutation = useAction(verifyTotpAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
} else {
router.push('/dashboard');
}
onError: (e) => {
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
router.push('/dashboard');
},
});
if (totpSessionId) {
return <TotpForm loading={verifyTotpMutation.status === 'executing'} onSubmit={(totpCode) => verifyTotpMutation.execute({ totpCode, totpSessionId })} />;
return (
<TotpForm
loading={verifyTotpMutation.status === 'executing'}
onSubmit={(totpCode) => verifyTotpMutation.execute({ totpCode, totpSessionId })}
/>
);
}
return <LoginForm loading={loginMutation.status === 'executing'} onSubmit={({ email, password }) => loginMutation.execute({ username: email, password })} />;
return (
<LoginForm
loading={loginMutation.status === 'executing'}
onSubmit={({ email, password }) => loginMutation.execute({ username: email, password })}
/>
);
}

View file

@ -11,14 +11,18 @@ export const RegisterContainer: React.FC = () => {
const router = useRouter();
const registerMutation = useAction(registerAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
} else {
router.push('/dashboard');
}
onError: (e) => {
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
router.push('/dashboard');
},
});
return <RegisterForm onSubmit={({ email, password }) => registerMutation.execute({ username: email, password })} loading={registerMutation.status === 'executing'} />;
return (
<RegisterForm
onSubmit={({ email, password }) => registerMutation.execute({ username: email, password })}
loading={registerMutation.status === 'executing'}
/>
);
};

View file

@ -15,18 +15,14 @@ export const ResetPasswordContainer: React.FC = () => {
const router = useRouter();
const resetPasswordMutation = useAction(resetPasswordAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
}
onError: (error) => {
if (error.serverError) toast.error(error.serverError);
},
});
const cancelRequestMutation = useAction(cancelResetPasswordAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
}
onError: (error) => {
if (error.serverError) toast.error(error.serverError);
},
});

View file

@ -45,7 +45,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const installMutation = useAction(installAppAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
setOptimisticStatus('installing');
@ -55,7 +55,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const uninstallMutation = useAction(uninstallAppAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
uninstallDisclosure.close();
@ -65,7 +65,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const stopMutation = useAction(stopAppAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
stopDisclosure.close();
@ -75,7 +75,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const startMutation = useAction(startAppAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
setOptimisticStatus('starting');
@ -84,7 +84,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const updateMutation = useAction(updateAppAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
updateDisclosure.close();
@ -94,7 +94,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const updateConfigMutation = useAction(updateAppConfigAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
updateSettingsDisclosure.close();
@ -106,7 +106,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
const resetMutation = useAction(resetAppAction, {
onError: (e) => {
toast.error(e.serverError!);
if (e.serverError) toast.error(e.serverError);
},
onExecute: () => {
resetAppDisclosure.open();

View file

@ -34,13 +34,12 @@ export const ChangePasswordForm = () => {
const router = useRouter();
const changePasswordMutation = useAction(changePasswordAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
} else {
toast.success(t('password-change-success'));
router.push('/');
}
onError: (e) => {
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
toast.success(t('password-change-success'));
router.push('/');
},
});

View file

@ -27,13 +27,12 @@ export const ChangeUsernameForm = ({ username }: Props) => {
type FormValues = z.infer<typeof schema>;
const changeUsernameMutation = useAction(changeUsernameAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
} else {
toast.success(t('change-username.success'));
router.push('/');
}
onError: (e) => {
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
toast.success(t('change-username.success'));
router.push('/');
},
});

View file

@ -29,28 +29,26 @@ export const OtpForm = (props: { totpEnabled: boolean }) => {
onExecute: () => {
setupOtpDisclosure.close();
},
onError: (e) => {
setPassword('');
if (e.serverError) toast.error(e.serverError);
},
onSuccess: (data) => {
if (!data.success) {
setPassword('');
toast.error(data.failure.reason);
} else {
setKey(data.key);
setUri(data.uri);
}
setKey(data.key);
setUri(data.uri);
},
});
const setupTotpMutation = useAction(setupTotpAction, {
onSuccess: (data) => {
if (!data.success) {
setTotpCode('');
toast.error(data.failure.reason);
} else {
setTotpCode('');
setKey('');
setUri('');
toast.success(t('2fa-enable-success'));
}
onError: (e) => {
setTotpCode('');
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
setTotpCode('');
setKey('');
setUri('');
toast.success(t('2fa-enable-success'));
},
});
@ -58,13 +56,12 @@ export const OtpForm = (props: { totpEnabled: boolean }) => {
onExecute: () => {
disableOtpDisclosure.close();
},
onSuccess: (data) => {
if (!data.success) {
setPassword('');
toast.error(data.failure.reason);
} else {
toast.success(t('2fa-disable-success'));
}
onError: (e) => {
setPassword('');
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
toast.success(t('2fa-disable-success'));
},
});

View file

@ -20,13 +20,12 @@ export const SettingsContainer = ({ initialValues, currentLocale }: Props) => {
const router = useRouter();
const updateSettingsMutation = useAction(updateSettingsAction, {
onSuccess: (data) => {
if (!data.success) {
toast.error(data.failure.reason);
} else {
toast.success(t('settings.settings.settings-updated'));
router.refresh();
}
onError: (e) => {
if (e.serverError) toast.error(e.serverError);
},
onSuccess: () => {
toast.success(t('settings.settings.settings-updated'));
router.refresh();
},
});
@ -36,7 +35,12 @@ export const SettingsContainer = ({ initialValues, currentLocale }: Props) => {
return (
<div className="card-body">
<SettingsForm initalValues={initialValues} currentLocale={currentLocale} loading={updateSettingsMutation.status === 'executing'} onSubmit={onSubmit} />
<SettingsForm
initalValues={initialValues}
currentLocale={currentLocale}
loading={updateSettingsMutation.status === 'executing'}
onSubmit={onSubmit}
/>
</div>
);
};

View file

@ -6,7 +6,7 @@ export const action = createSafeActionClient({
console.error('Error from server', e);
return {
serverError: e.message,
serverError: e.message || 'An unexpected error occurred',
};
},
});