fix(web): avoid formatting a missing user deletion date
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { UserStatus, type UserAdminResponseDto } from '@immich/sdk';
|
||||
import type { MessageFormatter } from 'svelte-i18n';
|
||||
import { getUserAdminActions } from '$lib/services/user-admin.service';
|
||||
|
||||
vi.mock('$app/navigation', () => ({ goto: vi.fn() }));
|
||||
vi.mock('@immich/ui', () => ({ modalManager: { show: vi.fn(), showDialog: vi.fn() } }));
|
||||
vi.mock('$lib/managers/auth-manager.svelte', () => ({ authManager: { user: { id: 'self' } } }));
|
||||
vi.mock('$lib/managers/server-config-manager.svelte', () => ({
|
||||
serverConfigManager: { value: { userDeleteDelay: 7 } },
|
||||
}));
|
||||
vi.mock('$lib/modals/PasswordResetSuccessModal.svelte', () => ({ default: {} }));
|
||||
vi.mock('$lib/modals/UserDeleteConfirmModal.svelte', () => ({ default: {} }));
|
||||
vi.mock('$lib/modals/UserRestoreConfirmModal.svelte', () => ({ default: {} }));
|
||||
vi.mock('$lib/queries/client', () => ({ executeMutation: vi.fn() }));
|
||||
vi.mock('$lib/queries/user-admin.query', () => ({ updateUserAdminMutation: vi.fn() }));
|
||||
vi.mock('$lib/route', () => ({ Route: { newUser: vi.fn(), viewUser: vi.fn(), editUser: vi.fn() } }));
|
||||
vi.mock('$lib/utils/i18n', () => ({ getFormatter: vi.fn() }));
|
||||
|
||||
describe('admin actions for active and deleted accounts', () => {
|
||||
it('does not format a deletion date for an active account', () => {
|
||||
const format = vi.fn((key: string) => key);
|
||||
const user = { id: 'other', deletedAt: null } as UserAdminResponseDto;
|
||||
const actions = getUserAdminActions(format as MessageFormatter, user);
|
||||
expect(actions.Restore.data).toBeUndefined();
|
||||
expect((actions.Restore.$if as () => boolean)()).toBe(false);
|
||||
expect(format).not.toHaveBeenCalledWith('admin.user_restore_scheduled_removal', expect.anything());
|
||||
expect((actions.Update.$if as () => boolean)()).toBe(true);
|
||||
expect((actions.ResetPassword.$if as () => boolean)()).toBe(true);
|
||||
});
|
||||
|
||||
it('offers restoration with a valid date and hides edits for a deleted account', () => {
|
||||
const format = vi.fn((key: string, _options?: unknown) => key);
|
||||
const user = { id: 'other', deletedAt: '2026-10-17T12:00:00Z', status: UserStatus.Deleted } as UserAdminResponseDto;
|
||||
const actions = getUserAdminActions(format as MessageFormatter, user);
|
||||
expect((actions.Restore.$if as () => boolean)()).toBe(true);
|
||||
expect(format).toHaveBeenCalledWith('admin.user_restore_scheduled_removal', {
|
||||
values: { date: new Date('2026-10-24T12:00:00Z') },
|
||||
});
|
||||
for (const action of [actions.Update, actions.Delete, actions.ResetPassword, actions.ResetPinCode]) {
|
||||
expect((action.$if as () => boolean)()).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps destructive account actions hidden for the current administrator', () => {
|
||||
const format = vi.fn((key: string) => key);
|
||||
const actions = getUserAdminActions(
|
||||
format as MessageFormatter,
|
||||
{ id: 'self', deletedAt: null } as UserAdminResponseDto,
|
||||
);
|
||||
expect((actions.Delete.$if as () => boolean)()).toBe(false);
|
||||
expect((actions.ResetPassword.$if as () => boolean)()).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -65,9 +65,9 @@ export const getUserAdminActions = ($t: MessageFormatter, user: UserAdminRespons
|
||||
icon: mdiDeleteRestore,
|
||||
title: $t('restore'),
|
||||
color: 'primary',
|
||||
data: {
|
||||
title: $t('admin.user_restore_scheduled_removal', { values: { date: getDeleteDate(user.deletedAt!) } }),
|
||||
},
|
||||
data: user.deletedAt
|
||||
? { title: $t('admin.user_restore_scheduled_removal', { values: { date: getDeleteDate(user.deletedAt) } }) }
|
||||
: undefined,
|
||||
$if: () => !!user.deletedAt && user.status === UserStatus.Deleted,
|
||||
onAction: () => modalManager.show(UserRestoreConfirmModal, { user }),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user