mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
fix(web): handle deleted user on details page (#18264)
This commit is contained in:
parent
989d9dbe51
commit
3fdc1df89c
@ -1867,6 +1867,7 @@
|
||||
"use_current_connection": "use current connection",
|
||||
"use_custom_date_range": "Use custom date range instead",
|
||||
"user": "User",
|
||||
"user_has_been_deleted": "This user has been deleted.",
|
||||
"user_id": "User ID",
|
||||
"user_liked": "{user} liked {type, select, photo {this photo} video {this video} asset {this asset} other {it}}",
|
||||
"created_at": "Created",
|
||||
|
@ -4,12 +4,12 @@
|
||||
import ConfirmModal from '$lib/modals/ConfirmModal.svelte';
|
||||
import { serverConfig } from '$lib/stores/server-config.store';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { deleteUserAdmin, type UserResponseDto } from '@immich/sdk';
|
||||
import { deleteUserAdmin, type UserAdminResponseDto, type UserResponseDto } from '@immich/sdk';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
user: UserResponseDto;
|
||||
onClose: (confirmed?: true) => void;
|
||||
onClose: (user?: UserAdminResponseDto) => void;
|
||||
}
|
||||
|
||||
let { user, onClose }: Props = $props();
|
||||
@ -20,14 +20,12 @@
|
||||
|
||||
const handleDeleteUser = async () => {
|
||||
try {
|
||||
const { deletedAt } = await deleteUserAdmin({
|
||||
const result = await deleteUserAdmin({
|
||||
id: user.id,
|
||||
userAdminDeleteDto: { force: forceDelete },
|
||||
});
|
||||
|
||||
if (deletedAt !== undefined) {
|
||||
onClose(true);
|
||||
}
|
||||
onClose(result);
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_delete_user'));
|
||||
}
|
||||
|
@ -1,34 +1,30 @@
|
||||
<script lang="ts">
|
||||
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
||||
import ConfirmModal from '$lib/modals/ConfirmModal.svelte';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { restoreUserAdmin, type UserResponseDto } from '@immich/sdk';
|
||||
import { restoreUserAdmin, type UserAdminResponseDto, type UserResponseDto } from '@immich/sdk';
|
||||
import { Button, Modal, ModalBody, ModalFooter } from '@immich/ui';
|
||||
import { mdiDeleteRestore } from '@mdi/js';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
interface Props {
|
||||
user: UserResponseDto;
|
||||
onClose: (confirmed?: true) => void;
|
||||
onClose: (user?: UserAdminResponseDto) => void;
|
||||
}
|
||||
|
||||
let { user, onClose }: Props = $props();
|
||||
|
||||
const handleRestoreUser = async () => {
|
||||
try {
|
||||
await restoreUserAdmin({ id: user.id });
|
||||
onClose(true);
|
||||
const result = await restoreUserAdmin({ id: user.id });
|
||||
onClose(result);
|
||||
} catch (error) {
|
||||
handleError(error, $t('errors.unable_to_restore_user'));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<ConfirmModal
|
||||
title={$t('restore_user')}
|
||||
confirmText={$t('continue')}
|
||||
confirmColor="success"
|
||||
onClose={(confirmed) => (confirmed ? handleRestoreUser() : onClose())}
|
||||
>
|
||||
{#snippet promptSnippet()}
|
||||
<Modal title={$t('restore_user')} {onClose} icon={mdiDeleteRestore} size="small" class="bg-light text-dark">
|
||||
<ModalBody>
|
||||
<p>
|
||||
<FormatMessage key="admin.user_restore_description" values={{ user: user.name }}>
|
||||
{#snippet children({ message })}
|
||||
@ -36,5 +32,16 @@
|
||||
{/snippet}
|
||||
</FormatMessage>
|
||||
</p>
|
||||
{/snippet}
|
||||
</ConfirmModal>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<div class="flex gap-3 w-full">
|
||||
<Button shape="round" color="secondary" fullWidth onclick={() => onClose()}>
|
||||
{$t('cancel')}
|
||||
</Button>
|
||||
<Button shape="round" color="primary" fullWidth onclick={() => handleRestoreUser()}>
|
||||
{$t('restore')}
|
||||
</Button>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
|
@ -18,8 +18,8 @@
|
||||
import { websocketEvents } from '$lib/stores/websocket';
|
||||
import { getByteUnitString } from '$lib/utils/byte-units';
|
||||
import { UserStatus, searchUsersAdmin, type UserAdminResponseDto } from '@immich/sdk';
|
||||
import { Button, IconButton, Link } from '@immich/ui';
|
||||
import { mdiDeleteRestore, mdiInfinity, mdiPencilOutline, mdiTrashCanOutline } from '@mdi/js';
|
||||
import { Button, HStack, IconButton, Link, Text } from '@immich/ui';
|
||||
import { mdiDeleteRestore, mdiInfinity, mdiPencilOutline, mdiPlusBoxOutline, mdiTrashCanOutline } from '@mdi/js';
|
||||
import { DateTime } from 'luxon';
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
@ -86,6 +86,13 @@
|
||||
</script>
|
||||
|
||||
<UserPageLayout title={data.meta.title} admin>
|
||||
{#snippet buttons()}
|
||||
<HStack gap={1}>
|
||||
<Button leadingIcon={mdiPlusBoxOutline} onclick={handleCreate} size="small" variant="ghost" color="secondary">
|
||||
<Text class="hidden md:block">{$t('create_user')}</Text>
|
||||
</Button>
|
||||
</HStack>
|
||||
{/snippet}
|
||||
<section id="setting-content" class="flex place-content-center sm:mx-4">
|
||||
<section class="w-full pb-28 lg:w-[850px]">
|
||||
<table class="my-5 w-full text-start">
|
||||
@ -163,7 +170,6 @@
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
<Button shape="round" size="small" onclick={handleCreate}>{$t('create_user')}</Button>
|
||||
</section>
|
||||
</section>
|
||||
</UserPageLayout>
|
||||
|
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import StatsCard from '$lib/components/admin-page/server-stats/stats-card.svelte';
|
||||
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
|
||||
import {
|
||||
@ -7,17 +6,18 @@
|
||||
NotificationType,
|
||||
} from '$lib/components/shared-components/notification/notification';
|
||||
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
|
||||
import { AppRoute } from '$lib/constants';
|
||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||
import PasswordResetSuccessModal from '$lib/modals/PasswordResetSuccessModal.svelte';
|
||||
import UserDeleteConfirmModal from '$lib/modals/UserDeleteConfirmModal.svelte';
|
||||
import UserEditModal from '$lib/modals/UserEditModal.svelte';
|
||||
import UserRestoreConfirmModal from '$lib/modals/UserRestoreConfirmModal.svelte';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { user as authUser } from '$lib/stores/user.store';
|
||||
import { getBytesWithUnit } from '$lib/utils/byte-units';
|
||||
import { handleError } from '$lib/utils/handle-error';
|
||||
import { updateUserAdmin } from '@immich/sdk';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Card,
|
||||
CardBody,
|
||||
@ -40,6 +40,7 @@
|
||||
mdiChartPie,
|
||||
mdiChartPieOutline,
|
||||
mdiCheckCircle,
|
||||
mdiDeleteRestore,
|
||||
mdiFeatureSearchOutline,
|
||||
mdiLockSmart,
|
||||
mdiOnepassword,
|
||||
@ -80,7 +81,14 @@
|
||||
const handleDelete = async () => {
|
||||
const result = await modalManager.show(UserDeleteConfirmModal, { user });
|
||||
if (result) {
|
||||
await goto(AppRoute.ADMIN_USERS);
|
||||
user = result;
|
||||
}
|
||||
};
|
||||
|
||||
const handleRestore = async () => {
|
||||
const result = await modalManager.show(UserRestoreConfirmModal, { user });
|
||||
if (result) {
|
||||
user = result;
|
||||
}
|
||||
};
|
||||
|
||||
@ -191,19 +199,36 @@
|
||||
>
|
||||
<Text class="hidden md:block">{$t('edit_user')}</Text>
|
||||
</Button>
|
||||
<Button
|
||||
color="danger"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
leadingIcon={mdiTrashCanOutline}
|
||||
onclick={() => handleDelete()}
|
||||
>
|
||||
<Text class="hidden md:block">{$t('delete_user')}</Text>
|
||||
</Button>
|
||||
{#if user.deletedAt}
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
leadingIcon={mdiDeleteRestore}
|
||||
class="ms-1"
|
||||
onclick={() => handleRestore()}
|
||||
>
|
||||
<Text class="hidden md:block">{$t('restore_user')}</Text>
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
color="danger"
|
||||
size="small"
|
||||
variant="ghost"
|
||||
leadingIcon={mdiTrashCanOutline}
|
||||
onclick={() => handleDelete()}
|
||||
>
|
||||
<Text class="hidden md:block">{$t('delete_user')}</Text>
|
||||
</Button>
|
||||
{/if}
|
||||
</HStack>
|
||||
{/snippet}
|
||||
<div>
|
||||
<Container size="large" center>
|
||||
{#if user.deletedAt}
|
||||
<Alert color="danger" class="my-4" title={$t('user_has_been_deleted')} icon={mdiTrashCanOutline} />
|
||||
{/if}
|
||||
|
||||
<div class="grid gap-4 grod-cols-1 lg:grid-cols-2 w-full">
|
||||
<div class="col-span-full flex gap-4 items-center my-4">
|
||||
<UserAvatar {user} size="md" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user