refactor: replace usages of custom toaster with react-hot-toast
This commit is contained in:
parent
d2fda696d7
commit
9fa8452e24
16 changed files with 70 additions and 179 deletions
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import { fireEvent, render, renderHook, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { createAppEntity } from '../../../../mocks/fixtures/app.fixtures';
|
||||
import { getTRPCMock, getTRPCMockError } from '../../../../mocks/getTrpcMock';
|
||||
import { server } from '../../../../mocks/server';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { AppDetailsContainer } from './AppDetailsContainer';
|
||||
|
||||
describe('Test: AppDetailsContainer', () => {
|
||||
|
@ -112,7 +111,6 @@ describe('Test: AppDetailsContainer', () => {
|
|||
// Arrange
|
||||
const app = createAppEntity({ overrides: { status: 'missing' } });
|
||||
server.use(getTRPCMock({ path: ['app', 'installApp'], type: 'mutation', response: app }));
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
const openModalButton = screen.getByRole('button', { name: 'Install' });
|
||||
fireEvent.click(openModalButton);
|
||||
|
@ -122,15 +120,12 @@ describe('Test: AppDetailsContainer', () => {
|
|||
fireEvent.click(installButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(result.current.toasts[0].title).toEqual('App installed successfully');
|
||||
expect(screen.getByText('App installed successfully')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a toast error when install mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(
|
||||
getTRPCMockError({
|
||||
path: ['app', 'installApp'],
|
||||
|
@ -149,9 +144,7 @@ describe('Test: AppDetailsContainer', () => {
|
|||
fireEvent.click(installButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Failed to install app: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -161,7 +154,6 @@ describe('Test: AppDetailsContainer', () => {
|
|||
// Arrange
|
||||
const app = createAppEntity({ overrides: { version: 2, latestVersion: 3 } });
|
||||
server.use(getTRPCMock({ path: ['app', 'updateApp'], type: 'mutation', response: app }));
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
const openModalButton = screen.getByRole('button', { name: 'Update' });
|
||||
fireEvent.click(openModalButton);
|
||||
|
@ -171,15 +163,12 @@ describe('Test: AppDetailsContainer', () => {
|
|||
modalUpdateButton.click();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(result.current.toasts[0].title).toEqual('App updated successfully');
|
||||
expect(screen.getByText('App updated successfully')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a toast error when update mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['app', 'updateApp'], type: 'mutation', message: 'my big error' }));
|
||||
const app = createAppEntity({ overrides: { version: 2, latestVersion: 3 }, overridesInfo: { tipi_version: 3 } });
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
|
@ -192,9 +181,7 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Failed to update app: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -204,7 +191,6 @@ describe('Test: AppDetailsContainer', () => {
|
|||
// Arrange
|
||||
const app = createAppEntity({ status: 'stopped' });
|
||||
server.use(getTRPCMock({ path: ['app', 'uninstallApp'], type: 'mutation', response: { id: app.id, config: {}, status: 'missing' } }));
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
const openModalButton = screen.getByRole('button', { name: 'Remove' });
|
||||
fireEvent.click(openModalButton);
|
||||
|
@ -215,15 +201,12 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(result.current.toasts[0].title).toEqual('App uninstalled successfully');
|
||||
expect(screen.getByText('App uninstalled successfully')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a toast error when uninstall mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['app', 'uninstallApp'], type: 'mutation', message: 'my big error' }));
|
||||
const app = createAppEntity({ status: 'stopped' });
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
|
@ -236,9 +219,7 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Failed to uninstall app: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -248,7 +229,6 @@ describe('Test: AppDetailsContainer', () => {
|
|||
// Arrange
|
||||
const app = createAppEntity({ status: 'stopped' });
|
||||
server.use(getTRPCMock({ path: ['app', 'startApp'], type: 'mutation', response: app }));
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
|
||||
// Act
|
||||
|
@ -257,15 +237,12 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(result.current.toasts[0].title).toEqual('App started successfully');
|
||||
expect(screen.getByText('App started successfully')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a toast error when start mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['app', 'startApp'], type: 'mutation', message: 'my big error' }));
|
||||
const app = createAppEntity({ status: 'stopped' });
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
|
@ -276,9 +253,7 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Failed to start app: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -288,7 +263,6 @@ describe('Test: AppDetailsContainer', () => {
|
|||
// Arrange
|
||||
const app = createAppEntity({ status: 'running' });
|
||||
server.use(getTRPCMock({ path: ['app', 'stopApp'], type: 'mutation', response: app }));
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
const openModalButton = screen.getByRole('button', { name: 'Stop' });
|
||||
fireEvent.click(openModalButton);
|
||||
|
@ -299,15 +273,12 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(result.current.toasts[0].title).toEqual('App stopped successfully');
|
||||
expect(screen.getByText('App stopped successfully')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a toast error when stop mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['app', 'stopApp'], type: 'mutation', message: 'my big error' }));
|
||||
const app = createAppEntity({ status: 'running' });
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
|
@ -320,9 +291,7 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Failed to stop app: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -332,7 +301,6 @@ describe('Test: AppDetailsContainer', () => {
|
|||
// Arrange
|
||||
const app = createAppEntity({ status: 'running', overridesInfo: { exposable: true } });
|
||||
server.use(getTRPCMock({ path: ['app', 'updateAppConfig'], type: 'mutation', response: app }));
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
const openModalButton = screen.getByRole('button', { name: 'Settings' });
|
||||
fireEvent.click(openModalButton);
|
||||
|
@ -343,15 +311,12 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(result.current.toasts[0].title).toEqual('App config updated successfully. Restart the app to apply the changes');
|
||||
expect(screen.getByText('App config updated successfully. Restart the app to apply the changes')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should display a toast error when update config mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['app', 'updateAppConfig'], type: 'mutation', message: 'my big error' }));
|
||||
const app = createAppEntity({ status: 'running', overridesInfo: { exposable: true } });
|
||||
render(<AppDetailsContainer app={app} />);
|
||||
|
@ -364,9 +329,7 @@ describe('Test: AppDetailsContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Failed to update app config: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useDisclosure } from '../../../../hooks/useDisclosure';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { AppLogo } from '../../../../components/AppLogo/AppLogo';
|
||||
import { AppStatus } from '../../../../components/AppStatus';
|
||||
import { AppActions } from '../../components/AppActions';
|
||||
|
@ -20,7 +20,6 @@ interface IProps {
|
|||
}
|
||||
|
||||
export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
||||
const { addToast } = useToastStore();
|
||||
const installDisclosure = useDisclosure();
|
||||
const uninstallDisclosure = useDisclosure();
|
||||
const stopDisclosure = useDisclosure();
|
||||
|
@ -41,11 +40,11 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
},
|
||||
onSuccess: () => {
|
||||
invalidate();
|
||||
addToast({ title: 'App installed successfully', status: 'success' });
|
||||
toast.success('App installed successfully');
|
||||
},
|
||||
onError: (e) => {
|
||||
invalidate();
|
||||
addToast({ title: 'Install error', description: e.message, status: 'error' });
|
||||
toast.error(`Failed to install app: ${e.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -56,9 +55,9 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
},
|
||||
onSuccess: () => {
|
||||
invalidate();
|
||||
addToast({ title: 'App uninstalled successfully', status: 'success' });
|
||||
toast.success('App uninstalled successfully');
|
||||
},
|
||||
onError: (e) => addToast({ title: 'Uninstall error', description: e.message, status: 'error' }),
|
||||
onError: (e) => toast.error(`Failed to uninstall app: ${e.message}`),
|
||||
});
|
||||
|
||||
const stop = trpc.app.stopApp.useMutation({
|
||||
|
@ -68,9 +67,9 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
},
|
||||
onSuccess: () => {
|
||||
invalidate();
|
||||
addToast({ title: 'App stopped successfully', status: 'success' });
|
||||
toast.success('App stopped successfully');
|
||||
},
|
||||
onError: (e) => addToast({ title: 'Stop error', description: e.message, status: 'error' }),
|
||||
onError: (e) => toast.error(`Failed to stop app: ${e.message}`),
|
||||
});
|
||||
|
||||
const update = trpc.app.updateApp.useMutation({
|
||||
|
@ -80,9 +79,9 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
},
|
||||
onSuccess: () => {
|
||||
invalidate();
|
||||
addToast({ title: 'App updated successfully', status: 'success' });
|
||||
toast.success('App updated successfully');
|
||||
},
|
||||
onError: (e) => addToast({ title: 'Update error', description: e.message, status: 'error' }),
|
||||
onError: (e) => toast.error(`Failed to update app: ${e.message}`),
|
||||
});
|
||||
|
||||
const start = trpc.app.startApp.useMutation({
|
||||
|
@ -91,18 +90,18 @@ export const AppDetailsContainer: React.FC<IProps> = ({ app }) => {
|
|||
},
|
||||
onSuccess: () => {
|
||||
invalidate();
|
||||
addToast({ title: 'App started successfully', status: 'success' });
|
||||
toast.success('App started successfully');
|
||||
},
|
||||
onError: (e) => addToast({ title: 'Start error', description: e.message, status: 'error' }),
|
||||
onError: (e) => toast.error(`Failed to start app: ${e.message}`),
|
||||
});
|
||||
|
||||
const updateConfig = trpc.app.updateAppConfig.useMutation({
|
||||
onMutate: () => updateSettingsDisclosure.close(),
|
||||
onSuccess: () => {
|
||||
invalidate();
|
||||
addToast({ title: 'App config updated successfully. Restart the app to apply the changes', status: 'success' });
|
||||
toast.success('App config updated successfully. Restart the app to apply the changes');
|
||||
},
|
||||
onError: (e) => addToast({ title: 'Update error', description: e.message, status: 'error' }),
|
||||
onError: (e) => toast.error(`Failed to update app config: ${e.message}`),
|
||||
});
|
||||
|
||||
const updateAvailable = Number(app.version || 0) < Number(app?.latestVersion || 0);
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { faker } from '@faker-js/faker';
|
||||
import React from 'react';
|
||||
import { fireEvent, render, renderHook, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { getTRPCMock, getTRPCMockError } from '../../../../mocks/getTrpcMock';
|
||||
import { server } from '../../../../mocks/server';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { LoginContainer } from './LoginContainer';
|
||||
|
||||
describe('Test: LoginContainer', () => {
|
||||
|
@ -64,7 +63,6 @@ describe('Test: LoginContainer', () => {
|
|||
|
||||
it('should show error message if login fails', async () => {
|
||||
// Arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['auth', 'login'], type: 'mutation', status: 500, message: 'my big error' }));
|
||||
render(<LoginContainer />);
|
||||
|
||||
|
@ -79,9 +77,7 @@ describe('Test: LoginContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText(/my big error/)).toBeInTheDocument();
|
||||
});
|
||||
const token = localStorage.getItem('token');
|
||||
expect(token).toBeNull();
|
||||
|
@ -118,7 +114,6 @@ describe('Test: LoginContainer', () => {
|
|||
|
||||
it('should show error message if totp code is invalid', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
const email = faker.internet.email();
|
||||
const password = faker.internet.password();
|
||||
const totpSessionId = faker.datatype.uuid();
|
||||
|
@ -150,9 +145,7 @@ describe('Test: LoginContainer', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('Invalid totp code');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText(/Invalid totp code/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useRouter } from 'next/router';
|
||||
import React, { useState } from 'react';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
import { AuthFormLayout } from '../../components/AuthFormLayout';
|
||||
import { LoginForm } from '../../components/LoginForm';
|
||||
|
@ -11,12 +11,11 @@ type FormValues = { email: string; password: string };
|
|||
export const LoginContainer: React.FC = () => {
|
||||
const [totpSessionId, setTotpSessionId] = useState<string | null>(null);
|
||||
const router = useRouter();
|
||||
const { addToast } = useToastStore();
|
||||
const utils = trpc.useContext();
|
||||
const login = trpc.auth.login.useMutation({
|
||||
onError: (e) => {
|
||||
localStorage.removeItem('token');
|
||||
addToast({ title: 'Login error', description: e.message, status: 'error' });
|
||||
toast.error(`Login failed: ${e.message}`);
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
if (data.totpSessionId) {
|
||||
|
@ -31,7 +30,7 @@ export const LoginContainer: React.FC = () => {
|
|||
|
||||
const verifyTotp = trpc.auth.verifyTotp.useMutation({
|
||||
onError: (e) => {
|
||||
addToast({ title: 'Error', description: e.message, status: 'error' });
|
||||
toast.error(`Verification failed: ${e.message}`);
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
localStorage.setItem('token', data.token);
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { faker } from '@faker-js/faker';
|
||||
import React from 'react';
|
||||
import { fireEvent, render, renderHook, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { getTRPCMock, getTRPCMockError } from '../../../../mocks/getTrpcMock';
|
||||
import { server } from '../../../../mocks/server';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { RegisterContainer } from './RegisterContainer';
|
||||
|
||||
describe('Test: RegisterContainer', () => {
|
||||
|
@ -42,7 +41,6 @@ describe('Test: RegisterContainer', () => {
|
|||
const email = faker.internet.email();
|
||||
const password = faker.internet.password();
|
||||
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['auth', 'register'], type: 'mutation', status: 500, message: 'my big error' }));
|
||||
render(<RegisterContainer />);
|
||||
|
||||
|
@ -59,9 +57,7 @@ describe('Test: RegisterContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].description).toEqual('my big error');
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(screen.getByText('Registration failed: my big error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
import { AuthFormLayout } from '../../components/AuthFormLayout';
|
||||
import { RegisterForm } from '../../components/RegisterForm';
|
||||
|
@ -8,13 +8,12 @@ import { RegisterForm } from '../../components/RegisterForm';
|
|||
type FormValues = { email: string; password: string };
|
||||
|
||||
export const RegisterContainer: React.FC = () => {
|
||||
const { addToast } = useToastStore();
|
||||
const router = useRouter();
|
||||
const utils = trpc.useContext();
|
||||
const register = trpc.auth.register.useMutation({
|
||||
onError: (e) => {
|
||||
localStorage.removeItem('token');
|
||||
addToast({ title: 'Register error', description: e.message, status: 'error' });
|
||||
toast.error(`Registration failed: ${e.message}`);
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
localStorage.setItem('token', data.token);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react';
|
||||
import { fireEvent, render, screen, waitFor, renderHook } from '../../../../../../tests/test-utils';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { getTRPCMock, getTRPCMockError } from '../../../../mocks/getTrpcMock';
|
||||
import { server } from '../../../../mocks/server';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { ResetPasswordContainer } from './ResetPasswordContainer';
|
||||
|
||||
const pushFn = jest.fn();
|
||||
|
@ -55,7 +54,6 @@ describe('ResetPasswordContainer', () => {
|
|||
|
||||
it('should show error toast if reset password mutation fails', async () => {
|
||||
// Arrange
|
||||
const { result, unmount } = renderHook(() => useToastStore());
|
||||
render(<ResetPasswordContainer isRequested />);
|
||||
const resetPasswordForm = screen.getByRole('button', { name: 'Reset password' });
|
||||
fireEvent.click(resetPasswordForm);
|
||||
|
@ -74,15 +72,12 @@ describe('ResetPasswordContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts[0].description).toBe(error.message);
|
||||
expect(screen.getByText(/Something went wrong/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should call the cancel request mutation when cancel button is clicked', async () => {
|
||||
// Arrange
|
||||
const { result, unmount } = renderHook(() => useToastStore());
|
||||
render(<ResetPasswordContainer isRequested />);
|
||||
server.use(getTRPCMock({ path: ['auth', 'cancelPasswordChangeRequest'], type: 'mutation', response: true }));
|
||||
|
||||
|
@ -93,10 +88,8 @@ describe('ResetPasswordContainer', () => {
|
|||
|
||||
// Assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts[0].title).toBe('Password change request cancelled');
|
||||
expect(screen.getByText('Password change request cancelled')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
unmount();
|
||||
});
|
||||
|
||||
it('should redirect to login page when Back to login button is clicked', async () => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Button } from '../../../../components/ui/Button';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
import { AuthFormLayout } from '../../components/AuthFormLayout';
|
||||
import { ResetPasswordForm } from '../../components/ResetPasswordForm';
|
||||
|
@ -13,7 +13,6 @@ type Props = {
|
|||
type FormValues = { password: string };
|
||||
|
||||
export const ResetPasswordContainer: React.FC<Props> = ({ isRequested }) => {
|
||||
const { addToast } = useToastStore();
|
||||
const router = useRouter();
|
||||
const utils = trpc.useContext();
|
||||
const resetPassword = trpc.auth.changeOperatorPassword.useMutation({
|
||||
|
@ -21,13 +20,13 @@ export const ResetPasswordContainer: React.FC<Props> = ({ isRequested }) => {
|
|||
utils.auth.checkPasswordChangeRequest.invalidate();
|
||||
},
|
||||
onError: (error) => {
|
||||
addToast({ title: 'Reset password error', description: error.message, status: 'error' });
|
||||
toast.error(`Failed to reset password ${error.message}`);
|
||||
},
|
||||
});
|
||||
const cancelRequest = trpc.auth.cancelPasswordChangeRequest.useMutation({
|
||||
onSuccess: () => {
|
||||
utils.auth.checkPasswordChangeRequest.invalidate();
|
||||
addToast({ title: 'Password change request cancelled', status: 'success' });
|
||||
toast.success('Password change request cancelled');
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import { server } from '@/client/mocks/server';
|
||||
import { getTRPCMock, getTRPCMockError } from '@/client/mocks/getTrpcMock';
|
||||
import { useToastStore } from '@/client/state/toastStore';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { render, screen, waitFor, fireEvent } from '../../../../../../tests/test-utils';
|
||||
import { ChangePasswordForm } from './ChangePasswordForm';
|
||||
|
@ -10,7 +8,6 @@ import { ChangePasswordForm } from './ChangePasswordForm';
|
|||
describe('<ChangePasswordForm />', () => {
|
||||
it('should show success toast upon password change', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['auth', 'changePassword'], type: 'mutation', response: true }));
|
||||
render(<ChangePasswordForm />);
|
||||
const currentPasswordInput = screen.getByRole('textbox', { name: 'currentPassword' });
|
||||
|
@ -27,15 +24,12 @@ describe('<ChangePasswordForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('success');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Password successfully changed');
|
||||
expect(screen.getByText('Password successfully changed')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error toast if change password failed', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['auth', 'changePassword'], type: 'mutation', message: 'Invalid password' }));
|
||||
render(<ChangePasswordForm />);
|
||||
const currentPasswordInput = screen.getByRole('textbox', { name: 'currentPassword' });
|
||||
|
@ -52,10 +46,7 @@ describe('<ChangePasswordForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('error');
|
||||
expect(result.current.toasts[0]?.title).toEqual('Error');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Invalid password');
|
||||
expect(screen.getByText(/Invalid password/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ import React from 'react';
|
|||
import { Input } from '@/components/ui/Input';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { trpc } from '@/utils/trpc';
|
||||
import { useToastStore } from '@/client/state/toastStore';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/router';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
const schema = z
|
||||
.object({
|
||||
|
@ -28,13 +28,12 @@ type FormValues = z.infer<typeof schema>;
|
|||
|
||||
export const ChangePasswordForm = () => {
|
||||
const router = useRouter();
|
||||
const { addToast } = useToastStore();
|
||||
const changePassword = trpc.auth.changePassword.useMutation({
|
||||
onError: (e) => {
|
||||
addToast({ title: 'Error', description: e.message, status: 'error' });
|
||||
toast.error(`Error changing password: ${e.message}`);
|
||||
},
|
||||
onSuccess: () => {
|
||||
addToast({ title: 'Success', description: 'Password successfully changed', status: 'success' });
|
||||
toast.success('Password successfully changed');
|
||||
router.push('/');
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React from 'react';
|
||||
import { server } from '@/client/mocks/server';
|
||||
import { getTRPCMock, getTRPCMockError } from '@/client/mocks/getTrpcMock';
|
||||
import { useToastStore } from '@/client/state/toastStore';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { render, screen, waitFor, fireEvent } from '../../../../../../tests/test-utils';
|
||||
import { OtpForm } from './OtpForm';
|
||||
|
||||
|
@ -48,7 +46,6 @@ describe('<OtpForm />', () => {
|
|||
|
||||
it('should show show error toast if password is incorrect while enabling 2FA', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: { totp_enabled: false, id: 12, username: 'test' } }));
|
||||
server.use(getTRPCMockError({ path: ['auth', 'getTotpUri'], type: 'mutation', message: 'Invalid password' }));
|
||||
render(<OtpForm />);
|
||||
|
@ -71,16 +68,12 @@ describe('<OtpForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('error');
|
||||
expect(result.current.toasts[0]?.title).toEqual('Error');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Invalid password');
|
||||
expect(screen.getByText(/Invalid password/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show show error toast if password is incorrect while disabling 2FA', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: { totp_enabled: true, id: 12, username: 'test' } }));
|
||||
server.use(getTRPCMockError({ path: ['auth', 'disableTotp'], type: 'mutation', message: 'Invalid password' }));
|
||||
render(<OtpForm />);
|
||||
|
@ -104,16 +97,12 @@ describe('<OtpForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('error');
|
||||
expect(result.current.toasts[0]?.title).toEqual('Error');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Invalid password');
|
||||
expect(screen.getByText(/Invalid password/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show success toast if password is correct while disabling 2FA', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: { totp_enabled: true, id: 12, username: 'test' } }));
|
||||
server.use(getTRPCMock({ path: ['auth', 'disableTotp'], type: 'mutation', response: true }));
|
||||
|
||||
|
@ -138,10 +127,7 @@ describe('<OtpForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('success');
|
||||
expect(result.current.toasts[0]?.title).toEqual('Success');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Two-factor authentication disabled');
|
||||
expect(screen.getByText('Two-factor authentication disabled')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -174,7 +160,6 @@ describe('<OtpForm />', () => {
|
|||
|
||||
it('should show error toast if submitted totp code is invalid', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['auth', 'getTotpUri'], type: 'mutation', response: { key: 'test', uri: 'test' } }));
|
||||
server.use(getTRPCMockError({ path: ['auth', 'setupTotp'], type: 'mutation', message: 'Invalid code' }));
|
||||
|
||||
|
@ -210,16 +195,12 @@ describe('<OtpForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('error');
|
||||
expect(result.current.toasts[0]?.title).toEqual('Error');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Invalid code');
|
||||
expect(screen.getByText(/Invalid code/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show success toast if submitted totp code is valid', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['auth', 'getTotpUri'], type: 'mutation', response: { key: 'test', uri: 'test' } }));
|
||||
server.use(getTRPCMock({ path: ['auth', 'setupTotp'], type: 'mutation', response: true }));
|
||||
render(<OtpForm />);
|
||||
|
@ -253,10 +234,7 @@ describe('<OtpForm />', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0]?.status).toEqual('success');
|
||||
expect(result.current.toasts[0]?.title).toEqual('Success');
|
||||
expect(result.current.toasts[0]?.description).toEqual('Two-factor authentication enabled');
|
||||
expect(screen.getByText('Two-factor authentication enabled')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import React from 'react';
|
||||
import { trpc } from '@/utils/trpc';
|
||||
import { Switch } from '@/components/ui/Switch';
|
||||
import { useToastStore } from '@/client/state/toastStore';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/Dialog';
|
||||
import { Input } from '@/components/ui/Input';
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import { OtpInput } from '@/components/ui/OtpInput';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
export const OtpForm = () => {
|
||||
const { addToast } = useToastStore();
|
||||
const [password, setPassword] = React.useState('');
|
||||
const [key, setKey] = React.useState('');
|
||||
const [uri, setUri] = React.useState('');
|
||||
|
@ -28,7 +27,7 @@ export const OtpForm = () => {
|
|||
},
|
||||
onError: (e) => {
|
||||
setPassword('');
|
||||
addToast({ title: 'Error', description: e.message, status: 'error' });
|
||||
toast.error(`Error getting TOTP URI: ${e.message}`);
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setKey(data.key);
|
||||
|
@ -40,13 +39,13 @@ export const OtpForm = () => {
|
|||
onMutate: () => {},
|
||||
onError: (e) => {
|
||||
setTotpCode('');
|
||||
addToast({ title: 'Error', description: e.message, status: 'error' });
|
||||
toast.error(`Error setting up TOTP: ${e.message}`);
|
||||
},
|
||||
onSuccess: () => {
|
||||
setTotpCode('');
|
||||
setKey('');
|
||||
setUri('');
|
||||
addToast({ title: 'Success', description: 'Two-factor authentication enabled', status: 'success' });
|
||||
toast.success('Two-factor authentication enabled');
|
||||
ctx.auth.me.invalidate();
|
||||
},
|
||||
});
|
||||
|
@ -57,10 +56,10 @@ export const OtpForm = () => {
|
|||
},
|
||||
onError: (e) => {
|
||||
setPassword('');
|
||||
addToast({ title: 'Error', description: e.message, status: 'error' });
|
||||
toast.error(`Error disabling TOTP: ${e.message}`);
|
||||
},
|
||||
onSuccess: () => {
|
||||
addToast({ title: 'Success', description: 'Two-factor authentication disabled', status: 'success' });
|
||||
toast.success('Two-factor authentication disabled');
|
||||
ctx.auth.me.invalidate();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import { useToastStore } from '@/client/state/toastStore';
|
||||
import { getTRPCMock, getTRPCMockError } from '@/client/mocks/getTrpcMock';
|
||||
import { server } from '@/client/mocks/server';
|
||||
import { GeneralActions } from './GeneralActions';
|
||||
import { fireEvent, render, renderHook, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
|
||||
describe('Test: GeneralActions', () => {
|
||||
it('should render without error', () => {
|
||||
|
@ -14,7 +13,6 @@ describe('Test: GeneralActions', () => {
|
|||
|
||||
it('should show toast if update mutation fails', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMock({ path: ['system', 'getVersion'], response: { current: '1.0.0', latest: '2.0.0' } }));
|
||||
server.use(getTRPCMockError({ path: ['system', 'update'], type: 'mutation', status: 500, message: 'Something went wrong' }));
|
||||
render(<GeneralActions />);
|
||||
|
@ -30,10 +28,7 @@ describe('Test: GeneralActions', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(result.current.toasts[0].title).toEqual('Error');
|
||||
expect(result.current.toasts[0].description).toEqual('Something went wrong');
|
||||
expect(screen.getByText(/Something went wrong/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -61,7 +56,6 @@ describe('Test: GeneralActions', () => {
|
|||
|
||||
it('should show toast if restart mutation fails', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['system', 'restart'], type: 'mutation', status: 500, message: 'Something went wrong' }));
|
||||
render(<GeneralActions />);
|
||||
const restartButton = screen.getByRole('button', { name: /Restart/i });
|
||||
|
@ -73,10 +67,7 @@ describe('Test: GeneralActions', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(result.current.toasts[0].title).toEqual('Error');
|
||||
expect(result.current.toasts[0].description).toEqual('Something went wrong');
|
||||
expect(screen.getByText(/Something went wrong/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import semver from 'semver';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { Button } from '../../../../components/ui/Button';
|
||||
import { useDisclosure } from '../../../../hooks/useDisclosure';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { RestartModal } from '../../components/RestartModal';
|
||||
import { UpdateModal } from '../../components/UpdateModal/UpdateModal';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
|
@ -12,7 +12,6 @@ export const GeneralActions = () => {
|
|||
const versionQuery = trpc.system.getVersion.useQuery(undefined, { staleTime: 0 });
|
||||
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const { addToast } = useToastStore();
|
||||
const { setPollStatus } = useSystemStore();
|
||||
const restartDisclosure = useDisclosure();
|
||||
const updateDisclosure = useDisclosure();
|
||||
|
@ -30,7 +29,7 @@ export const GeneralActions = () => {
|
|||
},
|
||||
onError: (error) => {
|
||||
updateDisclosure.close();
|
||||
addToast({ title: 'Error', description: error.message, status: 'error' });
|
||||
toast.error(`Error updating instance: ${error.message}`);
|
||||
},
|
||||
onSettled: () => {
|
||||
setLoading(false);
|
||||
|
@ -47,7 +46,7 @@ export const GeneralActions = () => {
|
|||
},
|
||||
onError: (error) => {
|
||||
restartDisclosure.close();
|
||||
addToast({ title: 'Error', description: error.message, status: 'error' });
|
||||
toast.error(`Error restarting instance: ${error.message}`);
|
||||
},
|
||||
onSettled: () => {
|
||||
setLoading(false);
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import { server } from '@/client/mocks/server';
|
||||
import { getTRPCMockError } from '@/client/mocks/getTrpcMock';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { SettingsContainer } from './SettingsContainer';
|
||||
import { fireEvent, render, renderHook, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
import { fireEvent, render, screen, waitFor } from '../../../../../../tests/test-utils';
|
||||
|
||||
describe('Test: SettingsContainer', () => {
|
||||
it('should render without error', () => {
|
||||
|
@ -14,7 +13,6 @@ describe('Test: SettingsContainer', () => {
|
|||
|
||||
it('should show toast if updateSettings mutation fails', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
server.use(getTRPCMockError({ path: ['system', 'updateSettings'], type: 'mutation', status: 500, message: 'Something went wrong' }));
|
||||
render(<SettingsContainer />);
|
||||
const submitButton = screen.getByRole('button', { name: 'Save' });
|
||||
|
@ -28,9 +26,7 @@ describe('Test: SettingsContainer', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('error');
|
||||
expect(result.current.toasts[0].title).toEqual('Error saving settings');
|
||||
expect(screen.getByText(/Something went wrong/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -50,7 +46,6 @@ describe('Test: SettingsContainer', () => {
|
|||
|
||||
it('should show toast if updateSettings mutation succeeds', async () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useToastStore());
|
||||
render(<SettingsContainer />);
|
||||
const submitButton = screen.getByRole('button', { name: 'Save' });
|
||||
|
||||
|
@ -59,8 +54,7 @@ describe('Test: SettingsContainer', () => {
|
|||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.toasts).toHaveLength(1);
|
||||
expect(result.current.toasts[0].status).toEqual('success');
|
||||
expect(screen.getByText(/Settings updated. Restart your instance to apply new settings./)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
import React, { useState } from 'react';
|
||||
import { trpc } from '@/utils/trpc';
|
||||
import { useToastStore } from '../../../../state/toastStore';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { SettingsForm, SettingsFormValues } from '../../components/SettingsForm';
|
||||
|
||||
export const SettingsContainer = () => {
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
const { addToast } = useToastStore();
|
||||
const getSettings = trpc.system.getSettings.useQuery();
|
||||
const updateSettings = trpc.system.updateSettings.useMutation({
|
||||
onSuccess: () => {
|
||||
addToast({ title: 'Settings updated', description: 'Restart your instance for settings to take effect', status: 'success' });
|
||||
toast.success('Settings updated. Restart your instance to apply new settings.');
|
||||
},
|
||||
onError: (e) => {
|
||||
if (e.shape?.data.zodError) {
|
||||
setErrors(e.shape.data.zodError);
|
||||
}
|
||||
|
||||
addToast({ title: 'Error saving settings', description: e.message, status: 'error' });
|
||||
toast.error(`Error saving settings: ${e.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue