refactor(dashboard): use onError on server actions
This commit is contained in:
parent
25c39b92e5
commit
76f9637d77
12 changed files with 106 additions and 83 deletions
|
@ -1,4 +1,4 @@
|
||||||
import { SocketEvent } from '@runtipi/shared';
|
import { SocketEvent } from '@runtipi/shared/src/schemas/socket';
|
||||||
import { Socket } from 'socket.io';
|
import { Socket } from 'socket.io';
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import pg from 'pg';
|
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 { copyDataDir, generateEnvFile } from './app.helpers';
|
||||||
import { logger } from '@/lib/logger';
|
import { logger } from '@/lib/logger';
|
||||||
import { compose } from '@/lib/docker';
|
import { compose } from '@/lib/docker';
|
||||||
|
@ -34,7 +35,7 @@ export class AppExecutors {
|
||||||
this.logger = logger;
|
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) {
|
if (err instanceof Error) {
|
||||||
SocketManager.emit({ type: 'app', event, data: { appId, error: err.message } });
|
SocketManager.emit({ type: 'app', event, data: { appId, error: err.message } });
|
||||||
this.logger.error(`An error occurred: ${err.message}`);
|
this.logger.error(`An error occurred: ${err.message}`);
|
||||||
|
|
|
@ -4209,6 +4209,11 @@ packages:
|
||||||
/base64-js@1.5.1:
|
/base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
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:
|
/binary-extensions@2.2.0:
|
||||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -4673,6 +4678,14 @@ packages:
|
||||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||||
dev: true
|
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:
|
/cosmiconfig@7.1.0:
|
||||||
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
|
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
|
@ -14,10 +14,11 @@ export function LoginContainer() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const loginMutation = useAction(loginAction, {
|
const loginMutation = useAction(loginAction, {
|
||||||
|
onError: (e) => {
|
||||||
|
if (e.serverError) toast.error(e.serverError);
|
||||||
|
},
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (!data.success) {
|
if (data.success && data.totpSessionId) {
|
||||||
toast.error(data.failure.reason);
|
|
||||||
} else if (data.success && data.totpSessionId) {
|
|
||||||
setTotpSessionId(data.totpSessionId);
|
setTotpSessionId(data.totpSessionId);
|
||||||
} else {
|
} else {
|
||||||
router.push('/dashboard');
|
router.push('/dashboard');
|
||||||
|
@ -26,18 +27,27 @@ export function LoginContainer() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const verifyTotpMutation = useAction(verifyTotpAction, {
|
const verifyTotpMutation = useAction(verifyTotpAction, {
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
router.push('/dashboard');
|
router.push('/dashboard');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (totpSessionId) {
|
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 })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,18 @@ export const RegisterContainer: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const registerMutation = useAction(registerAction, {
|
const registerMutation = useAction(registerAction, {
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
router.push('/dashboard');
|
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'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,18 +15,14 @@ export const ResetPasswordContainer: React.FC = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const resetPasswordMutation = useAction(resetPasswordAction, {
|
const resetPasswordMutation = useAction(resetPasswordAction, {
|
||||||
onSuccess: (data) => {
|
onError: (error) => {
|
||||||
if (!data.success) {
|
if (error.serverError) toast.error(error.serverError);
|
||||||
toast.error(data.failure.reason);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const cancelRequestMutation = useAction(cancelResetPasswordAction, {
|
const cancelRequestMutation = useAction(cancelResetPasswordAction, {
|
||||||
onSuccess: (data) => {
|
onError: (error) => {
|
||||||
if (!data.success) {
|
if (error.serverError) toast.error(error.serverError);
|
||||||
toast.error(data.failure.reason);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const installMutation = useAction(installAppAction, {
|
const installMutation = useAction(installAppAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
setOptimisticStatus('installing');
|
setOptimisticStatus('installing');
|
||||||
|
@ -55,7 +55,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const uninstallMutation = useAction(uninstallAppAction, {
|
const uninstallMutation = useAction(uninstallAppAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
uninstallDisclosure.close();
|
uninstallDisclosure.close();
|
||||||
|
@ -65,7 +65,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const stopMutation = useAction(stopAppAction, {
|
const stopMutation = useAction(stopAppAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
stopDisclosure.close();
|
stopDisclosure.close();
|
||||||
|
@ -75,7 +75,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const startMutation = useAction(startAppAction, {
|
const startMutation = useAction(startAppAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
setOptimisticStatus('starting');
|
setOptimisticStatus('starting');
|
||||||
|
@ -84,7 +84,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const updateMutation = useAction(updateAppAction, {
|
const updateMutation = useAction(updateAppAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
updateDisclosure.close();
|
updateDisclosure.close();
|
||||||
|
@ -94,7 +94,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const updateConfigMutation = useAction(updateAppConfigAction, {
|
const updateConfigMutation = useAction(updateAppConfigAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
updateSettingsDisclosure.close();
|
updateSettingsDisclosure.close();
|
||||||
|
@ -106,7 +106,7 @@ export const AppDetailsContainer: React.FC<AppDetailsContainerProps> = ({ app, l
|
||||||
|
|
||||||
const resetMutation = useAction(resetAppAction, {
|
const resetMutation = useAction(resetAppAction, {
|
||||||
onError: (e) => {
|
onError: (e) => {
|
||||||
toast.error(e.serverError!);
|
if (e.serverError) toast.error(e.serverError);
|
||||||
},
|
},
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
resetAppDisclosure.open();
|
resetAppDisclosure.open();
|
||||||
|
|
|
@ -34,13 +34,12 @@ export const ChangePasswordForm = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const changePasswordMutation = useAction(changePasswordAction, {
|
const changePasswordMutation = useAction(changePasswordAction, {
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
toast.success(t('password-change-success'));
|
toast.success(t('password-change-success'));
|
||||||
router.push('/');
|
router.push('/');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,12 @@ export const ChangeUsernameForm = ({ username }: Props) => {
|
||||||
type FormValues = z.infer<typeof schema>;
|
type FormValues = z.infer<typeof schema>;
|
||||||
|
|
||||||
const changeUsernameMutation = useAction(changeUsernameAction, {
|
const changeUsernameMutation = useAction(changeUsernameAction, {
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
toast.success(t('change-username.success'));
|
toast.success(t('change-username.success'));
|
||||||
router.push('/');
|
router.push('/');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,28 +29,26 @@ export const OtpForm = (props: { totpEnabled: boolean }) => {
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
setupOtpDisclosure.close();
|
setupOtpDisclosure.close();
|
||||||
},
|
},
|
||||||
|
onError: (e) => {
|
||||||
|
setPassword('');
|
||||||
|
if (e.serverError) toast.error(e.serverError);
|
||||||
|
},
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (!data.success) {
|
setKey(data.key);
|
||||||
setPassword('');
|
setUri(data.uri);
|
||||||
toast.error(data.failure.reason);
|
|
||||||
} else {
|
|
||||||
setKey(data.key);
|
|
||||||
setUri(data.uri);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const setupTotpMutation = useAction(setupTotpAction, {
|
const setupTotpMutation = useAction(setupTotpAction, {
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
setTotpCode('');
|
||||||
setTotpCode('');
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
setTotpCode('');
|
setTotpCode('');
|
||||||
setKey('');
|
setKey('');
|
||||||
setUri('');
|
setUri('');
|
||||||
toast.success(t('2fa-enable-success'));
|
toast.success(t('2fa-enable-success'));
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -58,13 +56,12 @@ export const OtpForm = (props: { totpEnabled: boolean }) => {
|
||||||
onExecute: () => {
|
onExecute: () => {
|
||||||
disableOtpDisclosure.close();
|
disableOtpDisclosure.close();
|
||||||
},
|
},
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
setPassword('');
|
||||||
setPassword('');
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
toast.success(t('2fa-disable-success'));
|
toast.success(t('2fa-disable-success'));
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,12 @@ export const SettingsContainer = ({ initialValues, currentLocale }: Props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const updateSettingsMutation = useAction(updateSettingsAction, {
|
const updateSettingsMutation = useAction(updateSettingsAction, {
|
||||||
onSuccess: (data) => {
|
onError: (e) => {
|
||||||
if (!data.success) {
|
if (e.serverError) toast.error(e.serverError);
|
||||||
toast.error(data.failure.reason);
|
},
|
||||||
} else {
|
onSuccess: () => {
|
||||||
toast.success(t('settings.settings.settings-updated'));
|
toast.success(t('settings.settings.settings-updated'));
|
||||||
router.refresh();
|
router.refresh();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,7 +35,12 @@ export const SettingsContainer = ({ initialValues, currentLocale }: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card-body">
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const action = createSafeActionClient({
|
||||||
console.error('Error from server', e);
|
console.error('Error from server', e);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
serverError: e.message,
|
serverError: e.message || 'An unexpected error occurred',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue